def visitPrimary(self, parsetree: SmallCParser.PrimaryContext): try: if parsetree.INTEGER() is not None: value = int(parsetree.INTEGER().getText()) return Primary(self.environment, value) elif parsetree.REAL() is not None: real = parsetree.REAL().getText() value = float(real) return Primary(self.environment, value) elif parsetree.CHARCONST() is not None: value = parsetree.CHARCONST().getText() # We are interested in the first character after the quotation # mark return Primary(self.environment, value[1]) elif parsetree.BOOLEAN() is not None: value = parsetree.BOOLEAN().getText() == "true" return Primary(self.environment, value) elif parsetree.identifier() is not None: return self.visit(parsetree.identifier()) elif parsetree.expr() is not None: return self.visit(parsetree.expr()) elif parsetree.functioncall() is not None: return self.visit(parsetree.functioncall()) except C2PException as e: line = parsetree.start.line column = parsetree.start.column MyErrorListener().semanticError(line, column, e.msg) line = parsetree.start.line column = parsetree.start.column msg = "unrecognized primary" MyErrorListener().semanticError(line, column, msg)
def visitVariable_id(self, parsetree: SmallCParser.Variable_idContext): is_pointer = parsetree.identifier().ASTERIKS() is not None is_alias = parsetree.identifier().AMPERSAND() is not None if parsetree.identifier().array_indexing() is None: array_size = 0 array_elements = [] else: # NOTE we assumed this is an integer array_size = int(parsetree.identifier( ).array_indexing().expr().getText()) if parsetree.identifier().array_init() is not None: if parsetree.expr() is not None: line = parsetree.start.line column = parsetree.start.column msg = "Illegal initialization for array '" + \ parsetree.identifier().IDENTIFIER().getText() + "'" MyErrorListener().semanticError(line, column, msg) array_elements = self.visit( parsetree.identifier().array_init()) if is_pointer or is_alias: identifier = parsetree.identifier().getChild(1).getText() else: identifier = parsetree.identifier().getChild(0).getText() if parsetree.expr() is None: expression = None else: expression = self.visit(parsetree.expr()) return VariableIdentifier(self.environment, identifier, expression, is_pointer, is_alias, array_size, array_elements)
def visitStmt(self, parsetree: SmallCParser.StmtContext): if parsetree.compound_stmt() is not None: return self.visit(parsetree.compound_stmt()) elif parsetree.cond_stmt() is not None: return self.visit(parsetree.cond_stmt()) elif parsetree.while_stmt() is not None: return self.visit(parsetree.while_stmt()) elif parsetree.for_stmt() is not None: return self.visit(parsetree.for_stmt()) elif parsetree.BREAK() is not None: return BreakStatement(self.environment) elif parsetree.CONTINUE() is not None: return ContinueStatement(self.environment) elif parsetree.RETURN() is not None: expression = self.visit(parsetree.expr()) return ReturnStatement(self.environment, expression) elif parsetree.expr() is not None: return self.visit(parsetree.expr()) elif parsetree.assignment() is not None: return self.visit(parsetree.assignment()) elif parsetree.functioncall() is not None: return self.visit(parsetree.functioncall()) else: line = parsetree.start.line column = parsetree.start.column msg = "unrecognized statement" MyErrorListener().semanticError(line, column, msg)
def visitAssignment(self, parsetree: SmallCParser.AssignmentContext): identifier = self.visit(parsetree.identifier()) expression = self.visit(parsetree.expr()) if identifier.array_size: if parsetree.expr() is not None: line = parsetree.start.line column = parsetree.start.column msg = "Cannot reinitialize array '" + identifier.name + "'" MyErrorListener().semanticError(line, column, msg) try: return Assignment(self.environment, identifier, expression) except C2PException as e: line = parsetree.start.line column = parsetree.start.column MyErrorListener().semanticError(line, column, e.msg)
def visitExpr(self, parsetree: SmallCParser.ExprContext): if parsetree.assignment() is not None: return self.visit(parsetree.assignment()) elif parsetree.condition() is not None: return self.visit(parsetree.condition()) elif parsetree.functioncall() is not None: return self.visit(parsetree.functioncall()) else: line = parsetree.start.line column = parsetree.start.column msg = "unrecognized expression" MyErrorListener().semanticError(line, column, msg)
def visitVar_decl(self, parsetree: SmallCParser.Var_declContext): type_specifier = self.visit(parsetree.type_specifier()) type_object = type_specifier.type_object var_decl_list = self.visit(parsetree.var_decl_list()) try: return VariableDeclaration(self.environment, type_object, var_decl_list) except C2PException as e: line = parsetree.start.line column = parsetree.start.column MyErrorListener().semanticError(line, column, e.msg)
def visitFunctioncall(self, parsetree: SmallCParser.FunctioncallContext): identifier = parsetree.identifier().IDENTIFIER().getText() if parsetree.param_list() is None: parameter_list = ParameterList(self.environment, []) else: parameter_list = self.visit(parsetree.param_list()) try: return FunctionCall(self.environment, identifier, parameter_list) except C2PException as e: line = parsetree.start.line column = parsetree.start.column MyErrorListener().semanticError(line, column, e.msg)
def visitFactor(self, parsetree: SmallCParser.FactorContext): if parsetree.factor() is not None: factor = self.visit(parsetree.factor()) if parsetree.EXCLAMATIONMARK() is not None: operator = parsetree.EXCLAMATIONMARK().getText() else: operator = parsetree.MINUS().getText() try: return Factor(self.environment, factor, operator) except C2PException as e: line = parsetree.start.line column = parsetree.start.column MyErrorListener().semanticError(line, column, e.msg) return self.visit(parsetree.primary())
def visitEquation(self, parsetree: SmallCParser.EquationContext): if parsetree.equation() is not None: equation = self.visit(parsetree.equation()) term = self.visit(parsetree.term()) if parsetree.MINUS() is None: operator = parsetree.PLUS().getText() else: operator = parsetree.MINUS().getText() try: return Equation(self.environment, equation, term, operator) except C2PException as e: line = parsetree.start.line column = parsetree.start.column MyErrorListener().semanticError(line, column, e.msg) return self.visit(parsetree.term())
def visitRelation(self, parsetree: SmallCParser.RelationContext): if len(parsetree.equation()) == 2: equation1 = self.visit(parsetree.equation(0)) equation2 = self.visit(parsetree.equation(1)) if parsetree.LEFTANGLE() is not None: operator = parsetree.LEFTANGLE().getText() else: operator = parsetree.RIGHTANGLE().getText() try: return Relation(self.environment, equation1, equation2, operator) except C2PException as e: line = parsetree.start.line column = parsetree.start.column MyErrorListener().semanticError(line, column, e.msg) return self.visit(parsetree.equation(0))
def visitComparison(self, parsetree: SmallCParser.ComparisonContext): if len(parsetree.relation()) == 2: relation1 = self.visit(parsetree.relation(0)) relation2 = self.visit(parsetree.relation(1)) if parsetree.EQUALITY() is not None: operator = parsetree.EQUALITY().getText() else: operator = parsetree.NEQUALITY().getText() try: return Comparison(self.environment, relation1, relation2, operator) except C2PException as e: line = parsetree.start.line column = parsetree.start.column MyErrorListener().semanticError(line, column, e.msg) return self.visit(parsetree.relation(0))
def visitTerm(self, parsetree: SmallCParser.TermContext): if parsetree.term() is not None: term = self.visit(parsetree.term()) factor = self.visit(parsetree.factor()) if parsetree.SLASH() is not None: operator = parsetree.SLASH().getText() elif parsetree.PROCENT() is not None: operator = parsetree.PROCENT().getText() else: operator = parsetree.ASTERIKS().getText() try: return Term(self.environment, term, factor, operator) except C2PException as e: line = parsetree.start.line column = parsetree.start.column MyErrorListener().semanticError(line, column, e.msg) return self.visit(parsetree.factor())
def visitFunction_definition(self, parsetree: SmallCParser.Function_definitionContext): self.environment.symbol_table.incrementScope() self.environment.call_stack.incrementDepth() type_spec = self.visit(parsetree.type_specifier()) return_type = type_spec.type_object identifier = parsetree.identifier() func_name = identifier.IDENTIFIER().getText() return_type.is_pointer = identifier.ASTERIKS() is not None return_type.is_reference = identifier.AMPERSAND() is not None if parsetree.param_decl_list() is None: parameter_decl_list = ParameterDeclarationList( self.environment, []) else: parameter_decl_list = self.visit(parsetree.param_decl_list()) address = self.environment.call_stack.getAddress() depth = self.environment.call_stack.getNestingDepth() self.environment.symbol_table.addFunction( func_name, return_type, parameter_decl_list, address, depth - 1) if parsetree.compound_stmt() is None: # forward declaration statements = None else: # function definition statements = self.visitCompound_stmt(parsetree.compound_stmt()) self.environment.call_stack.decrementDepth() try: func = Function(self.environment, return_type, func_name, parameter_decl_list, statements, parsetree.EXTERN() is not None) return func except C2PException as e: line = parsetree.start.line column = parsetree.start.column MyErrorListener().semanticError(line, column, e.msg) self.environment.symbol_table.decrementScope()
def run(input_file, output, saveast): lexer = SmallCLexer(FileStream(input_file)) stream = CommonTokenStream(lexer) parser = SmallCParser(stream) parser.removeErrorListeners() parser.addErrorListener(MyErrorListener()) parsetree = parser.smallc_program() environment = Environment() ast = ASTGenerator(environment, parsetree).generate() if os.path.isfile(output): # empty the file so only new code is saved open(output, 'w').close() ast.generateCode(output) if saveast: ast.storeASTToDisk() draw(ast)
def visitIdentifier(self, parsetree: SmallCParser.IdentifierContext): indirection = parsetree.ASTERIKS() is not None address_of = parsetree.AMPERSAND() is not None if parsetree.array_indexing() is None: array_size = 0 else: # NOTE we assumed this is an integer array_size = int(parsetree.array_indexing().expr()) if indirection or address_of: name = parsetree.getChild(1).getText() else: name = parsetree.getChild(0).getText() try: return Identifier(self.environment, name, indirection, address_of, array_size) except C2PException as e: line = parsetree.start.line column = parsetree.start.column MyErrorListener().semanticError(line, column, e.msg)
def visitType_specifier(self, parsetree: SmallCParser.Type_specifierContext): is_const = parsetree.CONST() is not None typetext = parsetree.getChild(int(is_const)).getText() if typetext == "bool": typename = BooleanType() elif typetext == "char": typename = CharacterType() elif typetext == "int": typename = IntegerType() elif typetext == "void": typename = VoidType() elif typetext == "float": typename = FloatType() else: line = parsetree.start.line column = parsetree.start.column msg = "'" + typename + "' is not a recognized type" MyErrorListener().semanticError(line, column, msg) typename.is_const = is_const return TypeSpecifier(self.environment, typename)
def visitArray_init(self, parsetree: SmallCParser.Array_initContext): i = 2 # skip first two tokens array_elements = [] type_specifier = parsetree.parentCtx.parentCtx.parentCtx.parentCtx.type_specifier() if type_specifier.CONST() is not None: array_type = type_specifier.getChild(1).getText() else: array_type = type_specifier.getChild(0).getText() children = parsetree.getChildCount() while(i < children): child = parsetree.getChild(i) if child.INTEGER() is not None: array_elements.append(int(child.INTEGER().getText())) if array_type != "int": line = parsetree.start.line column = parsetree.start.column msg = "Element of type 'int' does not match array type '" + array_type + "'" MyErrorListener().semanticError(line, column, msg) elif child.REAL() is not None: array_elements.append(float(child.REAL().getText()[:-1])) if array_type != "float": line = parsetree.start.line column = parsetree.start.column msg = "Element of type 'float' does not match array type '" + array_type + "'" MyErrorListener().semanticError(line, column, msg) elif child.CHARCONST() is not None: array_elements.append(child.CHARCONST().getText()[1]) if array_type != "char": line = parsetree.start.line column = parsetree.start.column msg = "Element of type 'char' does not match array type '" + array_type + "'" MyErrorListener().semanticError(line, column, msg) elif child.BOOLEAN() is not None: array_elements.append(bool(child.BOOLEAN().getText())) if array_type != "bool": line = parsetree.start.line column = parsetree.start.column msg = "Element of type 'bool' does not match array type '" + array_type + "'" MyErrorListener().semanticError(line, column, msg) elif child.identifier() is not None: # extract variable identifier identifier_name = child.identifier().IDENTIFIER().getText() if child.identifier().array_indexing() is not None: line = parsetree.start.line column = parsetree.start.column msg = "We do not support array indexing in array initializations at '" + \ identifier_name + "'" MyErrorListener().semanticError(line, column, msg) # look it up in symbol table symbol = self.environment.symbol_table.getSymbol( identifier_name) if symbol is None: line = parsetree.start.line column = parsetree.start.column msg = "Use of undeclared variable identifier '" + identifier_name + "'" MyErrorListener().semanticError(line, column, msg) else: if array_type != symbol.type.getCSymbol(): line = parsetree.start.line column = parsetree.start.column msg = "Type of element '" + identifier_name + "': '" + \ symbol.type.getCSymbol() + "' does not match array type '" + \ array_type + "'" MyErrorListener().semanticError(line, column, msg) else: # get indexed element value array_elements.append(symbol.value) i += 2 # skip a comma return array_elements