?? c-parse.y
字號:
NULL_TREE), NULL_TREE); } ;init: expr_no_commas | '{' '}' { $$ = build_nt (CONSTRUCTOR, NULL_TREE, NULL_TREE); if (pedantic) pedwarn ("ANSI C forbids empty initializer braces"); } | '{' initlist '}' { $$ = build_nt (CONSTRUCTOR, NULL_TREE, nreverse ($2)); } | '{' initlist ',' '}' { $$ = build_nt (CONSTRUCTOR, NULL_TREE, nreverse ($2)); } | error { $$ = NULL_TREE; } ;/* This chain is built in reverse order, and put in forward order where initlist is used. */initlist: init { $$ = build_tree_list (NULL_TREE, $1); } | initlist ',' init { $$ = tree_cons (NULL_TREE, $3, $1); } /* These are for labeled elements. */ | '[' expr_no_commas ELLIPSIS expr_no_commas ']' init { $$ = build_tree_list (tree_cons ($2, NULL_TREE, build_tree_list ($4, NULL_TREE)), $6); } | initlist ',' '[' expr_no_commas ELLIPSIS expr_no_commas ']' init { $$ = tree_cons (tree_cons ($4, NULL_TREE, build_tree_list ($6, NULL_TREE)), $8, $1); } | '[' expr_no_commas ']' init { $$ = build_tree_list ($2, $4); } | initlist ',' '[' expr_no_commas ']' init { $$ = tree_cons ($4, $6, $1); } | identifier ':' init { $$ = build_tree_list ($1, $3); } | initlist ',' identifier ':' init { $$ = tree_cons ($3, $5, $1); } ;nested_function: declarator { push_c_function_context (); if (! start_function (current_declspecs, $1, 1)) { pop_c_function_context (); YYERROR1; } reinit_parse_for_function (); store_parm_decls (); }/* This used to use compstmt_or_error. That caused a bug with input `f(g) int g {}', where the use of YYERROR1 above caused an error which then was handled by compstmt_or_error. There followed a repeated execution of that same rule, which called YYERROR1 again, and so on. */ compstmt { finish_function (1); pop_c_function_context (); } ;notype_nested_function: notype_declarator { push_c_function_context (); if (! start_function (current_declspecs, $1, 1)) { pop_c_function_context (); YYERROR1; } reinit_parse_for_function (); store_parm_decls (); }/* This used to use compstmt_or_error. That caused a bug with input `f(g) int g {}', where the use of YYERROR1 above caused an error which then was handled by compstmt_or_error. There followed a repeated execution of that same rule, which called YYERROR1 again, and so on. */ compstmt { finish_function (1); pop_c_function_context (); } ;/* Any kind of declarator (thus, all declarators allowed after an explicit typespec). */declarator: after_type_declarator | notype_declarator ;/* A declarator that is allowed only after an explicit typespec. */after_type_declarator: '(' after_type_declarator ')' { $$ = $2; } | after_type_declarator '(' parmlist_or_identifiers %prec '.' { $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); }/* | after_type_declarator '(' error ')' %prec '.' { $$ = build_nt (CALL_EXPR, $1, NULL_TREE, NULL_TREE); poplevel (0, 0, 0); } */ | after_type_declarator '[' expr ']' %prec '.' { $$ = build_nt (ARRAY_REF, $1, $3); } | after_type_declarator '[' ']' %prec '.' { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); } | '*' type_quals after_type_declarator %prec UNARY { $$ = make_pointer_declarator ($2, $3); } | TYPENAME ;/* Kinds of declarator that can appear in a parameter list in addition to notype_declarator. This is like after_type_declarator but does not allow a typedef name in parentheses as an identifier (because it would conflict with a function with that typedef as arg). */parm_declarator: parm_declarator '(' parmlist_or_identifiers %prec '.' { $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); }/* | parm_declarator '(' error ')' %prec '.' { $$ = build_nt (CALL_EXPR, $1, NULL_TREE, NULL_TREE); poplevel (0, 0, 0); } */ | parm_declarator '[' expr ']' %prec '.' { $$ = build_nt (ARRAY_REF, $1, $3); } | parm_declarator '[' ']' %prec '.' { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); } | '*' type_quals parm_declarator %prec UNARY { $$ = make_pointer_declarator ($2, $3); } | TYPENAME ;/* A declarator allowed whether or not there has been an explicit typespec. These cannot redeclare a typedef-name. */notype_declarator: notype_declarator '(' parmlist_or_identifiers %prec '.' { $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); }/* | notype_declarator '(' error ')' %prec '.' { $$ = build_nt (CALL_EXPR, $1, NULL_TREE, NULL_TREE); poplevel (0, 0, 0); } */ | '(' notype_declarator ')' { $$ = $2; } | '*' type_quals notype_declarator %prec UNARY { $$ = make_pointer_declarator ($2, $3); } | notype_declarator '[' expr ']' %prec '.' { $$ = build_nt (ARRAY_REF, $1, $3); } | notype_declarator '[' ']' %prec '.' { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); } | IDENTIFIER ;structsp: STRUCT identifier '{' { $$ = start_struct (RECORD_TYPE, $2); /* Start scope of tag before parsing components. */ } component_decl_list '}' { $$ = finish_struct ($<ttype>4, $5); /* Really define the structure. */ } | STRUCT '{' component_decl_list '}' { $$ = finish_struct (start_struct (RECORD_TYPE, NULL_TREE), $3); } | STRUCT identifier { $$ = xref_tag (RECORD_TYPE, $2); } | UNION identifier '{' { $$ = start_struct (UNION_TYPE, $2); } component_decl_list '}' { $$ = finish_struct ($<ttype>4, $5); } | UNION '{' component_decl_list '}' { $$ = finish_struct (start_struct (UNION_TYPE, NULL_TREE), $3); } | UNION identifier { $$ = xref_tag (UNION_TYPE, $2); } | ENUM identifier '{' { $<itype>3 = suspend_momentary (); $$ = start_enum ($2); } enumlist maybecomma_warn '}' { $$ = finish_enum ($<ttype>4, nreverse ($5)); resume_momentary ($<itype>3); } | ENUM '{' { $<itype>2 = suspend_momentary (); $$ = start_enum (NULL_TREE); } enumlist maybecomma_warn '}' { $$ = finish_enum ($<ttype>3, nreverse ($4)); resume_momentary ($<itype>2); } | ENUM identifier { $$ = xref_tag (ENUMERAL_TYPE, $2); } ;maybecomma: /* empty */ | ',' ;maybecomma_warn: /* empty */ | ',' { if (pedantic) pedwarn ("comma at end of enumerator list"); } ;component_decl_list: component_decl_list2 { $$ = $1; } | component_decl_list2 component_decl { $$ = chainon ($1, $2); pedwarn ("no semicolon at end of struct or union"); } ;component_decl_list2: /* empty */ { $$ = NULL_TREE; } | component_decl_list2 component_decl ';' { $$ = chainon ($1, $2); } | component_decl_list2 ';' { if (pedantic) pedwarn ("extra semicolon in struct or union specified"); } ;/* There is a shift-reduce conflict here, because `components' may start with a `typename'. It happens that shifting (the default resolution) does the right thing, because it treats the `typename' as part of a `typed_typespecs'. It is possible that this same technique would allow the distinction between `notype_initdecls' and `initdecls' to be eliminated. But I am being cautious and not trying it. */component_decl: typed_typespecs setspecs components { $$ = $3; current_declspecs = TREE_VALUE (declspec_stack); declspec_stack = TREE_CHAIN (declspec_stack); resume_momentary ($2); } | typed_typespecs { if (pedantic) pedwarn ("ANSI C forbids member declarations with no members"); shadow_tag($1); $$ = NULL_TREE; } | nonempty_type_quals setspecs components { $$ = $3; current_declspecs = TREE_VALUE (declspec_stack); declspec_stack = TREE_CHAIN (declspec_stack); resume_momentary ($2); } | nonempty_type_quals { if (pedantic) pedwarn ("ANSI C forbids member declarations with no members"); shadow_tag($1); $$ = NULL_TREE; } | error { $$ = NULL_TREE; } ;components: component_declarator | components ',' component_declarator { $$ = chainon ($1, $3); } ;component_declarator: save_filename save_lineno declarator maybe_attribute { $$ = grokfield ($1, $2, $3, current_declspecs, NULL_TREE); decl_attributes ($$, $4); } | save_filename save_lineno declarator ':' expr_no_commas maybe_attribute { $$ = grokfield ($1, $2, $3, current_declspecs, $5); decl_attributes ($$, $6); } | save_filename save_lineno ':' expr_no_commas { $$ = grokfield ($1, $2, NULL_TREE, current_declspecs, $4); } ;/* We chain the enumerators in reverse order. They are put in forward order where enumlist is used. (The order used to be significant, but no longer is so. However, we still maintain the order, just to be clean.) */enumlist: enumerator | enumlist ',' enumerator { $$ = chainon ($3, $1); } ;enumerator: identifier { $$ = build_enumerator ($1, NULL_TREE); } | identifier '=' expr_no_commas { $$ = build_enumerator ($1, $3); } ;typename: typed_typespecs absdcl { $$ = build_tree_list ($1, $2); } | nonempty_type_quals absdcl { $$ = build_tree_list ($1, $2); } ;absdcl: /* an absolute declarator */ /* empty */ { $$ = NULL_TREE; } | absdcl1 ;nonempty_type_quals: TYPE_QUAL { $$ = tree_cons (NULL_TREE, $1, NULL_TREE); } | nonempty_type_quals TYPE_QUAL { $$ = tree_cons (NULL_TREE, $2, $1); } ;type_quals: /* empty */ { $$ = NULL_TREE; } | type_quals TYPE_QUAL { $$ = tree_cons (NULL_TREE, $2, $1); } ;absdcl1: /* a nonempty absolute declarator */ '(' absdcl1 ')' { $$ = $2; } /* `(typedef)1' is `int'. */ | '*' type_quals absdcl1 %prec UNARY { $$ = make_pointer_declarator ($2, $3); } | '*' type_quals %prec UNARY { $$ = make_pointer_declarator ($2, NULL_TREE); } | absdcl1 '(' parmlist %prec '.' { $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); } | absdcl1 '[' expr ']' %prec '.' { $$ = build_nt (ARRAY_REF, $1, $3); } | absdcl1 '[' ']' %prec '.' { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); } | '(' parmlist %prec '.' { $$ = build_nt (CALL_EXPR, NULL_TREE, $2, NULL_TREE); } | '[' expr ']' %prec '.' { $$ = build_nt (ARRAY_REF, NULL_TREE, $2); } | '[' ']' %prec '.' { $$ = build_nt (ARRAY_REF, NULL_TREE, NULL_TREE); } ;/* at least one statement, the first of which parses without error. *//* stmts is used only after decls, so an invalid first statement is actually regarded as an invalid decl and part of the decls. */stmts: lineno_stmt_or_label | stmts lineno_stmt_or_label | stmts errstmt ;xstmts: /* empty */ | stmts ;errstmt: error ';' ;pushlevel: /* empty */ { emit_line_note (input_filename, lineno); pushlevel (0); clear_last_expr (); push_momentary (); expand_start_bindings (0); } ;/* Read zero or more forward-declarations for labels that nested functions can jump to. */maybe_label_decls: /* empty */ | label_decls { if (pedantic) pedwarn ("ANSI C forbids label declarations"); } ;label_decls: label_decl | label_decls label_decl ;label_decl: LABEL identifiers_or_typenames ';' { tree link; for (link = $2; link; link = TREE_CHAIN (link)) { tree label = shadow_label (TREE_VALUE (link)); C_DECLARED_LABEL_FLAG (label) = 1; declare_nonlocal_label (label); } }/* This is the body of a function definition. It causes syntax errors to ignore to the next openbrace. */compstmt_or_error: compstmt {} | error compstmt ;compstmt: '{' '}' { $$ = convert (void_type_node, integer_zero_node); } | '{' pushlevel maybe_label_decls decls xstmts '}' { emit_line_note (input_filename, lineno); expand_end_bindings (getdecls (), 1, 0); $$ = poplevel (1, 1, 0); pop_momentary (); } | '{' pushlevel maybe_label_decls error '}' { emit_line_note (input_filename, lineno); expand_end_bindings (getdecls (), kept_level_p (), 0); $$ = poplevel (kept_level_p (), 0, 0); pop_momentary (); } | '{' pushlevel maybe_label_decls stmts '}' { emit_line_note (input_filename, lineno); expand_end_bindings (getdecls (), kept_level_p (), 0); $$ = poplevel (kept_level_p (), 0, 0); pop_momentary (); } ;/* Value is number of statements counted as of the closeparen. */simple_if: if_prefix lineno_labeled_stmt/* Make sure expand_end_cond is run once for each call to expand_start_cond. Otherwise a crash is likely. */ | if_prefix error ;if_prefix: IF '(' expr ')' { emit_line_note ($<filename>-1, $<lineno>0); expand_start_cond (truthvalue_conversion ($3), 0); $<itype>1 = stmt_count; if_stmt_file = $<filename>-1; if_stmt_line = $<lineno>0; position_after_white_space (); } ;/* This is a subroutine of stmt. It is used twice, once for valid DO statements and once for catching errors in parsing the end test. */do_stmt_start: DO { stmt_count++; emit_line_note ($<filename>-1, $<lineno>0);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -