from string import ascii_uppercase from pyparsing import * class Node(object): def __init__(self, s, loc, toks): self.children = toks def __repr__(self): return '%s(%s)' % (self.__class__.__name__, ', '.join(map(str, self.children))) @classmethod def grammar(cls, expression): return expression.setParseAction(cls) class Module(Node): def __init__(self, s, loc, toks): self.body = toks super().__init__(s, loc, toks) class Expression(Node): def __init__(self, s, loc, toks): self.left, self.op, self.right = toks[0] super().__init__(s, loc, toks) class Main(Node): def __init__(self, s, loc, toks): self.body = toks super().__init__(s, loc, toks) class AliasDefinition(Node): def __init__(self, s, loc, toks): self.alias, self.value = toks super().__init__(s, loc, toks) class Alias(Node): def __init__(self, s, loc, toks): self.alias = toks[0] super().__init__(s, loc, toks) class Assignment(Node): def __init__(self, s, loc, toks): self.left, self.right = toks super().__init__(s, loc, toks) class MemoryAssignment(Node): def __init__(self, s, loc, toks): self.left, self.right = toks super().__init__(s, loc, toks) class AugmentedAssignment(Node): def __init__(self, s, loc, toks): self.left, self.operator, self.right = toks super().__init__(s, loc, toks) class BuiltinCall(Node): def __init__(self, s, loc, toks): self.name = toks[0] self.args = toks[1:] super().__init__(s, loc, toks) class FunctionCall(Node): def __init__(self, s, loc, toks): self.name = toks[0] super().__init__(s, loc, toks) class Register(Node): def __init__(self, s, loc, toks): self.r = toks[0] super().__init__(s, loc, toks) class Name(Node): def __init__(self, s, loc, toks): self.n = toks[0] super().__init__(s, loc, toks) class Variable(Node): def __init__(self, s, loc, toks): self.v = toks[0] super().__init__(s, loc, toks) class String(Node): def __init__(self, s, loc, toks): self.s = toks[0][1:-1] super().__init__(s, loc, toks) class Hex(Node): def __init__(self, s, loc, toks): self.h = toks[0] super().__init__(s, loc, toks) @property def i(self): return int(self.h, 16) class Integer(Node): def __int__(self, s, loc, toks): super().__init__(s, loc, toks) @property def i(self): return int(self.children[0]) class MemoryLocation(Node): def __init__(self, s, loc, toks): if len(toks) == 1: self.location = toks[0] self.simple = True else: self.left, self.op, self.right = toks self.simple = False super().__init__(s, loc, toks) class ForLoop(Node): def __init__(self, s, loc, toks): self.targets, self.iterator, self.body = toks super().__init__(s, loc, toks) class FunctionDefinition(Node): def __init__(self, s, loc, toks): self.alias = toks[0] self.body = toks[1:] super().__init__(s, loc, toks) class Import(Node): def __init__(self, s, loc, toks): self.module = '.'.join(toks[0]) super().__init__(s, loc, toks) class Data(Node): def __init__(self, s, loc, toks): self.alias = toks[0] self.values = toks[1:] super().__init__(s, loc, toks) indentStack = [1] def checkPeerIndent(s,l,t): curCol = col(l,s) if curCol != indentStack[-1]: if (not indentStack) or curCol > indentStack[-1]: raise ParseFatalException(s,l,"illegal nesting") raise ParseException(s,l,"not a peer entry") def checkSubIndent(s,l,t): curCol = col(l,s) if curCol > indentStack[-1]: indentStack.append( curCol ) else: raise ParseException(s,l,"not a subentry") def checkUnindent(s,l,t): if l >= len(s): return curCol = col(l,s) if not(curCol < indentStack[-1] and curCol <= indentStack[-2]): raise ParseException(s,l,"not an unindent") def doUnindent(): indentStack.pop() INDENT = lineEnd.suppress() + empty + empty.copy().setParseAction(checkSubIndent) UNDENT = FollowedBy(empty).setParseAction(checkUnindent) UNDENT.setParseAction(doUnindent) stmt = Forward() suite = OneOrMore(empty + stmt.setParseAction(checkPeerIndent)) register = Register.grammar(Word(ascii_uppercase, exact=1)) _nameish = Word(alphas + '_', alphanums + '_') name = Name.grammar(delimitedList(_nameish, '.', True)) func_decl = Suppress("def") + _nameish + Suppress(":") func_def = FunctionDefinition.grammar(func_decl + INDENT + suite + UNDENT) alias_identifier = Alias.grammar(_nameish) maindef = Main.grammar(Suppress('main:') + INDENT + suite + UNDENT) string = String.grammar(dblQuotedString) | String.grammar(sglQuotedString) numeric = Hex.grammar(Combine('0x' + Word(hexnums, exact=4))) | Integer.grammar(Word(nums)) constant = string | numeric memloc = MemoryLocation.grammar(Suppress('[') + (register | numeric) + Optional('+' + (register | numeric)) + Suppress(']')) func_call = FunctionCall.grammar(name + Suppress("()")) builtin_names = Forward() for key in BUILTINS: builtin_names |= Word(key) builtin_call = BuiltinCall.grammar(builtin_names + Suppress("(") + Optional(delimitedList(constant)) + Suppress(")")) operand = builtin_call | func_call | constant expr = Expression.grammar(operatorPrecedence(operand, [ (Literal('<<'), 2, opAssoc.LEFT), (Literal('|'), 2, opAssoc.LEFT), ])) for_decl = Suppress('for') + Group(delimitedList(register)) + Suppress('in') + (string | alias_identifier) + Suppress(':') for_loop = ForLoop.grammar(for_decl + INDENT + Group(suite) + UNDENT) math_operator = Literal('+') | Literal('-') | Literal('*') | Literal('/') | Literal('|') | Literal('&') | Literal('<<') | Literal('>>') rvalue = (alias_identifier | memloc | numeric | expr) assignment = Assignment.grammar(register + Suppress("=") + rvalue) aug_assignment = AugmentedAssignment.grammar(register + math_operator + Suppress('=') + rvalue) mem_assignment = MemoryAssignment.grammar(memloc + Suppress('=') + (register | numeric)) stmt << (assignment | aug_assignment | mem_assignment | for_loop | func_call) alias_rvalue = (builtin_call | name | numeric | expr) aliasdef = AliasDefinition.grammar(alias_identifier + Suppress("=") + alias_rvalue) import_def = Import.grammar(Suppress('import') + Group(delimitedList(Word(alphas, alphanums), '.'))) data_rvalue = delimitedList(alias_rvalue | string, ',') datadef = Data.grammar(alias_identifier + Suppress("= data") + data_rvalue) grammar = Module.grammar(ZeroOrMore(import_def) + ZeroOrMore(datadef | aliasdef) + Optional(maindef) + ZeroOrMore(func_def))