def __parse_assignment_operator(self) -> Ast: """ <assignment-operator> ::= '=' """ ast = Ast(AstType.ASSIGNMENT_OPERATOR) ast.add_child(self.__assert_token('=', TokenType.ASSIGN)) return ast
def __parse_type_specifier(self) -> Ast: """ <type-specifier> ::= <simple-type-specifier> """ ast = Ast(AstType.TYPE_SPECIFIER) ast.add_child(self.__parse_simple_type_specifier()) return ast
def __parse_const_qualifier(self) -> Ast: """ <const-qualifier> ::= 'const' """ ast = Ast(AstType.CONST_QUALIFIER) ast.add_child(self.__assert_token('const', TokenType.CONST)) return ast
def __parse_str_literal(self) -> Ast: ast = Ast(AstType.STR_LITERAL) token = self.__next_token() if token.tok_type != TokenType.STR_LITERAL: raise ExpectedStrLiteral(token.st_pos) ast.add_child(Ast(AstType.TOKEN, token)) return ast
def __parse_expression(self) -> Ast: """ <expression> ::= <additive-expression> """ ast = Ast(AstType.EXPRESSION) ast.add_child(self.__parse_additive_expression()) return ast
def __parse_integer_literal(self) -> Ast: ast = Ast(AstType.INTEGER_LITERAL) token = self.__next_token() if token.tok_type != TokenType.INTEGER_LITERAL: raise ExpectedInt32(token.st_pos) ast.add_child(Ast(AstType.TOKEN, token)) return ast
def __parse_initializer(self) -> Ast: """ <initializer> ::= '='<expression> """ ast = Ast(AstType.INITIALIZER) ast.add_child(self.__assert_token('=', TokenType.ASSIGN)) ast.add_child(self.__parse_expression()) return ast
def __parse_multiplicative_operator(self) -> Ast: """ <multiplicative-operator> ::= '*' | '/' """ ast = Ast(AstType.MULTIPLICATIVE_OPERATOR) token = self.__next_token() if token.tok_type not in [TokenType.MUL, TokenType.DIV]: raise ExpectedSymbol(token.st_pos, '* or /') ast.add_child(Ast(AstType.TOKEN, token)) return ast
def __parse_additive_operator(self) -> Ast: """ <additive-operator> ::= '+' | '-' """ ast = Ast(AstType.ADDITIVE_OPERATOR) token = self.__next_token() if token.tok_type not in [TokenType.ADD, TokenType.SUB]: raise ExpectedSymbol(token.st_pos, '+ or -') ast.add_child(Ast(AstType.TOKEN, token)) return ast
def __parse_identifier(self) -> Ast: ast = Ast(AstType.IDENTIFIER) token = self.__next_token(suppress_exception=True) if token is None: raise ExpectedIdentifier(self.__prev_token().st_pos) if token.tok_type != TokenType.IDENTIFIER: raise ExpectedIdentifier(token.st_pos) ast.add_child(Ast(AstType.TOKEN, token)) return ast
def __parse_relational_operator(self) -> Ast: """ <relational-operator> ::= '<' | '<=' | '>' | '>=' | '!=' | '==' """ ast = Ast(AstType.RELATIONAL_OPERATOR) token = self.__next_token() if token.tok_type not in TokenType.relations: raise ExpectedSymbol(token.st_pos, "'<' | '<=' | '>' | '>=' | '!=' | '=='") ast.add_child(Ast(AstType.TOKEN, token)) return ast
def __parse_simple_type_specifier(self) -> Ast: """ <simple-type-specifier> ::= 'void'|'int'|'char'|'double' """ ast = Ast(AstType.SIMPLE_TYPE_SPECIFIER) token = self.__next_token() if token.tok_type in TokenType.types: ast.add_child(Ast(AstType.TOKEN, token)) else: raise UnknownVariableType(token.st_pos, token.literal) return ast
def __parse_init_declarator(self) -> Ast: """ <init-declarator> ::= <identifier>[<initializer>] """ ast = Ast(AstType.INIT_DECLARATOR) ast.add_child(self.__parse_identifier()) token = self.__peek_token() if token.tok_type == TokenType.ASSIGN: ast.add_child(self.__parse_initializer()) return ast
def __parse_scan_statement(self) -> Ast: """ <scan-statement> ::= 'scan' '(' <identifier> ')' ';' """ ast = Ast(AstType.SCAN_STATEMENT) ast.add_child(self.__assert_token('scan', TokenType.SCAN)) ast.add_child(self.__assert_token('(', TokenType.LEFT_PARENTHESES)) ast.add_child(self.__parse_identifier()) ast.add_child(self.__assert_token(')', TokenType.RIGHT_PARENTHESES)) ast.add_child(self.__assert_token(';', TokenType.SEMICOLON)) return ast
def __parse_cast_expression(self) -> Ast: """ <cast-expression> ::= {'('<type-specifier>')'}<unary-expression> """ ast = Ast(AstType.CAST_EXPRESSION) while True: token = self.__peek_token(suppress_exception=True) if token is None: raise InvalidExpression(self.__prev_token().ed_pos) if token.tok_type != TokenType.LEFT_PARENTHESES: break ast.add_child(self.__assert_token('(', TokenType.LEFT_PARENTHESES)) token = self.__peek_token(suppress_exception=True) if token is None: raise InvalidExpression(self.__prev_token().ed_pos) if token.tok_type not in TokenType.types: self.__unread_token() break ast.add_child(self.__parse_type_specifier()) ast.add_child(self.__assert_token(')', TokenType.RIGHT_PARENTHESES)) ast.add_child(self.__parse_unary_expression()) return ast
def __parse_unary_expression(self) -> Ast: """ <unary-expression> ::= [<unary-operator>]<primary-expression> """ ast = Ast(AstType.UNARY_EXPRESSION) token = self.__peek_token(suppress_exception=True) if token is None: raise InvalidExpression(self.__prev_token().ed_pos) if token.tok_type in [TokenType.ADD, TokenType.SUB]: ast.add_child(self.__parse_unary_operator()) ast.add_child(self.__parse_primary_expression()) return ast
def __parse_printable(self) -> Ast: """ <printable> ::= <expression> | <string-literal> """ ast = Ast(AstType.PRINTABLE) token = self.__peek_token(suppress_exception=True) if token is None: raise ExpectedSymbol(self.__prev_token().ed_pos, 'string-literal or identifier') if token.tok_type == TokenType.STR_LITERAL: ast.add_child(self.__parse_str_literal()) else: ast.add_child(self.__parse_expression()) return ast
def __parse_print_statement(self) -> Ast: """ <print-statement> ::= 'print' '(' [<printable-list>] ')' ';' """ ast = Ast(AstType.PRINT_STATEMENT) ast.add_child(self.__assert_token('print', TokenType.PRINT)) ast.add_child(self.__assert_token('(', TokenType.LEFT_PARENTHESES)) token = self.__peek_token(suppress_exception=True) if token is None: raise ExpectedSymbol(self.__prev_token().ed_pos, ')') if token.tok_type != TokenType.RIGHT_PARENTHESES: ast.add_child(self.__parse_printable_list()) ast.add_child(self.__assert_token(')', TokenType.RIGHT_PARENTHESES)) ast.add_child(self.__assert_token(';', TokenType.SEMICOLON)) return ast
def __parse_statement_seq(self) -> Ast: """ <statement-seq> ::= {<statement>} """ ast = Ast(AstType.STATEMENT_SEQ) while True: token = self.__peek_token(suppress_exception=True) if token is None: raise ExpectedSymbol(self.__prev_token().ed_pos, '}') elif token.tok_type in [ TokenType.LEFT_BRACE, TokenType.IF, TokenType.SWITCH, TokenType.WHILE, TokenType.DO, TokenType.FOR, TokenType.BREAK, TokenType.CONTINUE, TokenType.RETURN, TokenType.PRINT, TokenType.SCAN, TokenType.IDENTIFIER, TokenType.SEMICOLON ]: ast.add_child(self.__parse_statement()) else: break return ast
def __parse_assignment_expression(self) -> Ast: """ <assignment-expression> ::= <identifier><assignment-operator><expression> """ ast = Ast(AstType.ASSIGNMENT_EXPRESSION) ast.add_child(self.__parse_identifier()) ast.add_child(self.__parse_assignment_operator()) ast.add_child(self.__parse_expression()) return ast
def __parse_function_definition(self) -> Ast: """ <function-definition> ::= <type-specifier><identifier><parameter-clause><compound-statement> """ ast = Ast(AstType.FUNCTION_DEFINITION) start_pos = self.__current_pos() try: ast.add_child(self.__parse_type_specifier()) ast.add_child(self.__parse_identifier()) ast.add_child(self.__parse_parameter_clause()) ast.add_child(self.__parse_compound_statement()) except TokenIndexOutOfRange as e: print(e, file=sys.stderr) raise InvalidFunctionDefinition(start_pos) return ast
def __parse_function_call(self) -> Ast: """ <function-call> ::= <identifier> '(' [<expression-list>] ')' """ ast = Ast(AstType.FUNCTION_CALL) ast.add_child(self.__parse_identifier()) ast.add_child(self.__assert_token('(', TokenType.LEFT_PARENTHESES)) token = self.__peek_token(suppress_exception=True) if token is None: raise ExpectedSymbol(self.__prev_token().ed_pos, ')') if token.tok_type != TokenType.RIGHT_PARENTHESES: ast.add_child(self.__parse_expression_list()) ast.add_child(self.__assert_token(')', TokenType.RIGHT_PARENTHESES)) return ast
def __parse_compound_statement(self) -> Ast: """ <compound-statement> ::= '{' {<variable-declaration>} <statement-seq> '}' """ ast = Ast(AstType.COMPOUND_STATEMENT) ast.add_child(self.__assert_token('{', TokenType.LEFT_BRACE)) while True: token = self.__peek_token(suppress_exception=True) if token is None: raise ExpectedSymbol(self.__prev_token().ed_pos, '}') if token.tok_type not in TokenType.types + [TokenType.CONST]: break ast.add_child(self.__parse_variable_declaration()) ast.add_child(self.__parse_statement_seq()) ast.add_child(self.__assert_token('}', TokenType.RIGHT_BRACE)) return ast
def __parse_jump_statement(self) -> Ast: """ <jump-statement> ::= 'break' ';' |'continue' ';' |<return-statement> """ ast = Ast(AstType.JUMP_STATEMENT) token = self.__peek_token() if token.tok_type == TokenType.BREAK: ast.add_child(self.__assert_token('break', TokenType.BREAK)) ast.add_child(self.__assert_token(';', TokenType.SEMICOLON)) elif token.tok_type == TokenType.CONTINUE: ast.add_child(self.__assert_token('continue', TokenType.CONTINUE)) ast.add_child(self.__assert_token(';', TokenType.SEMICOLON)) else: ast.add_child(self.__parse_return_statement()) return ast
def __parse_variable_declaration(self) -> Ast: """ <variable-declaration> ::= [<const-qualifier>]<type-specifier><init-declarator-list>';' """ ast = Ast(AstType.VARIABLE_DECLARATION) start_pos = self.__current_pos() try: token = self.__peek_token() if token.tok_type == TokenType.CONST: ast.add_child(self.__parse_const_qualifier()) ast.add_child(self.__parse_type_specifier()) ast.add_child(self.__parse_init_declarator_list()) ast.add_child(self.__assert_token(';', TokenType.SEMICOLON)) except TokenIndexOutOfRange as e: print(e, file=sys.stderr) raise InvalidVariableDeclaration(start_pos) return ast
def __parse_for_init_statement(self) -> Ast: """ <for-init-statement> ::= [<assignment-expression>{','<assignment-expression>}]';' """ ast = Ast(AstType.FOR_INIT_STATEMENT) token = self.__peek_token(suppress_exception=True) if token is None: raise ExpectedSymbol(self.__prev_token().ed_pos, ';') if token.tok_type != TokenType.SEMICOLON: ast.add_child(self.__parse_assignment_expression()) while True: token = self.__peek_token(suppress_exception=True) if token is None or token.tok_type != TokenType.COMMA: break ast.add_child(self.__assert_token(',', TokenType.COMMA)) ast.add_child(self.__parse_assignment_expression()) ast.add_child(self.__assert_token(';', TokenType.SEMICOLON)) return ast
def __parse_expression_list(self) -> Ast: """ <expression-list> ::= <expression>{','<expression>} """ ast = Ast(AstType.EXPRESSION_LIST) ast.add_child(self.__parse_expression()) while True: token = self.__peek_token(suppress_exception=True) if token is None or token.tok_type != TokenType.COMMA: break ast.add_child(self.__assert_token(',', TokenType.COMMA)) ast.add_child(self.__parse_expression()) return ast
def __parse_printable_list(self) -> Ast: """ <printable-list> ::= <printable> {',' <printable>} """ ast = Ast(AstType.PRINTABLE_LIST) ast.add_child(self.__parse_printable()) while True: token = self.__peek_token(suppress_exception=True) if token is None or token.tok_type != TokenType.COMMA: break ast.add_child(self.__assert_token(',', TokenType.COMMA)) ast.add_child(self.__parse_printable()) return ast
def __parse_parameter_declaration_list(self) -> Ast: """ <parameter-declaration-list> ::= <parameter-declaration>{','<parameter-declaration>} """ ast = Ast(AstType.PARAMETER_DECLARATION_LIST) ast.add_child(self.__parse_parameter_declaration()) while True: token = self.__peek_token(suppress_exception=True) if token is None or token.tok_type != TokenType.COMMA: break ast.add_child(self.__assert_token(',', TokenType.COMMA)) ast.add_child(self.__parse_parameter_declaration()) return ast
def __parse_c0(self) -> Ast: """ Analyse C0 program, generate the AST <C0-program> ::= {<variable-declaration>}{<function-definition>} """ ast = Ast(AstType.C0) # {<variable-declaration>} while self.__peek_token(suppress_exception=True) is not None: token = self.__peek_token() if token.tok_type == TokenType.CONST: ast.add_child(self.__parse_variable_declaration()) elif token.tok_type in TokenType.types: a, b, c = [ self.__next_token(suppress_exception=True) for _ in range(3) ] if c is None: raise InvalidVariableDeclaration(token.st_pos) for _ in range(3): self.__unread_token() if c.tok_type == TokenType.LEFT_PARENTHESES: ast.add_child(self.__parse_function_definition()) break else: ast.add_child(self.__parse_variable_declaration()) else: raise ExpectedTypeSpecifier(token.st_pos) # {<function-definition>} while self.__peek_token(suppress_exception=True) is not None: ast.add_child(self.__parse_function_definition()) return ast