def parse_compound_statement(index): """Parse a compound statement. A compound statement is a collection of several statements/declarations, enclosed in braces. """ p.symbols.new_scope() index = match_token(index, token_kinds.open_brack, ParserError.GOT) # Read block items (statements/declarations) until there are no more. items = [] while True: with log_error(): item, index = parse_statement(index) items.append(item) continue with log_error(): item, index = parse_declaration(index) items.append(item) continue break index = match_token(index, token_kinds.close_brack, ParserError.GOT) p.symbols.end_scope() return nodes.Compound(items), index
def parse_compound_statement(index): """Parse a compound statement. A compound statement is a collection of several statements/declarations, enclosed in braces. """ index = match_token(index, token_kinds.open_brack, ParserError.GOT) # Read block items (statements/declarations) until there are no more. items = [] while True: try: item, index = parse_statement(index) items.append(item) continue except ParserError as e: log_error(e) try: item, index = parse_declaration(index) items.append(item) continue except ParserError as e: log_error(e) # When both of our parsing attempts fail, break out of the loop break index = match_token(index, token_kinds.close_brack, ParserError.GOT) return nodes.Compound(items), index
def parse_root(index): """Parse the given tokens into an AST.""" items = [] while True: try: item, index = parse_main(index) items.append(item) except ParserError as e: log_error(e) else: continue try: item, index = parse_declaration(index) items.append(item) except ParserError as e: log_error(e) else: continue # If neither parse attempt above worked, break break # If there are tokens that remain unparsed, complain if not p.tokens[index:]: return nodes.Root(items), index else: raise_error("unexpected token", index, ParserError.AT)
def parse(tokens_to_parse): """Parse the given tokens into an AST. Also, as the entry point for the parser, responsible for setting the tokens global variable. """ p.best_error = None p.tokens = tokens_to_parse try: return parse_root(0)[0] except ParserError as e: log_error(e) error_collector.add(p.best_error) return None
def parse_statement(index): """Parse a statement. Try each possible type of statement, catching/logging exceptions upon parse failures. On the last try, raise the exception on to the caller. """ for func in (parse_compound_statement, parse_return, parse_break, parse_continue, parse_if_statement, parse_while_statement, parse_for_statement): try: return func(index) except ParserError as e: log_error(e) return parse_expr_statement(index)
def try_parse_func_decl(start, end): """Parse a function declarator between start and end. Expects that tokens[end-1] is a close parenthesis. If a function declarator is successfully parsed, returns the decl_node.Function object. Otherwise, returns None. """ open_paren = find_pair_backward(end - 1) try: params, index = parse_parameter_list(open_paren + 1) except ParserError as e: log_error(e) return None if index == end - 1: return decl_nodes.Function(params, parse_declarator(start, open_paren))
def parse_unary(index): """Parse unary expression.""" unary_args = {token_kinds.incr: (parse_unary, expr_nodes.PreIncr), token_kinds.decr: (parse_unary, expr_nodes.PreDecr), token_kinds.amp: (parse_cast, expr_nodes.AddrOf), token_kinds.star: (parse_cast, expr_nodes.Deref), token_kinds.bool_not: (parse_cast, expr_nodes.BoolNot), token_kinds.plus: (parse_cast, expr_nodes.UnaryPlus), token_kinds.minus: (parse_cast, expr_nodes.UnaryMinus), token_kinds.compl: (parse_cast, expr_nodes.Compl)} if token_in(index, unary_args): parse_func, NodeClass = unary_args[p.tokens[index].kind] subnode, index = parse_func(index + 1) return NodeClass(subnode), index elif token_is(index, token_kinds.sizeof_kw): with log_error(): node, index = parse_unary(index + 1) return expr_nodes.SizeofExpr(node), index from shivyc.parser.declaration import ( parse_abstract_declarator, parse_spec_qual_list) match_token(index + 1, token_kinds.open_paren, ParserError.AFTER) specs, index = parse_spec_qual_list(index + 2) node, index = parse_abstract_declarator(index) match_token(index, token_kinds.close_paren, ParserError.AT) decl_node = decl_nodes.Root(specs, [node]) return expr_nodes.SizeofType(decl_node), index + 1 else: return parse_postfix(index)
def parse_unary(index): """Parse unary expression.""" unary_args = { token_kinds.incr: (parse_unary, expr_nodes.PreIncr), token_kinds.decr: (parse_unary, expr_nodes.PreDecr), token_kinds.amp: (parse_cast, expr_nodes.AddrOf), token_kinds.star: (parse_cast, expr_nodes.Deref), token_kinds.bool_not: (parse_cast, expr_nodes.BoolNot), token_kinds.plus: (parse_cast, expr_nodes.UnaryPlus), token_kinds.minus: (parse_cast, expr_nodes.UnaryMinus), token_kinds.compl: (parse_cast, expr_nodes.Compl) } if token_in(index, unary_args): parse_func, NodeClass = unary_args[p.tokens[index].kind] subnode, index = parse_func(index + 1) return NodeClass(subnode), index elif token_is(index, token_kinds.sizeof_kw): with log_error(): node, index = parse_unary(index + 1) return expr_nodes.SizeofExpr(node), index from shivyc.parser.declaration import (parse_abstract_declarator, parse_spec_qual_list) match_token(index + 1, token_kinds.open_paren, ParserError.AFTER) specs, index = parse_spec_qual_list(index + 2) node, index = parse_abstract_declarator(index) match_token(index, token_kinds.close_paren, ParserError.AT) decl_node = decl_nodes.Root(specs, [node]) return expr_nodes.SizeofType(decl_node), index + 1 else: return parse_postfix(index)
def _get_first_for_clause(index): """Get the first clause of a for-statement. index - Index of the beginning of the first clause in the for-statement. returns - Tuple. First element is a node if a clause is found and None if there is no clause (i.e. semicolon terminating the clause). Second element is an integer index where the next token begins. If malformed, raises exception. """ if token_is(index, token_kinds.semicolon): return None, index + 1 try: return parse_declaration(index) except ParserError as e: log_error(e) clause, index = parse_expression(index) index = match_token(index, token_kinds.semicolon, ParserError.AFTER) return clause, index
def parse_root(index): """Parse the given tokens into an AST.""" items = [] while True: with log_error(): item, index = parse_func_definition(index) items.append(item) continue with log_error(): item, index = parse_declaration(index) items.append(item) continue # If neither parse attempt above worked, break break # If there are tokens that remain unparsed, complain if not p.tokens[index:]: return nodes.Root(items), index else: raise_error("unexpected token", index, ParserError.AT)
def parse(tokens_to_parse): """Parse the given tokens into an AST. Also, as the entry point for the parser, responsible for setting the tokens global variable. """ p.best_error = None p.tokens = tokens_to_parse with log_error(): return parse_root(0)[0] error_collector.add(p.best_error) return None
def parse_statement(index): """Parse a statement. Try each possible type of statement, catching/logging exceptions upon parse failures. On the last try, raise the exception on to the caller. """ for func in (parse_compound_statement, parse_return, parse_break, parse_continue, parse_if_statement, parse_while_statement, parse_for_statement): with log_error(): return func(index) return parse_expr_statement(index)
def _try_parse_func_decl(start, end, is_typedef=False): """Parse a function declarator between start and end. If a function declarator is successfully parsed, returns the decl_node.Function object. Otherwise, returns None. """ if not token_is(end - 1, token_kinds.close_paren): return None open_paren = _find_pair_backward(end - 1) with log_error(): params, index = parse_parameter_list(open_paren + 1) if index == end - 1: return decl_nodes.Function( params, _parse_declarator(start, open_paren, is_typedef)) return None
def parse_cast(index): """Parse cast expression.""" from shivyc.parser.declaration import ( parse_abstract_declarator, parse_spec_qual_list) with log_error(): match_token(index, token_kinds.open_paren, ParserError.AT) specs, index = parse_spec_qual_list(index + 1) node, index = parse_abstract_declarator(index) match_token(index, token_kinds.close_paren, ParserError.AT) decl_node = decl_nodes.Root(specs, [node]) expr_node, index = parse_cast(index + 1) return expr_nodes.Cast(decl_node, expr_node), index return parse_unary(index)
def parse_cast(index): """Parse cast expression.""" from shivyc.parser.declaration import (parse_abstract_declarator, parse_spec_qual_list) with log_error(): match_token(index, token_kinds.open_paren, ParserError.AT) specs, index = parse_spec_qual_list(index + 1) node, index = parse_abstract_declarator(index) match_token(index, token_kinds.close_paren, ParserError.AT) decl_node = decl_nodes.Root(specs, [node]) expr_node, index = parse_cast(index + 1) return expr_nodes.Cast(decl_node, expr_node), index return parse_unary(index)
def _get_first_for_clause(index): """Get the first clause of a for-statement. index - Index of the beginning of the first clause in the for-statement. returns - Tuple. First element is a node if a clause is found and None if there is no clause (i.e. semicolon terminating the clause). Second element is an integer index where the next token begins. If malformed, raises exception. """ if token_is(index, token_kinds.semicolon): return None, index + 1 with log_error(): return parse_declaration(index) clause, index = parse_expression(index) index = match_token(index, token_kinds.semicolon, ParserError.AFTER) return clause, index