function Token * parse__get_name(Parser *p){ Token *name = token_next(p); token_next(p); token_next(p); return name; } function void parse_note_list(Parser *ctx, AST_Node *parent) { if(token_match(ctx, TK_OpenParen)) { do { Token *name = token_expect(ctx, TK_Identifier); AST_Node *current = ast_note(ctx, name, name->intern_val, 0); ast_node_push_note(parent, current); parse_note_list(ctx, current); if(token_match(ctx, TK_Assign)) { current->expr = parse_expr(ctx); } } while(token_match(ctx, TK_Comma)); token_expect(ctx, TK_CloseParen); } } function void parse__notes(Parser *ctx, AST_Node *result) { while(token_match(ctx, TK_At)) { Token *name = token_expect(ctx, TK_Identifier); AST_Node *current = ast_note(ctx, name, name->intern_val, 0); ast_node_push_note(result, current); parse_note_list(ctx, current); if(token_match(ctx, TK_Assign)) { current->expr = parse_expr(ctx); } } } function AST_Node parse_notes(Parser *p){ AST_Node result = {}; parse__notes(p, &result); return result; } function AST_Node * parse_enum(Parser *p, Token *name){ AST_Node *result = 0; if(token_expect(p, TK_OpenBrace)){ result = ast_enum(p, name, name->intern_val); do{ AST_Node notes = parse_notes(p); Token *token = token_match(p, TK_Identifier); if(token){ Expr *expr = 0; if(token_match(p, TK_Assign)){ expr = parse_expr(p); } AST_Node *child = ast_enum_child(p, token, token->intern_val, expr); ast_node_pass_note_list(child,¬es); ast_node_push_child(result, child); } else{ break; } } while(token_match(p, TK_Comma)); token_expect(p, TK_CloseBrace); } return result; } function AST_Node * parse_variable(Parser *p, Token *name){ AST_Node *result = 0; Token *type_token = token_expect(p, TK_Identifier); if(type_token){ AST_Node *type = symbol_require_type(p, type_token); Token *star; while((star = token_match(p, TK_Mul))){ type = ast_type_pointer(p, star, type); } while((star = token_match(p, TK_OpenBracket))){ Expr *expr = parse_expr(p); type = ast_type_array(p, star, type, expr); token_expect(p, TK_CloseBracket); } Expr *expr = 0; if(token_match(p, TK_Assign)){ expr = parse_expr(p); } result = ast_variable(p, name, name->intern_val, type, expr); } return result; } function AST_Node * parse_struct(Parser *p, Token *name, AST_Kind kind, B32 is_global){ AST_Node *result = 0; if(token_expect(p, TK_OpenBrace)){ result = ast_struct(p, name, name?name->intern_val:(Intern_String){}, kind); if(is_global) symbol_register(p, result); for(;;){ AST_Node notes = parse_notes(p); AST_Node *mem = 0; Token *mem_name = token_match(p, TK_Identifier); if(mem_name){ if(token_expect(p, TK_Colon)){ if(token_match_keyword(p, keyword_struct)){ mem = parse_struct(p, mem_name, AK_Struct, false); } else if(token_match_keyword(p, keyword_union)){ mem = parse_struct(p, mem_name, AK_Union, false); } //else if(token_match_keyword(p, keyword_enum)){ //mem = parse_enum(p, mem_name); //} else if(token_is(p, TK_Identifier)){ mem = parse_variable(p, mem_name); token_expect(p, TK_Semicolon); } else parser_push_error(p, mem_name, "Unrecognized token while parsing struct"); if(mem){ ast_node_pass_note_list(mem, ¬es); ast_node_push_child(result, mem); } } else{ break; } } else if(token_match_keyword(p, keyword_union) && token_match(p, TK_Colon)){ mem = parse_struct(p, 0, AK_Union, false); ast_node_pass_note_list(mem, ¬es); ast_node_push_child(result, mem); } else if(token_match_keyword(p, keyword_struct) && token_match(p, TK_Colon)){ mem = parse_struct(p, 0, AK_Struct, false); ast_node_pass_note_list(mem, ¬es); ast_node_push_child(result, mem); } else if(token_expect(p, TK_CloseBrace)){ break; } else{ break; } } } return result; } function AST_Node * parse_typedef(Parser *p, Token *name){ Token *type_token = token_expect(p, TK_Identifier); AST_Node *type = symbol_require_type(p, type_token); AST_Node *result = ast_typedef(p, name, name->intern_val, type); token_expect(p, TK_Semicolon); return result; } function AST_Node_List * parse(Parser *p){ AST_Node_List *result = ast_node_new(p, AK_List, token_get(p), intern_empty); for(;;){ AST_Node *node = 0; AST_Node notes = parse_notes(p); if(token_is(p, TK_End)){ break; } else if(token_is(p, TK_Error)){ break; } else if(token_is(p, TK_Identifier) && // Peeking to be more error averse token_peek_is(p, 1, TK_Colon)){ if(token_peek_is_keyword(p, 2, keyword_struct)){ node = parse_struct(p, parse__get_name(p), AK_Struct, true); symbol_register(p, node); } else if(token_peek_is_keyword(p, 2, keyword_union)){ node = parse_struct(p, parse__get_name(p), AK_Union, true); symbol_register(p, node); } else if(token_peek_is_keyword(p, 2, keyword_enum)){ node = parse_enum(p, parse__get_name(p)); symbol_register(p, node); } else if(token_peek_is_keyword(p, 2, keyword_typedef)){ node = parse_typedef(p, parse__get_name(p)); symbol_register(p, node); } else{ token_next(p); } } else{ token_next(p); } if(node){ ast_node_pass_note_list(node, ¬es); ast_node_push_child(result, node); } else if(notes.first_note != 0){ parser_push_error(p, token_get(p), "Warning: notes got lost"); } } return result; }