def p_var_list(p): ''' var_list : identifier | var_list COMMA identifier ''' if len(p) == 2: p[1] = Node(p[1], args=None, attrs={ 'name': 'identifier', 'line': p.lineno(1), 'terminal': True }) p[0] = Node('var_list', args=[p[1]], attrs={'operator': OperatorType.N_ARY}) else: p[0] = p[1] p[1].args.append( Node(p[3], args=None, attrs={ 'name': 'identifier', 'line': p.lineno(3), 'terminal': True }))
def p_program(p): ''' program : function_def program | decl program | function_decl program | empty ''' if len(p) == 2: p[0] = None return if p[2] is None: p[0] = Node('program', args=[p[1]]) else: p[0] = Node('program', args=[p[1], *p[2].args])
def handle_function_def(node_stack, table_stack, node): msg = table_stack[0].set( node.args[0].symbol, Symbol( table_stack[0].scope, SymbolType.FUNCTION, { 'init': True, 'type': node.args[0].attrs['type'], 'name': node.args[0], 'arg_type': node.args[1].attrs['type'], 'arg': node.args[1], 'line': node.attrs['line'] })) info(table_stack[0].get(node.args[0].symbol), usage=False) if msg: log.error(msg) return Signal.CONTINUE table_stack.append(SymbolTable(SymbolScope.LOCAL, name=node.args[0].symbol)) table_stack[-1].set( node.args[1].symbol, Symbol( table_stack[-1].scope, SymbolType.VARIABLE, { 'value': None, 'type': node.args[1].attrs['type'], 'name': node.args[1], 'line': node.attrs.get('line') })) # psuedo node to mark function exit node_stack.append(Node('function_def_end', args=[node.args[0]], attrs={})) return_node = None node_stack.append(node.args[2])
def generate_function(node_stack, table_stack, table_cache, function): function_identifier = function.args[0] function_argument = function.args[1] function_body = function.args[2] table_stack.append(table_cache[function_identifier.symbol]) node_stack.append( Node('function_def_end', args=[function_identifier], attrs={})) output = [] # generate local variables generate_memory(table_stack[-1], True) function_symbol = table_stack[0].get(function.args[0].symbol) output.append(ASM('LABEL', function_symbol.attrs['label'])) # function is not main if function_identifier.symbol != 'main': output.append( ASM('POP', table_stack[-1].get(function_argument.symbol).get('memory'))) output.append(generate_body(table_stack, function_body)) if table_stack[-1].name == 'main': # if main then just exit the program since we're at the end output.append(ASM('STOP')) else: # if another function then let's return output.append(ASM('RETURN')) table_stack.pop() return output
def p_body(p): ''' body : LBRACE body_prime RBRACE ''' if p[2] is None: p[0] = Node('body', args=[]) else: p[0] = p[2]
def p_function_call(p): ''' function_call : identifier LPAR expr RPAR ''' p[1] = Node(p[1], args=None, attrs={ 'name': 'identifier', 'line': p.lineno(1), 'terminal': True }) p[0] = Node('function_call', args=[p[1], p[3]], attrs={ 'line': p.lineno(1), 'operator': OperatorType.BINARY })
def p_function_decl(p): ''' function_decl : kind identifier LPAR kind RPAR SEMI ''' p[2] = Node(p[2], args=None, attrs={ 'type': p[1].symbol, 'name': 'identifier', 'line': p.lineno(1), 'terminal': True }) p[0] = Node('function_decl', args=[p[2]], attrs={ 'type': p[4].symbol, 'line': p.lineno(2), 'operator': OperatorType.UNARY })
def p_stmt_prime(p): ''' stmt_prime : stmt stmt_prime | empty ''' if len(p) == 2: p[0] = None else: if p[2] is None: p[0] = p[1] else: p[0] = Node('stmt_prime', args=[p[1], p[2]])
def p_body_prime(p): ''' body_prime : decl body_prime | stmt body_prime | empty ''' if len(p) == 2: p[0] = None else: p[0] = Node('body', args=[p[1]]) if p[2] is not None: p[0].args.extend(p[2].args)
def p_expr(p): ''' expr : identifier ASSIGN expr | expr1 ''' if len(p) == 4: p[1] = Node(p[1], args=None, attrs={ 'name': 'identifier', 'line': p.lineno(1) }) p[0] = Node(p[2], args=[p[1], p[3]], attrs={ 'name': 'ASSIGN', 'line': p.lineno(1), 'operator': OperatorType.BINARY }) else: p[0] = p[1]
def p_factor(p): ''' factor : identifier | integer_literal | float_literal | function_call | LPAR expr RPAR ''' if len(p) == 2: if isinstance(p[1], str): p[0] = Node(p[1], args=None, attrs={ 'name': 'identifier', 'line': p.lineno(1), 'terminal': True }) elif isinstance(p[1], float): p[0] = Node(p[1], args=None, attrs={ 'name': 'float_literal', 'line': p.lineno(1), 'terminal': True, 'type': float }) elif isinstance(p[1], int): p[0] = Node(p[1], args=None, attrs={ 'name': 'integer_literal', 'line': p.lineno(1), 'terminal': True, 'type': int }) else: p[0] = p[1] else: p[0] = p[2]
def p_write_expr_list(p): ''' write_expr_list : expr write_expr_list_prime | string write_expr_list_prime ''' # expr if not isinstance(p[1], Node): p[1] = Node(p[1], args=[], attrs={ 'name': 'string', 'terminal': True, 'line': p.lineno(1) }) node = Node('write_expr_list', args=[p[1]]) if p[2] is None: p[0] = node else: p[0] = p[2] p[0].args = [p[1], *p[2].args]
def p_kind(p): ''' kind : int_kw | float_kw ''' if p[1] == 'int': p[0] = Node(int, args=None, attrs={ 'name': 'int_kw', 'type': int, 'line': p.lineno(1), 'terminal': True }) else: p[0] = Node(float, args=None, attrs={ 'name': 'float_kw', 'type': float, 'line': p.lineno(1), 'terminal': True })
def p_addop(p): ''' addop : PLUS | MINUS ''' if p[1] == '+': p[0] = Node(p[1], args=None, attrs={ 'name': 'PLUS', 'line': p.lineno(1), 'terminal': True, 'operator': OperatorType.BINARY }) else: p[0] = Node(p[1], args=None, attrs={ 'name': 'MINUS', 'line': p.lineno(1), 'terminal': True, 'operator': OperatorType.BINARY })
def p_mulop(p): ''' mulop : DIVIDE | MULTIPLY ''' if p[1] == '*': p[0] = Node(p[1], args=None, attrs={ 'name': 'MULTIPLY', 'line': p.lineno(1), 'terminal': True, 'operator': OperatorType.BINARY }) else: p[0] = Node(p[1], args=None, attrs={ 'name': 'DIVIDE', 'line': p.lineno(1), 'terminal': True, 'operator': OperatorType.BINARY })
def p_function_def(p): ''' function_def : kind identifier LPAR kind identifier RPAR body ''' p[2] = Node(p[2], args=None, attrs={ 'type': p[1].symbol, 'name': 'identifier', 'terminal': True }) p[5] = Node(p[5], args=None, attrs={ 'type': p[4].symbol, 'name': 'identifier', 'terminal': True }) p[0] = Node('function_def', args=[p[2], p[5], p[7]], attrs={ 'line': p.lineno(2), 'operator': OperatorType.TRINARY })
def p_uminus(p): ''' uminus : MINUS factor %prec uminus | factor ''' if p[1] == '-': p[0] = Node(p[1], args=[p[2]], attrs={ 'terminal': True, 'line': p.lineno(1), 'operator': OperatorType.UNARY }) else: p[0] = p[1]
def p_decl(p): ''' decl : kind var_list SEMI ''' for var in p[2].args: var.attrs['type'] = p[1].symbol p[0] = Node('decl', args=[*p[2].args], attrs={ 'name': 'decl', 'line': p.lineno(2), 'type': p[1].symbol, 'terminal': False })
def p_else_stmt(p): ''' else_stmt : else_kw stmt | empty ''' if len(p) == 2: p[0] = None else: p[0] = Node(p[1], args=[p[2]], attrs={ 'name': 'else_kw', 'terminal': True, 'line': p.lineno(1) })
def p_boolop(p): ''' boolop : LT | GT | EQUAL | LE | GE ''' name_map = {'<': 'LT', '>': 'GT', '==': 'EQUAL', '<=': 'LE', '>=': 'GE'} p[0] = Node(p[1], args=None, attrs={ 'name': name_map[p[1]], 'line': p.lineno(1), 'terminal': True, 'operator': OperatorType.BINARY })
def p_stmt(p): ''' stmt : expr SEMI | if_kw LPAR bool_expr RPAR stmt else_stmt | while_kw LPAR bool_expr RPAR stmt | read_kw var_list SEMI | write_kw write_expr_list SEMI | return_kw expr SEMI | LBRACE stmt_prime RBRACE ''' # expr if len(p) == 3: p[0] = p[1] else: if p[1] == 'if': if p[6] is None: p[0] = Node(p[1], args=[p[3], p[5]]) else: p[0] = Node(p[1], args=[p[3], p[5], p[6]]) elif p[1] == 'while': p[0] = Node(p[1], args=[p[3], p[5]], attrs={ 'name': 'while_kw', 'terminal': True, 'line': p.lineno(1), 'operator': OperatorType.BINARY }) elif p[1] == 'read': p[0] = Node(p[1], args=[*p[2].args], attrs={ 'name': 'read_kw', 'terminal': True, 'line': p.lineno(1), 'operator': OperatorType.N_ARY }) elif p[1] == 'write': p[0] = Node(p[1], args=[*p[2].args], attrs={ 'name': 'write_kw', 'terminal': True, 'line': p.lineno(1), 'operator': OperatorType.N_ARY }) elif p[1] == 'return': p[0] = Node(p[1], args=[p[2]], attrs={ 'name': 'return_kw', 'terminal': True, 'line': p.lineno(1), 'operator': OperatorType.UNARY }) elif p[1] == '{': p[0] = p[2] else: p[0] = p[1]