class Parser(object): scanner = None analyzer = None sourceFile = None symbolTableStack = None lookahead = '' firstIdFlag = False # Constructor def __init__(self, fileName): try: self.sourceFile = open(fileName, 'r') except IOError: sys.exit("Source file not found") self.scanner = Scanner(self.sourceFile) self.symbolTableStack = SymbolTableStack() self.analyzer = Analyzer(fileName, self.symbolTableStack) def parse(self): self.lookahead = self.scanner.getNextToken() self.systemGoal() print "Parsing Successful" self.sourceFile.close() def match(self, toMatch): lexeme = self.scanner.lexeme if(self.lookahead == toMatch): self.lookahead = self.scanner.getNextToken() return lexeme else: # print the caller # print inspect.stack()[1][3] self.matchError(toMatch) def systemGoal(self): if self.lookahead is "MP_PROGRAM": # 1 SystemGoal -> Program eof self.program() else: self.error("MP_PROGRAM") def program(self): if self.lookahead is "MP_PROGRAM": # 2 Program -> ProgramHeading ";" Block "." self.programHeading() self.match("MP_SCOLON") self.block() self.match("MP_PERIOD") else: self.error("MP_PROGRAM") def programHeading(self): if self.lookahead is "MP_PROGRAM": # 3 ProgramHeading -> "program" ProgramIdentifier self.match("MP_PROGRAM") self.programIdentifier() self.symbolTableStack.addTable('Main', self.analyzer.getLabel()) self.analyzer.genBranch(self.analyzer.getLabel()) else: self.error("MP_PROGRAM") def block(self): if self.lookahead in ["MP_VAR", "MP_BEGIN", "MP_FUNCTION", "MP_PROCEDURE"]: # 4 Block -> VariableDeclarationPart ProcedureAndFunctionDeclarationPart StatementPart self.variableDeclarationPart() self.procedureAndFunctionDeclarationPart() self.statementPart() else: self.error('"MP_VAR", "MP_BEGIN", "MP_FUNCTION", "MP_PROCEDURE"') def variableDeclarationPart(self): if self.lookahead is "MP_VAR": # 5 VariableDeclarationPart -> "var" VariableDeclaration ";" VariableDeclarationTail self.match("MP_VAR") self.firstIdFlag = True self.variableDeclaration() self.match("MP_SCOLON") self.variableDeclarationTail() elif self.lookahead in ["MP_BEGIN", "MP_FUNCTION", "MP_PROCEDURE"]: return else: self.error('"MP_VAR", "MP_BEGIN", "MP_FUNCTION", "MP_PROCEDURE"') def variableDeclarationTail(self): if self.lookahead in ["MP_PROCEDURE", "MP_FUNCTION", "MP_BEGIN"]: # 7 VariableDeclarationTail -> lambda return elif self.lookahead is "MP_IDENTIFIER": # 6 VariableDeclarationTail -> VariableDeclaration ";" VariableDeclarationTail self.variableDeclaration() self.match("MP_SCOLON") self.variableDeclarationTail() else: self.error('"MP_PROCEDURE", "MP_FUNCTION", "MP_BEGIN", "MP_IDENTIFIER", "MP_SCOLON"') def variableDeclaration(self): if self.lookahead is "MP_IDENTIFIER": # 8 VariableDeclaration -> IdentifierList ":" Type idList = self.identifierList() self.match("MP_COLON") varType = self.type() for name in idList: self.symbolTableStack.getCurrentTable().insertEntry(name, 'var', varType, '', self.firstIdFlag) self.firstIdFlag = False else: self.error("MP_IDENTIFIER") def type(self): if self.lookahead is "MP_INTEGER": # 9 Type -> "Integer" self.match("MP_INTEGER") return 'Integer' elif self.lookahead is "MP_FLOAT": # 108 Type -> "Float" self.match("MP_FLOAT") return 'Float' elif self.lookahead is "MP_STRING": # 109 Type -> "String" self.match("MP_STRING") return 'String' elif self.lookahead is "MP_BOOLEAN": # 110 Type -> "Boolean" self.match("MP_BOOLEAN") return 'Boolean' else: self.error("Integer, Float, String, Boolean") def procedureAndFunctionDeclarationPart(self): if self.lookahead is "MP_PROCEDURE": # 10 ProcedureAndFunctionDeclarationPart -> ProcedureDeclaration ProcedureAndFunctionDeclarationPart self.procedureDeclaration() self.procedureAndFunctionDeclarationPart() elif self.lookahead is "MP_FUNCTION": # 11 ProcedureAndFunctionDeclarationPart -> FunctionDeclaration ProcedureAndFunctionDeclarationPart self.functionDeclaration() self.procedureAndFunctionDeclarationPart() elif self.lookahead is "MP_BEGIN": # 12 ProcedureAndFunctionDeclarationPart -> lambda return else: self.error("Procedure, Function, Begin") def procedureDeclaration(self): if self.lookahead is "MP_PROCEDURE": # 13 ProcedureDeclaration -> ProcedureHeading ";" Block ";" self.procedureHeading(); self.match('MP_SCOLON') self.block() self.match('MP_SCOLON') else: self.error("Procedure") def functionDeclaration(self): if self.lookahead is "MP_FUNCTION": # 14 FunctionDeclaration -> FunctionHeading ";" Block ";" self.functionHeading() self.match("MP_SCOLON") self.block() self.match("MP_SCOLON") else: self.error("Function") def procedureHeading(self): if self.lookahead is "MP_PROCEDURE": # 15 ProcedureHeading -> "procedure" procedureIdentifier OptionalFormalParameterList self.match("MP_PROCEDURE") name = self.procedureIdentifier() self.analyzer.incrementLabel() self.symbolTableStack.getCurrentTable().insertEntry(name, 'procedure', label=self.analyzer.getLabel()) self.symbolTableStack.addTable(name, self.analyzer.getLabel()) self.optionalFormalParameterList() else: self.error("Procedure") def functionHeading(self): if self.lookahead is "MP_FUNCTION": # 16 FunctionHeading -> "function" functionIdentifier OptionalFormalParameterList ":" Type self.match("MP_FUNCTION") name = self.functionIdentifier() self.analyzer.incrementLabel() self.symbolTableStack.getCurrentTable().insertEntry(name, 'function', label=self.analyzer.getLabel()) self.symbolTableStack.addTable(name, self.analyzer.getLabel()) self.optionalFormalParameterList() self.match("MP_COLON") type = self.type() self.symbolTableStack.updateType(name, type) else: self.error("Function") def optionalFormalParameterList(self): if self.lookahead is 'MP_LPAREN': # 17 OptionalFormalParameterList -> "(" FormalParameterSection FormalParameterSectionTail ")" self.match('MP_LPAREN') self.firstIdFlag = True self.formalParameterSection() self.formalParameterSectionTail() self.match('MP_RPAREN') elif self.lookahead in ['MP_COLON', 'MP_SCOLON', 'MP_INTEGER', 'MP_FLOAT', 'MP_BOOLEAN', 'MP_STRING']: # 18 OptionalFormalParameterList -> lambda return else: self.error("(, :, ;, Integer, Float, Boolean, String") def formalParameterSectionTail(self): if self.lookahead is "MP_SCOLON": # 19 FormalParameterSectionTail -> ";" FormalParameterSection FormalParameterSectionTail self.match('MP_SCOLON') self.formalParameterSection() self.formalParameterSectionTail() elif self.lookahead is 'MP_RPAREN': # 20 FormalParameterSectionTail -> lambda return else: self.error(";, )") def formalParameterSection(self): if self.lookahead is 'MP_IDENTIFIER': # 21 FormalParameterSection -> ValueParameterSection self.valueParameterSection() elif self.lookahead is 'MP_VAR': # 22 FormalParameterSection -> VariableParameterSection self.variableParameterSection() else: self.error("Identifier, Var") def valueParameterSection(self): if self.lookahead is 'MP_IDENTIFIER': # 23 ValueParameterSection -> IdentifierList ":" Type identList = [] identList = self.identifierList(); self.match('MP_COLON') varType = self.type() for name in identList: self.symbolTableStack.getCurrentTable().insertEntry(name, 'dparam', varType, '', self.firstIdFlag) self.firstIdFlag = False else: self.error("Identifier") def variableParameterSection(self): if self.lookahead is 'MP_VAR': # 24 VariableParameterSection -> "var" IdentifierList ":" Type self.match('MP_VAR') identList = [] identList = self.identifierList(); self.match('MP_COLON') varType = self.type() for name in identList: self.symbolTableStack.getCurrentTable().insertEntry(name, 'iparam', varType, '', self.firstIdFlag) self.firstIdFlag = False else: self.error("Var") def statementPart(self): if self.lookahead is 'MP_BEGIN': # 25 StatementPart -> CompoundStatement label = self.symbolTableStack.getCurrentTable().label self.analyzer.genLabel(label) if label == 1: self.analyzer.initMainAR() self.compoundStatement() self.symbolTableStack.getCurrentTable().printTable() self.analyzer.endProcOrFunc(self.symbolTableStack.getCurrentTable()) self.symbolTableStack.popTable() else: self.error("Begin") def compoundStatement(self): if self.lookahead is 'MP_BEGIN': # 26 CompoundStatement -> "begin" StatementSequence "end" self.match('MP_BEGIN') self.analyzer.finishProcOrFuncAR() self.statementSequence() self.match('MP_END') else: self.error("begin") def statementSequence(self): if self.lookahead in ['MP_SCOLON', 'MP_IDENTIFIER', # 27 StatementSequence -> Statement StatementTail 'MP_BEGIN', 'MP_END', 'MP_READ', 'MP_WRITE', 'MP_IF', 'MP_ELSE', 'MP_REPEAT', 'MP_UNTIL', 'MP_WHILE', 'MP_FOR', 'MP_WRITELN']: self.statement() self.statementTail() else: self.error("'MP_SCOLON', 'MP_IDENTIFIER', 'MP_BEGIN', 'MP_END', 'MP_READ',\ 'MP_WRITE', 'MP_IF', 'MP_ELSE', 'MP_REPEAT', 'MP_UNTIL', 'MP_WHILE',\ 'MP_FOR', 'MP_WRITELN'") def statementTail(self): if self.lookahead is 'MP_SCOLON': # 28 StatementTail -> ";" Statement StatementTail self.match('MP_SCOLON') self.statement() self.statementTail() elif self.lookahead in ['MP_END', 'MP_UNTIL']: # 29 StatementTail -> lambda return else: self.error(";, end, until") def statement(self): if self.lookahead in ['MP_SCOLON', 'MP_END', 'MP_ELSE', 'MP_UNTIL']: # 30 Statement -> EmptyStatement self.emptyStatement() elif self.lookahead is 'MP_BEGIN': # 31 Statement -> CompoundStatement self.compoundStatement() elif self.lookahead is 'MP_READ': # 32 Statement -> ReadStatement self.readStatement() elif self.lookahead in ['MP_WRITE', 'MP_WRITELN']: # 33 Statement -> WriteStatement self.writeStatement() elif self.lookahead is 'MP_IDENTIFIER': # 39 Statement -> ProcedureStatement OR # 34 Statement -> AssignmentStatement # if MP_ASSIGN is second lookahead, go to AssignStatement, else go to ProcedureStatement second_lookahead = self.scanner.peekNextToken() if second_lookahead is 'MP_ASSIGN': self.assignmentStatement() else: self.procedureStatement() elif self.lookahead is 'MP_IF': # 35 Statement -> IfStatement self.ifStatement() elif self.lookahead is 'MP_WHILE': # 36 Statement -> WhileStatement self.whileStatement() elif self.lookahead is 'MP_REPEAT': # 37 Statement -> RepeatStatement self.repeatStatement() elif self.lookahead is 'MP_FOR': # 28 Statement -> ForStatement self.forStatement() else: self.error(";, end, else, until, begin, read, write, writeln, identifier, :=, if, while, repeat, for") def emptyStatement(self): if self.lookahead in ['MP_SCOLON', 'MP_END', # 40 EmptyStatement -> lambda 'MP_ELSE', 'MP_UNTIL']: return else: self.error(";, end, else, until") def readStatement(self): if self.lookahead is 'MP_READ': # 41 ReadStatement -> "read" "(" ReadParameter ReadParameterTail ")" self.match('MP_READ') self.match('MP_LPAREN') self.readParameter() self.readParameterTail() self.match('MP_RPAREN') else: self.error("read") def readParameterTail(self): if self.lookahead is 'MP_COMMA': # 42 ReadParameterTail -> "," ReadParameter ReadParameterTail self.match('MP_COMMA') self.readParameter() self.readParameterTail() elif self.lookahead is 'MP_RPAREN': # 43 ReadParameterTail -> lambda return else: self.error("comma, )") def readParameter(self): if self.lookahead is 'MP_IDENTIFIER': # 44 ReadParameter -> VariableIdentifier id = self.variableIdentifier() identRec = self.analyzer.processId(id) self.analyzer.genRead(identRec) else: self.error("identifier") def writeStatement(self): if self.lookahead is 'MP_WRITE': # 45 WriteStatement -> "write" "(" WriteParameter WriteParameterTail ")" self.match('MP_WRITE') self.match('MP_LPAREN') self.writeParameter(None) self.writeParameterTail() self.match('MP_RPAREN') elif self.lookahead is 'MP_WRITELN': # 111 WriteStatement -> writeln "(" WriteParameter WriteParameterTail ")" self.match('MP_WRITELN') self.match('MP_LPAREN') self.writeParameter('writeln') self.writeParameterTail('writeln') self.match('MP_RPAREN') else: self.error("write, writeln") def writeParameterTail(self, kind): if self.lookahead is 'MP_COMMA': # 46 WriteParameterTail -> "," WriteParameter self.match('MP_COMMA') self.writeParameter(kind) self.writeParameterTail(kind) elif self.lookahead is 'MP_RPAREN': # 47 WriteParameterTail -> lambda return else: self.error("comma, )") def writeParameter(self, kind): if self.lookahead in ['MP_LPAREN', 'MP_IDENTIFIER', # 48 WriteParameter -> OrdinalExpression 'MP_PLUS', 'MP_MINUS', 'MP_FLOAT_LIT', 'MP_FIXED_LIT', 'MP_STRING_LIT', 'MP_NOT', 'MP_INTEGER_LIT', 'MP_TRUE', 'MP_FALSE']: self.ordinalExpression() self.analyzer.genWrite() if kind == 'writeln': self.analyzer.genWriteln() else: self.error("(, identifier, +, -, any literal value, not") def assignmentStatement(self): # semantic records expressionRec = {} identRec = {} if self.lookahead is 'MP_IDENTIFIER': # 49 AssignmentStatement -> VariableIdentifier ":=" Expression OR id = self.variableIdentifier() identRec = self.analyzer.processId(id) self.match('MP_ASSIGN') expressionRec = self.expression() self.analyzer.genAssign(identRec, expressionRec) # This doesn't change parsing functionality # elif self.lookahead is 'MP_IDENTIFIER': # 50 AssignmentStatement -> FunctionIdentifier ":=" Expression # self.functionIdentifier() # self.match('MP_ASSIGN') # self.expression() else: self.error("identifier") def ifStatement(self): if self.lookahead is 'MP_IF': # 51 IfStatement -> "if" BooleanExpression "then" Statement OptionalElsePart self.match('MP_IF') self.booleanExpression() self.analyzer.incrementLabel() false_label_number = self.analyzer.getLabel() self.analyzer.genBranchFalse(false_label_number) # Generate branch to Optional Else if False self.match('MP_THEN') self.statement() self.analyzer.incrementLabel() skip_else_label_number = self.analyzer.getLabel() self.analyzer.genBranch(skip_else_label_number) # Generate Branch past optional else if was inside of 'then' self.analyzer.genLabel(false_label_number) self.optionalElsePart() self.analyzer.genLabel(skip_else_label_number) else: self.error("if") def optionalElsePart(self): #TODO: Table says else is ambiguous? haven't looked at it yet if self.lookahead is 'MP_ELSE': # 52 OptionalElsePart -> "else" Statement self.match('MP_ELSE') self.statement() elif self.lookahead in ['MP_SCOLON', 'MP_END', 'MP_UNTIL']: # 53 OptionalElsePart -> lambda return else: self.error("else, ;, end, until") def repeatStatement(self): if self.lookahead is 'MP_REPEAT': # 54 RepeatStatement -> "repeat" StatementSequence "until" BooleanExpression self.match('MP_REPEAT') self.analyzer.incrementLabel() starting_label = self.analyzer.getLabel() self.analyzer.genLabel(starting_label) self.statementSequence() self.match('MP_UNTIL') self.booleanExpression() self.analyzer.genBranchFalse(starting_label) else: self.error("repeat") def whileStatement(self): if self.lookahead is 'MP_WHILE': # 55 WhileStatement -> "while" BooleanExpression "do" Statement self.match('MP_WHILE') self.analyzer.incrementLabel() start_label = self.analyzer.getLabel() self.analyzer.genLabel(start_label) self.booleanExpression() self.analyzer.incrementLabel() false_label = self.analyzer.getLabel() self.analyzer.genBranchFalse(false_label) self.match('MP_DO') self.statement() self.analyzer.genBranch(start_label) self.analyzer.genLabel(false_label) else: self.error("while") def forStatement(self): ident_rec = {} expression_rec = {} if self.lookahead is 'MP_FOR': # 56 ForStatement -> "for" ControlVariable ":=" InitialValue StepValue FinalValue "do" Statement self.match('MP_FOR') ident_rec = self.controlVariable() self.match('MP_ASSIGN') expression_rec = self.initialValue() self.analyzer.genAssign(ident_rec, expression_rec) step = self.stepValue() self.analyzer.incrementLabel() start_label = self.analyzer.getLabel() self.analyzer.incrementLabel() false_label = self.analyzer.getLabel() self.analyzer.genLabel(start_label) self.finalValue() self.analyzer.genPushId(ident_rec) if(step == "to"): self.analyzer.genBoolean(">=", ident_rec, expression_rec) self.analyzer.genBranchFalse(false_label) elif(step == "downto"): self.analyzer.genBoolean("<=", ident_rec, expression_rec) self.analyzer.genBranchFalse(false_label) self.match('MP_DO') self.statement() if(step == "to"): self.analyzer.genPushInt(str(1)) elif(step == "downto"): self.analyzer.genPushInt(str(-1)) self.analyzer.genPushId(ident_rec) self.analyzer.output("ADDS") self.analyzer.genAssign(ident_rec, expression_rec) self.analyzer.genBranch(start_label) self.analyzer.genLabel(false_label) else: self.error("for") def controlVariable(self): identRec = {} if self.lookahead is 'MP_IDENTIFIER': # 57 ControlVariable -> VariableIdentifier id = self.variableIdentifier() identRec = self.analyzer.processId(id) identRec["lexeme"] = id return identRec else: self.error("identifier") def initialValue(self): if self.lookahead in ['MP_LPAREN', 'MP_IDENTIFIER', # 58 InitialValue -> OrdinalExpression 'MP_PLUS', 'MP_MINUS', 'MP_FLOAT_LIT', 'MP_FIXED_LIT', 'MP_STRING_LIT', 'MP_NOT', 'MP_INTEGER_LIT', 'MP_TRUE', 'MP_FALSE']: return self.ordinalExpression() else: self.error("(, identifier, +, -, any literal value, not") def stepValue(self): if self.lookahead is 'MP_TO': # 59 StepValue -> "to" return self.match('MP_TO') elif self.lookahead is 'MP_DOWNTO': # 60 StepValue -> "downto" return self.match('MP_DOWNTO') else: self.error("to, downto") def finalValue(self): if self.lookahead in ['MP_LPAREN', 'MP_IDENTIFIER', # 61 FinalValue -> OrdinalExpression 'MP_PLUS', 'MP_MINUS', 'MP_FLOAT_LIT', 'MP_FIXED_LIT', 'MP_STRING_LIT', 'MP_NOT', 'MP_INTEGER_LIT', 'MP_TRUE', 'MP_FALSE']: self.ordinalExpression() else: self.error("(, identifier, +, -, any literal value, not") def procedureStatement(self): if self.lookahead is 'MP_IDENTIFIER': # 62 ProcedureStatement -> ProcedureIdentifier OptionalActualParameterList self.analyzer.incrementSP(4) # leave space for function/procedure procedureName = self.procedureIdentifier() self.optionalActualParameterList() entry = self.symbolTableStack.getCurrentTable().find(procedureName) if entry != None: self.analyzer.genCall(entry['label']) else: print "Error: "+procedureName+" not found. It either doesn't exist or out of scope." sys.exit() else: self.error("identifier") def optionalActualParameterList(self): if self.lookahead is 'MP_LPAREN': # 63 OptionalActualParameterList -> "(" ActualParameter ActualParameterTail ")" self.match('MP_LPAREN') self.actualParameter() self.actualParameterTail() self.match('MP_RPAREN') elif self.lookahead in ['MP_SCOLON', 'MP_RPAREN', 'MP_END', 'MP_COMMA', # 64 OptionalActualParameterList -> lambda 'MP_THEN', 'MP_ELSE', 'MP_UNTIL', 'MP_TO', 'MP_DO', 'MP_DOWNTO', 'MP_EQUAL', 'MP_LTHAN', 'MP_GTHAN', 'MP_LEQUAL', 'MP_GEQUAL', 'MP_NEQUAL', 'MP_PLUS', 'MP_MINUS', 'MP_OR', 'MP_TIMES', 'MP_DIV', 'MP_MOD', 'MP_AND', 'MP_SLASH']: return else: self.error(";, ), end, comma, then, else, until, to do, downto, an equality operator, an arithmetic operator, and, mod") def actualParameterTail(self): if self.lookahead is 'MP_COMMA': # 65 ActualParameterTail -> "," ActualParameter ActualParameterTail self.match('MP_COMMA') self.actualParameter() self.actualParameterTail() elif self.lookahead is 'MP_RPAREN': # 66 ActualParameterTail -> lambda return else: self.error("comma, )") def actualParameter(self): if self.lookahead in ['MP_LPAREN', 'MP_IDENTIFIER', # 67 ActualParameter -> OrdinalExpression 'MP_PLUS', 'MP_MINUS', 'MP_FLOAT_LIT', 'MP_FIXED_LIT', 'MP_STRING_LIT', 'MP_NOT', 'MP_INTEGER_LIT', 'MP_TRUE', 'MP_FALSE']: self.ordinalExpression() else: self.error("(, identifier, +, -, any literal value, not") def expression(self): expression_rec = {} if self.lookahead in ['MP_LPAREN', 'MP_IDENTIFIER', # 68 Expression -> SimpleExpression OptionalRelationalPart 'MP_PLUS', 'MP_MINUS', 'MP_FLOAT_LIT', 'MP_FIXED_LIT', 'MP_STRING_LIT', 'MP_NOT', 'MP_INTEGER_LIT', 'MP_TRUE', 'MP_FALSE']: expression_rec = self.simpleExpression() expression_rec = self.optionalRelationalPart(expression_rec) return expression_rec # return self.mapTokenToType(self.lookahead) else: self.error("(, identifier, +, -, any literal value, not") def optionalRelationalPart(self, expression_rec): rightOp = {} leftOp = expression_rec if self.lookahead in ['MP_EQUAL', 'MP_LTHAN', # 69 OptionalRelationalPart -> RelationalOperator SimpleExpression 'MP_GTHAN', 'MP_LEQUAL', 'MP_GEQUAL', 'MP_NEQUAL']: operator = self.relationalOperator() rightOp = self.simpleExpression() self.analyzer.genBoolean(operator, leftOp, rightOp) expression_rec["type"] = 'Boolean' return expression_rec elif self.lookahead in ['MP_SCOLON', 'MP_RPAREN', # 70 OptionalRelationalPart -> lambda 'MP_END', 'MP_COMMA', 'MP_THEN', 'MP_ELSE', 'MP_UNTIL','MP_DO', 'MP_TO', 'MP_DOWNTO']: return expression_rec else: self.error("an equality operator, ;, ), then, else, until, do, to, downto") def relationalOperator(self): if self.lookahead is 'MP_EQUAL': # 71 RelationalOperator -> "=" operator = self.match('MP_EQUAL') elif self.lookahead is 'MP_LTHAN': # 72 RelationalOperator -> "<" operator = self.match('MP_LTHAN') elif self.lookahead is 'MP_GTHAN': # 73 RelationalOperator -> ">" operator = self.match('MP_GTHAN') elif self.lookahead is 'MP_LEQUAL': # 74 RelationalOperator -> "<=" operator = self.match('MP_LEQUAL') elif self.lookahead is 'MP_GEQUAL': # 75 RelationalOperator -> ">=" operator = self.match('MP_GEQUAL') elif self.lookahead is 'MP_NEQUAL': # 76 RelationalOperator -> "<>" operator = self.match('MP_NEQUAL') else: self.error("an equality operator") return operator def simpleExpression(self): # semantic records termRec = {} termTailRec = {} if self.lookahead in ['MP_LPAREN', 'MP_IDENTIFIER', # 77 SimpleExpression -> OptionalSign Term TermTail 'MP_PLUS', 'MP_MINUS', 'MP_FLOAT_LIT', 'MP_FIXED_LIT', 'MP_STRING_LIT', 'MP_NOT', 'MP_INTEGER_LIT', 'MP_TRUE', 'MP_FALSE']: sign = self.optionalSign() termRec = self.term() type = termRec['type'] if sign == "-": if type == "Integer": self.analyzer.genNeg() elif type in ["Float", "Fixed"]: self.analyzer.genNegf() termTailRec = termRec termTailRec = self.termTail(termTailRec) expressionRec = termTailRec # This is what Rocky suggested return expressionRec else: self.error("(, identifier, +, -, any literal value, not") def termTail(self, termTailRec = {}): # Semantic Records addopRec = {} termRec = {} if self.lookahead in ['MP_PLUS', 'MP_MINUS', 'MP_OR']: # 78 TermTail -> AddingOperator Term TermTail addopRec["lexeme"] = self.addingOperator() termRec = self.term() resultRec = self.analyzer.genArithmetic(termTailRec, addopRec, termRec) self.termTail(resultRec) termTailRec = resultRec return termTailRec elif self.lookahead in ['MP_SCOLON', 'MP_RPAREN', 'MP_END', # 79 TermTail -> lambda 'MP_COMMA', 'MP_THEN', 'MP_ELSE', 'MP_UNTIL', 'MP_DO', 'MP_TO', 'MP_DOWNTO', 'MP_EQUAL', 'MP_LTHAN', 'MP_GTHAN', 'MP_LEQUAL', 'MP_GEQUAL', 'MP_NEQUAL']: return termTailRec else: self.error("+, -, or, ;, ), end, comma, then, else, until, do, to, downto, an equality operator") def optionalSign(self): if self.lookahead is 'MP_PLUS': # 80 OptionalSign -> "+" self.match('MP_PLUS') elif self.lookahead is 'MP_MINUS': # 81 OptionalSign -> "-" return self.match('MP_MINUS') elif self.lookahead in ['MP_LPAREN', 'MP_IDENTIFIER', # 82 OptionalSign -> lambda 'MP_NOT', 'MP_INTEGER_LIT', 'MP_FLOAT_LIT', 'MP_FIXED_LIT', 'MP_STRING_LIT', 'MP_TRUE', 'MP_FALSE']: return else: self.error("+, -, (, identifier, +, -, any literal value, not") def addingOperator(self): if self.lookahead is 'MP_PLUS': # 83 AddingOperator -> "+" return self.match('MP_PLUS') elif self.lookahead is 'MP_MINUS': # 84 AddingOperator -> "-" return self.match('MP_MINUS') elif self.lookahead is 'MP_OR': # 85 AddingOperator -> "or" return self.match('MP_OR') else: self.error("+, -, or") def term(self): termRec = {} if self.lookahead in ['MP_LPAREN', # 86 Term -> Factor FactorTail 'MP_IDENTIFIER', 'MP_NOT', 'MP_INTEGER_LIT', 'MP_FLOAT_LIT', 'MP_FIXED_LIT', 'MP_STRING_LIT', 'MP_TRUE', 'MP_FALSE']: termRec["type"] = self.factor() termRec = self.factorTail(termRec) return termRec # return self.mapTokenToType(self.lookahead) else: self.error("(, identifier, +, -, any literal value, not") def factorTail(self, termRec): rightOp = {} operator = {} if self.lookahead in ['MP_TIMES', 'MP_DIV', # 87 FactorTail -> MultiplyingOperator Factor FactorTail 'MP_MOD', 'MP_AND', 'MP_SLASH']: operator["lexeme"] = self.multiplyingOperator() rightOp["type"] = self.factor() self.analyzer.genArithmetic(termRec, operator, rightOp) self.factorTail(rightOp) return termRec elif self.lookahead in ['MP_SCOLON', 'MP_RPAREN', 'MP_END', # 88 FactorTail -> lambda 'MP_COMMA', 'MP_THEN', 'MP_ELSE', 'MP_UNTIL', 'MP_DO', 'MP_TO', 'MP_DOWNTO', 'MP_EQUAL', 'MP_LTHAN', 'MP_GTHAN', 'MP_LEQUAL', 'MP_GEQUAL', 'MP_NEQUAL', 'MP_PLUS', 'MP_MINUS', 'MP_OR']: return termRec else: self.error("*, div, mod, and /, ;, ), end, comma, then, else, until, do, to, downto, an equality operator, +, -, or") def multiplyingOperator(self): if self.lookahead is 'MP_TIMES': # 89 MultiplyingOperator -> "*" return self.match('MP_TIMES') elif self.lookahead is 'MP_DIV': # 90 MultiplyingOperator -> "div" return self.match('MP_DIV') elif self.lookahead is 'MP_MOD': # 91 MultiplyingOperator -> "mod" return self.match('MP_MOD') elif self.lookahead is 'MP_AND': # 92 MultiplyingOperator -> "and" return self.match('MP_AND') elif self.lookahead is 'MP_SLASH': # 112 MultiplyingOperator -> "/" return self.match('MP_SLASH') else: self.error("*, div, mod, and, /") def factor(self): # semantic record identRec = {} if self.lookahead in ['MP_INTEGER_LIT']: # 93 Factor -> UnsignedInteger integer = self.match('MP_INTEGER_LIT') self.analyzer.genPushInt(integer) return "Integer" elif self.lookahead is 'MP_IDENTIFIER': # 94 Factor -> VariableIdentifier OR # 97 Factor -> FunctionIdentifier OptionalActualParameterList id_kind = self.analyzer.processId(self.scanner.lexeme)["kind"] if id_kind == "function": self.analyzer.incrementSP(4) # leave space for function/procedure's display register id = self.functionIdentifier() self.optionalActualParameterList() entry = self.symbolTableStack.getCurrentTable().find(id) if entry != None: self.analyzer.genCall(entry['label']) # self.analyzer.popDisplayAndParams(id) else: print "Error: "+id+" not found. It either doesn't exist or out of scope." sys.exit() elif id_kind in ["var", "iparam", "dparam"]: id = self.variableIdentifier() identRec["lexeme"] = id self.analyzer.genPushId(identRec) return self.analyzer.processId(id)["type"] elif self.lookahead is 'MP_NOT': # 95 Factor -> "not" Factor self.match('MP_NOT'); self.factor() self.analyzer.genNot() return "Boolean" elif self.lookahead is 'MP_LPAREN': # 96 Factor -> "(" Expression ")" self.match('MP_LPAREN') type = self.expression()["type"] self.match('MP_RPAREN') return type elif self.lookahead in ['MP_FLOAT_LIT']: # 113 Factor -> UnsignedFloat float = self.match('MP_FLOAT_LIT') self.analyzer.genPushFloat(float) return "Float" elif self.lookahead in ['MP_FIXED_LIT']: # 113 Factor -> UnsignedFloat fixed = self.match('MP_FIXED_LIT') self.analyzer.genPushFloat(fixed) return "Float" elif self.lookahead in ['MP_STRING_LIT']: # 114 Factor -> StringLiteral string = self.match('MP_STRING_LIT') self.analyzer.genPushString(string) return "String" elif self.lookahead in ['MP_TRUE']: # 115 Factor -> "True" self.match('MP_TRUE') self.analyzer.genPushBoolean(1) return "Boolean" elif self.lookahead in ['MP_FALSE']: # 116 Factor -> "False" self.match('MP_FALSE') self.analyzer.genPushBoolean(0) return "Boolean" else: self.error("(, identifier, +, -, any literal value, not") def programIdentifier(self): if(self.lookahead == "MP_IDENTIFIER"): # 98 ProgramIdentifier -> Identifier return self.match("MP_IDENTIFIER") else: self.error("identifier") def variableIdentifier(self): if(self.lookahead == "MP_IDENTIFIER"): # 99 VariableIdentifier -> Identifier return self.match("MP_IDENTIFIER") else: self.error("identifier") def procedureIdentifier(self): if(self.lookahead == "MP_IDENTIFIER"): # 100 ProcedureIdentifier -> Identifier return self.match("MP_IDENTIFIER") else: self.error("identifier") def functionIdentifier(self): if(self.lookahead == "MP_IDENTIFIER"): # 101 FunctionIdentifier -> Identifier return self.match("MP_IDENTIFIER") else: self.error("identifier") def booleanExpression(self): if(self.lookahead in ["MP_LPAREN", "MP_IDENTIFIER", # 102 BooleanExpression -> Expression "MP_PLUS", "MP_MINUS", "MP_NOT", "MP_INTEGER_LIT", 'MP_FLOAT_LIT', 'MP_FIXED_LIT', 'MP_STRING_LIT', 'MP_TRUE', 'MP_FALSE']): self.expression() else: self.error("(, identifier, +, -, any literal value, not, +, -") def ordinalExpression(self): if(self.lookahead in ["MP_LPAREN", "MP_IDENTIFIER", # 103 OrdinalExpression -> Expression "MP_PLUS", "MP_MINUS", "MP_NOT", "MP_INTEGER_LIT", 'MP_FLOAT_LIT', 'MP_FIXED_LIT', 'MP_STRING_LIT', 'MP_TRUE', 'MP_FALSE']): return self.expression() else: self.error("(, identifier, +, -, any literal value, not, +, -") def identifierList(self): if(self.lookahead == "MP_IDENTIFIER"): # 104 IdentifierList -> Identifier IdentifierTail ident = [] ident.append(self.scanner.lexeme) self.match("MP_IDENTIFIER") self.identifierTail(ident) return ident else: self.error("identifier") def identifierTail(self,ident): if(self.lookahead == "MP_COMMA"): # 105 IdentifierTail -> "," Identifier IdentifierTail self.match("MP_COMMA") ident.append(self.scanner.lexeme) self.match("MP_IDENTIFIER") self.identifierTail(ident) elif(self.lookahead == "MP_COLON"): # 106 IdentifierTail -> lambda return else: self.error("comma, :") def error(self, expected): print "ERROR: Syntax error found on line " + str(self.scanner.getLineNumber()) + ", column " + str(self.scanner.getColumnNumber()) print "Found " + self.scanner.lexeme + " when expected one of: " + expected # print the caller # print inspect.stack()[1][3] sys.exit() def matchError(self, expected): print "ERROR: Match error found on line " + str(self.scanner.getLineNumber()) + ", column " + str(self.scanner.getColumnNumber()) + " lexeme: " + self.scanner.lexeme print "Found " + self.lookahead + " when expected " + expected # print the caller sys.exit()
class Parser(object): scanner = None analyzer = None sourceFile = None symbolTableStack = None lookahead = '' firstIdFlag = False # Constructor def __init__(self, fileName): try: self.sourceFile = open(fileName, 'r') except IOError: sys.exit("Source file not found") self.scanner = Scanner(self.sourceFile) self.symbolTableStack = SymbolTableStack() self.analyzer = Analyzer(fileName, self.symbolTableStack) def parse(self): self.lookahead = self.scanner.getNextToken() self.systemGoal() print "Parsing Successful" self.sourceFile.close() def match(self, toMatch): lexeme = self.scanner.lexeme if (self.lookahead == toMatch): self.lookahead = self.scanner.getNextToken() return lexeme else: # print the caller # print inspect.stack()[1][3] self.matchError(toMatch) def systemGoal(self): if self.lookahead is "MP_PROGRAM": # 1 SystemGoal -> Program eof self.program() else: self.error("MP_PROGRAM") def program(self): if self.lookahead is "MP_PROGRAM": # 2 Program -> ProgramHeading ";" Block "." self.programHeading() self.match("MP_SCOLON") self.block() self.match("MP_PERIOD") else: self.error("MP_PROGRAM") def programHeading(self): if self.lookahead is "MP_PROGRAM": # 3 ProgramHeading -> "program" ProgramIdentifier self.match("MP_PROGRAM") self.programIdentifier() self.symbolTableStack.addTable('Main', self.analyzer.getLabel()) self.analyzer.genBranch(self.analyzer.getLabel()) else: self.error("MP_PROGRAM") def block(self): if self.lookahead in [ "MP_VAR", "MP_BEGIN", "MP_FUNCTION", "MP_PROCEDURE" ]: # 4 Block -> VariableDeclarationPart ProcedureAndFunctionDeclarationPart StatementPart self.variableDeclarationPart() self.procedureAndFunctionDeclarationPart() self.statementPart() else: self.error('"MP_VAR", "MP_BEGIN", "MP_FUNCTION", "MP_PROCEDURE"') def variableDeclarationPart(self): if self.lookahead is "MP_VAR": # 5 VariableDeclarationPart -> "var" VariableDeclaration ";" VariableDeclarationTail self.match("MP_VAR") self.firstIdFlag = True self.variableDeclaration() self.match("MP_SCOLON") self.variableDeclarationTail() elif self.lookahead in ["MP_BEGIN", "MP_FUNCTION", "MP_PROCEDURE"]: return else: self.error('"MP_VAR", "MP_BEGIN", "MP_FUNCTION", "MP_PROCEDURE"') def variableDeclarationTail(self): if self.lookahead in ["MP_PROCEDURE", "MP_FUNCTION", "MP_BEGIN" ]: # 7 VariableDeclarationTail -> lambda return elif self.lookahead is "MP_IDENTIFIER": # 6 VariableDeclarationTail -> VariableDeclaration ";" VariableDeclarationTail self.variableDeclaration() self.match("MP_SCOLON") self.variableDeclarationTail() else: self.error( '"MP_PROCEDURE", "MP_FUNCTION", "MP_BEGIN", "MP_IDENTIFIER", "MP_SCOLON"' ) def variableDeclaration(self): if self.lookahead is "MP_IDENTIFIER": # 8 VariableDeclaration -> IdentifierList ":" Type idList = self.identifierList() self.match("MP_COLON") varType = self.type() for name in idList: self.symbolTableStack.getCurrentTable().insertEntry( name, 'var', varType, '', self.firstIdFlag) self.firstIdFlag = False else: self.error("MP_IDENTIFIER") def type(self): if self.lookahead is "MP_INTEGER": # 9 Type -> "Integer" self.match("MP_INTEGER") return 'Integer' elif self.lookahead is "MP_FLOAT": # 108 Type -> "Float" self.match("MP_FLOAT") return 'Float' elif self.lookahead is "MP_STRING": # 109 Type -> "String" self.match("MP_STRING") return 'String' elif self.lookahead is "MP_BOOLEAN": # 110 Type -> "Boolean" self.match("MP_BOOLEAN") return 'Boolean' else: self.error("Integer, Float, String, Boolean") def procedureAndFunctionDeclarationPart(self): if self.lookahead is "MP_PROCEDURE": # 10 ProcedureAndFunctionDeclarationPart -> ProcedureDeclaration ProcedureAndFunctionDeclarationPart self.procedureDeclaration() self.procedureAndFunctionDeclarationPart() elif self.lookahead is "MP_FUNCTION": # 11 ProcedureAndFunctionDeclarationPart -> FunctionDeclaration ProcedureAndFunctionDeclarationPart self.functionDeclaration() self.procedureAndFunctionDeclarationPart() elif self.lookahead is "MP_BEGIN": # 12 ProcedureAndFunctionDeclarationPart -> lambda return else: self.error("Procedure, Function, Begin") def procedureDeclaration(self): if self.lookahead is "MP_PROCEDURE": # 13 ProcedureDeclaration -> ProcedureHeading ";" Block ";" self.procedureHeading() self.match('MP_SCOLON') self.block() self.match('MP_SCOLON') else: self.error("Procedure") def functionDeclaration(self): if self.lookahead is "MP_FUNCTION": # 14 FunctionDeclaration -> FunctionHeading ";" Block ";" self.functionHeading() self.match("MP_SCOLON") self.block() self.match("MP_SCOLON") else: self.error("Function") def procedureHeading(self): if self.lookahead is "MP_PROCEDURE": # 15 ProcedureHeading -> "procedure" procedureIdentifier OptionalFormalParameterList self.match("MP_PROCEDURE") name = self.procedureIdentifier() self.analyzer.incrementLabel() self.symbolTableStack.getCurrentTable().insertEntry( name, 'procedure', label=self.analyzer.getLabel()) self.symbolTableStack.addTable(name, self.analyzer.getLabel()) self.optionalFormalParameterList() else: self.error("Procedure") def functionHeading(self): if self.lookahead is "MP_FUNCTION": # 16 FunctionHeading -> "function" functionIdentifier OptionalFormalParameterList ":" Type self.match("MP_FUNCTION") name = self.functionIdentifier() self.analyzer.incrementLabel() self.symbolTableStack.getCurrentTable().insertEntry( name, 'function', label=self.analyzer.getLabel()) self.symbolTableStack.addTable(name, self.analyzer.getLabel()) self.optionalFormalParameterList() self.match("MP_COLON") type = self.type() self.symbolTableStack.updateType(name, type) else: self.error("Function") def optionalFormalParameterList(self): if self.lookahead is 'MP_LPAREN': # 17 OptionalFormalParameterList -> "(" FormalParameterSection FormalParameterSectionTail ")" self.match('MP_LPAREN') self.firstIdFlag = True self.formalParameterSection() self.formalParameterSectionTail() self.match('MP_RPAREN') elif self.lookahead in [ 'MP_COLON', 'MP_SCOLON', 'MP_INTEGER', 'MP_FLOAT', 'MP_BOOLEAN', 'MP_STRING' ]: # 18 OptionalFormalParameterList -> lambda return else: self.error("(, :, ;, Integer, Float, Boolean, String") def formalParameterSectionTail(self): if self.lookahead is "MP_SCOLON": # 19 FormalParameterSectionTail -> ";" FormalParameterSection FormalParameterSectionTail self.match('MP_SCOLON') self.formalParameterSection() self.formalParameterSectionTail() elif self.lookahead is 'MP_RPAREN': # 20 FormalParameterSectionTail -> lambda return else: self.error(";, )") def formalParameterSection(self): if self.lookahead is 'MP_IDENTIFIER': # 21 FormalParameterSection -> ValueParameterSection self.valueParameterSection() elif self.lookahead is 'MP_VAR': # 22 FormalParameterSection -> VariableParameterSection self.variableParameterSection() else: self.error("Identifier, Var") def valueParameterSection(self): if self.lookahead is 'MP_IDENTIFIER': # 23 ValueParameterSection -> IdentifierList ":" Type identList = [] identList = self.identifierList() self.match('MP_COLON') varType = self.type() for name in identList: self.symbolTableStack.getCurrentTable().insertEntry( name, 'dparam', varType, '', self.firstIdFlag) self.firstIdFlag = False else: self.error("Identifier") def variableParameterSection(self): if self.lookahead is 'MP_VAR': # 24 VariableParameterSection -> "var" IdentifierList ":" Type self.match('MP_VAR') identList = [] identList = self.identifierList() self.match('MP_COLON') varType = self.type() for name in identList: self.symbolTableStack.getCurrentTable().insertEntry( name, 'iparam', varType, '', self.firstIdFlag) self.firstIdFlag = False else: self.error("Var") def statementPart(self): if self.lookahead is 'MP_BEGIN': # 25 StatementPart -> CompoundStatement label = self.symbolTableStack.getCurrentTable().label self.analyzer.genLabel(label) if label == 1: self.analyzer.initMainAR() self.compoundStatement() self.symbolTableStack.getCurrentTable().printTable() self.analyzer.endProcOrFunc( self.symbolTableStack.getCurrentTable()) self.symbolTableStack.popTable() else: self.error("Begin") def compoundStatement(self): if self.lookahead is 'MP_BEGIN': # 26 CompoundStatement -> "begin" StatementSequence "end" self.match('MP_BEGIN') self.analyzer.finishProcOrFuncAR() self.statementSequence() self.match('MP_END') else: self.error("begin") def statementSequence(self): if self.lookahead in [ 'MP_SCOLON', 'MP_IDENTIFIER', # 27 StatementSequence -> Statement StatementTail 'MP_BEGIN', 'MP_END', 'MP_READ', 'MP_WRITE', 'MP_IF', 'MP_ELSE', 'MP_REPEAT', 'MP_UNTIL', 'MP_WHILE', 'MP_FOR', 'MP_WRITELN' ]: self.statement() self.statementTail() else: self.error( "'MP_SCOLON', 'MP_IDENTIFIER', 'MP_BEGIN', 'MP_END', 'MP_READ',\ 'MP_WRITE', 'MP_IF', 'MP_ELSE', 'MP_REPEAT', 'MP_UNTIL', 'MP_WHILE',\ 'MP_FOR', 'MP_WRITELN'") def statementTail(self): if self.lookahead is 'MP_SCOLON': # 28 StatementTail -> ";" Statement StatementTail self.match('MP_SCOLON') self.statement() self.statementTail() elif self.lookahead in ['MP_END', 'MP_UNTIL']: # 29 StatementTail -> lambda return else: self.error(";, end, until") def statement(self): if self.lookahead in ['MP_SCOLON', 'MP_END', 'MP_ELSE', 'MP_UNTIL']: # 30 Statement -> EmptyStatement self.emptyStatement() elif self.lookahead is 'MP_BEGIN': # 31 Statement -> CompoundStatement self.compoundStatement() elif self.lookahead is 'MP_READ': # 32 Statement -> ReadStatement self.readStatement() elif self.lookahead in ['MP_WRITE', 'MP_WRITELN' ]: # 33 Statement -> WriteStatement self.writeStatement() elif self.lookahead is 'MP_IDENTIFIER': # 39 Statement -> ProcedureStatement OR # 34 Statement -> AssignmentStatement # if MP_ASSIGN is second lookahead, go to AssignStatement, else go to ProcedureStatement second_lookahead = self.scanner.peekNextToken() if second_lookahead is 'MP_ASSIGN': self.assignmentStatement() else: self.procedureStatement() elif self.lookahead is 'MP_IF': # 35 Statement -> IfStatement self.ifStatement() elif self.lookahead is 'MP_WHILE': # 36 Statement -> WhileStatement self.whileStatement() elif self.lookahead is 'MP_REPEAT': # 37 Statement -> RepeatStatement self.repeatStatement() elif self.lookahead is 'MP_FOR': # 28 Statement -> ForStatement self.forStatement() else: self.error( ";, end, else, until, begin, read, write, writeln, identifier, :=, if, while, repeat, for" ) def emptyStatement(self): if self.lookahead in [ 'MP_SCOLON', 'MP_END', # 40 EmptyStatement -> lambda 'MP_ELSE', 'MP_UNTIL' ]: return else: self.error(";, end, else, until") def readStatement(self): if self.lookahead is 'MP_READ': # 41 ReadStatement -> "read" "(" ReadParameter ReadParameterTail ")" self.match('MP_READ') self.match('MP_LPAREN') self.readParameter() self.readParameterTail() self.match('MP_RPAREN') else: self.error("read") def readParameterTail(self): if self.lookahead is 'MP_COMMA': # 42 ReadParameterTail -> "," ReadParameter ReadParameterTail self.match('MP_COMMA') self.readParameter() self.readParameterTail() elif self.lookahead is 'MP_RPAREN': # 43 ReadParameterTail -> lambda return else: self.error("comma, )") def readParameter(self): if self.lookahead is 'MP_IDENTIFIER': # 44 ReadParameter -> VariableIdentifier id = self.variableIdentifier() identRec = self.analyzer.processId(id) self.analyzer.genRead(identRec) else: self.error("identifier") def writeStatement(self): if self.lookahead is 'MP_WRITE': # 45 WriteStatement -> "write" "(" WriteParameter WriteParameterTail ")" self.match('MP_WRITE') self.match('MP_LPAREN') self.writeParameter(None) self.writeParameterTail() self.match('MP_RPAREN') elif self.lookahead is 'MP_WRITELN': # 111 WriteStatement -> writeln "(" WriteParameter WriteParameterTail ")" self.match('MP_WRITELN') self.match('MP_LPAREN') self.writeParameter('writeln') self.writeParameterTail('writeln') self.match('MP_RPAREN') else: self.error("write, writeln") def writeParameterTail(self, kind): if self.lookahead is 'MP_COMMA': # 46 WriteParameterTail -> "," WriteParameter self.match('MP_COMMA') self.writeParameter(kind) self.writeParameterTail(kind) elif self.lookahead is 'MP_RPAREN': # 47 WriteParameterTail -> lambda return else: self.error("comma, )") def writeParameter(self, kind): if self.lookahead in [ 'MP_LPAREN', 'MP_IDENTIFIER', # 48 WriteParameter -> OrdinalExpression 'MP_PLUS', 'MP_MINUS', 'MP_FLOAT_LIT', 'MP_FIXED_LIT', 'MP_STRING_LIT', 'MP_NOT', 'MP_INTEGER_LIT', 'MP_TRUE', 'MP_FALSE' ]: self.ordinalExpression() self.analyzer.genWrite() if kind == 'writeln': self.analyzer.genWriteln() else: self.error("(, identifier, +, -, any literal value, not") def assignmentStatement(self): # semantic records expressionRec = {} identRec = {} if self.lookahead is 'MP_IDENTIFIER': # 49 AssignmentStatement -> VariableIdentifier ":=" Expression OR id = self.variableIdentifier() identRec = self.analyzer.processId(id) self.match('MP_ASSIGN') expressionRec = self.expression() self.analyzer.genAssign(identRec, expressionRec) # This doesn't change parsing functionality # elif self.lookahead is 'MP_IDENTIFIER': # 50 AssignmentStatement -> FunctionIdentifier ":=" Expression # self.functionIdentifier() # self.match('MP_ASSIGN') # self.expression() else: self.error("identifier") def ifStatement(self): if self.lookahead is 'MP_IF': # 51 IfStatement -> "if" BooleanExpression "then" Statement OptionalElsePart self.match('MP_IF') self.booleanExpression() self.analyzer.incrementLabel() false_label_number = self.analyzer.getLabel() self.analyzer.genBranchFalse( false_label_number ) # Generate branch to Optional Else if False self.match('MP_THEN') self.statement() self.analyzer.incrementLabel() skip_else_label_number = self.analyzer.getLabel() self.analyzer.genBranch( skip_else_label_number ) # Generate Branch past optional else if was inside of 'then' self.analyzer.genLabel(false_label_number) self.optionalElsePart() self.analyzer.genLabel(skip_else_label_number) else: self.error("if") def optionalElsePart(self): #TODO: Table says else is ambiguous? haven't looked at it yet if self.lookahead is 'MP_ELSE': # 52 OptionalElsePart -> "else" Statement self.match('MP_ELSE') self.statement() elif self.lookahead in ['MP_SCOLON', 'MP_END', 'MP_UNTIL']: # 53 OptionalElsePart -> lambda return else: self.error("else, ;, end, until") def repeatStatement(self): if self.lookahead is 'MP_REPEAT': # 54 RepeatStatement -> "repeat" StatementSequence "until" BooleanExpression self.match('MP_REPEAT') self.analyzer.incrementLabel() starting_label = self.analyzer.getLabel() self.analyzer.genLabel(starting_label) self.statementSequence() self.match('MP_UNTIL') self.booleanExpression() self.analyzer.genBranchFalse(starting_label) else: self.error("repeat") def whileStatement(self): if self.lookahead is 'MP_WHILE': # 55 WhileStatement -> "while" BooleanExpression "do" Statement self.match('MP_WHILE') self.analyzer.incrementLabel() start_label = self.analyzer.getLabel() self.analyzer.genLabel(start_label) self.booleanExpression() self.analyzer.incrementLabel() false_label = self.analyzer.getLabel() self.analyzer.genBranchFalse(false_label) self.match('MP_DO') self.statement() self.analyzer.genBranch(start_label) self.analyzer.genLabel(false_label) else: self.error("while") def forStatement(self): ident_rec = {} expression_rec = {} if self.lookahead is 'MP_FOR': # 56 ForStatement -> "for" ControlVariable ":=" InitialValue StepValue FinalValue "do" Statement self.match('MP_FOR') ident_rec = self.controlVariable() self.match('MP_ASSIGN') expression_rec = self.initialValue() self.analyzer.genAssign(ident_rec, expression_rec) step = self.stepValue() self.analyzer.incrementLabel() start_label = self.analyzer.getLabel() self.analyzer.incrementLabel() false_label = self.analyzer.getLabel() self.analyzer.genLabel(start_label) self.finalValue() self.analyzer.genPushId(ident_rec) if (step == "to"): self.analyzer.genBoolean(">=", ident_rec, expression_rec) self.analyzer.genBranchFalse(false_label) elif (step == "downto"): self.analyzer.genBoolean("<=", ident_rec, expression_rec) self.analyzer.genBranchFalse(false_label) self.match('MP_DO') self.statement() if (step == "to"): self.analyzer.genPushInt(str(1)) elif (step == "downto"): self.analyzer.genPushInt(str(-1)) self.analyzer.genPushId(ident_rec) self.analyzer.output("ADDS") self.analyzer.genAssign(ident_rec, expression_rec) self.analyzer.genBranch(start_label) self.analyzer.genLabel(false_label) else: self.error("for") def controlVariable(self): identRec = {} if self.lookahead is 'MP_IDENTIFIER': # 57 ControlVariable -> VariableIdentifier id = self.variableIdentifier() identRec = self.analyzer.processId(id) identRec["lexeme"] = id return identRec else: self.error("identifier") def initialValue(self): if self.lookahead in [ 'MP_LPAREN', 'MP_IDENTIFIER', # 58 InitialValue -> OrdinalExpression 'MP_PLUS', 'MP_MINUS', 'MP_FLOAT_LIT', 'MP_FIXED_LIT', 'MP_STRING_LIT', 'MP_NOT', 'MP_INTEGER_LIT', 'MP_TRUE', 'MP_FALSE' ]: return self.ordinalExpression() else: self.error("(, identifier, +, -, any literal value, not") def stepValue(self): if self.lookahead is 'MP_TO': # 59 StepValue -> "to" return self.match('MP_TO') elif self.lookahead is 'MP_DOWNTO': # 60 StepValue -> "downto" return self.match('MP_DOWNTO') else: self.error("to, downto") def finalValue(self): if self.lookahead in [ 'MP_LPAREN', 'MP_IDENTIFIER', # 61 FinalValue -> OrdinalExpression 'MP_PLUS', 'MP_MINUS', 'MP_FLOAT_LIT', 'MP_FIXED_LIT', 'MP_STRING_LIT', 'MP_NOT', 'MP_INTEGER_LIT', 'MP_TRUE', 'MP_FALSE' ]: self.ordinalExpression() else: self.error("(, identifier, +, -, any literal value, not") def procedureStatement(self): if self.lookahead is 'MP_IDENTIFIER': # 62 ProcedureStatement -> ProcedureIdentifier OptionalActualParameterList self.analyzer.incrementSP(4) # leave space for function/procedure procedureName = self.procedureIdentifier() self.optionalActualParameterList() entry = self.symbolTableStack.getCurrentTable().find(procedureName) if entry != None: self.analyzer.genCall(entry['label']) else: print "Error: " + procedureName + " not found. It either doesn't exist or out of scope." sys.exit() else: self.error("identifier") def optionalActualParameterList(self): if self.lookahead is 'MP_LPAREN': # 63 OptionalActualParameterList -> "(" ActualParameter ActualParameterTail ")" self.match('MP_LPAREN') self.actualParameter() self.actualParameterTail() self.match('MP_RPAREN') elif self.lookahead in [ 'MP_SCOLON', 'MP_RPAREN', 'MP_END', 'MP_COMMA', # 64 OptionalActualParameterList -> lambda 'MP_THEN', 'MP_ELSE', 'MP_UNTIL', 'MP_TO', 'MP_DO', 'MP_DOWNTO', 'MP_EQUAL', 'MP_LTHAN', 'MP_GTHAN', 'MP_LEQUAL', 'MP_GEQUAL', 'MP_NEQUAL', 'MP_PLUS', 'MP_MINUS', 'MP_OR', 'MP_TIMES', 'MP_DIV', 'MP_MOD', 'MP_AND', 'MP_SLASH' ]: return else: self.error( ";, ), end, comma, then, else, until, to do, downto, an equality operator, an arithmetic operator, and, mod" ) def actualParameterTail(self): if self.lookahead is 'MP_COMMA': # 65 ActualParameterTail -> "," ActualParameter ActualParameterTail self.match('MP_COMMA') self.actualParameter() self.actualParameterTail() elif self.lookahead is 'MP_RPAREN': # 66 ActualParameterTail -> lambda return else: self.error("comma, )") def actualParameter(self): if self.lookahead in [ 'MP_LPAREN', 'MP_IDENTIFIER', # 67 ActualParameter -> OrdinalExpression 'MP_PLUS', 'MP_MINUS', 'MP_FLOAT_LIT', 'MP_FIXED_LIT', 'MP_STRING_LIT', 'MP_NOT', 'MP_INTEGER_LIT', 'MP_TRUE', 'MP_FALSE' ]: self.ordinalExpression() else: self.error("(, identifier, +, -, any literal value, not") def expression(self): expression_rec = {} if self.lookahead in [ 'MP_LPAREN', 'MP_IDENTIFIER', # 68 Expression -> SimpleExpression OptionalRelationalPart 'MP_PLUS', 'MP_MINUS', 'MP_FLOAT_LIT', 'MP_FIXED_LIT', 'MP_STRING_LIT', 'MP_NOT', 'MP_INTEGER_LIT', 'MP_TRUE', 'MP_FALSE' ]: expression_rec = self.simpleExpression() expression_rec = self.optionalRelationalPart(expression_rec) return expression_rec # return self.mapTokenToType(self.lookahead) else: self.error("(, identifier, +, -, any literal value, not") def optionalRelationalPart(self, expression_rec): rightOp = {} leftOp = expression_rec if self.lookahead in [ 'MP_EQUAL', 'MP_LTHAN', # 69 OptionalRelationalPart -> RelationalOperator SimpleExpression 'MP_GTHAN', 'MP_LEQUAL', 'MP_GEQUAL', 'MP_NEQUAL' ]: operator = self.relationalOperator() rightOp = self.simpleExpression() self.analyzer.genBoolean(operator, leftOp, rightOp) expression_rec["type"] = 'Boolean' return expression_rec elif self.lookahead in [ 'MP_SCOLON', 'MP_RPAREN', # 70 OptionalRelationalPart -> lambda 'MP_END', 'MP_COMMA', 'MP_THEN', 'MP_ELSE', 'MP_UNTIL', 'MP_DO', 'MP_TO', 'MP_DOWNTO' ]: return expression_rec else: self.error( "an equality operator, ;, ), then, else, until, do, to, downto" ) def relationalOperator(self): if self.lookahead is 'MP_EQUAL': # 71 RelationalOperator -> "=" operator = self.match('MP_EQUAL') elif self.lookahead is 'MP_LTHAN': # 72 RelationalOperator -> "<" operator = self.match('MP_LTHAN') elif self.lookahead is 'MP_GTHAN': # 73 RelationalOperator -> ">" operator = self.match('MP_GTHAN') elif self.lookahead is 'MP_LEQUAL': # 74 RelationalOperator -> "<=" operator = self.match('MP_LEQUAL') elif self.lookahead is 'MP_GEQUAL': # 75 RelationalOperator -> ">=" operator = self.match('MP_GEQUAL') elif self.lookahead is 'MP_NEQUAL': # 76 RelationalOperator -> "<>" operator = self.match('MP_NEQUAL') else: self.error("an equality operator") return operator def simpleExpression(self): # semantic records termRec = {} termTailRec = {} if self.lookahead in [ 'MP_LPAREN', 'MP_IDENTIFIER', # 77 SimpleExpression -> OptionalSign Term TermTail 'MP_PLUS', 'MP_MINUS', 'MP_FLOAT_LIT', 'MP_FIXED_LIT', 'MP_STRING_LIT', 'MP_NOT', 'MP_INTEGER_LIT', 'MP_TRUE', 'MP_FALSE' ]: sign = self.optionalSign() termRec = self.term() type = termRec['type'] if sign == "-": if type == "Integer": self.analyzer.genNeg() elif type in ["Float", "Fixed"]: self.analyzer.genNegf() termTailRec = termRec termTailRec = self.termTail(termTailRec) expressionRec = termTailRec # This is what Rocky suggested return expressionRec else: self.error("(, identifier, +, -, any literal value, not") def termTail(self, termTailRec={}): # Semantic Records addopRec = {} termRec = {} if self.lookahead in ['MP_PLUS', 'MP_MINUS', 'MP_OR' ]: # 78 TermTail -> AddingOperator Term TermTail addopRec["lexeme"] = self.addingOperator() termRec = self.term() resultRec = self.analyzer.genArithmetic(termTailRec, addopRec, termRec) self.termTail(resultRec) termTailRec = resultRec return termTailRec elif self.lookahead in [ 'MP_SCOLON', 'MP_RPAREN', 'MP_END', # 79 TermTail -> lambda 'MP_COMMA', 'MP_THEN', 'MP_ELSE', 'MP_UNTIL', 'MP_DO', 'MP_TO', 'MP_DOWNTO', 'MP_EQUAL', 'MP_LTHAN', 'MP_GTHAN', 'MP_LEQUAL', 'MP_GEQUAL', 'MP_NEQUAL' ]: return termTailRec else: self.error( "+, -, or, ;, ), end, comma, then, else, until, do, to, downto, an equality operator" ) def optionalSign(self): if self.lookahead is 'MP_PLUS': # 80 OptionalSign -> "+" self.match('MP_PLUS') elif self.lookahead is 'MP_MINUS': # 81 OptionalSign -> "-" return self.match('MP_MINUS') elif self.lookahead in [ 'MP_LPAREN', 'MP_IDENTIFIER', # 82 OptionalSign -> lambda 'MP_NOT', 'MP_INTEGER_LIT', 'MP_FLOAT_LIT', 'MP_FIXED_LIT', 'MP_STRING_LIT', 'MP_TRUE', 'MP_FALSE' ]: return else: self.error("+, -, (, identifier, +, -, any literal value, not") def addingOperator(self): if self.lookahead is 'MP_PLUS': # 83 AddingOperator -> "+" return self.match('MP_PLUS') elif self.lookahead is 'MP_MINUS': # 84 AddingOperator -> "-" return self.match('MP_MINUS') elif self.lookahead is 'MP_OR': # 85 AddingOperator -> "or" return self.match('MP_OR') else: self.error("+, -, or") def term(self): termRec = {} if self.lookahead in [ 'MP_LPAREN', # 86 Term -> Factor FactorTail 'MP_IDENTIFIER', 'MP_NOT', 'MP_INTEGER_LIT', 'MP_FLOAT_LIT', 'MP_FIXED_LIT', 'MP_STRING_LIT', 'MP_TRUE', 'MP_FALSE' ]: termRec["type"] = self.factor() termRec = self.factorTail(termRec) return termRec # return self.mapTokenToType(self.lookahead) else: self.error("(, identifier, +, -, any literal value, not") def factorTail(self, termRec): rightOp = {} operator = {} if self.lookahead in [ 'MP_TIMES', 'MP_DIV', # 87 FactorTail -> MultiplyingOperator Factor FactorTail 'MP_MOD', 'MP_AND', 'MP_SLASH' ]: operator["lexeme"] = self.multiplyingOperator() rightOp["type"] = self.factor() self.analyzer.genArithmetic(termRec, operator, rightOp) self.factorTail(rightOp) return termRec elif self.lookahead in [ 'MP_SCOLON', 'MP_RPAREN', 'MP_END', # 88 FactorTail -> lambda 'MP_COMMA', 'MP_THEN', 'MP_ELSE', 'MP_UNTIL', 'MP_DO', 'MP_TO', 'MP_DOWNTO', 'MP_EQUAL', 'MP_LTHAN', 'MP_GTHAN', 'MP_LEQUAL', 'MP_GEQUAL', 'MP_NEQUAL', 'MP_PLUS', 'MP_MINUS', 'MP_OR' ]: return termRec else: self.error( "*, div, mod, and /, ;, ), end, comma, then, else, until, do, to, downto, an equality operator, +, -, or" ) def multiplyingOperator(self): if self.lookahead is 'MP_TIMES': # 89 MultiplyingOperator -> "*" return self.match('MP_TIMES') elif self.lookahead is 'MP_DIV': # 90 MultiplyingOperator -> "div" return self.match('MP_DIV') elif self.lookahead is 'MP_MOD': # 91 MultiplyingOperator -> "mod" return self.match('MP_MOD') elif self.lookahead is 'MP_AND': # 92 MultiplyingOperator -> "and" return self.match('MP_AND') elif self.lookahead is 'MP_SLASH': # 112 MultiplyingOperator -> "/" return self.match('MP_SLASH') else: self.error("*, div, mod, and, /") def factor(self): # semantic record identRec = {} if self.lookahead in ['MP_INTEGER_LIT' ]: # 93 Factor -> UnsignedInteger integer = self.match('MP_INTEGER_LIT') self.analyzer.genPushInt(integer) return "Integer" elif self.lookahead is 'MP_IDENTIFIER': # 94 Factor -> VariableIdentifier OR # 97 Factor -> FunctionIdentifier OptionalActualParameterList id_kind = self.analyzer.processId(self.scanner.lexeme)["kind"] if id_kind == "function": self.analyzer.incrementSP( 4) # leave space for function/procedure's display register id = self.functionIdentifier() self.optionalActualParameterList() entry = self.symbolTableStack.getCurrentTable().find(id) if entry != None: self.analyzer.genCall(entry['label']) # self.analyzer.popDisplayAndParams(id) else: print "Error: " + id + " not found. It either doesn't exist or out of scope." sys.exit() elif id_kind in ["var", "iparam", "dparam"]: id = self.variableIdentifier() identRec["lexeme"] = id self.analyzer.genPushId(identRec) return self.analyzer.processId(id)["type"] elif self.lookahead is 'MP_NOT': # 95 Factor -> "not" Factor self.match('MP_NOT') self.factor() self.analyzer.genNot() return "Boolean" elif self.lookahead is 'MP_LPAREN': # 96 Factor -> "(" Expression ")" self.match('MP_LPAREN') type = self.expression()["type"] self.match('MP_RPAREN') return type elif self.lookahead in ['MP_FLOAT_LIT']: # 113 Factor -> UnsignedFloat float = self.match('MP_FLOAT_LIT') self.analyzer.genPushFloat(float) return "Float" elif self.lookahead in ['MP_FIXED_LIT']: # 113 Factor -> UnsignedFloat fixed = self.match('MP_FIXED_LIT') self.analyzer.genPushFloat(fixed) return "Float" elif self.lookahead in ['MP_STRING_LIT' ]: # 114 Factor -> StringLiteral string = self.match('MP_STRING_LIT') self.analyzer.genPushString(string) return "String" elif self.lookahead in ['MP_TRUE']: # 115 Factor -> "True" self.match('MP_TRUE') self.analyzer.genPushBoolean(1) return "Boolean" elif self.lookahead in ['MP_FALSE']: # 116 Factor -> "False" self.match('MP_FALSE') self.analyzer.genPushBoolean(0) return "Boolean" else: self.error("(, identifier, +, -, any literal value, not") def programIdentifier(self): if (self.lookahead == "MP_IDENTIFIER" ): # 98 ProgramIdentifier -> Identifier return self.match("MP_IDENTIFIER") else: self.error("identifier") def variableIdentifier(self): if (self.lookahead == "MP_IDENTIFIER" ): # 99 VariableIdentifier -> Identifier return self.match("MP_IDENTIFIER") else: self.error("identifier") def procedureIdentifier(self): if (self.lookahead == "MP_IDENTIFIER" ): # 100 ProcedureIdentifier -> Identifier return self.match("MP_IDENTIFIER") else: self.error("identifier") def functionIdentifier(self): if (self.lookahead == "MP_IDENTIFIER" ): # 101 FunctionIdentifier -> Identifier return self.match("MP_IDENTIFIER") else: self.error("identifier") def booleanExpression(self): if (self.lookahead in [ "MP_LPAREN", "MP_IDENTIFIER", # 102 BooleanExpression -> Expression "MP_PLUS", "MP_MINUS", "MP_NOT", "MP_INTEGER_LIT", 'MP_FLOAT_LIT', 'MP_FIXED_LIT', 'MP_STRING_LIT', 'MP_TRUE', 'MP_FALSE' ]): self.expression() else: self.error("(, identifier, +, -, any literal value, not, +, -") def ordinalExpression(self): if (self.lookahead in [ "MP_LPAREN", "MP_IDENTIFIER", # 103 OrdinalExpression -> Expression "MP_PLUS", "MP_MINUS", "MP_NOT", "MP_INTEGER_LIT", 'MP_FLOAT_LIT', 'MP_FIXED_LIT', 'MP_STRING_LIT', 'MP_TRUE', 'MP_FALSE' ]): return self.expression() else: self.error("(, identifier, +, -, any literal value, not, +, -") def identifierList(self): if (self.lookahead == "MP_IDENTIFIER" ): # 104 IdentifierList -> Identifier IdentifierTail ident = [] ident.append(self.scanner.lexeme) self.match("MP_IDENTIFIER") self.identifierTail(ident) return ident else: self.error("identifier") def identifierTail(self, ident): if (self.lookahead == "MP_COMMA" ): # 105 IdentifierTail -> "," Identifier IdentifierTail self.match("MP_COMMA") ident.append(self.scanner.lexeme) self.match("MP_IDENTIFIER") self.identifierTail(ident) elif (self.lookahead == "MP_COLON"): # 106 IdentifierTail -> lambda return else: self.error("comma, :") def error(self, expected): print "ERROR: Syntax error found on line " + str( self.scanner.getLineNumber()) + ", column " + str( self.scanner.getColumnNumber()) print "Found " + self.scanner.lexeme + " when expected one of: " + expected # print the caller # print inspect.stack()[1][3] sys.exit() def matchError(self, expected): print "ERROR: Match error found on line " + str( self.scanner.getLineNumber()) + ", column " + str( self.scanner.getColumnNumber( )) + " lexeme: " + self.scanner.lexeme print "Found " + self.lookahead + " when expected " + expected # print the caller sys.exit()