summaryrefslogtreecommitdiff
path: root/gerbonara/gerber/am_read.py
diff options
context:
space:
mode:
authorjaseg <git@jaseg.de>2021-11-10 21:39:03 +0100
committerjaseg <git@jaseg.de>2021-11-10 21:39:03 +0100
commitd21a2e67ff34d3f29e37a01f926b9e8f72003637 (patch)
tree8218f339a3336283c060aa5657a76a463b8e1982 /gerbonara/gerber/am_read.py
parent125eb821b9f5d4c58b17d43e318e9a6829120d03 (diff)
downloadgerbonara-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.py255
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)