diff options
author | jaseg <git@jaseg.de> | 2021-11-10 21:39:03 +0100 |
---|---|---|
committer | jaseg <git@jaseg.de> | 2021-11-10 21:39:03 +0100 |
commit | d21a2e67ff34d3f29e37a01f926b9e8f72003637 (patch) | |
tree | 8218f339a3336283c060aa5657a76a463b8e1982 /gerbonara/gerber/am_read.py | |
parent | 125eb821b9f5d4c58b17d43e318e9a6829120d03 (diff) | |
download | gerbonara-d21a2e67ff34d3f29e37a01f926b9e8f72003637.tar.gz gerbonara-d21a2e67ff34d3f29e37a01f926b9e8f72003637.tar.bz2 gerbonara-d21a2e67ff34d3f29e37a01f926b9e8f72003637.zip |
WIP
Diffstat (limited to 'gerbonara/gerber/am_read.py')
-rw-r--r-- | gerbonara/gerber/am_read.py | 255 |
1 files changed, 0 insertions, 255 deletions
diff --git a/gerbonara/gerber/am_read.py b/gerbonara/gerber/am_read.py deleted file mode 100644 index c50bd01..0000000 --- a/gerbonara/gerber/am_read.py +++ /dev/null @@ -1,255 +0,0 @@ -#! /usr/bin/env python -# -*- coding: utf-8 -*- - -# copyright 2014 Hamilton Kibbe <ham@hamiltonkib.be> -# copyright 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. -""" This module provides RS-274-X AM macro modifiers parsing. -""" - -from .am_opcode import OpCode - -import string - -class Token: - ADD = "+" - SUB = "-" - # compatibility as many gerber writes do use non compliant X - MULT = ("x", "X") - DIV = "/" - OPERATORS = (ADD, SUB, *MULT, DIV) - LEFT_PARENS = "(" - RIGHT_PARENS = ")" - EQUALS = "=" - EOF = "EOF" - - -def token_to_opcode(token): - if token == Token.ADD: - return OpCode.ADD - elif token == Token.SUB: - return OpCode.SUB - elif token in Token.MULT: - return OpCode.MUL - elif token == Token.DIV: - return OpCode.DIV - else: - return None - - -def precedence(token): - if token == Token.ADD or token == Token.SUB: - return 1 - elif token in Token.MULT or token == Token.DIV: - return 2 - else: - return 0 - - -def is_op(token): - return token in Token.OPERATORS - - -class Scanner: - - def __init__(self, s): - self.buff = s - self.n = 0 - - def eof(self): - return self.n == len(self.buff) - - def peek(self): - if not self.eof(): - return self.buff[self.n] - - return Token.EOF - - def ungetc(self): - if self.n > 0: - self.n -= 1 - - def getc(self): - if self.eof(): - return "" - - c = self.buff[self.n] - self.n += 1 - return c - - def readint(self): - n = "" - while not self.eof() and (self.peek() in string.digits): - n += self.getc() - return int(n) - - def readfloat(self): - n = "" - while not self.eof() and (self.peek() in string.digits or self.peek() == "."): - n += self.getc() - # weird case where zero is ommited inthe last modifider, like in ',0.' - if n == ".": - return 0 - return float(n) - - def readstr(self, end="*"): - s = "" - while not self.eof() and self.peek() != end: - s += self.getc() - return s.strip() - - -def print_instructions(instructions): - for opcode, argument in instructions: - print("%s %s" % (OpCode.str(opcode), - str(argument) if argument is not None else "")) - - -def read_macro(macro): - instructions = [] - - for block in macro.split("*"): - - is_primitive = False - is_equation = False - - found_equation_left_side = False - found_primitive_code = False - - equation_left_side = 0 - primitive_code = 0 - - unary_minus_allowed = False - unary_minus = False - - if Token.EQUALS in block: - is_equation = True - else: - is_primitive = True - - scanner = Scanner(block) - - # inlined here for compactness and convenience - op_stack = [] - - def pop(): - return op_stack.pop() - - def push(op): - op_stack.append(op) - - def top(): - return op_stack[-1] - - def empty(): - return len(op_stack) == 0 - - while not scanner.eof(): - - c = scanner.getc() - - if c == ",": - found_primitive_code = True - - # add all instructions on the stack to finish last modifier - while not empty(): - instructions.append((token_to_opcode(pop()), None)) - - unary_minus_allowed = True - - elif c in Token.OPERATORS: - if c == Token.SUB and unary_minus_allowed: - unary_minus = True - unary_minus_allowed = False - continue - - while not empty() and is_op(top()) and precedence(top()) >= precedence(c): - instructions.append((token_to_opcode(pop()), None)) - - push(c) - - elif c == Token.LEFT_PARENS: - push(c) - - elif c == Token.RIGHT_PARENS: - while not empty() and top() != Token.LEFT_PARENS: - instructions.append((token_to_opcode(pop()), None)) - - if empty(): - raise ValueError("unbalanced parentheses") - - # discard "(" - pop() - - elif c.startswith("$"): - n = scanner.readint() - - if is_equation and not found_equation_left_side: - equation_left_side = n - else: - instructions.append((OpCode.LOAD, n)) - - elif c == Token.EQUALS: - found_equation_left_side = True - - elif c == "0": - if is_primitive and not found_primitive_code: - instructions.append((OpCode.PUSH, scanner.readstr("*"))) - found_primitive_code = True - else: - # decimal or integer disambiguation - if scanner.peek() not in '.' or scanner.peek() == Token.EOF: - instructions.append((OpCode.PUSH, 0)) - - elif c in "123456789.": - scanner.ungetc() - - if is_primitive and not found_primitive_code: - primitive_code = scanner.readint() - else: - n = scanner.readfloat() - if unary_minus: - unary_minus = False - n *= -1 - - instructions.append((OpCode.PUSH, n)) - else: - # whitespace or unknown char - pass - - # add all instructions on the stack to finish last modifier (if any) - while not empty(): - instructions.append((token_to_opcode(pop()), None)) - - # at end, we either have a primitive or a equation - if is_primitive and found_primitive_code: - instructions.append((OpCode.PRIM, primitive_code)) - - if is_equation: - instructions.append((OpCode.STORE, equation_left_side)) - - return instructions - -if __name__ == '__main__': - import sys - - instructions = read_macro(sys.argv[1]) - - print("insructions:") - print_instructions(instructions) - - print("eval:") - from .am_primitive import eval_macro - for primitive in eval_macro(instructions, 'mm'): - print(primitive) |