Source code for sivicncdriver.gcode.gcode

"""
A module to parse G-codes.
"""

from sivicncdriver.settings import logger

__all__ = ['parse']


class Stack:
    """
    A Simple LIFO.
    """

    def __init__(self, in_str):
        """
        __init__ method.

        :param in_str: The string which is to be stacked.
        :type in_str: str
        """
        self.in_str = in_str
        self.next = None

    def __str__(self):
        return self.in_str

    def token(self):
        """
        Yields the elements of the stack.
        """
        while len(self.in_str) > 0:
            yield self.pop()

    def pop(self):
        """
        Pop an element.

        :return: The first element of the string.
        :rtype: str
        """
        r = self.peek()
        self.next = None
        return r

    def peek(self):
        """
        Peek the next element to be popped without popping it.

        :return: The next element
        :rtype: str
        """
        if not self.next:
            self.next = self.in_str[0]
            self.in_str = self.in_str[1:]
        return self.next

    def is_empty(self):
        """
        Returns True if the stack is empty.
        """
        return len(self.in_str) <= 0

SEPARATOR = ('\n', ' ', '(', '=')


def parse_iterator(gcode):
    """
    Function used by the ``parse`` function.

    :param gcode: The gcode which is to be parsed.
    :type gcode: str
    """
    stack = Stack(gcode + '\n')
    line = 0
    for c in stack.token():
        if c in ' %':
            continue
        elif c is '(':
            com = ''
            while stack.peek() is not ')':
                com += stack.pop()
            stack.pop()  # removes the ')'
            yield ('__comment__', com, line)
        elif c is '\n':
            yield ('__next__', '__next__', line)
            line += 1
        else:
            try:
                yield (c, parse_value(stack), line)
            except ValueError:
                yield ('__error__', c, line)


[docs]def parse(gcode): """ Parse gcode. It yields a dict for each line with : name name of the code (G, M) value an integer args a dict with the code arguments, ex : {'Y':3.0} :param gcode: The gcode which is to be parsed. :type gcode: str """ name = "" value = 0 args = {} for i in parse_iterator(gcode): if i[0] == '__error__': yield {'name': '__error__', 'line': i[2], 'value': i[1]} elif not i[0] == '__next__': if i[0] == '__new_var__': name = '' value = None for a in i[1].keys(): OpNode.var[a] = i[1][a] yield { 'name': '__new_var__', 'var': a, 'value': i[1][a], 'line': i[2] } if i[0] in ('G', 'M'): name = i[0] value = i[1] elif i[0] in 'XYZIJKN': args[i[0]] = i[1] elif i[0] == '__comment__': if name is "": name = 'comment' args['comment'] = i[1] elif name is not "": yield {'name': name, 'value': value, 'args': args, 'line': i[2]} name = "" value = 0 args = {} yield {'name': name, 'value': value, 'args': args, 'line': i[2]}
def parse_value(stack): """ Parse a value in the stack. :param stack: The parser's stack. :return: The value. """ r = '' while not (stack.is_empty() or (stack.peek() in SEPARATOR and r)): r += stack.pop() return float(r)