def assignment_or_function_call(token): """ Implements recursive descent for the rule: <assignment_or_function_call> ==> 24 TokenType.Identifier TokenType.AssignmentOperator <expression> TokenType.Semicolon | 25 TokenType.Identifier TokenType.OpenBracket <expression> TokenType.CloseBracket TokenType.AssignmentOperator <expression> TokenType.Semicolon | 26 TokenType.Identifier TokenType.OpenParen <expression_list> TokenType.CloseParen TokenType.Semicolon """ if token.t_type == TokenType.Identifier: next_offset_before_statement = CG.next_offset # get the param's identifier and look it up identifier = token.lexeme Parser.error_on_variable_usage(identifier) er_lhs = Parser.s_table.find_in_all_scopes(identifier) Parser.match(token, TokenType.Identifier) if token.t_type == TokenType.AssignmentOperator: print(24, end=" ") Parser.match(token, TokenType.AssignmentOperator) er_rhs = Parser.expression(token) Parser.match(token, TokenType.Semicolon) CG.code_gen_assign(er_lhs, er_rhs) elif token.t_type == TokenType.OpenBracket: print(25, end=" ") Parser.match(token, TokenType.OpenBracket) er_subscript = Parser.expression(token) Parser.match(token, TokenType.CloseBracket) Parser.match(token, TokenType.AssignmentOperator) er_rhs = Parser.expression(token) Parser.match(token, TokenType.Semicolon) CG.code_gen_assign(er_lhs, er_rhs, dest_subscript=er_subscript) elif token.t_type == TokenType.OpenParen: print(26, end=" ") Parser.match(token, TokenType.OpenParen) param_list = Parser.expression_list(token) Parser.match(token, TokenType.CloseParen) Parser.match(token, TokenType.Semicolon) # First handle built-in functions if identifier in CG.BUILT_IN_FUNCTIONS.keys(): function, data_type = CG.BUILT_IN_FUNCTIONS[identifier] function(data_type, param_list) else: Parser.call_function(identifier, er_lhs, param_list) else: Parser.raise_production_not_found_error( token, 'assignment_or_function_call') # Reclaim stack space that was used during this statement CG.next_offset = next_offset_before_statement else: Parser.raise_production_not_found_error( token, 'assignment_or_function_call')
def variable_or_function_call(token): """ Implements recursive descent for the rule: <variable_or_function_call> ==> 49 TokenType.Identifier TokenType.OpenBracket <expression> TokenType.CloseBracket | 50 TokenType.OpenParen <expression_list> TokenType.CloseParen | 51 TokenType.Identifier :return: an ExpressionRecord that holds: 49 the value at array_id[subscript], if it was an array 50 the return value of the function, if it was a function; 51 the value of the variable, if it was a variable id """ if token.t_type == TokenType.Identifier: identifier = token.lexeme exp_rec = Parser.s_table.find_in_all_scopes(identifier) Parser.match(token, TokenType.Identifier) if token.t_type == TokenType.OpenBracket: print(49, end=" ") Parser.match(token, TokenType.OpenBracket) er_subscript = Parser.expression(token) # Input validation: verify that the subscript is an integer, # and that exp_rec contains an array if er_subscript.data_type != DataTypes.INT: raise SemanticError("Subscript is not an integer", Parser.file_reader.get_line_data()) if not DataTypes.is_array(exp_rec.data_type): raise SemanticError( "Subscript applied to variable %s, " "which is not an array" % identifier, Parser.file_reader.get_line_data()) # Match ]: wait until after potential error messages to do this Parser.match(token, TokenType.CloseBracket) # TODO: make this a function in CG # Make a temp ExpressionRecord to hold the value at # array[subscript], and return it result_exp_rec = ExpressionRecord(DataTypes.array_to_basic( exp_rec.data_type), CG.next_offset, is_temp=True, is_reference=False) CG.next_offset -= 4 CG.code_gen_assign(result_exp_rec, exp_rec, src_subscript=er_subscript) return result_exp_rec elif token.t_type == TokenType.OpenParen: print(50, end=" ") if not isinstance(exp_rec, FunctionSignature) and \ not identifier in CG.BUILT_IN_FUNCTIONS.keys(): raise SemanticError( "Tried to call %s as a function, " "but it was not a function." % identifier, Parser.file_reader.get_line_data()) # exp_rec is actually a function signature, so call it that func_signature = exp_rec Parser.match(token, TokenType.OpenParen) er_params = Parser.expression_list(token) Parser.match(token, TokenType.CloseParen) return Parser.call_function(identifier, func_signature, er_params) else: print(51, end=" ") return exp_rec else: raise Parser.raise_production_not_found_error( token, "variable_or_function_call")