📄 parse.y
字号:
{ resume_momentary ($2); if (IS_AGGR_TYPE_CODE (TREE_CODE ($1))) note_got_semicolon ($1); } | typed_declspecs initdecls ';' { resume_momentary ($2); note_list_got_semicolon ($1); } | declmods notype_initdecls ';' { resume_momentary ($2); } | typed_declspecs ';' { shadow_tag ($1); note_list_got_semicolon ($1); } | declmods ';' { warning ("empty declaration"); } ;/* Any kind of declarator (thus, all declarators allowed after an explicit typespec). */declarator: after_type_declarator %prec EMPTY | notype_declarator %prec EMPTY ;/* This is necessary to postpone reduction of `int()()()()'. */fcast_or_absdcl: LEFT_RIGHT %prec EMPTY { $$ = build_parse_node (CALL_EXPR, NULL_TREE, empty_parms (), NULL_TREE); } | fcast_or_absdcl LEFT_RIGHT %prec EMPTY { $$ = build_parse_node (CALL_EXPR, $$, empty_parms (), NULL_TREE); } ;/* ANSI type-id (8.1) */type_id: typed_typespecs absdcl { $$ = build_decl_list ($$, $2); } | nonempty_type_quals absdcl { $$ = build_decl_list ($$, $2); } | typespec absdcl { $$ = build_decl_list (get_decl_list ($$), $2); } | typed_typespecs %prec EMPTY { $$ = build_decl_list ($$, NULL_TREE); } | nonempty_type_quals %prec EMPTY { $$ = build_decl_list ($$, NULL_TREE); } ;/* 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. In the result, declspecs have a non-NULL TREE_VALUE, attributes do not. */typed_declspecs: typed_typespecs %prec EMPTY | typed_declspecs1 ;typed_declspecs1: declmods typespec { $$ = decl_tree_cons (NULL_TREE, $2, $$); } | typespec reserved_declspecs %prec HYPERUNARY { $$ = decl_tree_cons (NULL_TREE, $$, $2); } | typespec reserved_typespecquals reserved_declspecs { $$ = decl_tree_cons (NULL_TREE, $$, chainon ($2, $3)); } | declmods typespec reserved_declspecs { $$ = decl_tree_cons (NULL_TREE, $2, chainon ($3, $$)); } | declmods typespec reserved_typespecquals { $$ = decl_tree_cons (NULL_TREE, $2, chainon ($3, $$)); } | declmods typespec reserved_typespecquals reserved_declspecs { $$ = decl_tree_cons (NULL_TREE, $2, chainon ($3, chainon ($4, $$))); } ;reserved_declspecs: SCSPEC { if (extra_warnings) warning ("`%s' is not at beginning of declaration", IDENTIFIER_POINTER ($$)); $$ = build_decl_list (NULL_TREE, $$); } | reserved_declspecs typespecqual_reserved { $$ = decl_tree_cons (NULL_TREE, $2, $$); } | reserved_declspecs SCSPEC { if (extra_warnings) warning ("`%s' is not at beginning of declaration", IDENTIFIER_POINTER ($2)); $$ = decl_tree_cons (NULL_TREE, $2, $$); } | reserved_declspecs attributes { $$ = decl_tree_cons ($2, NULL_TREE, $1); } | attributes { $$ = decl_tree_cons ($1, NULL_TREE, NULL_TREE); } ;/* 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. In the result, declspecs have a non-NULL TREE_VALUE, attributes do not. */declmods: nonempty_type_quals %prec EMPTY { TREE_STATIC ($$) = 1; } | SCSPEC { $$ = IDENTIFIER_AS_LIST ($$); } | declmods TYPE_QUAL { $$ = decl_tree_cons (NULL_TREE, $2, $$); TREE_STATIC ($$) = 1; } | declmods SCSPEC { if (extra_warnings && TREE_STATIC ($$)) warning ("`%s' is not at beginning of declaration", IDENTIFIER_POINTER ($2)); $$ = decl_tree_cons (NULL_TREE, $2, $$); TREE_STATIC ($$) = TREE_STATIC ($1); } | declmods attributes { $$ = decl_tree_cons ($2, NULL_TREE, $1); } | attributes { $$ = decl_tree_cons ($1, NULL_TREE, NULL_TREE); } ;/* Used instead of declspecs where storage classes are not allowed (that is, for typenames and structure components). C++ can takes storage classes for structure components. Don't accept a typedef-name if anything but a modifier precedes it. */typed_typespecs: typespec %prec EMPTY { $$ = get_decl_list ($$); } | nonempty_type_quals typespec { $$ = decl_tree_cons (NULL_TREE, $2, $$); } | typespec reserved_typespecquals { $$ = decl_tree_cons (NULL_TREE, $$, $2); } | nonempty_type_quals typespec reserved_typespecquals { $$ = decl_tree_cons (NULL_TREE, $2, chainon ($3, $$)); } ;reserved_typespecquals: typespecqual_reserved { $$ = build_decl_list (NULL_TREE, $$); } | reserved_typespecquals typespecqual_reserved { $$ = decl_tree_cons (NULL_TREE, $2, $$); } ;/* 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: structsp | TYPESPEC %prec EMPTY | complete_type_name | TYPEOF '(' expr ')' { $$ = TREE_TYPE ($3); if (pedantic && !in_system_header) pedwarn ("ANSI C++ forbids `typeof'"); } | TYPEOF '(' type_id ')' { $$ = groktypename ($3); if (pedantic && !in_system_header) pedwarn ("ANSI C++ forbids `typeof'"); } | SIGOF '(' expr ')' { tree type = TREE_TYPE ($3); if (IS_AGGR_TYPE (type)) { sorry ("sigof type specifier"); $$ = type; } else { error ("`sigof' applied to non-aggregate expression"); $$ = error_mark_node; } } | SIGOF '(' type_id ')' { tree type = groktypename ($3); if (IS_AGGR_TYPE (type)) { sorry ("sigof type specifier"); $$ = type; } else { error("`sigof' applied to non-aggregate type"); $$ = error_mark_node; } } ;/* A typespec that is a reserved word, or a type qualifier. */typespecqual_reserved: TYPESPEC | TYPE_QUAL | structsp ;initdecls: initdcl0 | initdecls ',' initdcl ;notype_initdecls: notype_initdcl0 | notype_initdecls ',' initdcl ;nomods_initdecls: nomods_initdcl0 | nomods_initdecls ',' initdcl ;maybeasm: /* empty */ { $$ = NULL_TREE; } | asm_keyword '(' string ')' { if (TREE_CHAIN ($3)) $3 = combine_strings ($3); $$ = $3; } ;initdcl0: declarator exception_specification_opt maybeasm maybe_attribute '=' { split_specs_attrs ($<ttype>0, ¤t_declspecs, &prefix_attributes); if (TREE_CODE (current_declspecs) != TREE_LIST) current_declspecs = get_decl_list (current_declspecs); if (have_extern_spec && !used_extern_spec) { current_declspecs = decl_tree_cons (NULL_TREE, get_identifier ("extern"), current_declspecs); used_extern_spec = 1; } $<itype>5 = suspend_momentary (); $<ttype>$ = start_decl ($<ttype>1, current_declspecs, 1, $2); cplus_decl_attributes ($<ttype>$, $4, prefix_attributes); } init/* Note how the declaration of the variable is in effect while its init is parsed! */ { cp_finish_decl ($<ttype>6, $7, $3, 0, LOOKUP_ONLYCONVERTING); $$ = $<itype>5; } | declarator exception_specification_opt maybeasm maybe_attribute { tree d; split_specs_attrs ($<ttype>0, ¤t_declspecs, &prefix_attributes); if (TREE_CODE (current_declspecs) != TREE_LIST) current_declspecs = get_decl_list (current_declspecs); if (have_extern_spec && !used_extern_spec) { current_declspecs = decl_tree_cons (NULL_TREE, get_identifier ("extern"), current_declspecs); used_extern_spec = 1; } $$ = suspend_momentary (); d = start_decl ($<ttype>1, current_declspecs, 0, $2); cplus_decl_attributes (d, $4, prefix_attributes); cp_finish_decl (d, NULL_TREE, $3, 0, 0); } ;initdcl: declarator exception_specification_opt maybeasm maybe_attribute '=' { $<ttype>$ = start_decl ($<ttype>1, current_declspecs, 1, $2); cplus_decl_attributes ($<ttype>$, $4, prefix_attributes); } init/* Note how the declaration of the variable is in effect while its init is parsed! */ { cp_finish_decl ($<ttype>6, $7, $3, 0, LOOKUP_ONLYCONVERTING); } | declarator exception_specification_opt maybeasm maybe_attribute { $<ttype>$ = start_decl ($<ttype>1, current_declspecs, 0, $2); cplus_decl_attributes ($<ttype>$, $4, prefix_attributes); cp_finish_decl ($<ttype>$, NULL_TREE, $3, 0, 0); } ;notype_initdcl0: notype_declarator exception_specification_opt maybeasm maybe_attribute '=' { split_specs_attrs ($<ttype>0, ¤t_declspecs, &prefix_attributes); $<itype>5 = suspend_momentary (); $<ttype>$ = start_decl ($<ttype>1, current_declspecs, 1, $2); cplus_decl_attributes ($<ttype>$, $4, prefix_attributes); } init/* Note how the declaration of the variable is in effect while its init is parsed! */ { cp_finish_decl ($<ttype>6, $7, $3, 0, LOOKUP_ONLYCONVERTING); $$ = $<itype>5; } | notype_declarator exception_specification_opt maybeasm maybe_attribute { tree d; split_specs_attrs ($<ttype>0, ¤t_declspecs, &prefix_attributes); $$ = suspend_momentary (); d = start_decl ($<ttype>1, current_declspecs, 0, $2); cplus_decl_attributes (d, $4, prefix_attributes); cp_finish_decl (d, NULL_TREE, $3, 0, 0); } ;nomods_initdcl0: notype_declarator exception_specification_opt maybeasm maybe_attribute '=' { current_declspecs = NULL_TREE; prefix_attributes = NULL_TREE; $<itype>5 = suspend_momentary (); $<ttype>$ = start_decl ($1, current_declspecs, 1, $2); cplus_decl_attributes ($<ttype>$, $4, prefix_attributes); } init/* Note how the declaration of the variable is in effect while its init is parsed! */ { cp_finish_decl ($<ttype>6, $7, $3, 0, LOOKUP_ONLYCONVERTING); $$ = $<itype>5; } | notype_declarator exception_specification_opt maybeasm maybe_attribute { tree d; current_declspecs = NULL_TREE; prefix_attributes = NULL_TREE; $$ = suspend_momentary (); d = start_decl ($1, current_declspecs, 0, $2); cplus_decl_attributes (d, $4, prefix_attributes); cp_finish_decl (d, NULL_TREE, $3, 0, 0); } ;/* 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 '(' nonnull_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 ;/* A nonempty list of identifiers, including typenames. */identifiers_or_typenames: identifier { $$ = build_tree_list (NULL_TREE, $1); } | identifiers_or_typenames ',' identifier { $$ = chainon ($1, build_tree_list (NULL_TREE, $3)); } ;maybe_init: %prec EMPTY /* empty */ { $$ = NULL_TREE; } | '=' init { $$ = $2; }init: expr_no_commas %prec '=' | '{' '}' { $$ = build_nt (CONSTRUCTOR, NULL_TREE, NULL_TREE); TREE_HAS_CONSTRUCTOR ($$) = 1; } | '{' initlist '}' { $$ = build_nt (CONSTRUCTOR, NULL_TREE, nreverse ($2)); TREE_HAS_CONSTRUCTOR ($$) = 1; } | '{' initlist ',' '}' { $$ = build_nt (CONSTRUCTOR, NULL_TREE, nreverse ($2)); TREE_HAS_CONSTRUCTOR ($$) = 1; } | 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, $$); } | initlist ',' init { $$ = tree_cons (NULL_TREE, $3, $$); } /* These are for labeled elements. */ | '[' expr_no_commas ']' init { $$ = build_tree_list ($2, $4); } | initlist ',' CASE expr_no_commas ':' init { $$ = tree_cons ($4, $6, $$); } | identifier ':' init { $$ = build_tree_list ($$, $3); } | initlist ',' identifier ':' init { $$ = tree_cons ($3, $5, $$); } ;structsp: ENUM identifier '{' { $<itype>3 = suspend_momentary (); $$ = start_enum ($2); } enumlist maybecomma_warn '}' { $$ = finish_enum ($<ttype>4, $5); resume_momentary ((int) $<itype>3); check_for_missing_semicolon ($<ttype>4); } | ENUM identifier '{' '}' { $$ = finish_enum (start_enum ($2), NULL_TREE); check_for_missing_semicolon ($$); } | ENUM '{' { $<itype>2 = suspend_momentary (); $$ = start_enum (make_anon_name ()); } enumlist maybecomma_warn '}' { $$ = finish_enum ($<ttype>3, $4); resume_momentary ((int) $<itype>1); check_for_missing_semicolon ($<ttype>3); } | ENUM '{' '}' { $$ = finish_enum (start_enum (make_anon_name()), NULL_TREE); check_for_missing_semicolon ($$); } | ENUM identifier { $$ = xref_tag (enum_type_node, $2, NULL_TREE, 1); } | ENUM complex_type_name { $$ = xref_tag (
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -