diff options
author | Paulo Henrique Silva <ph.silva@gmail.com> | 2014-10-26 20:55:22 -0200 |
---|---|---|
committer | Paulo Henrique Silva <ph.silva@gmail.com> | 2014-10-26 20:55:22 -0200 |
commit | d5c8d896d87e02d32d0c0758a09f051c141006f6 (patch) | |
tree | 50e2788e5dfc63db909a3613fff6934a0e80b153 /gerber/parser.py | |
parent | d0eedf3dd7ee4fbf19f51de319e48dd964b93561 (diff) | |
parent | 4f076d7b769b0f488888d268a9a199b7545afdd7 (diff) | |
download | gerbonara-d5c8d896d87e02d32d0c0758a09f051c141006f6.tar.gz gerbonara-d5c8d896d87e02d32d0c0758a09f051c141006f6.tar.bz2 gerbonara-d5c8d896d87e02d32d0c0758a09f051c141006f6.zip |
Merge pull request #4 from hamiltonkibbe/master
Many fixes in parsing, rendering and new features
Diffstat (limited to 'gerber/parser.py')
-rw-r--r-- | gerber/parser.py | 370 |
1 files changed, 0 insertions, 370 deletions
diff --git a/gerber/parser.py b/gerber/parser.py deleted file mode 100644 index 67893af..0000000 --- a/gerber/parser.py +++ /dev/null @@ -1,370 +0,0 @@ -#! /usr/bin/env python -# -*- coding: utf-8 -*- - -# Copyright 2013-2014 Paulo Henrique Silva <ph.silva@gmail.com> - -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at - -# http://www.apache.org/licenses/LICENSE-2.0 - -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import re -import json - - -class Statement(object): - def __init__(self, type): - self.type = type - - def __str__(self): - s = "<{0} ".format(self.__class__.__name__) - - for key, value in self.__dict__.items(): - s += "{0}={1} ".format(key, value) - - s = s.rstrip() + ">" - return s - - -class ParamStmt(Statement): - def __init__(self, param): - Statement.__init__(self, "PARAM") - self.param = param - - - -class FSParamStmt(ParamStmt): - def __init__(self, param, zero="L", notation="A", x="24", y="24"): - ParamStmt.__init__(self, param) - self.zero = zero - self.notation = notation - self.x = x - self.y = y - - def to_gerber(self): - return '%FS{0}{1}X{2}Y{3}*%'.format(self.zero, self.notation, - self.x, self.y) - -class MOParamStmt(ParamStmt): - def __init__(self, param, mo): - ParamStmt.__init__(self, param) - self.mo = mo - - def to_gerber(self): - return '%MO{0}*%'.format(self.mo) - -class IPParamStmt(ParamStmt): - def __init__(self, param, ip): - ParamStmt.__init__(self, param) - self.ip = ip - - def to_gerber(self): - return '%IP{0}*%'.format(self.ip) - - -class OFParamStmt(ParamStmt): - def __init__(self, param, a, b): - ParamStmt.__init__(self, param) - self.a = a - self.b = b - - def to_gerber(self): - ret = '%OF' - if self.a: - ret += 'A' + self.a - if self.b: - ret += 'B' + self.b - return ret + '*%' - - -class LPParamStmt(ParamStmt): - def __init__(self, param, lp): - ParamStmt.__init__(self, param) - self.lp = lp - - def to_gerber(self): - return '%LP{0}*%'.format(self.lp) - - -class ADParamStmt(ParamStmt): - def __init__(self, param, d, shape, modifiers): - ParamStmt.__init__(self, param) - self.d = d - self.shape = shape - if modifiers is not None: - self.modifiers = [[x for x in m.split("X")] for m in modifiers.split(",")] - else: - self.modifiers = [] - - def to_gerber(self): - return '%ADD{0}{1},{2}*%'.format(self.d, self.shape, - ','.join(['X'.join(e) for e in self.modifiers])) - -class AMParamStmt(ParamStmt): - def __init__(self, param, name, macro): - ParamStmt.__init__(self, param) - self.name = name - self.macro = macro - - def to_gerber(self): - #think this is right... - return '%AM{0}*{1}*%'.format(self.name, self.macro) - -class INParamStmt(ParamStmt): - def __init__(self, param, name): - ParamStmt.__init__(self, param) - self.name = name - - def to_gerber(self): - return '%IN{0}*%'.format(self.name) - - -class LNParamStmt(ParamStmt): - def __init__(self, param, name): - ParamStmt.__init__(self, param) - self.name = name - - def to_gerber(self): - return '%LN{0}*%'.format(self.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 - self.i = i - self.j = j - self.op = op - - def to_gerber(self): - ret = '' - if self.function: - ret += self.function - if self.x: - ret += 'X{0}'.format(self.x) - if self.y: - ret += 'Y{0}'.format(self.y) - if self.i: - ret += 'I{0}'.format(self.i) - if self.j: - ret += 'J{0}'.format(self.j) - if self.op: - ret += self.op - return ret + '*' - - -class ApertureStmt(Statement): - def __init__(self, d): - Statement.__init__(self, "APERTURE") - self.d = int(d) - - def to_gerber(self): - return 'G54D{0}*'.format(self.d) - -class CommentStmt(Statement): - def __init__(self, comment): - Statement.__init__(self, "COMMENT") - self.comment = comment - - def to_gerber(self): - return 'G04{0}*'.format(self.comment) - -class EofStmt(Statement): - def __init__(self): - Statement.__init__(self, "EOF") - - def to_gerber(self): - return 'M02*' - -class UnknownStmt(Statement): - def __init__(self, line): - Statement.__init__(self, "UNKNOWN") - self.line = line - - -class GerberParser(object): - NUMBER = r"[\+-]?\d+" - DECIMAL = r"[\+-]?\d+([.]?\d+)?" - STRING = r"[a-zA-Z0-9_+\-/!?<>”’(){}.\|&@# :]+" - NAME = r"[a-zA-Z_$][a-zA-Z_$0-9]+" - FUNCTION = r"G\d{2}" - - COORD_OP = r"D[0]?[123]" - - FS = r"(?P<param>FS)(?P<zero>(L|T))?(?P<notation>(A|I))X(?P<x>[0-7][0-7])Y(?P<y>[0-7][0-7])" - MO = r"(?P<param>MO)(?P<mo>(MM|IN))" - IP = r"(?P<param>IP)(?P<ip>(POS|NEG))" - LP = r"(?P<param>LP)(?P<lp>(D|C))" - AD_CIRCLE = r"(?P<param>AD)D(?P<d>\d+)(?P<shape>C)[,](?P<modifiers>[^,]*)" - AD_RECT = r"(?P<param>AD)D(?P<d>\d+)(?P<shape>R)[,]?(?P<modifiers>[^,]+)?" - AD_OBROUND = r"(?P<param>AD)D(?P<d>\d+)(?P<shape>O)[,](?P<modifiers>[^,]*)" - AD_POLY = r"(?P<param>AD)D(?P<d>\d+)(?P<shape>P)[,](?P<modifiers>[^,]*)" - AD_MACRO = r"(?P<param>AD)D(?P<d>\d+)(?P<shape>{name})[,]?(?P<modifiers>[^,]+)?".format(name=NAME) - AM = r"(?P<param>AM)(?P<name>{name})\*(?P<macro>.*)".format(name=NAME) - - # begin deprecated - OF = r"(?P<param>OF)(A(?P<a>{decimal}))?(B(?P<b>{decimal}))?".format(decimal=DECIMAL) - IN = r"(?P<param>IN)(?P<name>.*)" - LN = r"(?P<param>LN)(?P<name>.*)" - # end deprecated - - PARAMS = (FS, MO, IP, LP, AD_CIRCLE, AD_RECT, AD_OBROUND, AD_POLY, AD_MACRO, AM, OF, IN, LN) - PARAM_STMT = [re.compile(r"%{0}\*%".format(p)) for p in PARAMS] - - COORD_STMT = re.compile(( - r"(?P<function>{function})?" - 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, function=FUNCTION, op=COORD_OP))) - - APERTURE_STMT = re.compile(r"(G54)?D(?P<d>\d+)\*") - - #COMMENT_STMT = re.compile(r"G04(?P<comment>{string})(\*)?".format(string=STRING)) - #spec is unclear on whether all chars allowed in comment string - - #seems reasonable to be more permissive. - COMMENT_STMT = re.compile(r"G04(?P<comment>[^*]*)(\*)?") - - EOF_STMT = re.compile(r"(?P<eof>M02)\*") - - def __init__(self, ctx=None): - self.statements = [] - self.ctx = ctx - - def parse(self, filename): - fp = open(filename, "r") - data = fp.readlines() - - for stmt in self._parse(data): - self.statements.append(stmt) - if self.ctx: - self.ctx.evaluate(stmt) - - def dump_json(self): - stmts = {"statements": [stmt.__dict__ for stmt in self.statements]} - return json.dumps(stmts) - - def dump_str(self): - s = "" - for stmt in self.statements: - s += str(stmt) + "\n" - return s - - def dump(self): - self.ctx.dump() - - def _parse(self, data): - oldline = '' - - for i, line in enumerate(data): - line = oldline + line.strip() - - # skip empty lines - if not len(line): - continue - - # deal with multi-line parameters - if line.startswith("%") and not line.endswith("%"): - oldline = line - continue - - did_something = True # make sure we do at least one loop - while did_something and len(line) > 0: - did_something = False - # coord - (coord, r) = self._match_one(self.COORD_STMT, line) - if coord: - yield CoordStmt(**coord) - line = r - did_something = True - continue - - # aperture selection - (aperture, r) = self._match_one(self.APERTURE_STMT, line) - if aperture: - yield ApertureStmt(**aperture) - - did_something = True - line = r - continue - - # comment - (comment, r) = self._match_one(self.COMMENT_STMT, line) - if comment: - yield CommentStmt(comment["comment"]) - did_something = True - line = r - continue - - # parameter - (param, r) = self._match_one_from_many(self.PARAM_STMT, line) - if param: - if param["param"] == "FS": - yield FSParamStmt(**param) - elif param["param"] == "MO": - yield MOParamStmt(**param) - elif param["param"] == "IP": - yield IPParamStmt(**param) - elif param["param"] == "LP": - yield LPParamStmt(**param) - elif param["param"] == "AD": - yield ADParamStmt(**param) - elif param["param"] == "AM": - yield AMParamStmt(**param) - elif param["param"] == "OF": - yield OFParamStmt(**param) - elif param["param"] == "IN": - yield INParamStmt(**param) - elif param["param"] == "LN": - yield LNParamStmt(**param) - else: - yield UnknownStmt(line) - did_something = True - line = r - continue - - # eof - (eof, r) = self._match_one(self.EOF_STMT, line) - if eof: - yield EofStmt() - did_something = True - line = r - continue - - if False: - print self.COORD_STMT.pattern - print self.APERTURE_STMT.pattern - print self.COMMENT_STMT.pattern - print self.EOF_STMT.pattern - for i in self.PARAM_STMT: - print i.pattern - - if line.find('*') > 0: - yield UnknownStmt(line) - did_something = True - line = "" - continue - - oldline = line - - def _match_one(self, expr, data): - match = expr.match(data) - if match is None: - return ({}, None) - else: - return (match.groupdict(), data[match.end(0):]) - - def _match_one_from_many(self, exprs, data): - for expr in exprs: - match = expr.match(data) - if match: - return (match.groupdict(), data[match.end(0):]) - - return ({}, None) |