129 lines
3 KiB
Python
129 lines
3 KiB
Python
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
import re
|
|
|
|
def red(s):
|
|
return '\033[1;31m{0}\033[0;m'.format(s)
|
|
|
|
class Statement:
|
|
pass
|
|
|
|
class ParamStmt(Statement):
|
|
pass
|
|
|
|
class CoordStmt(Statement):
|
|
pass
|
|
|
|
class ApertureStmt(Statement):
|
|
pass
|
|
|
|
class CommentStmt(Statement):
|
|
def __init__(self, comment):
|
|
self.comment = comment
|
|
|
|
class EofStmt(Statement):
|
|
pass
|
|
|
|
class UnexpectedStmt(Statement):
|
|
def __init__(self, line):
|
|
self.line = line
|
|
|
|
class GerberContext:
|
|
x = 0
|
|
y = 0
|
|
|
|
class Gerber:
|
|
NUMBER = r"[\+-]?\d+"
|
|
FUNCTION = r"G\d{2}"
|
|
STRING = r"[a-zA-Z0-9_+-/!?<>”’(){}.\|&@# :]+"
|
|
|
|
COORD_OP = r"D[0]?[123]"
|
|
|
|
PARAM_STMT = re.compile(r"%.*%")
|
|
|
|
COORD_STMT = re.compile((
|
|
r"(?P<f>{f})?"
|
|
r"(X(?P<x>{number}))?(Y(?P<y>{number}))?"
|
|
r"(I(?P<i>{number}))?(J(?P<j>{number}))?"
|
|
r"(?P<op>{op})?\*".format(number=NUMBER, f=FUNCTION, op=COORD_OP)))
|
|
|
|
APERTURE_STMT = re.compile(r"(G54)?D\d+\*")
|
|
|
|
COMMENT_STMT = re.compile(r"G04(?P<comment>{string})\*".format(string=STRING))
|
|
|
|
EOF_STMT = re.compile(r"M02\*")
|
|
|
|
def __init__(self):
|
|
self.apertures = {}
|
|
self.ctx = GerberContext()
|
|
|
|
def parse(self, filename):
|
|
|
|
fp = open(filename, "r")
|
|
data = fp.readlines()
|
|
|
|
self.tokens = list(self.tokenize(data))
|
|
for token in self.tokens:
|
|
if isinstance(token, UnexpectedStmt):
|
|
print filename
|
|
print red("[UNEXPECTED TOKEN]")
|
|
print self.COORD_STMT.pattern
|
|
print token.line
|
|
|
|
def tokenize(self, data):
|
|
multiline = None
|
|
|
|
for i, line in enumerate(data):
|
|
# remove EOL
|
|
if multiline:
|
|
line = multiline + line.strip()
|
|
else:
|
|
line = line.strip()
|
|
|
|
# deal with multi-line parameters
|
|
if line.startswith("%") and not line.endswith("%"):
|
|
multiline = line
|
|
continue
|
|
else:
|
|
multiline = None
|
|
|
|
# parameter
|
|
match = self.PARAM_STMT.match(line)
|
|
if match:
|
|
yield ParamStmt()
|
|
continue
|
|
|
|
# coord
|
|
matches = self.COORD_STMT.finditer(line)
|
|
if matches:
|
|
for match in matches:
|
|
yield CoordStmt()
|
|
continue
|
|
|
|
# aperture selection
|
|
match = self.APERTURE_STMT.match(line)
|
|
if match:
|
|
yield ApertureStmt()
|
|
continue
|
|
|
|
# comment
|
|
match = self.COMMENT_STMT.match(line)
|
|
if match:
|
|
yield CommentStmt(match.groupdict("comment"))
|
|
continue
|
|
|
|
# eof
|
|
match = self.EOF_STMT.match(line)
|
|
if match:
|
|
yield EofStmt()
|
|
continue
|
|
|
|
yield UnexpectedStmt(line)
|
|
|
|
if __name__ == "__main__":
|
|
import sys
|
|
|
|
for f in sys.argv[1:]:
|
|
g = Gerber()
|
|
g.parse(f)
|