def __init__(self, name, index=None): if not isValidIdentifier(name): raise ManoParserError('Invalid base identifier name.') if index and not isValidIdentifier(index): raise ManoParserError('Invalid index identifier name.') self.name = name self.index = index
def __init__(self, operator, operand): if operator not in UNARY_OPS: raise ManoParserError('Invalid unary operator.') if not isValidIdentifier(operand): raise ManoParserError('Invalid operand for unary operator %s.' % operator) self.operator = operator self.operand = operand
def addVar(self, name, typ): if not isValidIdentifier(name): raise ManoParserError('Invalid identifier name.') if name in self.vars or name in self.params: raise ManoParserError('Duplicate variable declaration.') if not isinstance(typ, Type): raise ManoParserError('Attempted assign a non-Type object as ' 'variable type.') self.vars[name] = (typ, None)
def addParam(self, name, typ): if not isValidIdentifier(name): raise ManoParserError('Invalid identifier name.') if name in self.vars or name in self.params: raise ManoParserError('Duplicate parameter declaration.') if not isinstance(typ, Type): raise ManoParserError('Attempted to assign a non-Type object as ' 'parameter type.') self.params.append(name) self.vars[name] = (typ, None)
def __init__(self, operator, left, right): if operator not in BINARY_OPS: raise ManoParserError('Invalid binary operator.') if not isValidIdentifier(left): raise ManoParserError('Invalid left operand for operator %s.' % operator) if not isValidIdentifier(right): raise ManoParserError('Invalid right operand for operator %s.' % operator) self.operator = operator self.left = left self.right = right
def __init__(self, name, size=None): if name == 'WORD': self.name = name self.size = 1 elif name in ('STRING', 'ARRAY'): if size is not None and size > 0: self.name = name self.size = size else: raise ManoParserError('Invalid var size.') else: raise ManoParserError('Invalid type.')
def __init__(self, function, arguments): if not isValidIdentifier(function): raise ManoParserError('Invalid function identifier in call expression.') self.function = function self.arguments = [] for i in arguments: if not isValidIdentifier(i): raise ManoParserError('Invalid argument identifier in call expression.') self.arguments.append(i)
def __init__(self, target, expression, index=None, label=None, condition=None): if target and not isValidIdentifier(target): raise ManoParserError('Invalid identifier in assignment statement.') if index and not isValidIdentifier(index): raise ManoParserError('Invalid index in assignment statement.') if not isinstance(expression, Expression): raise ManoParserError('Invalid expression in assignment statement.') self.target = target self.index = index self.expression = expression CodeLine.__init__(self, label, condition)
def addConst(self, name, typ, value=None): if not isValidIdentifier(name): raise ManoParserError('Invalid const identifier.') if name in self.vars or name in self.params: raise ManoParserError('Duplicate constant declaration.') if not isinstance(typ, Type): raise ManoParserError('Attempted to assign a non-Type object as ' 'constant type.') if not isValueOfType(value, typ): raise ManoParserError('Attempted to assign an invalid default value.') self.vars[name] = (typ, value)
def parse_func_head(tokenlist, func): line = tokenlist.read() try: key = line.pop(0) if key != 'FUNC': raise ManoParserError('Non-function statement in global scope.') name = line.pop(0) if not isValidIdentifier(name): print name raise ManoParserError('Invalid function name.') key = line.pop(0) if key != '(': raise ManoParserError('No parenthesis found after function name.') while line[0] != ')': vartype = parse_type(line) varname = line.pop(0) if not isValidIdentifier(varname): raise ManoParserError('Invalid parameter name.') func.addParam(varname, vartype) if line[0] == ',': line.pop(0) key = line.pop(0) if key != ')': raise ManoParserError('No parenthesis found after parameters.') key = line.pop(0) if key != 'RETURNS': raise ManoParserError( 'Could not find "RETURNS" in function header.') rettype = parse_type(line) func.setReturnType(rettype) key = line.pop(0) if key != ':': raise ManoParserError('No colon found after function header.') if len(line): raise ManoParserError('Garbage found after function header.') except IndexError: raise ManoParserError('Error parsing function header.') return name
def parse_vars(tokenlist, func): line = tokenlist.read() if line != ['VARS', ':']: raise ManoParserError('Error parsing vars header.') while tokenlist.peek() != ['CODE', ':']: line = tokenlist.read() vartype = parse_type(line) varname = line.pop(0) if not isValidIdentifier(varname): raise ManoParserError('Invalid variable name.') if len(line): raise ManoParserError('Garbage found after var declaration.') func.addVar(varname, vartype)
def parse_expression(tokens, func): if len(tokens) == 1: if isValidIdentifier(tokens[0]): return Identifier(tokens[0]) else: return Identifier(create_constant(tokens[0], func)) elif len(tokens) == 4 and tokens[1] == '[' and tokens[-1] == ']': name = tokens[0] index = tokens[2] if not isValidIdentifier(index): index = create_constant(index, func) return Identifier(name, index) elif len(tokens) >= 3 and tokens[1] == '(' and tokens[-1] == ')': calltarget = tokens[0] arg_tokens = tokens[2:-1] arguments = [] for i in xrange(0, len(arg_tokens), 2): if not isValidIdentifier(arg_tokens[i]): arguments.append(create_constant(arg_tokens[i], func)) else: arguments.append(arg_tokens[i]) return Call(calltarget, arguments) elif tokens[0] in UNARY_OPS: operator = tokens[0] operand = tokens[1] if not isValidIdentifier(operand): operand = parse_number([operand]) value = eval(operator + str(operand)) return Identifier(create_constant(str(value), func)) return UnaryOperation(operator, operand) elif tokens[1] in BINARY_OPS: operator = tokens[1] left = tokens[0] right = tokens[2] if not isValidIdentifier(left) and not isValidIdentifier(right): left = parse_number(left) right = parse_number(right) value = eval(str(left) + operator + str(right)) return Identifier(create_constant(str(value), func)) if not isValidIdentifier(left): left = create_constant(left, func) if not isValidIdentifier(right): right = create_constant(right, func) return BinaryOperation(operator, left, right) else: raise ManoParserError('Could not parse expression.')
def parse_number(tokens): num = tokens.pop(0) if num.startswith('0x'): num = int(num, 16) else: num = int(num) if num <= 0xffff: return num else: raise ManoParserError('Numeric literal too large.')
def parse_type(tokens): type = tokens.pop(0) if type == 'NONE': return None elif type == 'WORD': return Type('WORD') elif type in ('STRING', 'ARRAY'): key = tokens.pop(0) if key != '[': raise ManoParserError('Invalid type.') size = parse_number(tokens) key = tokens.pop(0) if key != ']': raise ManoParserError('Invalid type.') return Type(type, size) else: raise ManoParserError('Invalid type.')
def parse_program(text): functions = {} tokenlist = tokenizer(text) try: while tokenlist: func = Function() funcname = parse_func_head(tokenlist, func) parse_vars(tokenlist, func) parse_code(tokenlist, func) func.addCodeLine(ReturnLine()) key = tokenlist.read() if key != ['END']: raise ManoParserError('No END found after function header.') functions[funcname] = func except: raise return functions
def parse_code(tokenlist, func): line = tokenlist.read() if line != ['CODE', ':']: raise ManoParserError('Error parsing code header.') label = None while tokenlist.peek() != ['END']: try: line = tokenlist.read() # Non-statements. if line[0][0] == '#': continue elif len(line) >= 2 and line[1] == ':': label = line[0] continue # Condition condition = None if len(line) >= 2 and line[1] == '?': condition = line.pop(0) line.pop(0) # Statement. if line[0] == 'GOTO': code = GotoLine(line[1], label, condition) elif line[0] == 'READ': code = ReadLine(line[1], label, condition) elif line[0] == 'PRINT': if len(line) == 1: code = PrintLine(None, label, condition) else: if not isValidIdentifier(line[1]): line[1] = create_constant(line[1], func) code = PrintLine(line[1], label, condition) elif line[0] == 'RETURN': if len(line) > 1: code = ReturnLine(line[1], label, condition) else: code = ReturnLine(None, label, condition) elif '=' in line: target = line.pop(0) if line[0] == '[' and line[2] == ']': index = line[1] if not isValidIdentifier(index): index = create_constant(index, func) line = line[3:] else: index = None line.pop(0) # = expression = parse_expression(line, func) code = AssignLine(target, expression, index, label, condition) elif line[1] == '(' and line[-1] == ')': expression = parse_expression(line, func) code = AssignLine(None, expression, None, label, condition) else: raise ManoParserError('Could not parse statement.') except IndexError: raise ManoParserError('Error parsing statement.') func.addCodeLine(code) label = None
def __init__(self, target=None, label=None, condition=None): if target and not isValidIdentifier(target): raise ManoParserError('Invalid identifier in return statement.') self.target = target CodeLine.__init__(self, label, condition)
def setReturnType(self, typ): if typ is not None and not isinstance(typ, Type): raise ManoParserError('Attempted assign a non-Type object as function ' 'return type.') self.return_type = typ
def addCodeLine(self, line): if not isinstance(line, CodeLine): raise ManoParserError('Attempted to assign a non-CodeLine object as ' 'function code.') self.code.append(line)