%defines %output "mini_c.tab.cpp" %{ #include #include "ast.h" /* 定义了 ASTNode 结构和 new_* 系列函数 */ ASTNode *ast_root = NULL; /* 最终的 AST 根 */ int yylex(void); void yyerror(const char *s); #define LOC(YYL) SourceLoc{ (YYL).first_line, (YYL).first_column } static ASTNode* make_type_spec_node(int ts) { ASTNode* n = new ASTNode(ASTTag::SPECIFIER); n->ival = ts; return n; } %} %nonassoc LOWER_THAN_ELSE %nonassoc ELSE %locations %union { int ival; /* 运算符枚举、数值常量等整数值 */ char *sval; /* 标识符、字符串、常量的原始文本 */ ASTNode *node; /* AST 子树 */ } /*—— 所有会产生 ASTNode* 的 nonterminal ——*/ %type primary_expression postfix_expression argument_expression_list unary_expression cast_expression multiplicative_expression additive_expression shift_expression relational_expression equality_expression and_expression exclusive_or_expression inclusive_or_expression logical_and_expression logical_or_expression conditional_expression assignment_expression expression constant_expression declaration declaration_specifiers init_declarator_list init_declarator struct_or_union_specifier struct_declaration_list struct_declaration specifier_qualifier_list struct_declarator_list struct_declarator enum_specifier enumerator_list enumerator declarator direct_declarator pointer type_qualifier_list parameter_type_list parameter_list parameter_declaration identifier_list type_name abstract_declarator direct_abstract_declarator initializer initializer_list designation designator_list designator statement labeled_statement compound_statement block_item_list block_item expression_statement selection_statement iteration_statement jump_statement translation_unit external_declaration function_definition declaration_list ; /*—— 运算符枚举,用 ival 存 ——*/ %type assignment_operator unary_operator %type storage_class_specifier type_qualifier function_specifier %type type_specifier %type struct_or_union /*—— token 的语义值类型 ——*/ %token IDENTIFIER %token CONSTANT %token STRING_LITERAL %token TYPE_NAME %token SIZEOF %token PTR_OP INC_OP DEC_OP LEFT_OP RIGHT_OP %token LE_OP GE_OP EQ_OP NE_OP AND_OP OR_OP %token MUL_ASSIGN DIV_ASSIGN MOD_ASSIGN ADD_ASSIGN SUB_ASSIGN %token LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN XOR_ASSIGN OR_ASSIGN %token TYPEDEF EXTERN STATIC AUTO REGISTER INLINE RESTRICT %token CHAR SHORT INT LONG SIGNED UNSIGNED FLOAT DOUBLE CONST VOLATILE VOID %token BOOL COMPLEX IMAGINARY %token STRUCT UNION ENUM ELLIPSIS %token CASE DEFAULT IF ELSE SWITCH WHILE DO FOR GOTO CONTINUE BREAK RETURN %start translation_unit %% primary_expression : IDENTIFIER { $$ = new_id_node($1, LOC(@1)); } | CONSTANT { $$ = new_const_node($1, LOC(@1)); } | STRING_LITERAL { $$ = new_string_node($1, LOC(@1)); } | '(' expression ')' { $$ = $2; $$->loc = LOC(@3); } ; postfix_expression : primary_expression { $$ = $1; } | postfix_expression '[' expression ']' { $$ = new_array_ref_node($1, $3, LOC(@2)); } | postfix_expression '(' ')' { $$ = new_func_call_node($1, NULL, LOC(@2)); } | postfix_expression '(' argument_expression_list ')' { $$ = new_func_call_node($1, $3, LOC(@2)); } | postfix_expression '.' IDENTIFIER { $$ = new_struct_ref_node($1, $3, false, LOC(@2)); } | postfix_expression PTR_OP IDENTIFIER { $$ = new_struct_ref_node($1, $3, true, LOC(@2)); } | postfix_expression INC_OP { $$ = new_post_inc_node($1, LOC(@2)); } | postfix_expression DEC_OP { $$ = new_post_dec_node($1, LOC(@2)); } | '(' type_name ')' '{' initializer_list '}' { $$ = new_compound_literal_node($2, $5, LOC(@1)); } | '(' type_name ')' '{' initializer_list ',' '}' { $$ = new_compound_literal_node($2, $5, LOC(@1)); } ; argument_expression_list : assignment_expression { $$ = new_arg_list($1, LOC(@1)); } | argument_expression_list ',' assignment_expression { $$ = append_arg_list($1, $3, LOC(@2)); } ; unary_expression : postfix_expression { $$ = $1; } | INC_OP unary_expression { $$ = new_pre_inc_node($2, LOC(@1)); } | DEC_OP unary_expression { $$ = new_pre_dec_node($2, LOC(@1)); } | unary_operator cast_expression { $$ = new_unary_op_node($1, $2, LOC(@1)); } | SIZEOF unary_expression { $$ = new_sizeof_node($2, false, LOC(@1)); } | SIZEOF '(' type_name ')' { $$ = new_sizeof_node($3, true, LOC(@1)); } ; unary_operator : '&' { $$ = op_address; } | '*' { $$ = op_deref; } | '+' { $$ = op_unary_plus; } | '-' { $$ = op_neg; } | '~' { $$ = op_bitnot; } | '!' { $$ = op_not; } ; cast_expression : unary_expression { $$ = $1; } | '(' type_name ')' cast_expression { $$ = new_cast_node($2, $4, LOC(@1)); } ; multiplicative_expression : cast_expression { $$ = $1; } | multiplicative_expression '*' cast_expression { $$ = new_binop_node('*', $1, $3, LOC(@2)); } | multiplicative_expression '/' cast_expression { $$ = new_binop_node('/', $1, $3, LOC(@2)); } | multiplicative_expression '%' cast_expression { $$ = new_binop_node('%', $1, $3, LOC(@2)); } ; additive_expression : multiplicative_expression { $$ = $1; } | additive_expression '+' multiplicative_expression { $$ = new_binop_node('+', $1, $3, LOC(@2)); } | additive_expression '-' multiplicative_expression { $$ = new_binop_node('-', $1, $3, LOC(@2)); } ; shift_expression : additive_expression { $$ = $1; } | shift_expression LEFT_OP additive_expression { $$ = new_binop_node(SHL, $1, $3, LOC(@2)); } | shift_expression RIGHT_OP additive_expression { $$ = new_binop_node(SHR, $1, $3, LOC(@2)); } ; relational_expression : shift_expression { $$ = $1; } | relational_expression '<' shift_expression { $$ = new_binop_node('<', $1, $3, LOC(@2)); } | relational_expression '>' shift_expression { $$ = new_binop_node('>', $1, $3, LOC(@2)); } | relational_expression LE_OP shift_expression { $$ = new_binop_node(LE, $1, $3, LOC(@2)); } | relational_expression GE_OP shift_expression { $$ = new_binop_node(GE, $1, $3, LOC(@2)); } ; equality_expression : relational_expression { $$ = $1; } | equality_expression EQ_OP relational_expression { $$ = new_binop_node(EQ, $1, $3, LOC(@2)); } | equality_expression NE_OP relational_expression { $$ = new_binop_node(NE, $1, $3, LOC(@2)); } ; and_expression : equality_expression { $$ = $1; } | and_expression '&' equality_expression { $$ = new_binop_node('&', $1, $3, LOC(@2)); } ; exclusive_or_expression : and_expression { $$ = $1; } | exclusive_or_expression '^' and_expression { $$ = new_binop_node('^', $1, $3, LOC(@2)); } ; inclusive_or_expression : exclusive_or_expression { $$ = $1; } | inclusive_or_expression '|' exclusive_or_expression { $$ = new_binop_node('|', $1, $3, LOC(@2)); } ; logical_and_expression : inclusive_or_expression { $$ = $1; } | logical_and_expression AND_OP inclusive_or_expression { $$ = new_logical_and_node($1, $3, LOC(@2)); } ; logical_or_expression : logical_and_expression { $$ = $1; } | logical_or_expression OR_OP logical_and_expression { $$ = new_logical_or_node($1, $3, LOC(@2)); } ; conditional_expression : logical_or_expression { $$ = $1; } | logical_or_expression '?' expression ':' conditional_expression { $$ = new_conditional_node($1, $3, $5, LOC(@2)); } ; assignment_expression : conditional_expression { $$ = $1; } | unary_expression assignment_operator assignment_expression { $$ = new_assign_node($1, $2, $3, LOC(@2)); } ; assignment_operator : '=' { $$ = op_assign; } | MUL_ASSIGN { $$ = op_mul_assign; } | DIV_ASSIGN { $$ = op_div_assign; } | MOD_ASSIGN { $$ = op_mod_assign; } | ADD_ASSIGN { $$ = op_add_assign; } | SUB_ASSIGN { $$ = op_sub_assign; } | LEFT_ASSIGN { $$ = op_shl_assign; } | RIGHT_ASSIGN { $$ = op_shr_assign; } | AND_ASSIGN { $$ = op_and_assign; } | XOR_ASSIGN { $$ = op_xor_assign; } | OR_ASSIGN { $$ = op_or_assign; } ; expression : assignment_expression { $$ = $1; } | expression ',' assignment_expression { $$ = new_expr_list($1, $3, LOC(@2)); } ; constant_expression : conditional_expression { $$ = $1; } ; /* 声明相关 */ declaration : declaration_specifiers ';' { $$ = new_decl_stmt($1, LOC(@2)); } | declaration_specifiers init_declarator_list ';' { $$ = new_declaration($1, $2, LOC(@3)); } ; declaration_specifiers : storage_class_specifier { $$ = new_spec_list($1, LOC(@1)); } | storage_class_specifier declaration_specifiers { $$ = append_spec_list($2, $1, LOC(@1)); } | type_specifier { $$ = new_spec_list($1, LOC(@1)); } | type_specifier declaration_specifiers { $$ = append_spec_list($2, $1, LOC(@1)); } | type_qualifier { $$ = new_spec_list($1, LOC(@1)); } | type_qualifier declaration_specifiers { $$ = append_spec_list($2, $1, LOC(@1)); } | function_specifier { $$ = new_spec_list($1, LOC(@1)); } | function_specifier declaration_specifiers { $$ = append_spec_list($2, $1, LOC(@1)); } ; init_declarator_list : init_declarator { $$ = new_init_list($1, LOC(@1)); } | init_declarator_list ',' init_declarator { $$ = append_init_list($1, $3, LOC(@2)); } ; init_declarator : declarator { $$ = new_init_decl($1, NULL, LOC(@1)); } | declarator '=' initializer { $$ = new_init_decl($1, $3, LOC(@2)); } ; storage_class_specifier : TYPEDEF { $$ = SC_TYPEDEF; } | EXTERN { $$ = SC_EXTERN; } | STATIC { $$ = SC_STATIC; } | AUTO { $$ = SC_AUTO; } | REGISTER { $$ = SC_REGISTER; } ; type_specifier : VOID { $$ = make_type_spec_node(TS_VOID); } | CHAR { $$ = make_type_spec_node(TS_CHAR); } | SHORT { $$ = make_type_spec_node(TS_SHORT); } | INT { $$ = make_type_spec_node(TS_INT); } | LONG { $$ = make_type_spec_node(TS_LONG); } | FLOAT { $$ = make_type_spec_node(TS_FLOAT); } | DOUBLE { $$ = make_type_spec_node(TS_DOUBLE); } | SIGNED { $$ = make_type_spec_node(TS_SIGNED); } | UNSIGNED { $$ = make_type_spec_node(TS_UNSIGNED); } | BOOL { $$ = make_type_spec_node(TS_BOOL); } | COMPLEX { $$ = make_type_spec_node(TS_COMPLEX); } | IMAGINARY { $$ = make_type_spec_node(TS_IMAGINARY); } | struct_or_union_specifier { $$ = $1; } | enum_specifier { $$ = $1; } | TYPE_NAME { $$ = make_type_spec_node(TS_TYPE_NAME); } ; struct_or_union_specifier : struct_or_union IDENTIFIER '{' struct_declaration_list '}' { $$ = new_struct_su_node(static_cast($1), $2, $4, LOC(@2)); } | struct_or_union '{' struct_declaration_list '}' { $$ = new_struct_su_node(static_cast($1), nullptr, $3, LOC(@2)); } | struct_or_union IDENTIFIER { $$ = new_struct_su_node(static_cast($1), $2, nullptr, LOC(@2)); } ; struct_or_union : STRUCT { $$ = SU_STRUCT; } | UNION { $$ = SU_UNION; } ; struct_declaration_list : struct_declaration { $$ = new_sdecl_list($1, LOC(@1)); } | struct_declaration_list struct_declaration { $$ = append_sdecl_list($1, $2, LOC(@2)); } ; struct_declaration : specifier_qualifier_list struct_declarator_list ';' { $$ = new_struct_decl($1, $2, LOC(@3)); } ; specifier_qualifier_list : type_specifier specifier_qualifier_list { $$ = append_specq_list($2, $1, LOC(@1)); } | type_specifier { $$ = new_specq_list($1, LOC(@1)); } | type_qualifier specifier_qualifier_list { $$ = append_specq_list($2, $1, LOC(@1)); } | type_qualifier { $$ = new_specq_list($1, LOC(@1)); } ; struct_declarator_list : struct_declarator { $$ = new_sdeclarator_list($1, LOC(@1)); } | struct_declarator_list ',' struct_declarator { $$ = append_sdeclarator_list($1, $3, LOC(@2)); } ; struct_declarator : declarator { $$ = $1; } | ':' constant_expression { $$ = new_bitfield_node(NULL, $2, LOC(@1)); } | declarator ':' constant_expression { $$ = new_bitfield_node($1, $3, LOC(@2)); } ; enum_specifier : ENUM '{' enumerator_list '}' { $$ = new_enum_node(NULL, $3, LOC(@1)); } | ENUM IDENTIFIER '{' enumerator_list '}' { $$ = new_enum_node($2, $4, LOC(@1)); } | ENUM '{' enumerator_list ',' '}' { $$ = new_enum_node(NULL, $3, LOC(@1)); } | ENUM IDENTIFIER '{' enumerator_list ',' '}' { $$ = new_enum_node($2, $4, LOC(@1)); } | ENUM IDENTIFIER { $$ = new_enum_node($2, NULL, LOC(@1)); } ; enumerator_list : enumerator { $$ = new_enum_list($1, LOC(@1)); } | enumerator_list ',' enumerator { $$ = append_enum_list($1, $3, LOC(@2)); } ; enumerator : IDENTIFIER { $$ = new_enum_const($1, NULL, LOC(@1)); } | IDENTIFIER '=' constant_expression { $$ = new_enum_const($1, $3, LOC(@1)); } ; type_qualifier : CONST { $$ = TQ_CONST; } | RESTRICT { $$ = TQ_RESTRICT; } | VOLATILE { $$ = TQ_VOLATILE; } ; function_specifier : INLINE { $$ = FS_INLINE; } ; declarator : pointer direct_declarator { $$ = new_declarator_node($1, $2, LOC(@1)); } | direct_declarator { $$ = new_declarator_node(NULL, $1, LOC(@1)); } ; direct_declarator : IDENTIFIER { $$ = new_decl_ident($1, LOC(@1)); } | '(' declarator ')' { $$ = $2; $$->loc = LOC(@3); } | direct_declarator '[' type_qualifier_list assignment_expression ']' { $$ = new_array_decl($1, $3, $4, NULL, NULL, LOC(@2)); } | direct_declarator '[' type_qualifier_list ']' { $$ = new_array_decl($1, $3, NULL, NULL, NULL, LOC(@2)); } | direct_declarator '[' assignment_expression ']' { $$ = new_array_decl($1, NULL, $3, NULL, NULL, LOC(@2)); } | direct_declarator '[' STATIC type_qualifier_list assignment_expression ']' { $$ = new_array_decl($1, $4, $5, true, NULL, LOC(@2)); } | direct_declarator '[' type_qualifier_list STATIC assignment_expression ']' { $$ = new_array_decl($1, $3, $5, true, NULL, LOC(@2)); } | direct_declarator '[' type_qualifier_list '*' ']' { $$ = new_array_decl($1, $3, NULL, NULL, true, LOC(@2)); } | direct_declarator '[' '*' ']' { $$ = new_array_decl($1, NULL, NULL, NULL, true, LOC(@2)); } | direct_declarator '[' ']' { $$ = new_array_decl($1, NULL, NULL, NULL, false, LOC(@2)); } | direct_declarator '(' parameter_type_list ')' { $$ = new_func_decl($1, $3, LOC(@2)); } | direct_declarator '(' identifier_list ')' { $$ = new_oldstyle_func_decl($1, $3, LOC(@2)); } | direct_declarator '(' ')' { $$ = new_func_decl($1, NULL, LOC(@2)); } ; pointer : '*' { $$ = new_pointer(NULL, LOC(@1)); } | '*' type_qualifier_list { $$ = new_pointer($2, LOC(@1)); } | '*' pointer { $$ = prepend_pointer(NULL, $2, LOC(@1)); } | '*' type_qualifier_list pointer { $$ = prepend_pointer($2, $3, LOC(@1)); } ; type_qualifier_list : type_qualifier { $$ = new_tq_list($1, LOC(@1)); } | type_qualifier_list type_qualifier { $$ = append_tq_list($1, $2, LOC(@2)); } ; parameter_type_list : parameter_list { $$ = $1; } | parameter_list ',' ELLIPSIS { $$ = new_param_list_ellipsis($1, LOC(@2)); } ; parameter_list : parameter_declaration { $$ = new_param_list($1, LOC(@1)); } | parameter_list ',' parameter_declaration { $$ = append_param_list($1, $3, LOC(@2)); } ; parameter_declaration : declaration_specifiers declarator { $$ = new_param_decl($1, $2, LOC(@2)); } | declaration_specifiers abstract_declarator { $$ = new_param_decl($1, $2, LOC(@2)); } | declaration_specifiers { $$ = new_param_decl($1, NULL, LOC(@1)); } ; identifier_list : IDENTIFIER { $$ = new_id_list($1, LOC(@1)); } | identifier_list ',' IDENTIFIER { $$ = append_id_list($1, $3, LOC(@3)); } ; type_name : specifier_qualifier_list { $$ = new_type_name($1, NULL, LOC(@1)); } | specifier_qualifier_list abstract_declarator { $$ = new_type_name($1, $2, LOC(@1)); } ; abstract_declarator : pointer { $$ = new_abs_decl($1, NULL, LOC(@1)); } | direct_abstract_declarator { $$ = new_abs_decl(NULL, $1, LOC(@1)); } | pointer direct_abstract_declarator { $$ = new_abs_decl($1, $2, LOC(@1)); } ; direct_abstract_declarator : '(' abstract_declarator ')' { $$ = $2; $$->loc = LOC(@3); } | '[' ']' { $$ = new_abs_array(NULL, NULL, LOC(@1)); } | '[' assignment_expression ']' { $$ = new_abs_array($2, NULL, LOC(@1)); } | direct_abstract_declarator '[' ']' { $$ = new_abs_array_child($1, NULL, NULL, LOC(@2)); } | direct_abstract_declarator '[' assignment_expression ']' { $$ = new_abs_array_child($1, $3, NULL, LOC(@2)); } | '[' '*' ']' { $$ = new_abs_array(NULL, true, LOC(@1)); } | direct_abstract_declarator '[' '*' ']' { $$ = new_abs_array_child($1, NULL, true, LOC(@2)); } | '(' ')' { $$ = new_abs_func(NULL, LOC(@1)); } | '(' parameter_type_list ')' { $$ = new_abs_func($2, LOC(@1)); } | direct_abstract_declarator '(' ')' { $$ = new_abs_func_child($1, NULL, LOC(@2)); } | direct_abstract_declarator '(' parameter_type_list ')' { $$ = new_abs_func_child($1, $3, LOC(@2)); } ; initializer : assignment_expression { $$ = new_init_expr($1, LOC(@1)); } | '{' initializer_list '}' { $$ = new_init_list_node($2, LOC(@1)); } | '{' initializer_list ',' '}' { $$ = new_init_list_node($2, LOC(@1)); } ; initializer_list : initializer { $$ = new_init_item_list($1, LOC(@1)); } | designation initializer { $$ = new_designated_init($1, $2, LOC(@1)); } | initializer_list ',' initializer { $$ = append_init_item($1, $3, LOC(@2)); } | initializer_list ',' designation initializer { $$ = append_designated_init($1, $3, $4, LOC(@2)); } ; designation : designator_list '=' { $$ = $1; } ; designator_list : designator { $$ = new_designator_list($1, LOC(@1)); } | designator_list designator { $$ = append_designator_list($1, $2, LOC(@2)); } ; designator : '[' constant_expression ']' { $$ = new_array_designator($2, LOC(@1)); } | '.' IDENTIFIER { $$ = new_field_designator($2, LOC(@1)); } ; statement : labeled_statement { $$ = $1; } | compound_statement { $$ = $1; } | expression_statement { $$ = $1; } | selection_statement { $$ = $1; } | iteration_statement { $$ = $1; } | jump_statement { $$ = $1; } ; labeled_statement : IDENTIFIER ':' statement { $$ = new_labeled_stmt_id($1, $3, LOC(@1)); } | CASE constant_expression ':' statement { $$ = new_case_stmt($2, $4, LOC(@1)); } | DEFAULT ':' statement { $$ = new_default_stmt($3, LOC(@1)); } ; compound_statement : '{' '}' { $$ = new_compound_stmt(NULL, LOC(@1)); } | '{' block_item_list '}' { $$ = new_compound_stmt($2, LOC(@1)); } ; block_item_list : block_item { $$ = new_block_item_list($1, LOC(@1)); } | block_item_list block_item { $$ = append_block_item_list($1, $2, LOC(@2)); } ; block_item : declaration { $$ = new_block_decl($1, LOC(@1)); } | statement { $$ = new_block_stmt($1, LOC(@1)); } ; expression_statement : ';' { $$ = NULL; } | expression ';' { $$ = new_expr_stmt($1, LOC(@2)); } ; selection_statement : IF '(' expression ')' statement %prec LOWER_THAN_ELSE { $$ = new_if_stmt($3, $5, NULL, LOC(@1)); } | IF '(' expression ')' statement ELSE statement { $$ = new_if_stmt($3, $5, $7, LOC(@1)); } | SWITCH '(' expression ')' statement { $$ = new_switch_stmt($3, $5, LOC(@1)); } ; iteration_statement : WHILE '(' expression ')' statement { $$ = new_while_stmt($3, $5, LOC(@1)); } | DO statement WHILE '(' expression ')' ';' { $$ = new_do_while_stmt($2, $5, LOC(@1)); } | FOR '(' expression_statement expression_statement ')' statement { $$ = new_for_stmt($3, $4, NULL, $6, LOC(@1)); } | FOR '(' expression_statement expression_statement expression ')' statement { $$ = new_for_stmt($3, $4, $5, $7, LOC(@1)); } | FOR '(' declaration expression_statement ')' statement { $$ = new_for_decl_stmt($3, $4, NULL, $6, LOC(@1)); } | FOR '(' declaration expression_statement expression ')' statement { $$ = new_for_decl_stmt($3, $4, $5, $7, LOC(@1)); } ; jump_statement : GOTO IDENTIFIER ';' { $$ = new_goto_stmt($2, LOC(@1)); } | CONTINUE ';' { $$ = new_continue_stmt(LOC(@1)); } | BREAK ';' { $$ = new_break_stmt(LOC(@1)); } | RETURN ';' { $$ = new_return_stmt(NULL, LOC(@1)); } | RETURN expression ';' { $$ = new_return_stmt($2, LOC(@1)); } ; translation_unit : external_declaration { ast_root = $$ = $1; } | translation_unit external_declaration { ast_root = $$ = new_translation_unit($1, $2, LOC(@2)); } ; external_declaration : function_definition { $$ = $1; } | declaration { $$ = new_decl_stmt($1, LOC(@1)); } ; function_definition : declaration_specifiers declarator declaration_list compound_statement { $$ = new_function_def($1, $2, $3, $4, LOC(@2)); } | declaration_specifiers declarator compound_statement { $$ = new_function_def($1, $2, NULL, $3, LOC(@2)); } ; declaration_list : declaration { $$ = new_declaration_list($1, LOC(@1)); } | declaration_list declaration { $$ = append_declaration_list($1, $2, LOC(@2)); } ; %% #include extern char yytext[]; extern int column; void yyerror(char const *s) { fflush(stdout); printf("\n%*s\n%*s\n", column, "^", column, s); }