def __parse(self, tokens): """ The recursive parser that builds the parse tree from one line of source code. :param tokens: The tokens from the source line separated by whitespace in a list of strings. :exception: raises a syntax_error.SyntaxError with the message 'Incomplete statement' if the statement is incomplete (e.g. there are no tokens left and this method was called). :exception: raises a syntax_error.SyntaxError with the message 'Invalid token {token}' if an unrecognized token is encountered (e.g. not one of the tokens listed above). :return: """ if len(tokens) < 1: return firstToken = tokens[0] if firstToken is self.COMMENT_TOKEN: return if firstToken.isdigit(): node = literal_node.LiteralNode(firstToken) self.parseTrees.append(node) elif firstToken.isidentifier(): self.symTbl[firstToken] = '' node = variable_node.VariableNode(firstToken, self.symTbl) self.parseTrees.append(node) elif firstToken == self.ASSIGNMENT_TOKEN: first = self.parseTrees.pop() second = self.parseTrees.pop() valid = self.checkIfPoppedNodesAreValidForAssignmentNode( first, second) if valid == True: node = assignment_node.AssignmentNode(first, second, self.symTbl, firstToken) self.parseTrees.append(node) node.evaluate() else: self.syntaxError = True raise syntax_error.SyntaxError('Incomplete Statement' + ' line Number ' + str(self.lineNum)) elif firstToken in self.MATH_TOKENS: first = self.parseTrees.pop() second = self.parseTrees.pop() valid = self.checkIfPoppedNodesAreValidForMathNode(first, second) if valid == True: node = math_node.MathNode(first, second, firstToken) self.parseTrees.append(node) else: self.syntaxError = True raise syntax_error.SyntaxError('Incomplete Statement' + ' line Number ' + str(self.lineNum)) self.__parse(tokens[1:])
def __parse(self, tokens): """ The recursive parser that builds the parse tree from one line of source code. :param tokens: The tokens from the source line separated by whitespace in a list of strings. :exception: raises a syntax_error.SyntaxError with the message 'Incomplete statement' if the statement is incomplete (e.g. there are no tokens left and this method was called). :exception: raises a syntax_error.SyntaxError with the message 'Invalid token {token}' if an unrecognized token is encountered (e.g. not one of the tokens listed above). :return: """ if len(tokens) > 0: token = tokens.pop(0) else: return if token is self.COMMENT_TOKEN: return None elif token is self.PRINT_TOKEN: return print_node.PrintNode(self.__parse(tokens)) elif token.isdigit(): return literal_node.LiteralNode(token) elif token == '=': return assignment_node.AssignmentNode(self.__parse(tokens), self.__parse(tokens), self.symTbl, token) elif token in self.MATH_TOKENS: left = self.__parse(tokens) right = self.__parse(tokens) if not isinstance(left, (literal_node.LiteralNode, math_node.MathNode, variable_node.VariableNode)): raise syntax_error.SyntaxError('Incomplete expression') if not isinstance(right, (literal_node.LiteralNode, math_node.MathNode, variable_node.VariableNode)): raise syntax_error.SyntaxError('Incomplete expression') return math_node.MathNode(left, right, token) elif token.isidentifier(): return variable_node.VariableNode(token, self.symTbl) else: raise syntax_error.SyntaxError("Invalid token {" + str(token) + "}")
def __parse(self, tokens): """ The recursive parser that builds the parse tree from one line of source code. :param tokens: The tokens from the source line separated by whitespace in a list of strings. :exception: raises a syntax_error.SyntaxError with the message 'Incomplete statement' if the statement is incomplete (e.g. there are no tokens left and this method was called). :exception: raises a syntax_error.SyntaxError with the message 'Invalid token {token}' if an unrecognized token is encountered (e.g. not one of the tokens listed above). :return: """ if len(tokens) == 0: return elif tokens[0].isidentifier(): node = variable_node.VariableNode(tokens[0], self.symTbl) self.parseTrees.append(node) elif tokens[0].isdigit(): node = literal_node.LiteralNode(int(tokens[0])) self.parseTrees.append(node) elif tokens[0] == '=': node = assignment_node.AssignmentNode(self.parseTrees.pop(), self.parseTrees.pop(), self.symTbl, tokens[0]) self.parseTrees.append(node) elif tokens[0] == '@': node = print_node.PrintNode(self.parseTrees.pop()) self.parseTrees.append(node) elif tokens[0] in self.MATH_TOKENS: x = self.parseTrees.pop() y = self.parseTrees.pop() if not isinstance(x, (variable_node.VariableNode, literal_node.LiteralNode, math_node.MathNode)): raise syntax_error.SyntaxError('Incomplete Statement') if not isinstance(y, (variable_node.VariableNode, literal_node.LiteralNode, math_node.MathNode)): raise syntax_error.SyntaxError('Incomplete Statement') node = math_node.MathNode(x, y, tokens[0]) self.parseTrees.append(node) else: raise syntax_error.SyntaxError("Invalid token") self.__parse(tokens[1:]) """
def __parse(self, tokens): """ The recursive parser that builds the parse tree from one line of source code. :param tokens: The tokens from the source line separated by whitespace in a list of strings. :exception: raises a syntax_error.SyntaxError with the message 'Incomplete statement' if the statement is incomplete (e.g. there are no tokens left and this method was called). :exception: raises a syntax_error.SyntaxError with the message 'Invalid token {token}' if an unrecognized token is encountered (e.g. not one of the tokens listed above). :return: """ if len(tokens) <= 0: raise (syntax_error.SyntaxError("Invalid Expression")) current = tokens[0] if len(tokens) > 0: if type(tokens) is str: tokens = None else: tokens.pop(0) if current == self.ASSIGNMENT_TOKEN: if len(tokens) > 0: return assignment_node.AssignmentNode(self.__parse(tokens.pop(0)),self.__parse(tokens),self.symTbl,'=') else: raise syntax_error.SyntaxError('Incomplete statement') elif current in self.MATH_TOKENS: return math_node.MathNode(self.__parse(tokens),self.__parse(tokens), current) elif current == self.PRINT_TOKEN: if len(tokens)>0: return print_node.PrintNode(self.__parse(tokens)) else: return print_node.PrintNode() elif current.isdigit(): return literal_node.LiteralNode(current) elif current.isalpha(): return variable_node.VariableNode(current,self.symTbl) elif current == self.COMMENT_TOKEN: pass elif current is None: raise syntax_error.SyntaxError('Incomplete statement') else: raise syntax_error.SyntaxError('Invalid token ' + current)
def __parse(self, tokens): """ The recursive parser that builds the parse tree from one line of source code. :param tokens: The tokens from the source line separated by whitespace in a list of strings. :exception: raises a syntax_error.SyntaxError with the message 'Incomplete statement' if the statement is incomplete (e.g. there are no tokens left and this method was called). :exception: raises a syntax_error.SyntaxError with the message 'Invalid token {token}' if an unrecognized token is encountered (e.g. not one of the tokens listed above). :return: """ # pass print('tokens are',tokens) token_list = ['+', '-', '*', '//', '#', '=', '@'] if not tokens: raise syntax_error.SyntaxError('Incomplete statement') for i in tokens: if not i.isdigit() and not i.isidentifier(): if i not in token_list: raise syntax_error.SyntaxError('Invalid token {i}') i =0 while(i < len(tokens)): if tokens[i] == PreTee.COMMENT_TOKEN: i+=1 elif tokens[i].isidentifier(): variable_node.VariableNode(tokens[i], self.symTbl[tokens[i]]) i+=1 elif tokens[i].isdigit(): literal_node.LiteralNode(tokens[i]) i+=1 elif tokens[i] in PreTee.MATH_TOKENS: left_val = self.__parse(tokens[i+1]) right_val = self.__parse(tokens[i+2]) math_node.MathNode(left_val, right_val, tokens[i]) i+=2
def __parse(self, tokens): """ The recursive parser that builds the parse tree from one line of source code. :param tokens: The tokens from the source line separated by whitespace in a list of strings. :exception: raises a syntax_error.SyntaxError with the message 'Incomplete statement' if the statement is incomplete (e.g. there are no tokens left and this method was called). :exception: raises a syntax_error.SyntaxError with the message 'Invalid token {token}' if an unrecognized token is encountered (e.g. not one of the tokens listed above). :return: the object of one of node classes based on the type token. Node classes: literal_node.LiteralNode, variable_node.VariableNode, assignment_node.AssignmentNode, print_node.PrintNode, math_node.MathNode """ if len(tokens) is 0: raise syntax_error.SyntaxError('Incomplete statement') token = tokens.pop() if token.isdigit(): return literal_node.LiteralNode(token) elif token.isidentifier(): return variable_node.VariableNode(token, self.symTbl) elif token is self.ASSIGNMENT_TOKEN: return assignment_node.AssignmentNode(self.__parse(tokens), self.__parse(tokens), self.symTbl, token) elif token is self.PRINT_TOKEN: if len(tokens) > 0: return print_node.PrintNode(self.__parse(tokens)) else: return print_node.PrintNode() elif token in self.MATH_TOKENS: return math_node.MathNode(self.__parse(tokens), self.__parse(tokens), token) else: raise syntax_error.SyntaxError('Invalid token ' + token)
def __parse(self, tokens): """ The recursive parser that builds the parse tree from one line of source code. :param tokens: The tokens from the source line separated by whitespace in a list of strings. :exception: raises a syntax_error.SyntaxError with the message 'Incomplete statement' if the statement is incomplete (e.g. there are no tokens left and this method was called). :exception: raises a syntax_error.SyntaxError with the message 'Invalid token {token}' if an unrecognized token is encountered (e.g. not one of the tokens listed above). :return: """ # no token left if len(tokens) < 1: # error message: Incomplete statement self.syntaxError = True return syntax_error.SyntaxError("Incomplete statement") elif len(tokens) == 1: if tokens[0].isdigit(): return literal_node.LiteralNode(int(tokens[0])) elif tokens[0].isidentifier(): return variable_node.VariableNode(tokens[0], self.symTbl) else: # error message: Invalid token self.syntaxError = True return syntax_error.SyntaxError("Invalid token %s" % tokens[0]) elif tokens[0] in self.MATH_TOKENS: # leaf nodes required to construct the left expression parse tree leavesNeed = 1 for i in range(1, len(tokens)): if tokens[i].isdigit() or tokens[i].isidentifier(): # a leaf node leavesNeed -= 1 elif tokens[i] in self.MATH_TOKENS: # a interior node, need one more leaf node to construct the # full binary tree leavesNeed += 1 else: # error message: Invalid token self.syntaxError = True return syntax_error.SyntaxError("Invalid token %s" % tokens[i]) # has all nodes required to construct the left expression if leavesNeed == 0: # construct the left and right expression left = self.__parse(tokens[1:i + 1]) right = self.__parse(tokens[i + 1:]) # error raised in construction of left expression if isinstance(left, syntax_error.SyntaxError): return left # error raised in construction of right expression if isinstance(right, syntax_error.SyntaxError): return right return math_node.MathNode(left, right, tokens[0]) else: # error message: Invalid token self.syntaxError = True return syntax_error.SyntaxError("Invalid token %s" % tokens[0])
def parse(self): """ The public parse is responsible for looping over the lines of source code and constructing the parseTree, as a series of calls to the helper function that are appended to this list. It needs to handle and display any syntax_error.SyntaxError exceptions that get raised. : return None """ file = open(self.srcFile) for line in file: self.lineNum += 1 tokens = line.split() # empty line if len(tokens) == 0: continue # assignment statement if tokens[0] == self.ASSIGNMENT_TOKEN: # lack of tokens if len(tokens) < 3: self.syntaxError = True # error message: Incomplete statement print("\nFile \"%s\", line %d" % (self.srcFile, self.lineNum), file=sys.stderr) print(" %sSyntaxError: Incomplete statement" % line, file=sys.stderr) continue # left token is not valid variable name if not tokens[1].isidentifier(): self.syntaxError = True # error message: Bad assignment to non-variable print("\nFile \"%s\", line %d" % (self.srcFile, self.lineNum), file=sys.stderr) print(" %sSyntaxError: Bad assignment to non-variable" % line, file=sys.stderr) continue # construct parse tree for expression on the right expression = self.__parse(tokens[2:]) # error raised during the construction of parse tree if isinstance(expression, syntax_error.SyntaxError): # print out the error message print("\nFile \"%s\", line %d" % (self.srcFile, self.lineNum), file=sys.stderr) print(" %sSyntaxError: %s" % (line, expression), file=sys.stderr) else: # create a new AssignmentNode self.parseTrees.append( assignment_node.AssignmentNode( variable_node.VariableNode(tokens[1], self.symTbl), expression, self.symTbl, tokens[0])) # print statement elif tokens[0] == self.PRINT_TOKEN: # empty expression if len(tokens) == 1: self.parseTrees.append(print_node.PrintNode(None)) else: # construct parse tree for the expression expression = self.__parse(tokens[1:]) # create a new PrintNode self.parseTrees.append(print_node.PrintNode(expression)) # comment line elif tokens[0] == self.COMMENT_TOKEN: continue else: self.syntaxError = True # error message: Invalid token print("\nFile \"%s\", line %d" % (self.srcFile, self.lineNum), file=sys.stderr) print(" %sSyntaxError: Invalid token %s" % (line, tokens[0]), file=sys.stderr) file.close()