def test_scope_local(self): u = Scope(None) i = Integer() u.insert("Integer", i) p = Scope(u) c = Constant(i, 5) p.insert("const", c) self.assertTrue(u.local("Integer")) self.assertTrue(p.local("const")) self.assertEqual(None, u.find("const")) self.assertEqual(i, p.find("Integer"))
def test_scope_insert(self): s = Scope(None) i = Integer() s.insert("Integer", i) self.assertEqual(i, s.find("Integer"))
class Parser: def __init__(self, scanner, output_object, parser_type, style): """Initializes the parser with a scanner and output style (text or graph). """ self.scanner = scanner self.last = None self.current = None self.style = style self.parser_type = parser_type self.output_object = output_object # The stack is used to store non-terminals for output. The # ParserObserver uses it to determine indentation and construct # edges for the graph. self.stack = [] # Used as IDs for non-terminals in the graph. self.graph_index = 0 # Number of tokens skipped after an error has occured. self.num_tokens_skipped = 0 # Whether to supress error messages. self.supress = False # Whether to display output (will be false when an error occurs). self.display = True # The last token mismatched. Used to make sure mismatched tokens do not # increment supression counters more than once. self.last_mismatch = None self.weak_tokens = {";", ":", ",", ")", "]", "END"} def next(self): """Get the next token. From Peter's lecture.""" self.last = self.current self.current = self.scanner.next() while self.current.kind == "INVALID": self.current = self.scanner.next() def invalid_token(self, e): """Handles an invalid token. Will print an error message if not supressed. """ if not self.supress: self.supress = True self.num_tokens_skipped = 0 self.display = False sys.stderr.write(e.message + "\n") self.last_mismatch = self.current def increment_skip(self): """If errors are being supressed, increment tokens skipped.""" # Do not increment the counter if the token has already been # mismatched before. if self.supress and (self.last_mismatch == None or self.last_mismatch != self.current): self.num_tokens_skipped += 1 if self.num_tokens_skipped > 7: self.supress = False self.num_tokens_skipped = 0 @ParserObserver.terminal def match(self, kind): """Match a token to kind(s). Parts from Peter's lecture. Return the token matched. """ try: self.increment_skip() # Match token with a set of kinds. if type(kind) is set: # Token matched. if self.current.kind in kind: self.next() return self.last # Token mismatch. Throw an exception. else: raise ParserInvalidKindError(kind, self.current) # Match token with a single kind else: # Token matched. if self.current.kind == kind: self.next() return self.last # Token mismatch. Throw an exception else: raise ParserInvalidKindError(kind, self.current) except ParserInvalidKindError as e: # Handle the exception. self.invalid_token(e) def sync(self, kinds, terminals): """Resync the parser when there is a mismatch of non-weak symbols. The function will skip tokens until reaching a strong token in kinds or a symbol that terminates the program. """ # Skip until finding a strong symbol in kinds. while self.current.kind not in kinds: # Raise an exception due to mismatch try: raise ParserInvalidKindError("Type", self.current) except ParserInvalidKindError as e: self.invalid_token(e) # The program ended before the parser is able to sync. end the loop. if self.current.kind in terminals: return False # Skip the current token. self.next() # Sucessfully re-synced the parser. return True def insert(self, name, value): """Insert an entry into the symbol table.""" try: if self.current_scope.local(name.value): raise DuplicateDeclarationError(name) self.current_scope.insert(name.value, value) except DuplicateDeclarationError as e: self.invalid_token(e) def find(self, name): """Find an identifier in the symbol table.""" try: entry = self.current_scope.find(name) if entry == None: raise EntryNotFoundInSymbolTable(self.last) return entry except EntryNotFoundInSymbolTable as e: self.invalid_token(e) def set_record_scope(self, entry): """Set the current scope to be a record's scope.""" if isinstance(entry, Variable) or isinstance(entry, Field): # Record can be either in variable or field. if isinstance(entry.type, Array) and isinstance(entry.type.element_type, Record): # An array of record. self.record_scope = entry.type.element_type.scope elif isinstance(entry.type, Record): # a record variable. self.record_scope = entry.type.scope else: self.record_scope = None else: self.record_scope = None def negate_relation(self, relation): """Negate the relation in a condition.""" negation_map = {"=": "#", "#": "=", ">": "<=", "<": ">=", ">=": "<", "<=": ">"} return negation_map[relation] @ParserObserver.selector def selector(self, location): """Match the grammar of a selector.""" ret = None # 0 to many patterns. while True: if self.current.kind == "[": self.match("[") self.stack.append("ExpressionList") expressions = self.expression_list() self.match("]") for expression in expressions: if not isinstance(location, Location) or not isinstance(location.type, Array): # Not an array variable. try: raise InvalidArray(location.type, self.last) except InvalidArray as e: self.invalid_token(e) cur = Index(location, expression) cur.token = self.last ret = cur location = cur elif self.current.kind == ".": self.match(".") name = self.match("identifier") if name == None: continue if self.record_scope == None: # Not a record variable. try: raise InvalidRecord(location.type, self.last) except InvalidRecord as e: self.invalid_token(e) break # Access the record's scope and find the variable with name. self.current_scope = self.record_scope entry = self.find(name.value) var = VariableAST(name.value, entry) self.set_record_scope(entry) cur = FieldAST(location, var) ret = cur location = cur else: # Pattern ended. break self.current_scope = self.program_scope return ret @ParserObserver.non_terminal def designator(self): """Match the grammar for a designator.""" name = self.match("identifier") if name == None: return None entry = self.find(name.value) if isinstance(entry, Constant): var = Number(entry) elif isinstance(entry, Variable): var = VariableAST(name.value, entry) else: # Identifier in designator cannot be a type. try: raise InvalidDesignator(entry, self.last) except InvalidDesignator as e: self.invalid_token(e) return VariableAST("INVALID", Variable(Invalid())) self.set_record_scope(entry) self.stack.append("Selector") ret = self.selector(var) if ret == None: ret = var if not isinstance(ret, Location) and not isinstance(ret, Number): try: raise InvalidDesignator(ret.type, self.last) except InvalidDesignator as e: self.invalid_token(e) return VariableAST("INVALID", Variable(Invalid())) return ret @ParserObserver.non_terminal def identifier_list(self): """Match the grammar for a identifier list.""" id_list = [] identifier = self.match("identifier") id_list.append(identifier) # 0 to many patterns. while True: if self.current.kind == ",": self.match(",") identifier = self.match("identifier") id_list.append(identifier) else: # Pattern ended. break return id_list @ParserObserver.non_terminal def expression_list(self): """Match the grammar for a expression list.""" exp_list = [] self.stack.append("Expression") exp_list.append(self.expression()) # 0 to many patterns. while True: if self.current.kind == ",": self.match(",") self.stack.append("Expression") expression = self.expression() exp_list.append(expression) else: # Pattern ended. break return exp_list @ParserObserver.non_terminal def read(self): """Match the grammar for a read.""" self.match("READ") self.stack.append("Designator") location = self.designator() if not isinstance(location, Location) or location.type != self.integer_type: # Not an integer variable. try: raise InvalidRead(location.type, self.last) except InvalidRead as e: self.invalid_token(e) r = Read(location) r.token = self.last return r @ParserObserver.non_terminal def write(self): """Match the grammar for a write.""" self.match("WRITE") self.stack.append("Expression") expression = self.expression() if expression.type != self.integer_type: # Not an integer. try: raise InvalidWrite(expression.type, self.last) except InvalidWrite as e: self.invalid_token(e) return Write(expression) @ParserObserver.non_terminal def condition(self): """Match the grammar for a condition.""" self.stack.append("Expression") left = self.expression() # Match a token with a set of kinds. kinds = {"=", "#", "<", ">", "<=", ">="} relation = self.match(kinds) self.stack.append("Expression") right = self.expression() if left.type != self.integer_type or right.type != self.integer_type: # Either is not of Constant or Variable of type integer. try: raise InvalidCondition(left.type, right.type, self.last) except InvalidCondition as e: self.invalid_token(e) return Condition(left, right, relation.kind) @ParserObserver.non_terminal def while_instruction(self): """Match the grammar for a while.""" self.match("WHILE") self.stack.append("Condition") condition = self.condition() self.match("DO") self.stack.append("Instructions") instructions = self.instructions() self.match("END") # Replaces while with repeat in AST left = condition.left right = condition.right inverse = self.negate_relation(condition.relation) inverse_left = copy.deepcopy(left) inverse_right = copy.deepcopy(right) inverse_condition = Condition(inverse_left, inverse_right, inverse) repeat = Repeat(inverse_condition, instructions) repeat.next = None return If(condition, repeat, None) @ParserObserver.non_terminal def repeat(self): """Match the grammar for a repeat.""" self.match("REPEAT") self.stack.append("Instructions") instructions = self.instructions() self.match("UNTIL") self.stack.append("Condition") condition = self.condition() self.match("END") return Repeat(condition, instructions) @ParserObserver.non_terminal def if_instruction(self): """Match the grammar for an if.""" self.match("IF") self.stack.append("Condition") condition = self.condition() self.match("THEN") self.stack.append("Instructions") instructions_true = self.instructions() instructions_false = None # Optional match. if self.current.kind == "ELSE": self.match("ELSE") self.stack.append("Instructions") instructions_false = self.instructions() self.match("END") return If(condition, instructions_true, instructions_false) @ParserObserver.non_terminal def assign(self): """Match the grammar for an assign.""" self.stack.append("Designator") location = self.designator() self.match(":=") self.stack.append("Expression") expression = self.expression() if not isinstance(location, Location) or location.type != expression.type: # Left side is not variable, or right side is a type, or types of # both sides do not match up. try: raise InvalidAssignment(location.type, expression.type, self.last) except InvalidAssignment as e: self.invalid_token(e) return Assign(location, expression) @ParserObserver.non_terminal def instruction(self): """Match the grammar for an instruction.""" # The set of kinds to be matched. kinds = {"identifier", "IF", "REPEAT", "WHILE", "READ", "WRITE"} # The symbols that signal end of an instruction. In this case, # . and eof singal the end of the program, which must be the # end of an instruction. terminals = {"END", ".", "eof"} if self.current.kind == "identifier": self.stack.append("Assign") return self.assign() elif self.current.kind == "IF": self.stack.append("If") return self.if_instruction() elif self.current.kind == "REPEAT": self.stack.append("Repeat") return self.repeat() elif self.current.kind == "WHILE": self.stack.append("While") return self.while_instruction() elif self.current.kind == "READ": self.stack.append("Read") return self.read() elif self.current.kind == "WRITE": self.stack.append("Write") return self.write() elif self.current.kind == "END": # END signifies the end of instructions. return None else: # No match is made and no END of ending instructions. An error has # occured and the symbol missing is not weak. The parser must resync # with the code. if not self.sync(kinds, terminals): return None @ParserObserver.non_terminal def instructions(self): """Match the grammar for instructions.""" self.stack.append("Instruction") head = instruction = self.instruction() # 0 or more patterns. while True: # These symbols preceed or end instructions. End the loop. if self.current.kind in {"THEN", "ELSE", "REPEAT", "DO", "END", "UNTIL", ".", "eof"}: break # A normal or a mismatch. If necessary resync will happen in # instruction. else: self.match(";") self.stack.append("Instruction") next_instruction = self.instruction() if next_instruction == None: continue instruction.next = next_instruction instruction = instruction.next if instruction != None: instruction.next = None return head @ParserObserver.non_terminal def factor(self): """Match the grammar for a factor.""" ret = None if self.current.kind == "integer": num = self.match("integer") const = Constant(self.integer_type, num.value) ret = Number(const) elif self.current.kind == "identifier": self.stack.append("Designator") ret = self.designator() elif self.current.kind == "(": self.match("(") self.stack.append("Expression") ret = self.expression() self.match(")") else: # An error has occured. Raise and catch it so we can handle the # error without crashing the program. try: self.increment_skip() raise ParserInvalidKindError("Factor", self.current) except ParserInvalidKindError as e: self.invalid_token(e) return ret @ParserObserver.non_terminal def term(self): """Match the grammar for a term.""" self.stack.append("Factor") operator_map = {"*": "*", "DIV": "/", "MOD": "%"} cur = self.factor() # 0 or more patterns. while True: if self.current.kind == "*" or self.current.kind == "DIV" or self.current.kind == "MOD": if self.current.kind == "*": operator = self.match("*") elif self.current.kind == "DIV": operator = self.match("DIV") else: operator = self.match("MOD") self.stack.append("Factor") var = self.factor() if isinstance(cur, Number) and isinstance(var, Number): # Constant folding. try: val = int(eval(str(cur.entry.value) + str(operator_map[operator.kind]) + str(var.entry.value))) except ZeroDivisionError: # Divide by 0 error. self.invalid_token(DivideByZero(self.last)) break const = Constant(self.integer_type, val) cur = Number(const) else: if isinstance(cur, VariableAST) and ( isinstance(cur.variable, Array) or isinstance(cur.variable, Record) ): # Trying to perform an operation on non-integers. try: raise InvalidArithmeticOperation(cur, self.last) except InvalidArithmeticOperation as e: self.invalid_token(e) else: cur = Binary(operator.kind, cur, var, self.integer_type) # Remember the token for node in case of run time errors. cur.token = self.last else: # Pattern ended. break return cur @ParserObserver.non_terminal def expression(self): """Match the grammar of an expression.""" operator = None if self.current.kind == "+": operator = self.match("+") elif self.current.kind == "-": operator = self.match("-") self.stack.append("Term") cur = self.term() if operator != None and operator.kind == "-": # Negate the expression if needed. if isinstance(cur, Number): # Constant folding. cur = Number(Constant(self.integer_type, eval(str(operator.kind) + str(cur.entry.value)))) else: if isinstance(cur, VariableAST) and ( isinstance(cur.variable, Array) or isinstance(cur.variable, Record) ): # Trying to perform an operation on non-integers. try: raise InvalidArithmeticOperation(cur, self.last) except InvalidArithmeticOperation as e: self.invalid_token(e) else: cur = Binary(operator.kind, Number(Constant(self.integer_type, 0)), cur, self.integer_type) # Remember the token for node in case of run time errors. cur.token = self.last # 0 or more patterns. while True: if self.current.kind in {"+", "-"}: if self.current.kind == "+": operator = self.match("+") else: operator = self.match("-") self.stack.append("Term") var = self.term() if isinstance(cur, Number) and isinstance(var, Number): # Constant folding. cur = Number( Constant( self.integer_type, eval(str(cur.entry.value) + str(operator.kind) + str(var.entry.value)) ) ) else: if isinstance(cur, VariableAST) and ( isinstance(cur.variable, Array) or isinstance(cur.variable, Record) ): # Trying to perform an operation on non-integers. try: raise InvalidArithmeticOperation(cur, self.last) except InvalidArithmeticOperation as e: self.invalid_token(e) else: cur = Binary(operator.kind, cur, var, self.integer_type) # Remember token for node in case of run time errors. cur.token = self.last else: # Pattern ended. break if cur == None: # Return an invalid variable node in case of parsing errors. cur = VariableAST("INVALID", Variable(Invalid())) return cur @ParserObserver.non_terminal def type(self): """Match the grammar of a type.""" type_obj = None if self.current.kind == "identifier": name = self.match("identifier") # Return the type object found in current scope try: type_obj = self.current_scope.find(name.value) if type_obj == None: raise IdentifierUsedBeforeDeclared(name) elif not isinstance(type_obj, Type): raise IdentifierDoesNotDenoteType(name, type_obj) except (IdentifierUsedBeforeDeclared, IdentifierDoesNotDenoteType) as e: type_obj = Invalid() self.invalid_token(e) elif self.current.kind == "ARRAY": self.match("ARRAY") self.stack.append("Expression") size = self.expression() try: if not isinstance(size, Number) or (isinstance(size, Number) and size.entry.value <= 0): # Arrays need to have size greater than 0. raise InvalidArraySize(size, self.last) except InvalidArraySize as e: type_obj = Invalid() self.invalid_token(e) return type_obj self.match("OF") self.stack.append("Type") t = self.type() # Create an Array type object. type_obj = Array(t, size.entry.value) elif self.current.kind == "RECORD": self.match("RECORD") # Create a new scope for the record and set the current scope # to the record scope. record_scope = Scope(self.current_scope) self.current_scope = record_scope # 0 or more patterns. while True: if self.current.kind == "identifier": self.stack.append("IdentifierList") id_list = self.identifier_list() self.match(":") self.stack.append("Type") t = self.type() self.match(";") # Insert the type objects into the current scope. field = Field(t) for name in id_list: self.insert(name, field) else: # pattern ended. break self.match("END") # Create a Record object with the current scope. Also set the # current scope to the outer scope and remove the outer pointer. type_obj = Record(self.current_scope) outer = self.current_scope.outer self.current_scope.outer = None self.current_scope = outer else: # An error has occured. Raise and catch it so we can handle the # error without crashing the program. try: self.increment_skip() raise ParserInvalidKindError("Type", self.current) except ParserInvalidKindError as e: self.invalid_token(e) return type_obj @ParserObserver.non_terminal def const_decl(self): """Match the grammar of a const declaration.""" self.match("CONST") # 0 or more patterns. while True: if self.current.kind == "identifier": name = self.match("identifier") self.match("=") self.stack.append("Expression") value = self.expression() self.match(";") try: if isinstance(value, Number): # Create Constant object and insert into symbol table. const = Constant(self.integer_type, value.entry.value) self.insert(name, const) else: self.insert(name, Variable(Invalid())) raise InvalidConstantValue(value, self.last) except InvalidConstantValue as e: self.invalid_token(e) else: # Pattern ended. break @ParserObserver.non_terminal def type_decl(self): """Match the grammar of a type declaration.""" self.match("TYPE") # 0 or more patterns. while True: if self.current.kind == "identifier": name = self.match("identifier") self.match("=") self.stack.append("Type") t = self.type() self.match(";") self.insert(name, t) else: # Pattern ended. break @ParserObserver.non_terminal def var_decl(self): """Match the grammar of a var declaration.""" self.match("VAR") # 0 or more patterns. while True: if self.current.kind == "identifier": self.stack.append("IdentifierList") id_list = self.identifier_list() self.match(":") self.stack.append("Type") var_type = self.type() self.match(";") # Create Variable object(s) and insert them into symbol table. for name in id_list: var = Variable(var_type) self.insert(name, var) else: # Pattern ended. break @ParserObserver.non_terminal def declarations(self): """Match the grammar of declarations.""" # Strong symbols for resync kinds = {"CONST", "TYPE", "VAR"} # Signify end of declaration. terminals = {".", "eof", "BEGIN"} # 0 or more patterns. while True: if self.current.kind == "CONST": self.stack.append("ConstDecl") self.const_decl() elif self.current.kind == "TYPE": self.stack.append("TypeDecl") self.type_decl() elif self.current.kind == "VAR": self.stack.append("VarDecl") self.var_decl() # A normal end of declaration. elif self.current.kind in {"BEGIN", "END"}: break # A strong symbol mismatch. Need to resync the parser. else: if not self.sync(kinds, terminals): return @ParserObserver.non_terminal def program(self): """Match the grammar of the program.""" # Create the program scope self.program_scope = Scope(self.universe_scope) self.current_scope = self.program_scope self.match("PROGRAM") begin_name = self.match("identifier") self.match(";") self.stack.append("Declarations") self.declarations() # AST instruction tree. tree = None # Optional begin symbol. if self.current.kind == "BEGIN": self.match("BEGIN") self.stack.append("Instructions") tree = self.instructions() self.match("END") end_name = self.match("identifier") # Throw an exception if there is a program name mismatch if ( begin_name == None or end_name == None or begin_name.value == None or end_name.value == None or begin_name.value != end_name.value ): try: raise ProgramNameMismatch(begin_name, end_name) except ProgramNameMismatch as e: self.invalid_token(e) self.match(".") self.match("eof") return tree def parse(self): """Method called by sc to parse the code.""" # Create the universe scope. self.universe_scope = Scope(None) self.record_scope = None self.integer_type = Integer() self.universe_scope.insert("INTEGER", self.integer_type) # Start by getting the first token. self.next() # Start parsing by matching the grammar of program. self.stack.append("Program") tree = self.program() # Display the output only if no error has occured. if self.display: if self.parser_type == "-t": # Set the program scope if printing symbol table. self.output_object.program_scope = self.program_scope elif self.parser_type == "-a": # Set the program scope and instruction tree for AST output. self.output_object.program_scope = self.program_scope self.output_object.tree = tree elif self.parser_type == "-i": # Set the environment and instruction tree for interpreter. visitor = SymbolTableVisitor() self.output_object.env = self.current_scope.accept(visitor) self.output_object.tree = tree self.output_object.display()
class Parser: """Takes a list of tokens and performs semantic analysis to check if input adheres to grammar. Outputs to stdout a textual representation of the CST via the call stack. Parser is also capable of outputting graphical output """ # initializes Parser instance and parses a list of tokens # cmd line arguments determine output type def __init__(self, observer = Observer(), token_list=[], print_symbol_table = 0, visitor = Visitor()): self.current = 0 # current position in token list self.token_list = token_list # token list received from scanner self.kind_map = Token.kind_map # dictionary of token kinds self.observer = observer # output class determined by cmd line arguments self.total_error_flag = 0 # detects if an error occurs anywhere in the program self.universe = Scope(None) # universe scope self.universe.insert("INTEGER", integerInstance) # universe scope only holds integer self.program_scope = Scope(self.universe) # program scope to hold program names self.current_scope = self.program_scope # current scope for switching between scopes self.print_symbol_table = print_symbol_table # determines whether to print cst or st self.visitor = visitor # parse the token list def parse(self): instructions = self._program() # do not print any output if error occurs if self.total_error_flag == 0: if self.print_symbol_table == 0: self.observer.print_output() elif self.print_symbol_table == 1: self.visitor.visitScope(self.program_scope) self.visitor.end() elif self.print_symbol_table == 2: currinstruction = instructions self.visitor.start() # while(currinstruction is not None): currinstruction.visit(self.visitor) # currinstruction = currinstruction._next elif self.print_symbol_table == 3: # build environment pass def build_environment(self): pass # check if the currently parsed token is a token we are # expecting to find # kind = expected kind of token def match(self, kind): if self.token_list[self.current].kind == self.kind_map[kind]: self.observer.print_token(self.token_list[self.current]) self.current += 1 ### for returning identifier names return self.token_list[self.current-1].get_token_name() else: self.total_error_flag = 1 sys.stderr.write("error: expected token kind \'{0}\', " "received unexpected token \'{1}\'" " @({2}, {3})".format(kind, self.token_list[self.current], self.token_list[self.current].start_position, self.token_list[self.current].end_position) + '\n') # set expectation of creating a program # by following the program production def _program(self): # print "Program" self.observer.begin_program() self.match("PROGRAM") name = self.match("IDENTIFIER") self.match(";") self._declarations() instructions = None if self.token_list[self.current].kind == self.kind_map["BEGIN"]: self.match("BEGIN") instructions = self._instructions() self.match("END") end_name = self.match("IDENTIFIER") self.match(".") self.observer.end_program() if not name == end_name: self.total_error_flag = 1 sys.stderr.write("error: program identifier does not match end identifier\n") if not self.token_list[self.current].kind == self.kind_map["EOF"]: self.total_error_flag = 1 sys.stderr.write("error: trash detected after program end:\n" "Token \'{0}\'".format(self.token_list[self.current]) + '\n') return instructions # set expectation of creating a declaration # by following the declaration production def _declarations(self): self.observer.begin_declarations() while (self.token_list[self.current].kind == self.kind_map["CONST"]) or \ (self.token_list[self.current].kind == self.kind_map["TYPE"]) or \ (self.token_list[self.current].kind == self.kind_map["VAR"]): if self.token_list[self.current].kind == self.kind_map["CONST"]: self._constdecl() elif self.token_list[self.current].kind == self.kind_map["TYPE"]: self._typedecl() elif self.token_list[self.current].kind == self.kind_map["VAR"]: self._vardecl() else: pass self.observer.end_declarations() # set expectation of creating a ConstDecl # by following the ConstDecl production def _constdecl(self): # print "ConstDecl" self.observer.begin_constdecl() self.match("CONST") # return_obj = None while self.token_list[self.current].kind == self.kind_map["IDENTIFIER"]: name = self.match("IDENTIFIER") # check if const name in local scope if self.program_scope.local(name): self.total_error_flag = 1 sys.stderr.write("error: attempted to redefine identifier\n") self.match("=") e = self._expression() if not isinstance(e, NumberNode): self.total_error_flag = 1 sys.stderr.write("error: constdecl received nonconst exp\n") # exit(1) self.match(";") #return_obj = e # add it we formed a constant if isinstance(e.constant, Constant): # is it constant object or constant name self.program_scope.insert(name, e.constant) else: self.total_error_flag = 1 sys.stderr.write("error: attempted to define const with nonconst object\n") self.observer.end_constdecl() # return return_obj # set expectation of creating a TypeDecl # by following the TypeDecl production def _typedecl(self): # print "TypeDecl" self.observer.begin_typedecl() self.match("TYPE") #return_type = None while self.token_list[self.current].kind == self.kind_map["IDENTIFIER"]: name = self.match("IDENTIFIER") self.match("=") # type of current Type return_type = self._type() self.match(";") if return_type is None: self.total_error_flag = 1 sys.stderr.write("error: type not found\n") return None if not self.current_scope.local(name): self.current_scope.insert(name, return_type) else: self.total_error_flag = 1 sys.stderr.write("error: attempting to redefine variable\n") self.observer.end_typedecl() # return return_type # set expectation of creating a VarDecl # by following the VarDecl production def _vardecl(self): # print "VarDecl" self.observer.begin_vardecl() self.match("VAR") id_list = [] return_type = None while self.token_list[self.current].kind == self.kind_map["IDENTIFIER"]: id_list = self._identifier_list() self.match(":") return_type = self._type() # type of current identifier if return_type is None: self.total_error_flag = 1 sys.stderr.write("error: type not found\n") return None self.match(";") for name in id_list: if not self.current_scope.local(name): self.current_scope.insert(name, Variable(return_type)) else: self.total_error_flag = 1 sys.stderr.write("error: attempting to redefine var\n") self.observer.end_vardecl() return return_type # set expectation of creating a Type # by following the Type production def _type(self): # print "Type" self.observer.begin_type() return_type = None if self.token_list[self.current].kind == self.kind_map["IDENTIFIER"]: name = self.match("IDENTIFIER") # get the name of an identifier return_type = self.current_scope.find(name) if return_type is None: self.total_error_flag = 1 sys.stderr.write("error: indentifier not found. attempting to assign " "uncreated type\n") self.observer.end_type() return None if isinstance(return_type, Type): self.observer.end_type() return return_type else: self.total_error_flag = 1 sys.stderr.write("error: found not Type object\n") return None elif self.token_list[self.current].kind == self.kind_map["ARRAY"]: self.match("ARRAY") length = None e = self._expression() if isinstance(e, NumberNode): length = e.constant.value else: self.total_error_flag = 1 sys.stderr.write("error: not a valid type for array length\n") self.match("OF") array_type = self._type() if array_type is None: self.total_error_flag = 1 sys.stderr.write("error: array type not found\n") return None return_type = Array(length, array_type) self.observer.end_type() return return_type elif self.token_list[self.current].kind == self.kind_map["RECORD"]: self.match("RECORD") id_list = [] outer_scope = self.current_scope self.current_scope = Scope(outer_scope) while self.token_list[self.current].kind == self.kind_map["IDENTIFIER"]: id_list = self._identifier_list() self.match(":") record_field_type = self._type() if record_field_type is None: self.total_error_flag = 1 sys.stderr.write("error: record field type nonexistent\n") self.match(";") for name in id_list: if not self.current_scope.local(name): self.current_scope.insert(name, Variable(record_field_type)) else: self.total_error_flag = 1 sys.stderr.write("error: attempting to redefine field\n") return None self.match("END") return_type = Record(self.current_scope) outer_scope = self.current_scope.outer_scope self.current_scope.outer_scope = None self.current_scope = outer_scope self.observer.end_type() return return_type else: self.total_error_flag = 1 sys.stderr.out("error: expecting Identifier, ARRAY, or RECORD\n") self.observer.end_type() # set expectation of creating a Expression # by following the Expression production def _expression(self): self.observer.begin_expression() node = self.nexpression() self.observer.end_expression() return node def nexpression(self): outer_operation = -1 if self.token_list[self.current].kind == self.kind_map["+"]: outer_operation = self.match("+") elif self.token_list[self.current].kind == self.kind_map["-"]: outer_operation = self.match("-") subtree = self._term() node = subtree if (self.token_list[self.current].kind == self.kind_map["+"]) or \ (self.token_list[self.current].kind == self.kind_map["-"]): inner_operation = "" if self.token_list[self.current].kind == self.kind_map["+"]: inner_operation = self.match("+") elif self.token_list[self.current].kind == self.kind_map["-"]: inner_operation = self.match("-") else: self.total_error_flag = 1 sys.stderr.write("error: expecting \'+\' or \'-\'\n") subtree_right = self._term() if isinstance(subtree, NumberNode) and isinstance(subtree_right, NumberNode): result = 0 if inner_operation == "+": result = int(subtree.type.value) + int(subtree_right.type.value) elif inner_operation == "-": result = int(subtree.type.value) + int(subtree_right.type.value) else: pass c = Constant(integerInstance, result) num_node = NumberNode(c) node = num_node else: bn = BinaryNode(inner_operation, subtree, subtree_right) node = bn else: node = subtree if outer_operation == "-": # how to do negative numbers? if isinstance(node, BinaryNode): if isinstance(node.exp_left, NumberNode) and isinstance(node.exp_right, NumberNode): op = node.operator left_value = node.exp_left.value right_value = node.exp_right.value op_result = 0 if op == "+": op_result = left_value + right_value elif op == "-": op_result = left_value - right_value elif op == "*": op_result = left_value * right_value elif op == "DIV": op_result = left_value / right_value elif op == "MOD": op_result = left_value % right_value else: sys.stderr.write("error: invalid op") result = -1*op_result c = Constant(integerInstance, result) num_node = NumberNode(c) node = num_node elif isinstance(node, NumberNode): c = Constant(integerInstance, 0 - node.constant.value) num_node = NumberNode(c) node = num_node return node # set expectation of creating a Term # by following the Term production def _term(self): self.observer.begin_term() node = self.nterm() #return singular factor or binary node self.observer.end_term() return node def nterm(self): sub_left = self._factor() node = sub_left operation = 0 if (self.token_list[self.current].kind == self.kind_map["*"])or \ (self.token_list[self.current].kind == self.kind_map["DIV"]) or \ (self.token_list[self.current].kind == self.kind_map["MOD"]): if self.token_list[self.current].kind == self.kind_map["*"]: operation = self.match("*") elif self.token_list[self.current].kind == self.kind_map["DIV"]: operation = self.match("DIV") elif self.token_list[self.current].kind == self.kind_map["MOD"]: operation = self.match("MOD") else: self.total_error_flag = 1 sys.stderr.out("error: expecting \'*\', \'DIV\', or \'MOD\'\n") sub_right = self.nterm() if isinstance(sub_left, NumberNode) and isinstance(sub_right, NumberNode): result = 0 if operation == "*": result = int(sub_left.constant.value) * int(sub_right.constant.value) elif operation == "DIV": result = int(sub_left.constant.value) / int(sub_right.constant.value) elif operation == "MOD": result = int(sub_left.constant.value) % int(sub_right.constant.value) c = Constant(integerInstance, result) num_node = NumberNode(c) return num_node else: bn = BinaryNode(operation, sub_left, sub_right) return bn else: return sub_left # set expectation of creating a Factor # by following the Factor production def _factor(self): self.observer.begin_factor() node = None if self.token_list[self.current].kind == self.kind_map["INTEGER"]: int_value = self.match("INTEGER") c = Constant(integerInstance, int_value) node = NumberNode(c) # make a number node of out of the constant # return number node elif self.token_list[self.current].kind == self.kind_map["IDENTIFIER"]: sub_tree = self._designator() node = sub_tree elif self.token_list[self.current].kind == self.kind_map["("]: self.match("(") sub_tree = self._expression() self.match(")") node = sub_tree else: self.total_error_flag = 1 sys.stdout.error("error: expecting integer, identifier or \'(\'\n") self.observer.end_factor() return node # set expectation of creating a Instructions # by following the Instructions production def _instructions(self): self.observer.begin_instructions() head = self._instruction() curr = head while self.token_list[self.current].kind == self.kind_map[";"]: self.match(";") temp = self._instruction() curr._next = temp curr = temp self.observer.end_instructions() return head # set expectation of creating a Instruction # by following the Instruction production def _instruction(self): # print "Instruction" self.observer.begin_instruction() node = None if self.token_list[self.current].kind == self.kind_map["IDENTIFIER"]: node = self._assign() elif self.token_list[self.current].kind == self.kind_map["IF"]: node = self._if() elif self.token_list[self.current].kind == self.kind_map["REPEAT"]: node = self._repeat() elif self.token_list[self.current].kind == self.kind_map["WHILE"]: node = self._while() elif self.token_list[self.current].kind == self.kind_map["READ"]: node = self._read() elif self.token_list[self.current].kind == self.kind_map["WRITE"]: node = self._write() else: self.total_error_flag = 1 sys.stderr.write("error: not a valid instruction\n" "@({0}, {1})".format(self.token_list[self.current].start_position, self.token_list[self.current].end_position)) self.observer.end_instruction() return node # set expectation of creating a Assign # by following the Assign production def _assign(self): # print "Assign" self.observer.begin_assign() subtree_left = self._designator() if not (isinstance(subtree_left, VariableNode) or isinstance(subtree_left, FieldNode) or isinstance(subtree_left, IndexNode)): print type(subtree_left) sys.stderr.write("error: assign") stl_type = subtree_left.type self.match(":=") subtree_right = self._expression() str_type = subtree_right.type if not type(stl_type) == type(str_type): sys.stderr.write("error: assigning things that don't have the same type\n") assign_node = AssignNode(None, subtree_left, subtree_right) self.observer.end_assign() return assign_node # set expectation of creating a If # by following the If production def _if(self): # print "If" self.observer.begin_if() self.match("IF") condition = self._condition() self.match("THEN") instructions_true = self._instructions() instructions_false = None if self.token_list[self.current].kind == self.kind_map["ELSE"]: self.match("ELSE") instructions_false = self._instructions() self.match("END") self.observer.end_if() if_node = IfNode(None, condition, instructions_true, instructions_false) return if_node # set expectation of creating a Repeat # by following the Repeat production def _repeat(self): self.observer.begin_repeat() self.match("REPEAT") instructions = self._instructions() self.match("UNTIL") condition = self._condition() self.match("END") self.observer.end_repeat() repeat_node = RepeatNode(None, condition, instructions) return repeat_node # set expectation of creating a While # by following the While production def _while(self): self.observer.begin_while() self.match("WHILE") condition = self._condition() self.match("DO") instructions = self._instructions() self.match("END") self.observer.end_while() negation_condition_node = self.get_negation(condition) repeat_node = RepeatNode(None, negation_condition_node, instructions) if_node = IfNode(None, condition, repeat_node, None) return if_node def get_negation(self, condition_node): relation_negation = {"=":"#", "#":"=", "<":">", ">":"<", "<=":">=", ">=":"<="} negation_condition_node = ConditionNode(condition_node.exp_left, condition_node.exp_right, relation_negation[condition_node.relation]) return negation_condition_node # set expectation of creating a Condition # by following the Condition production def _condition(self): self.observer.begin_condition() left = self._expression() relation = "" if self.token_list[self.current].kind == self.kind_map["="]: # self.match("=") relation = self.match("=") elif self.token_list[self.current].kind == self.kind_map["#"]: # self.match("#") relation = self.match("#") elif self.token_list[self.current].kind == self.kind_map["<"]: # self.match("<") relation = self.match("<") elif self.token_list[self.current].kind == self.kind_map[">"]: # self.match(">") relation = self.match(">") elif self.token_list[self.current].kind == self.kind_map["<="]: # self.match("<=") relation = self.match("<=") elif self.token_list[self.current].kind == self.kind_map[">="]: # self.match(">=") relation = self.match(">=") else: self.total_error_flag = 1 sys.stderr.write("error: not a valid condition\n" "@({0}, {1})".format(self.token_list[self.current].start_position, self.token_list[self.current].end_position)) right = self._expression() self.observer.end_condition() condition_subtree = ConditionNode(left, right, relation) return condition_subtree # set expectation of creating a Write # by following the Write production def _write(self): self.observer.begin_write() self.match("WRITE") expression = self._expression() if not isinstance(expression.type, Integer): self.total_error_flag = 1 sys.stderr.write("error: expression in write not of type integer") exit(1) self.observer.end_write() write_node = WriteNode(None, expression) return write_node # set expectation of creating a Read # by following the Read production def _read(self): self.observer.begin_read() self.match("READ") designator = self._designator() if not isinstance(designator.type, Integer): self.total_error_flag = 1 sys.stderr.write("error: designator in read not an integer") exit(1) self.observer.end_read() read_node = ReadNode(None, designator) return read_node # set expectation of creating a Designator # by following the Designator production def _designator(self): self.observer.begin_designator() var_name = self.match("IDENTIFIER") ret_obj = self.program_scope.find(var_name) pass_obj = None if isinstance(ret_obj, Variable): pass_obj = VariableNode(ret_obj._type, ret_obj, var_name) elif isinstance(ret_obj, Constant): pass_obj = NumberNode(ret_obj) else: self.total_error_flag = 1 sys.stderr.write("error: variable name not pointing var or const\n") exit(1) subtree = self._selector(pass_obj) self.observer.end_designator() return subtree # set expectation of creating a Selector # by following the Selector production def _selector(self, variable_node): self.observer.begin_selector() return_object = variable_node while (self.token_list[self.current].kind == self.kind_map["["]) \ or (self.token_list[self.current].kind == self.kind_map["."]): if self.token_list[self.current].kind == self.kind_map["["]: if not isinstance(return_object.type, Array): sys.stderr.write("error: not an array") self.match("[") exp_list = self._expression_list() self.match("]") node = return_object for e in exp_list: if not isinstance(e.type, Integer): sys.stderr.write("error: noninteger found in selector\n") index_type = return_object.type._type # print "it", type(index_type) # print "index type: ", type(index_type) index_node = IndexNode(index_type, node, exp_list[0]) for i in range(1, len(exp_list)): node = index_node index_type = node.type._type index_node = IndexNode(index_type, node, exp_list[i]) return_object = index_node elif self.token_list[self.current].kind == self.kind_map["."]: self.match(".") field_var_name = self.match("IDENTIFIER") if not isinstance(return_object.type, Record): sys.stderr.write("error: attempting to select field from non-record type\n") if(return_object.type.scope.local(field_var_name)): field_var_obj = return_object.type.scope.find(field_var_name) field_type = field_var_obj._type field_right_var_obj = VariableNode(field_type, field_var_obj, field_var_name) node = FieldNode(field_type, return_object, field_right_var_obj) return_object = node else: self.total_error_flag = 1 sys.stderr.write("error: not a valid selector\n" "@({0}, {1})".format(self.token_list[self.current].start_position, self.token_list[self.current].end_position)) self.observer.end_selector() return return_object # set expectation of creating a IdentifierList # by following the IdentifierList production def _identifier_list(self): self.observer.begin_identifier_list() name = self.match("IDENTIFIER") id_list = [] id_list.append(name) while self.token_list[self.current].kind == self.kind_map[","]: self.match(",") name = self.match("IDENTIFIER") id_list.append(name) self.observer.end_identifier_list() return id_list # set expectation of creating a ExpressionList # by following the ExpressionList production def _expression_list(self): # return list of expressions - added return in assignment 5 self.observer.begin_expression_list() exp_list = [] name = self._expression() exp_list.append(name) while self.token_list[self.current].kind == self.kind_map[","]: self.match(",") name = self._expression() exp_list.append(name) self.observer.end_expression_list() return exp_list
class Parser: """Takes a list of tokens and performs semantic analysis to check if input adheres to grammar. Outputs to stdout a textual representation of the CST via the call stack. Parser is also capable of outputting graphical output """ # initializes Parser instance and parses a list of tokens # cmd line arguments determine output type def __init__(self, observer = Observer(), token_list=[], print_symbol_table = 0, visitor = Visitor()): self.current = 0 # current position in token list self.token_list = token_list # token list received from scanner self.kind_map = Token.kind_map # dictionary of token kinds self.observer = observer # output class determined by cmd line arguments self.total_error_flag = 0 # detects if an error occurs anywhere in the program self.universe = Scope(None) # universe scope self.universe.insert("INTEGER", Integer()) # universe scope only holds integer self.program_scope = Scope(self.universe) # program scope to hold program names self.current_scope = self.program_scope # current scope for switching between scopes self.print_symbol_table = print_symbol_table # determines whether to print cst or st self.visitor = visitor # parse the token list def parse(self): self._program() # do not print any output if error occurs if self.total_error_flag == 0: if self.print_symbol_table == 0: self.observer.print_output() elif self.print_symbol_table == 1: self.visitor.visitScope(self.program_scope) self.visitor.end() # check if the currently parsed token is a token we are # expecting to find # kind = expected kind of token def match(self, kind): if self.token_list[self.current].kind == self.kind_map[kind]: self.observer.print_token(self.token_list[self.current]) self.current += 1 ### for returning identifier names return self.token_list[self.current-1].get_token_name() else: self.total_error_flag = 1 sys.stderr.write("error: expected token kind \'{0}\', " "received unexpected token \'{1}\'" " @({2}, {3})".format(kind, self.token_list[self.current], self.token_list[self.current].start_position, self.token_list[self.current].end_position) + '\n') # set expectation of creating a program # by following the program production def _program(self): # print "Program" self.observer.begin_program() self.match("PROGRAM") name = self.match("IDENTIFIER") self.match(";") self._declarations() if self.token_list[self.current].kind == self.kind_map["BEGIN"]: self.match("BEGIN") self._instructions() self.match("END") end_name = self.match("IDENTIFIER") self.match(".") self.observer.end_program() if not name == end_name: self.total_error_flag = 1 sys.stderr.write("error: program identifier does not match end identifier\n") if not self.token_list[self.current].kind == self.kind_map["EOF"]: self.total_error_flag = 1 sys.stderr.write("error: trash detected after program end:\n" "Token \'{0}\'".format(self.token_list[self.current]) + '\n') # set expectation of creating a declaration # by following the declaration production def _declarations(self): self.observer.begin_declarations() while (self.token_list[self.current].kind == self.kind_map["CONST"]) or \ (self.token_list[self.current].kind == self.kind_map["TYPE"]) or \ (self.token_list[self.current].kind == self.kind_map["VAR"]): if self.token_list[self.current].kind == self.kind_map["CONST"]: self._constdecl() elif self.token_list[self.current].kind == self.kind_map["TYPE"]: self._typedecl() elif self.token_list[self.current].kind == self.kind_map["VAR"]: self._vardecl() else: pass self.observer.end_declarations() # set expectation of creating a ConstDecl # by following the ConstDecl production def _constdecl(self): # print "ConstDecl" self.observer.begin_constdecl() self.match("CONST") while self.token_list[self.current].kind == self.kind_map["IDENTIFIER"]: name = self.match("IDENTIFIER") # check if const name in local scope if self.program_scope.local(name): self.total_error_flag = 1 sys.stderr.write("error: attempted to redefine identifier\n") self.match("=") e = self._expression() self.match(";") # add it we formed a constant if isinstance(e, Constant): # is it constant object or constant name self.program_scope.insert(name, e) else: self.total_error_flag = 1 sys.stderr.write("error: attempted to define const with nonconst object\n") self.observer.end_constdecl() # set expectation of creating a TypeDecl # by following the TypeDecl production def _typedecl(self): # print "TypeDecl" self.observer.begin_typedecl() self.match("TYPE") while self.token_list[self.current].kind == self.kind_map["IDENTIFIER"]: name = self.match("IDENTIFIER") self.match("=") # type of current Type return_type = self._type() self.match(";") if return_type is None: self.total_error_flag = 1 sys.stderr.write("error: type not found\n") return None if not self.current_scope.local(name): self.current_scope.insert(name, return_type) else: self.total_error_flag = 1 sys.stderr.write("error: attempting to redefine variable\n") self.observer.end_typedecl() # set expectation of creating a VarDecl # by following the VarDecl production def _vardecl(self): # print "VarDecl" self.observer.begin_vardecl() self.match("VAR") id_list = [] return_type = None while self.token_list[self.current].kind == self.kind_map["IDENTIFIER"]: id_list = self._identifier_list() self.match(":") return_type = self._type() # type of current identifier if return_type is None: self.total_error_flag = 1 sys.stderr.write("error: type not found\n") return None self.match(";") for name in id_list: if not self.current_scope.local(name): self.current_scope.insert(name, Variable(return_type)) else: self.total_error_flag = 1 sys.stderr.write("error: attempting to redefine var\n") self.observer.end_vardecl() # set expectation of creating a Type # by following the Type production def _type(self): # print "Type" self.observer.begin_type() return_type = None if self.token_list[self.current].kind == self.kind_map["IDENTIFIER"]: name = self.match("IDENTIFIER") # get the name of an identifier return_type = self.current_scope.find(name) if return_type is None: self.total_error_flag = 1 sys.stderr.write("error: indentifier not found. attempting to assign " "uncreated type\n") self.observer.end_type() return None if isinstance(return_type, Type): self.observer.end_type() return return_type else: self.total_error_flag = 1 sys.stderr.write("error: found not Type object\n") return None elif self.token_list[self.current].kind == self.kind_map["ARRAY"]: self.match("ARRAY") length = None e = self._expression() # get length of array if isinstance(e, Constant): length = e else: self.total_error_flag = 1 sys.stderr.write("error: not a valid type for array length\n") self.match("OF") array_type = self._type() # check if array_type is already defined if array_type is None: self.total_error_flag = 1 sys.stderr.write("error: array type not found\n") return None return_type = Array(length, array_type) self.observer.end_type() return return_type elif self.token_list[self.current].kind == self.kind_map["RECORD"]: self.match("RECORD") id_list = [] outer_scope = self.current_scope self.current_scope = Scope(outer_scope) while self.token_list[self.current].kind == self.kind_map["IDENTIFIER"]: id_list = self._identifier_list() self.match(":") # type of current identifier(s) record_field_type = self._type() if record_field_type is None: self.total_error_flag = 1 sys.stderr.write("error: record field type nonexistent\n") self.match(";") for name in id_list: if not self.current_scope.local(name): self.current_scope.insert(name, Variable(record_field_type)) else: self.total_error_flag = 1 sys.stderr.write("error: attempting to redefine field\n") return None self.match("END") return_type = Record(self.current_scope) outer_scope = self.current_scope.outer_scope self.current_scope.outer_scope = None self.current_scope = outer_scope self.observer.end_type() return return_type else: self.total_error_flag = 1 sys.stderr.out("error: expecting Identifier, ARRAY, or RECORD\n") self.observer.end_type() # set expectation of creating a Expression # by following the Expression production def _expression(self): self.observer.begin_expression() if self.token_list[self.current].kind == self.kind_map["+"]: self.match("+") elif self.token_list[self.current].kind == self.kind_map["-"]: self.match("-") self._term() while (self.token_list[self.current].kind == self.kind_map["+"]) or \ (self.token_list[self.current].kind == self.kind_map["-"]): if self.token_list[self.current].kind == self.kind_map["+"]: self.match("+") elif self.token_list[self.current].kind == self.kind_map["-"]: self.match("-") else: self.total_error_flag = 1 sys.stderr.write("error: expecting \'+\' or \'-\'\n") self._term() self.observer.end_expression() e = Constant(self.universe.find("INTEGER"), 5) return e # set expectation of creating a Term # by following the Term production def _term(self): self.observer.begin_term() self._factor() while (self.token_list[self.current].kind == self.kind_map["*"])or \ (self.token_list[self.current].kind == self.kind_map["DIV"]) or \ (self.token_list[self.current].kind == self.kind_map["MOD"]): if self.token_list[self.current].kind == self.kind_map["*"]: self.match("*") elif self.token_list[self.current].kind == self.kind_map["DIV"]: self.match("DIV") elif self.token_list[self.current].kind == self.kind_map["MOD"]: self.match("MOD") else: self.total_error_flag = 1 sys.stderr.out("error: expecting \'*\', \'DIV\', or \'MOD\'\n") self._factor() self.observer.end_term() # set expectation of creating a Factor # by following the Factor production def _factor(self): self.observer.begin_factor() if self.token_list[self.current].kind == self.kind_map["INTEGER"]: self.match("INTEGER") elif self.token_list[self.current].kind == self.kind_map["IDENTIFIER"]: self._designator() elif self.token_list[self.current].kind == self.kind_map["("]: self.match("(") self._expression() self.match(")") else: self.total_error_flag = 1 sys.stdout.error("error: expecting integer, identifier or \'(\'\n") self.observer.end_factor() # set expectation of creating a Instructions # by following the Instructions production def _instructions(self): self.observer.begin_instructions() self._instruction() while self.token_list[self.current].kind == self.kind_map[";"]: self.match(";") self._instruction() self.observer.end_instructions() # set expectation of creating a Instruction # by following the Instruction production def _instruction(self): # print "Instruction" self.observer.begin_instruction() if self.token_list[self.current].kind == self.kind_map["IDENTIFIER"]: self._assign() elif self.token_list[self.current].kind == self.kind_map["IF"]: self._if() elif self.token_list[self.current].kind == self.kind_map["REPEAT"]: self._repeat() elif self.token_list[self.current].kind == self.kind_map["WHILE"]: self._while() elif self.token_list[self.current].kind == self.kind_map["READ"]: self._read() elif self.token_list[self.current].kind == self.kind_map["WRITE"]: self._write() else: self.total_error_flag = 1 sys.stderr.write("error: not a valid instruction\n" "@({0}, {1})".format(self.token_list[self.current].start_position, self.token_list[self.current].end_position)) self.observer.end_instruction() # set expectation of creating a Assign # by following the Assign production def _assign(self): # print "Assign" self.observer.begin_assign() self._designator() self.match(":=") self._expression() self.observer.end_assign() # set expectation of creating a If # by following the If production def _if(self): # print "If" self.observer.begin_if() self.match("IF") self._condition() self.match("THEN") self._instructions() if self.token_list[self.current].kind == self.kind_map["ELSE"]: self.match("ELSE") self._instructions() self.match("END") self.observer.end_if() # set expectation of creating a Repeat # by following the Repeat production def _repeat(self): self.observer.begin_repeat() self.match("REPEAT") self._instructions() self.match("UNTIL") self._condition() self.match("END") self.observer.end_repeat() # set expectation of creating a While # by following the While production def _while(self): self.observer.begin_while() self.match("WHILE") self._condition() self.match("DO") self._instructions() self.match("END") self.observer.end_while() # set expectation of creating a Condition # by following the Condition production def _condition(self): self.observer.begin_condition() self._expression() if self.token_list[self.current].kind == self.kind_map["="]: self.match("=") elif self.token_list[self.current].kind == self.kind_map["#"]: self.match("#") elif self.token_list[self.current].kind == self.kind_map["<"]: self.match("<") elif self.token_list[self.current].kind == self.kind_map[">"]: self.match(">") elif self.token_list[self.current].kind == self.kind_map["<="]: self.match("<=") elif self.token_list[self.current].kind == self.kind_map[">="]: self.match(">=") else: self.total_error_flag = 1 sys.stderr.write("error: not a valid condition\n" "@({0}, {1})".format(self.token_list[self.current].start_position, self.token_list[self.current].end_position)) self._expression() self.observer.end_condition() # set expectation of creating a Write # by following the Write production def _write(self): self.observer.begin_write() self.match("WRITE") self._expression() self.observer.end_write() # set expectation of creating a Read # by following the Read production def _read(self): self.observer.begin_read() self.match("READ") self._designator() self.observer.end_read() # set expectation of creating a Designator # by following the Designator production def _designator(self): self.observer.begin_designator() self.match("IDENTIFIER") self._selector() self.observer.end_designator() # set expectation of creating a Selector # by following the Selector production def _selector(self): self.observer.begin_selector() while (self.token_list[self.current].kind == self.kind_map["["]) \ or (self.token_list[self.current].kind == self.kind_map["."]): if self.token_list[self.current].kind == self.kind_map["["]: self.match("[") self._expression_list() self.match("]") elif self.token_list[self.current].kind == self.kind_map["."]: self.match(".") self.match("IDENTIFIER") else: self.total_error_flag = 1 sys.stderr.write("error: not a valid selector\n" "@({0}, {1})".format(self.token_list[self.current].start_position, self.token_list[self.current].end_position)) self.observer.end_selector() # set expectation of creating a IdentifierList # by following the IdentifierList production def _identifier_list(self): self.observer.begin_identifier_list() name = self.match("IDENTIFIER") id_list = [] id_list.append(name) while self.token_list[self.current].kind == self.kind_map[","]: self.match(",") name = self.match("IDENTIFIER") id_list.append(name) self.observer.end_identifier_list() return id_list # set expectation of creating a ExpressionList # by following the ExpressionList production def _expression_list(self): self.observer.begin_expression_list() self._expression() while self.token_list[self.current].kind == self.kind_map[","]: self.match(",") self._expression() self.observer.end_expression_list()