From d97fe511790f05f069425e278ad8506bae41d0a8 Mon Sep 17 00:00:00 2001 From: Paulo Henrique Silva Date: Wed, 18 Dec 2013 18:05:48 -0200 Subject: Improved AD param parsing and other nicities. * AD parsing is improved and simplified. All modifiers are now parsed and splitted. * Refactor to remove token notation. It is not a token it is a statement. * Added simple json export --- gerber/gerber.py | 197 ++++++++++++++++++++++++------------------------------- 1 file changed, 84 insertions(+), 113 deletions(-) (limited to 'gerber') diff --git a/gerber/gerber.py b/gerber/gerber.py index 339c054..954eed1 100644 --- a/gerber/gerber.py +++ b/gerber/gerber.py @@ -2,6 +2,7 @@ # -*- coding: utf-8 -*- import re +import json def red(s): @@ -9,18 +10,19 @@ def red(s): class Statement: - def __init__(self): - pass + def __init__(self, type): + self.type = type class ParamStmt(Statement): - def __init__(self, type): - self.type = type + def __init__(self, param): + Statement.__init__(self, "PARAM") + self.param = param class FSParamStmt(ParamStmt): - def __init__(self, type, zero, notation, x, y): - ParamStmt.__init__(self, type) + def __init__(self, param, zero, notation, x, y): + ParamStmt.__init__(self, param) self.zero = zero self.notation = notation self.x = x @@ -28,89 +30,60 @@ class FSParamStmt(ParamStmt): class MOParamStmt(ParamStmt): - def __init__(self, type, mo): - ParamStmt.__init__(self, type) + def __init__(self, param, mo): + ParamStmt.__init__(self, param) self.mo = mo class IPParamStmt(ParamStmt): - def __init__(self, type, ip): - ParamStmt.__init__(self, type) + def __init__(self, param, ip): + ParamStmt.__init__(self, param) self.ip = ip class OFParamStmt(ParamStmt): - def __init__(self, type, a, b): - ParamStmt.__init__(self, type) + def __init__(self, param, a, b): + ParamStmt.__init__(self, param) self.a = a self.b = b class LPParamStmt(ParamStmt): - def __init__(self, type, lp): - ParamStmt.__init__(self, type) + def __init__(self, param, lp): + ParamStmt.__init__(self, param) self.lp = lp class ADParamStmt(ParamStmt): - def __init__(self, type, d, shape): - ParamStmt.__init__(self, type) + def __init__(self, param, d, aperture, modifiers): + ParamStmt.__init__(self, param) self.d = d - self.shape = shape - - -class ADCircleParamStmt(ADParamStmt): - def __init__(self, type, d, shape, definition): - ADParamStmt.__init__(self, type, d, shape) - self.definition = definition - - -class ADRectParamStmt(ADParamStmt): - def __init__(self, type, d, shape, definition): - ADParamStmt.__init__(self, type, d, shape) - self.definition = definition - - -class ADObroundParamStmt(ADParamStmt): - def __init__(self, type, d, shape, definition): - ADParamStmt.__init__(self, type, d, shape) - self.definition = definition - - -class ADPolyParamStmt(ADParamStmt): - def __init__(self, type, d, shape, definition): - ADParamStmt.__init__(self, type, d, shape) - self.definition = definition - - -class ADMacroParamStmt(ADParamStmt): - def __init__(self, type, d, name, definition): - ADParamStmt.__init__(self, type, d, "M") - self.name = name - self.definition = definition + self.aperture = aperture + self.modifiers = [[x for x in m.split("X")] for m in modifiers.split(",")] class AMParamStmt(ParamStmt): - def __init__(self, type, name, macro): - ParamStmt.__init__(self, type) + def __init__(self, param, name, macro): + ParamStmt.__init__(self, param) self.name = name self.macro = macro class INParamStmt(ParamStmt): - def __init__(self, type, name): - ParamStmt.__init__(self, type) + def __init__(self, param, name): + ParamStmt.__init__(self, param) self.name = name class LNParamStmt(ParamStmt): - def __init__(self, type, name): - ParamStmt.__init__(self, type) + def __init__(self, param, name): + ParamStmt.__init__(self, param) self.name = name class CoordStmt(Statement): def __init__(self, function, x, y, i, j, op): + Statement.__init__(self, "COORD") self.function = function self.x = x self.y = y @@ -121,20 +94,24 @@ class CoordStmt(Statement): class ApertureStmt(Statement): def __init__(self, d): + Statement.__init__(self, "APERTURE") self.d = int(d) class CommentStmt(Statement): def __init__(self, comment): + Statement.__init__(self, "COMMENT") self.comment = comment class EofStmt(Statement): - pass + def __init__(self): + Statement.__init__(self, "EOF") class UnknownStmt(Statement): def __init__(self, line): + Statement.__init__(self, "UNKNOWN") self.line = line @@ -206,27 +183,28 @@ class GerberContext: class Gerber: NUMBER = r"[\+-]?\d+" - FUNCTION = r"G\d{2}" + DECIMAL = r"[\+-]?\d+([.]?\d+)?" STRING = r"[a-zA-Z0-9_+\-/!?<>”’(){}.\|&@# :]+" NAME = "[a-zA-Z_$][a-zA-Z_$0-9]+" + FUNCTION = r"G\d{2}" COORD_OP = r"D[0]?[123]" - FS = r"(?PFS)(?P(L|T))(?P(A|I))X(?P[0-7][0-7])Y(?P[0-7][0-7])" - MO = r"(?PMO)(?P(MM|IN))" - IP = r"(?PIP)(?P(POS|NEG))" - LP = r"(?PLP)(?P(D|C))" - AD_CIRCLE = r"(?PADD)(?P\d+)(?PC)(?P.*)" - AD_RECT = r"(?PADD)(?P\d+)(?PR)(?P.*)" - AD_OBROUND = r"(?PADD)(?P\d+)(?PO)(?P.*)" - AD_POLY = r"(?PADD)(?P\d+)(?PP)(?P.*)" - AD_MACRO = r"(?PADD)(?P\d+)(?P[^CROP,].*)(?P.*)".format(name=NAME) - AM = r"(?PAM)(?P{name})\*(?P.*)".format(name=NAME) + FS = r"(?PFS)(?P(L|T))(?P(A|I))X(?P[0-7][0-7])Y(?P[0-7][0-7])" + MO = r"(?PMO)(?P(MM|IN))" + IP = r"(?PIP)(?P(POS|NEG))" + LP = r"(?PLP)(?P(D|C))" + AD_CIRCLE = r"(?PAD)D(?P\d+)(?PC)[,](?P[^,]*)" + AD_RECT = r"(?PAD)D(?P\d+)(?PR)[,](?P[^,]*)" + AD_OBROUND = r"(?PAD)D(?P\d+)(?PO)[,](?P[^,]*)" + AD_POLY = r"(?PAD)D(?P\d+)(?PP)[,](?P[^,]*)" + AD_MACRO = r"(?PAD)D(?P\d+)+(?P{name})[,](?P[^,]*)".format(name=NAME) + AM = r"(?PAM)(?P{name})\*(?P.*)".format(name=NAME) # begin deprecated - OF = r"(?POF)(A(?P[+-]?\d+(.?\d*)))?(B(?P[+-]?\d+(.?\d*)))?" - IN = r"(?PIN)(?P.*)" - LN = r"(?PLN)(?P.*)" + OF = r"(?POF)(A(?P{decimal}))?(B(?P{decimal}))?".format(decimal=DECIMAL) + IN = r"(?PIN)(?P.*)" + LN = r"(?PLN)(?P.*)" # end deprecated PARAMS = (FS, MO, IP, LP, AD_CIRCLE, AD_RECT, AD_OBROUND, AD_MACRO, AD_POLY, AM, OF, IN, LN) @@ -245,17 +223,22 @@ class Gerber: EOF_STMT = re.compile(r"(?PM02)\*") def __init__(self): - self.tokens = [] + self.statements = [] self.ctx = GerberContext() def parse(self, filename): fp = open(filename, "r") data = fp.readlines() - for token in self._tokenize(data): - self._evaluate(token) + for stmt in self._parse(data): + self.statements.append(stmt) + self._evaluate(stmt) - def _tokenize(self, data): + def dump(self): + stmts = {"statements": [stmt.__dict__ for stmt in self.statements]} + return json.dumps(stmts) + + def _parse(self, data): multiline = None for i, line in enumerate(data): @@ -298,32 +281,23 @@ class Gerber: # parameter param = self._match_one_from_many(self.PARAM_STMT, line) if param: - if param["type"] == "FS": + if param["param"] == "FS": yield FSParamStmt(**param) - elif param["type"] == "MO": + elif param["param"] == "MO": yield MOParamStmt(**param) - elif param["type"] == "IP": + elif param["param"] == "IP": yield IPParamStmt(**param) - elif param["type"] == "LP": + elif param["param"] == "LP": yield LPParamStmt(**param) - elif param["type"] == "AD": - if param["shape"] == "C": - yield ADCircleParamStmt(**param) - elif param["shape"] == "R": - yield ADRectParamStmt(**param) - elif param["shape"] == "O": - yield ADObroundParamStmt(**param) - elif param["shape"] == "P": - yield ADPolyParamStmt(**param) - else: - yield ADMacroParamStmt(**param) - elif param["type"] == "AM": + elif param["param"] == "AD": + yield ADParamStmt(**param) + elif param["param"] == "AM": yield AMParamStmt(**param) - elif param["type"] == "OF": + elif param["param"] == "OF": yield OFParamStmt(**param) - elif param["type"] == "IN": + elif param["param"] == "IN": yield INParamStmt(**param) - elif param["type"] == "LN": + elif param["param"] == "LN": yield LNParamStmt(**param) else: yield UnknownStmt(line) @@ -336,9 +310,6 @@ class Gerber: yield EofStmt() continue - print red("UNKNOWN TOKEN") - print "{0}:'{1}'".format(red(str(i+1)), line) - if False: print self.COORD_STMT.pattern print self.APERTURE_STMT.pattern @@ -377,38 +348,38 @@ class Gerber: return result - def _evaluate(self, token): - if isinstance(token, (CommentStmt, UnknownStmt, EofStmt)): + def _evaluate(self, stmt): + if isinstance(stmt, (CommentStmt, UnknownStmt, EofStmt)): return - elif isinstance(token, ParamStmt): - self._evaluate_param(token) + elif isinstance(stmt, ParamStmt): + self._evaluate_param(stmt) - elif isinstance(token, CoordStmt): - self._evaluate_coord(token) + elif isinstance(stmt, CoordStmt): + self._evaluate_coord(stmt) - elif isinstance(token, ApertureStmt): - self._evaluate_aperture(token) + elif isinstance(stmt, ApertureStmt): + self._evaluate_aperture(stmt) else: - raise Exception("Invalid token to evaluate") + raise Exception("Invalid statement to evaluate") - def _evaluate_param(self, param): - if param.type == "FS": - self.ctx.set_coord_format(param.zero, param.x, param.y) - self.ctx.set_coord_notation(param.notation) + def _evaluate_param(self, stmt): + if stmt.param == "FS": + self.ctx.set_coord_format(stmt.zero, stmt.x, stmt.y) + self.ctx.set_coord_notation(stmt.notation) - def _evaluate_coord(self, coord): - self.ctx.move(coord.x, coord.y) + def _evaluate_coord(self, stmt): + self.ctx.move(stmt.x, stmt.y) - def _evaluate_aperture(self, aperture): - self.ctx.aperture(aperture.d) + def _evaluate_aperture(self, stmt): + self.ctx.aperture(stmt.d) if __name__ == "__main__": import sys for f in sys.argv[1:]: - print f g = Gerber() g.parse(f) + print g.dump() -- cgit