📄 c-parse.in
字号:
;datadecl: typed_declspecs setspecs initdecls ';' { current_declspecs = TREE_VALUE (declspec_stack); prefix_attributes = TREE_PURPOSE (declspec_stack); declspec_stack = TREE_CHAIN (declspec_stack); resume_momentary ($2); } | declmods setspecs notype_initdecls ';' { current_declspecs = TREE_VALUE (declspec_stack); prefix_attributes = TREE_PURPOSE (declspec_stack); declspec_stack = TREE_CHAIN (declspec_stack); resume_momentary ($2); } | typed_declspecs ';' { shadow_tag_warned ($1, 1); pedwarn ("empty declaration"); } | declmods ';' { pedwarn ("empty declaration"); } ;/* This combination which saves a lineno before a decl is the normal thing to use, rather than decl itself. This is to avoid shift/reduce conflicts in contexts where statement labels are allowed. */lineno_decl: save_filename save_lineno decl { } ;decls: lineno_decl | errstmt | decls lineno_decl | lineno_decl errstmt ;/* records the type and storage class specs to use for processing the declarators that follow. Maintains a stack of outer-level values of current_declspecs, for the sake of parm declarations nested in function declarators. */setspecs: /* empty */ { $$ = suspend_momentary (); pending_xref_error (); declspec_stack = tree_cons (prefix_attributes, current_declspecs, declspec_stack); current_declspecs = $<ttype>0; prefix_attributes = NULL_TREE; } ;setattrs: /* empty */ { prefix_attributes = chainon (prefix_attributes, $<ttype>0); } ;decl: typed_declspecs setspecs initdecls ';' { current_declspecs = TREE_VALUE (declspec_stack); prefix_attributes = TREE_PURPOSE (declspec_stack); declspec_stack = TREE_CHAIN (declspec_stack); resume_momentary ($2); } | declmods setspecs notype_initdecls ';' { current_declspecs = TREE_VALUE (declspec_stack); prefix_attributes = TREE_PURPOSE (declspec_stack); declspec_stack = TREE_CHAIN (declspec_stack); resume_momentary ($2); } | typed_declspecs setspecs nested_function { current_declspecs = TREE_VALUE (declspec_stack); prefix_attributes = TREE_PURPOSE (declspec_stack); declspec_stack = TREE_CHAIN (declspec_stack); resume_momentary ($2); } | declmods setspecs notype_nested_function { current_declspecs = TREE_VALUE (declspec_stack); prefix_attributes = TREE_PURPOSE (declspec_stack); declspec_stack = TREE_CHAIN (declspec_stack); resume_momentary ($2); } | typed_declspecs ';' { shadow_tag ($1); } | declmods ';' { pedwarn ("empty declaration"); } ;/* Declspecs which contain at least one type specifier or typedef name. (Just `const' or `volatile' is not enough.) A typedef'd name following these is taken as a name to be declared. */typed_declspecs: typespec reserved_declspecs { $$ = tree_cons (NULL_TREE, $1, $2); } | declmods typespec reserved_declspecs { $$ = chainon ($3, tree_cons (NULL_TREE, $2, $1)); } ;reserved_declspecs: /* empty */ { $$ = NULL_TREE; } | reserved_declspecs typespecqual_reserved { $$ = tree_cons (NULL_TREE, $2, $1); } | reserved_declspecs SCSPEC { if (extra_warnings) warning ("`%s' is not at beginning of declaration", IDENTIFIER_POINTER ($2)); $$ = tree_cons (NULL_TREE, $2, $1); } ;/* List of just storage classes and type modifiers. A declaration can start with just this, but then it cannot be used to redeclare a typedef-name. */declmods: TYPE_QUAL { $$ = tree_cons (NULL_TREE, $1, NULL_TREE); TREE_STATIC ($$) = 1; } | SCSPEC { $$ = tree_cons (NULL_TREE, $1, NULL_TREE); } | declmods TYPE_QUAL { $$ = tree_cons (NULL_TREE, $2, $1); TREE_STATIC ($$) = 1; } | declmods SCSPEC { if (extra_warnings && TREE_STATIC ($1)) warning ("`%s' is not at beginning of declaration", IDENTIFIER_POINTER ($2)); $$ = tree_cons (NULL_TREE, $2, $1); TREE_STATIC ($$) = TREE_STATIC ($1); } ;/* Used instead of declspecs where storage classes are not allowed (that is, for typenames and structure components). Don't accept a typedef-name if anything but a modifier precedes it. */typed_typespecs: typespec reserved_typespecquals { $$ = tree_cons (NULL_TREE, $1, $2); } | nonempty_type_quals typespec reserved_typespecquals { $$ = chainon ($3, tree_cons (NULL_TREE, $2, $1)); } ;reserved_typespecquals: /* empty */ { $$ = NULL_TREE; } | reserved_typespecquals typespecqual_reserved { $$ = tree_cons (NULL_TREE, $2, $1); } ;/* A typespec (but not a type qualifier). Once we have seen one of these in a declaration, if a typedef name appears then it is being redeclared. */typespec: TYPESPEC | structsp | TYPENAME { /* For a typedef name, record the meaning, not the name. In case of `foo foo, bar;'. */ $$ = lookup_name ($1); }ifobjc | CLASSNAME protocolrefs { $$ = get_static_reference ($1, $2); } | OBJECTNAME protocolrefs { $$ = get_object_reference ($2); }end ifobjc | TYPEOF '(' expr ')' { $$ = TREE_TYPE ($3); } | TYPEOF '(' typename ')' { $$ = groktypename ($3); } ;/* A typespec that is a reserved word, or a type qualifier. */typespecqual_reserved: TYPESPEC | TYPE_QUAL | structsp ;initdecls: initdcl | initdecls ',' initdcl ;notype_initdecls: notype_initdcl | notype_initdecls ',' initdcl ;maybeasm: /* empty */ { $$ = NULL_TREE; } | ASM_KEYWORD '(' string ')' { if (TREE_CHAIN ($3)) $3 = combine_strings ($3); $$ = $3; } ;initdcl: declarator maybeasm maybe_attribute '=' { $<ttype>$ = start_decl ($1, current_declspecs, 1, $3, prefix_attributes); start_init ($<ttype>$, $2, global_bindings_p ()); } init/* Note how the declaration of the variable is in effect while its init is parsed! */ { finish_init (); finish_decl ($<ttype>5, $6, $2); } | declarator maybeasm maybe_attribute { tree d = start_decl ($1, current_declspecs, 0, $3, prefix_attributes); finish_decl (d, NULL_TREE, $2); } ;notype_initdcl: notype_declarator maybeasm maybe_attribute '=' { $<ttype>$ = start_decl ($1, current_declspecs, 1, $3, prefix_attributes); start_init ($<ttype>$, $2, global_bindings_p ()); } init/* Note how the declaration of the variable is in effect while its init is parsed! */ { finish_init (); decl_attributes ($<ttype>5, $3, prefix_attributes); finish_decl ($<ttype>5, $6, $2); } | notype_declarator maybeasm maybe_attribute { tree d = start_decl ($1, current_declspecs, 0, $3, prefix_attributes); finish_decl (d, NULL_TREE, $2); } ;/* the * rules are dummies to accept the Apollo extended syntax so that the header files compile. */maybe_attribute: /* empty */ { $$ = NULL_TREE; } | attributes { $$ = $1; } ; attributes: attribute { $$ = $1; } | attributes attribute { $$ = chainon ($1, $2); } ;attribute: ATTRIBUTE '(' '(' attribute_list ')' ')' { $$ = $4; } ;attribute_list: attrib { $$ = $1; } | attribute_list ',' attrib { $$ = chainon ($1, $3); } ; attrib: /* empty */ { $$ = NULL_TREE; } | any_word { $$ = build_tree_list ($1, NULL_TREE); } | any_word '(' IDENTIFIER ')' { $$ = build_tree_list ($1, build_tree_list (NULL_TREE, $3)); } | any_word '(' IDENTIFIER ',' nonnull_exprlist ')' { $$ = build_tree_list ($1, tree_cons (NULL_TREE, $3, $5)); } | any_word '(' exprlist ')' { $$ = build_tree_list ($1, $3); } ;/* This still leaves out most reserved keywords, shouldn't we include them? */any_word: identifier | SCSPEC | TYPESPEC | TYPE_QUAL ;/* Initializers. `init' is the entry point. */init: expr_no_commas | '{' { really_start_incremental_init (NULL_TREE); /* Note that the call to clear_momentary is in process_init_element. */ push_momentary (); } initlist_maybe_comma '}' { $$ = pop_init_level (0); if ($$ == error_mark_node && ! (yychar == STRING || yychar == CONSTANT)) pop_momentary (); else pop_momentary_nofree (); } | error { $$ = error_mark_node; } ;/* `initlist_maybe_comma' is the guts of an initializer in braces. */initlist_maybe_comma: /* empty */ { if (pedantic) pedwarn ("ANSI C forbids empty initializer braces"); } | initlist1 maybecomma ;initlist1: initelt | initlist1 ',' initelt ;/* `initelt' is a single element of an initializer. It may use braces. */initelt: expr_no_commas { process_init_element ($1); } | '{' { push_init_level (0); } initlist_maybe_comma '}' { process_init_element (pop_init_level (0)); } | error /* These are for labeled elements. The syntax for an array element initializer conflicts with the syntax for an Objective-C message, so don't include these productions in the Objective-C grammar. */ifc | '[' expr_no_commas ELLIPSIS expr_no_commas ']' '=' { set_init_index ($2, $4); } initelt | '[' expr_no_commas ']' '=' { set_init_index ($2, NULL_TREE); } initelt | '[' expr_no_commas ']' { set_init_index ($2, NULL_TREE); } initeltend ifc | identifier ':' { set_init_label ($1); } initelt | '.' identifier '=' { set_init_label ($2); } initelt ;nested_function: declarator { push_c_function_context (); if (! start_function (current_declspecs, $1, prefix_attributes, NULL_TREE, 1)) { pop_c_function_context (); YYERROR1; } reinit_parse_for_function (); } xdecls { 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, prefix_attributes, NULL_TREE, 1)) { pop_c_function_context (); YYERROR1; } reinit_parse_for_function (); } xdecls { 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); } | attributes setattrs after_type_declarator { $$ = $3; } | TYPENAMEifobjc | OBJECTNAMEend ifobjc ;/* 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); } | attributes setattrs parm_declarator { $$ = $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 '.'
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -