From efe5d835eaa26d8696c3352c4e1ed42da16fe27b Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Thu, 7 Dec 2017 23:48:02 +0100 Subject: wip --- src/ee/kicad/__init__.py | 2 - src/ee/kicad/_parse_kicad_pcb.py | 146 --------------------------------------- src/ee/kicad/pcb/__init__.py | 128 ++++++++++++++++++++++++++++++++++ src/ee/kicad/sexpr/__init__.py | 123 +++++++++++++++++++++++++++++++++ 4 files changed, 251 insertions(+), 148 deletions(-) delete mode 100644 src/ee/kicad/_parse_kicad_pcb.py create mode 100644 src/ee/kicad/pcb/__init__.py create mode 100644 src/ee/kicad/sexpr/__init__.py (limited to 'src/ee/kicad') diff --git a/src/ee/kicad/__init__.py b/src/ee/kicad/__init__.py index efc20a2..8d5acd1 100644 --- a/src/ee/kicad/__init__.py +++ b/src/ee/kicad/__init__.py @@ -4,12 +4,10 @@ from ee import EeException from ee.kicad.read_schematic import read_schematic, read_schematics from ee.kicad.to_bom import to_bom, to_bom_xml from .model import * -from ._parse_kicad_pcb import parse_kicad_pcb __all__ = [ "Component", "ComponentField", - "parse_kicad_pcb", "Position", "read_schematic", "read_schematics", diff --git a/src/ee/kicad/_parse_kicad_pcb.py b/src/ee/kicad/_parse_kicad_pcb.py deleted file mode 100644 index 5ea4d1b..0000000 --- a/src/ee/kicad/_parse_kicad_pcb.py +++ /dev/null @@ -1,146 +0,0 @@ -EVENT_START = 1 -EVENT_END = 2 -EVENT_LPAREN = 3 -EVENT_RPAREN = 4 -EVENT_TEXT = 5 - -def state_to_str(s): - if s == EVENT_START: - return "EVENT_START" - if s == EVENT_END: - return "EVENT_END" - if s == EVENT_LPAREN: - return "EVENT_LPAREN" - if s == EVENT_RPAREN: - return "EVENT_RPAREN" - if s == EVENT_TEXT: - return "EVENT_TEXT" - return "UNKNOWN STATE" - -def parse_kicad_pcb(path): - class state(object): - def __init__(self): - self.f = open(path, "r")#, 128 * 1024) - self.state = EVENT_START - self.buffer = [] - - def text(self): - return self._text - - def close(self): - if self.f: - f = self.f - self.f = None - f.close() - - def _read_c(self): - # TODO: count lines and characters - if self.buffer: - c = self.buffer[0] - while c == '\n': - del self.buffer[0] - c = self.buffer[0] - return c - - c = self.f.read(1024) - if not c: - return c - - self.buffer.extend(c) - return self._read_c() - -# if self.buffer: -# c = self.buffer[0] -# del self.buffer[0] -# return c -# -# c = self.f.read(1) -# while c and c == '\n': -# c = self.f.read(1) -# return c - - def _unread(self, s): - for c in s: - self.buffer.append(c) -# print("unreading: '{}', buffer={}".format(s, str(self.buffer))) - - def _read_token(self): - s = "" - while True: - c = self._read_c() - - if not c: - return s if s else None - - if c == " ": - # Ignore leading blanks - if not s: - continue - - if c == "(" or c == ")": - if not s: - return c - self._unread(c) - return s.rstrip() - - if c == " ": - return s - - if c == "\"": - while c: - c = self._read_c() - - if c == "\"": - break - - s += c - return s - s += c - - return s.rstrip() - - def next(self): - s = self.state -# print("next: current state={}, buffer={}".format(self.state_to_str(s), self.buffer)) - self._text = None - if s == EVENT_END: - raise Exception("Invalid state, state=END") - - token = self._read_token() -# print("token={}".format(token)) - - if token is None: - self.state = EVENT_END - self.close() - return (EVENT_END, None) - - if token == "(": - self.state = EVENT_LPAREN - return (EVENT_LPAREN, None) - if token == ")": - self.state = EVENT_RPAREN - return (EVENT_RPAREN, None) - - self._text = token - self.state = EVENT_TEXT - return (EVENT_TEXT, token) - - s = state() - (event, token) = s.next() - while event != EVENT_END: - yield (event, token) - (event, token) = s.next() - -#indent = 0 -#for (event_type, text) in parse_kicad_pcb("alpha.kicad_pcb"): -# if event_type == EVENT_LPAREN: -# prefix = " " * indent -# indent = indent + 1 -# print(prefix + "(") -# elif event_type == EVENT_RPAREN: -# indent = indent - 1 -# prefix = " " * indent -# print(prefix + ")") -# elif event_type == EVENT_TEXT: -# prefix = " " * indent -# print("{}{}".format(prefix, text)) diff --git a/src/ee/kicad/pcb/__init__.py b/src/ee/kicad/pcb/__init__.py new file mode 100644 index 0000000..bfd352f --- /dev/null +++ b/src/ee/kicad/pcb/__init__.py @@ -0,0 +1,128 @@ +from .. import sexpr + +def auto_str(cls): + def __str__(self): + return str({k: [str(x) for x in v] if isinstance(v, list) else str(v) for k, v in vars(self).items()}) + + cls.__str__ = __str__ + return cls + +@auto_str +class KicadPcb(object): + def __init__(self, **kwargs): + for k, v in kwargs.items(): + setattr(self, k, v) + +@auto_str +class General(object): + def __init__(self, **kwargs): + for k, v in kwargs.items(): + setattr(self, k, v) + +@auto_str +class Module(object): + def __init__(self, **kwargs): + for k, v in kwargs.items(): + setattr(self, k, v) + +def parse(path): + count = 0 + p = sexpr.parse(path) + p = sexpr.logging_parser(p) + (event, token) = next(p) + assert event == sexpr.EVENT_LPAREN + + (event, token) = next(p) + assert event == sexpr.EVENT_TEXT and token == "kicad_pcb" + + idx = 0 + def _consume(): + nonlocal idx + idx = idx + 1 +# print("consume: idx={}".format(idx)) + (event, token) = next(p) +# print("consume: event={}".format(event)) + while event != sexpr.EVENT_RPAREN: + if event == sexpr.EVENT_LPAREN: + _consume() + elif event == sexpr.EVENT_TEXT: + pass + (event, token) = next(p) +# print("consume: event={}".format(event)) +# print("consume: done".format()) + idx = idx - 1 + + def _parse_kicad_pcb(): + modules = [] + args = {"modules": modules} + + (event, token) = next(p) + while event == sexpr.EVENT_LPAREN: + (event, token) = next(p) + if token == "version": + args[token] = _parse_text(rparen = True) + elif token == "general": + args[token] = _parse_general() + elif token == "module": + modules.append(_parse_module()) + else: + _consume() + (event, token) = next(p) + + return KicadPcb(**args) + + def _parse_text(optional = False, rparen = False): + (event, token) = next(p) + if not optional: + assert event == sexpr.EVENT_TEXT + else: + assert event == sexpr.EVENT_TEXT or event == sexpr.EVENT_RPAREN + if event == sexpr.EVENT_RPAREN: + return None + text = token + if rparen: + (event, token) = next(p) + assert event == sexpr.EVENT_RPAREN + return text + + def _parse_general(): + args = {} + + (event, token) = next(p) + while event == sexpr.EVENT_LPAREN: + (event, token) = next(p) + if token == "no_connects": + args[token] =_parse_text(rparen = True) + elif token == "area": + args[token] = (_parse_text(), _parse_text(), _parse_text(), _parse_text(rparen = True)) + elif token == "thickness": + args[token] = _parse_text(rparen = True) + else: + _consume() + (event, token) = next(p) + return General(**args) + + def _parse_module(): + args = {} + + args["footprint"] = _parse_text() + + (event, token) = next(p) + while event == sexpr.EVENT_LPAREN: + (event, token) = next(p) + if token == "layer": + args[token] = _parse_text(rparen = True) + elif token == "at": + x = _parse_text() + y = _parse_text() + rot = _parse_text(optional = True, rparen = True) + args[token] = (x, y, rot or 0) + else: + _consume() + (event, token) = next(p) + return Module(**args) + + kicad_pcb = _parse_kicad_pcb() +# (event, token) = next(p) +# assert event == sexpr.EVENT_END + return kicad_pcb diff --git a/src/ee/kicad/sexpr/__init__.py b/src/ee/kicad/sexpr/__init__.py new file mode 100644 index 0000000..a8604dc --- /dev/null +++ b/src/ee/kicad/sexpr/__init__.py @@ -0,0 +1,123 @@ +EVENT_START = 1 +EVENT_END = 2 +EVENT_LPAREN = 3 +EVENT_RPAREN = 4 +EVENT_TEXT = 5 + +def state_to_str(s): + if s == EVENT_START: + return "EVENT_START" + if s == EVENT_END: + return "EVENT_END" + if s == EVENT_LPAREN: + return "EVENT_LPAREN" + if s == EVENT_RPAREN: + return "EVENT_RPAREN" + if s == EVENT_TEXT: + return "EVENT_TEXT" + return "UNKNOWN STATE" + +def logging_parser(parser): + for (event, token) in parser: + if token: + print("SEXPR: event={}, token={}".format(state_to_str(event), token or "")) + else: + print("SEXPR: event={}".format(state_to_str(event))) + yield (event, token) + +def parse(path): + class state(object): + def __init__(self): + self.f = open(path, "r")#, 128 * 1024) + self.state = EVENT_START + self.buffer = [] + + def text(self): + return self._text + + def close(self): + if self.f: + f = self.f + self.f = None + f.close() + + def _read_c(self): + # TODO: count lines and characters + if self.buffer: + c = self.buffer[0] + del self.buffer[0] + return c + + c = self.f.read(1) + while c and c == '\n': + c = self.f.read(1) + return c + + def _unread(self, s): + for c in s: + self.buffer.append(c) + + def _read_token(self): + s = "" + while True: + c = self._read_c() + + if not c: + return s if s else None + + if c == " ": + # Ignore leading blanks + if not s: + continue + + if c == "(" or c == ")": + if not s: + return c + self._unread(c) + return s.rstrip() + + if c == " ": + return s + + if c == "\"": + while c: + c = self._read_c() + + if c == "\"": + break + + s += c + return s + s += c + + return s.rstrip() + + def next(self): + s = self.state + self._text = None + if s == EVENT_END: + raise Exception("Invalid state, state=END") + + token = self._read_token() + + if token is None: + self.state = EVENT_END + self.close() + return (EVENT_END, None) + + if token == "(": + self.state = EVENT_LPAREN + return (EVENT_LPAREN, None) + if token == ")": + self.state = EVENT_RPAREN + return (EVENT_RPAREN, None) + + self._text = token + self.state = EVENT_TEXT + return (EVENT_TEXT, token) + + s = state() + (event, token) = s.next() + while event != EVENT_END: + yield (event, token) + (event, token) = s.next() -- cgit v1.2.3