📄 cpp5.y
字号:
declaration_qualifier_list TYPEDEFname
| declaration_qualifier_list global_or_scoped_typedefname
| typedef_type_specifier storage_class
| TYPEDEFname storage_class
| global_or_scoped_typedefname storage_class
| typedef_declaration_specifier declaration_qualifier
;
typedef_type_specifier: /* typedef types */
type_qualifier_list TYPEDEFname
| type_qualifier_list global_or_scoped_typedefname
| TYPEDEFname type_qualifier
| global_or_scoped_typedefname type_qualifier
| typedef_type_specifier type_qualifier
;
/* There are really several distinct sets of storage_classes. The
sets vary depending on whether the declaration is at file scope, is a
declaration within a struct/class, is within a function body, or in a
function declaration/definition (prototype parameter declarations).
They are grouped here to simplify the grammar, and can be
semantically checked. Note that this approach tends to ease the
syntactic restrictions in the grammar slightly, but allows for future
language development, and tends to provide superior diagnostics and
error recovery (i_e.: a syntax error does not disrupt the parse).
File File Member Member Local Local Formal
Var Funct Var Funct Var Funct Params
TYPEDEF x x x x x x
EXTERN x x x x
STATIC x x x x x
AUTO x x
REGISTER x x
FRIEND x
OVERLOAD x x x
INLINE x x x
VIRTUAL x x
*/
storage_class:
EXTERN
| TYPEDEF
| STATIC
| AUTO
| REGISTER
| FRIEND /* C++, not ANSI C */
| OVERLOAD /* C++, not ANSI C */
| INLINE /* C++, not ANSI C */
| VIRTUAL /* C++, not ANSI C */
;
basic_type_name:
INT
| CHAR
| SHORT
| LONG
| FLOAT
| DOUBLE
| SIGNED
| UNSIGNED
| VOID
;
elaborated_type_name_elaboration:
aggregate_name_elaboration
| enum_name_elaboration
;
elaborated_type_name:
aggregate_name
| enum_name
;
/* Since the expression "new type_name" MIGHT use an elaborated
type and a derivation, it MIGHT have a ':'. This fact conflicts
with the requirement that a new expression can be placed between
a '?' and a ':' in a conditional expression (at least it confuses
LR(1) parsers). Hence the aggregate_name_elaboration is
responsible for a series of SR conflicts on ':'.*/
/* The intermediate actions {} represent points at which the
database of typedef names must be updated in C++. This is
critical to the lexer, which must begin to tokenize based on this
new information. */
aggregate_name_elaboration:
aggregate_name derivation_opt '{' member_declaration_list_opt '}'
| aggregate_key derivation_opt '{' member_declaration_list_opt '}'
;
/* We distinguish between the above, which support elaboration,
and this set of productions so that we can provide special
declaration specifiers for operator_new_type, and for conversion
functions. Note that without this restriction a large variety of
conflicts appear when processing operator_new and conversions
operators (which can be followed by a ':' in a ternary ?:
expression) */
/* Note that at the end of each of the following rules we should
be sure that the tag name is in, or placed in the indicated
scope. If no scope is specified, then we must add it to our
current scope IFF it cannot be found in an external lexical
scope. */
aggregate_name:
aggregate_key tag_name
| global_scope scope aggregate_key tag_name
| global_scope aggregate_key tag_name
| scope aggregate_key tag_name
;
derivation_opt:
/* nothing */
| ':' derivation_list
;
derivation_list:
parent_class
| derivation_list ',' parent_class
;
parent_class:
global_opt_scope_opt_typedefname
| VIRTUAL access_specifier_opt global_opt_scope_opt_typedefname
| access_specifier virtual_opt global_opt_scope_opt_typedefname
;
virtual_opt:
/* nothing */
| VIRTUAL
;
access_specifier_opt:
/* nothing */
| access_specifier
;
access_specifier:
PUBLIC
| PRIVATE
| PROTECTED
;
aggregate_key:
STRUCT
| UNION
| CLASS /* C++, not ANSI C */
;
/* Note that an empty list is ONLY allowed under C++. The grammar
can be modified so that this stands out. The trick is to define
member_declaration_list, and have that referenced for non-trivial
lists. */
member_declaration_list_opt:
/* nothing */
| member_declaration_list_opt member_declaration
;
member_declaration:
member_declaring_list ';'
| member_default_declaring_list ';'
| access_specifier ':' /* C++, not ANSI C */
| new_function_definition /* C++, not ANSI C */
| constructor_function_in_class /* C++, not ANSI C */
| sue_type_specifier ';' /* C++, not ANSI C */
| sue_type_specifier_elaboration ';' /* C++, not ANSI C */
| identifier_declarator ';' /* C++, not ANSI C
access modification
conversion functions,
unscoped destructors */
| typedef_declaration_specifier ';' /* friend T */ /* C++, not ANSI C */
| sue_declaration_specifier ';' /* friend class C*/ /* C++, not ANSI C */
;
member_default_declaring_list: /* doesn't redeclare typedef*/
type_qualifier_list
identifier_declarator member_pure_opt
| declaration_qualifier_list
identifier_declarator member_pure_opt /* C++, not ANSI C */
| member_default_declaring_list ','
identifier_declarator member_pure_opt
| type_qualifier_list bit_field_identifier_declarator
| declaration_qualifier_list bit_field_identifier_declarator /* C++, not ANSI C */
| member_default_declaring_list ',' bit_field_identifier_declarator
;
/* There is a conflict when "struct A" is used as a declaration
specifier, and there is a chance that a bit field name will be
provided. To fix this syntactically would require distinguishing
non_elaborating_declaration_specifiers the way I handled
non_elaborating_type_specifiers. I think this should be a
constraint error anyway :-). */
member_declaring_list: /* Can possibly redeclare typedefs */
type_specifier declarator member_pure_opt
| basic_type_name declarator member_pure_opt
| global_or_scoped_typedefname declarator member_pure_opt
| member_conflict_declaring_item
| member_declaring_list ',' declarator member_pure_opt
| type_specifier bit_field_declarator
| basic_type_name bit_field_declarator
| TYPEDEFname bit_field_declarator
| global_or_scoped_typedefname bit_field_declarator
| declaration_specifier bit_field_declarator /* constraint violation: storage class used */
| member_declaring_list ',' bit_field_declarator
;
/* The following conflict with constructors-
member_conflict_declaring_item:
TYPEDEFname declarator member_pure_opt
| declaration_specifier declarator member_pure_opt /* C++, not ANSI C * /
;
so we inline expand declarator to get the following productions...
*/
member_conflict_declaring_item:
TYPEDEFname identifier_declarator member_pure_opt
| TYPEDEFname parameter_typedef_declarator member_pure_opt
| TYPEDEFname simple_paren_typedef_declarator member_pure_opt
| declaration_specifier identifier_declarator member_pure_opt
| declaration_specifier parameter_typedef_declarator member_pure_opt
| declaration_specifier simple_paren_typedef_declarator member_pure_opt
| member_conflict_paren_declaring_item
;
/* The following still conflicts with constructors-
member_conflict_paren_declaring_item:
TYPEDEFname paren_typedef_declarator member_pure_opt
| declaration_specifier paren_typedef_declarator member_pure_opt
;
so paren_typedef_declarator is expanded inline to get...*/
member_conflict_paren_declaring_item:
TYPEDEFname asterisk_or_ampersand
'(' simple_paren_typedef_declarator ')' member_pure_opt
| TYPEDEFname unary_modifier
'(' simple_paren_typedef_declarator ')' member_pure_opt
| TYPEDEFname asterisk_or_ampersand
'(' TYPEDEFname ')' member_pure_opt
| TYPEDEFname unary_modifier
'(' TYPEDEFname ')' member_pure_opt
| TYPEDEFname asterisk_or_ampersand
paren_typedef_declarator member_pure_opt
| TYPEDEFname unary_modifier
paren_typedef_declarator member_pure_opt
| declaration_specifier asterisk_or_ampersand
'(' simple_paren_typedef_declarator ')' member_pure_opt
| declaration_specifier unary_modifier
'(' simple_paren_typedef_declarator ')' member_pure_opt
| declaration_specifier asterisk_or_ampersand
'(' TYPEDEFname ')' member_pure_opt
| declaration_specifier unary_modifier
'(' TYPEDEFname ')' member_pure_opt
| declaration_specifier asterisk_or_ampersand
paren_typedef_declarator member_pure_opt
| declaration_specifier unary_modifier
paren_typedef_declarator member_pure_opt
| member_conflict_paren_postfix_declaring_item
;
/* but we still have the following conflicts with constructors-
member_conflict_paren_postfix_declaring_item:
TYPEDEFname postfix_paren_typedef_declarator member_pure_opt
| declaration_specifier postfix_paren_typedef_declarator member_pure_opt
;
so we expand paren_postfix_typedef inline and get...*/
member_conflict_paren_postfix_declaring_item:
TYPEDEFname '(' paren_typedef_declarator ')'
member_pure_opt
| TYPEDEFname '(' simple_paren_typedef_declarator
postfixing_abstract_declarator ')' member_pure_opt
| TYPEDEFname '(' TYPEDEFname
postfixing_abstract_declarator ')' member_pure_opt
| TYPEDEFname '(' paren_typedef_declarator ')'
postfixing_abstract_declarator member_pure_opt
| declaration_specifier '(' paren_typedef_declarator ')'
member_pure_opt
| declaration_specifier '(' simple_paren_typedef_declarator
postfixing_abstract_declarator ')' member_pure_opt
| declaration_specifier '(' TYPEDEFname
postfixing_abstract_declarator ')' member_pure_opt
| declaration_specifier '(' paren_typedef_declarator ')'
postfixing_abstract_declarator member_pure_opt
;
/* ...and we are done. Now all the conflicts appear on ';',
which can be semantically evaluated/disambiguated */
member_pure_opt:
/* nothing */
| '=' OCTALconstant /* C++, not ANSI C */ /* Pure function*/
;
/* Note that bit field names, where redefining TYPEDEFnames,
cannot be parenthesized in C++ (due to ambiguities), and hence
this part of the grammar is simpler than ANSI C. :-) The problem
occurs because:
TYPEDEFname ( TYPEDEFname) : .....
doesn't look like a bit field, rather it looks like a constructor
definition! */
bit_field_declarator:
bit_field_identifier_declarator
| TYPEDEFname {} ':' constant_expression
;
/* The actions taken in the "{}" above and below are intended to
allow the symbol table to be updated when the declarator is
complete. It is critical for code like:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -