📄 cpp5.y
字号:
as a declaration, and then report a constraint error.
In contrast, declarations such as:
class T;
class A;
class B;
main(){
T( F()); // constraint error: cannot declare local function
T (A::B::a); // constraint error: cannot declare member as a local value
are *parsed* as declarations, and *then* given semantic error
reports. It is incorrect for a parser to "change its mind" based
on constraints. If your C++ compiler claims that the above 2
lines are expressions, then *I* claim that they are wrong. */
paren_identifier_declarator:
scope_opt_identifier
| scope_opt_complex_name
| '(' paren_identifier_declarator ')'
;
/* Note that CLCL IDENTIFIER is NOT part of scope_opt_identifier,
but it is part of global_opt_scope_opt_identifier. It is ONLY
valid for referring to an identifier, and NOT valid for declaring
(or importing an external declaration of) an identifier. This
disambiguates the following code, which would otherwise be
syntactically and semantically ambiguous:
class base {
static int i; // element i;
float member_function(void);
};
base i; // global i
float base::member_function(void) {
i; // refers to static int element "i" of base
::i; // refers to global "i", with type "base"
{
base :: i; // import of global "i", like "base (::i);"?
// OR reference to global??
}
}
*/
primary_expression:
global_opt_scope_opt_identifier
| global_opt_scope_opt_complex_name
| THIS /* C++, not ANSI C */
| constant
| string_literal_list
| '(' comma_expression ')'
;
/* I had to disallow struct, union, or enum elaborations during
operator_function_name. The ANSI C++ Working paper is vague
about whether this should be part of the syntax, or a constraint.
The ambiguities that resulted were more than LALR could handle,
so the easiest fix was to be more specific. This means that I
had to in-line expand type_specifier_or_name far enough that I
would be able to exclude elaborations. This need is what drove
me to distinguish a whole series of tokens based on whether they
include elaborations:
struct A { ... }
or simply a reference to an aggregate or enumeration:
enum A
The latter, as well an non-aggregate types are what make up
non_elaborating_type_specifier */
/* Note that the following does not include type_qualifier_list.
Hence, whenever non_elaborating_type_specifier is used, an
adjacent rule is supplied containing type_qualifier_list. It is
not generally possible to know immediately (i_e., reduce) a
type_qualifier_list, as a TYPEDEFname that follows might not be
part of a type specifier, but might instead be "TYPEDEFname ::*".
*/
non_elaborating_type_specifier:
sue_type_specifier
| basic_type_specifier
| typedef_type_specifier
| basic_type_name
| TYPEDEFname
| global_or_scoped_typedefname
;
/* The following introduces MANY conflicts. Requiring and
allowing '(' ')' around the `type' when the type is complex would
help a lot. */
operator_function_name:
OPERATOR any_operator
| OPERATOR type_qualifier_list operator_function_ptr_opt
| OPERATOR non_elaborating_type_specifier operator_function_ptr_opt
;
/* The following causes several ambiguities on * and &. These
conflicts would also be removed if parens around the `type' were
required in the derivations for operator_function_name */
/* Interesting aside: The use of right recursion in the
production for operator_function_ptr_opt gives both the correct
parsing, AND removes a conflict! Right recursion permits the
parser to defer reductions (a.k.a.: delay resolution), and
effectively make a second pass! */
operator_function_ptr_opt:
/* nothing */
| unary_modifier operator_function_ptr_opt
| asterisk_or_ampersand operator_function_ptr_opt
;
/* List of operators we can overload */
any_operator:
'+'
| '-'
| '*'
| '/'
| '%'
| '^'
| '&'
| '|'
| '~'
| '!'
| '<'
| '>'
| LS
| RS
| ANDAND
| OROR
| ARROW
| ARROWstar
| '.'
| DOTstar
| ICR
| DECR
| LE
| GE
| EQ
| NE
| assignment_operator
| '(' ')'
| '[' ']'
| NEW
| DELETE
| ','
;
/* The following production for type_qualifier_list was specially
placed BEFORE the definition of postfix_expression to resolve a
reduce-reduce conflict set correctly. Note that a
type_qualifier_list is only used in a declaration, whereas a
postfix_expression is clearly an example of an expression. Hence
we are helping with the "if it can be a declaration, then it is"
rule. The reduce conflicts are on ')', ',' and '='. Do not move
the following productions */
type_qualifier_list_opt:
/* Nothing */
| type_qualifier_list
;
/* Note that the next set of productions in this grammar gives
post-increment a higher precedence that pre-increment. This is
not clearly stated in the C++ Reference manual, and is only
implied by the grammar in the ANSI C Standard. */
/* I *DON'T* use argument_expression_list_opt to simplify the
grammar shown below. I am deliberately deferring any decision
until *after* the closing paren, and using
"argument_expression_list_opt" would commit prematurely. This is
critical to proper conflict resolution. */
/* The {} in the following rules allow the parser to tell the
lexer to search for the member name in the appropriate scope,
much the way the CLCL operator works.*/
postfix_expression:
primary_expression
| postfix_expression '[' comma_expression ']'
| postfix_expression '(' ')'
| postfix_expression '(' argument_expression_list ')'
| postfix_expression {} '.' member_name
| postfix_expression {} ARROW member_name
| postfix_expression ICR
| postfix_expression DECR
/* The next 4 rules are the source of cast ambiguity */
| TYPEDEFname '(' ')'
| global_or_scoped_typedefname '(' ')'
| TYPEDEFname '(' argument_expression_list ')'
| global_or_scoped_typedefname '(' argument_expression_list ')'
| basic_type_name '(' assignment_expression ')'
/* If the following rule is added to the grammar, there
will be 3 additional reduce-reduce conflicts. They will
all be resolved in favor of NOT using the following rule,
so no harm will be done. However, since the rule is
semantically illegal we will omit it until we are
enhancing the grammar for error recovery */
/* | basic_type_name '(' ')' /* Illegal: no such constructor*/
;
/* The last two productions in the next set are questionable, but
do not induce any conflicts. I need to ask X3J16 : Having them
means that we have complex member function deletes like:
const unsigned int :: ~ const unsigned int
*/
member_name:
scope_opt_identifier
| scope_opt_complex_name
| basic_type_name CLCL '~' basic_type_name /* C++, not ANSI C */
| declaration_qualifier_list CLCL '~' declaration_qualifier_list
| type_qualifier_list CLCL '~' type_qualifier_list
;
argument_expression_list:
assignment_expression
| argument_expression_list ',' assignment_expression
;
unary_expression:
postfix_expression
| ICR unary_expression
| DECR unary_expression
| asterisk_or_ampersand cast_expression
| '-' cast_expression
| '+' cast_expression
| '~' cast_expression
| '!' cast_expression
| SIZEOF unary_expression
| SIZEOF '(' type_name ')'
| allocation_expression
;
/* Note that I could have moved the newstore productions to a
lower precedence level than multiplication (binary '*'), and
lower than bitwise AND (binary '&'). These moves are the nice
way to disambiguate a trailing unary '*' or '&' at the end of a
freestore expression. Since the freestore expression (with such
a grammar and hence precedence given) can never be the left
operand of a binary '*' or '&', the ambiguity would be removed.
These problems really surface when the binary operators '*' or
'&' are overloaded, but this must be syntactically disambiguated
before the semantic checking is performed... Unfortunately, I am
not creating the language, only writing a grammar that reflects
its specification, and hence I cannot change its precedence
assignments. If I had my druthers, I would probably prefer
surrounding the type with parens all the time, and avoiding the
dangling * and & problem all together.*/
/* Following are C++, not ANSI C */
allocation_expression:
global_opt_scope_opt_operator_new '(' type_name ')'
operator_new_initializer_opt
| global_opt_scope_opt_operator_new '(' argument_expression_list ')' '(' type_name ')'
operator_new_initializer_opt
/* next two rules are the source of * and & ambiguities */
| global_opt_scope_opt_operator_new operator_new_type
| global_opt_scope_opt_operator_new '(' argument_expression_list ')' operator_new_type
;
/* Following are C++, not ANSI C */
global_opt_scope_opt_operator_new:
NEW
| global_or_scope NEW
;
operator_new_type:
type_qualifier_list operator_new_declarator_opt
operator_new_initializer_opt
| non_elaborating_type_specifier operator_new_declarator_opt
operator_new_initializer_opt
;
/* Right recursion is critical in the following productions to
avoid a conflict on TYPEDEFname */
operator_new_declarator_opt:
/* Nothing */
| operator_new_array_declarator
| asterisk_or_ampersand operator_new_declarator_opt
| unary_modifier operator_new_declarator_opt
;
operator_new_array_declarator:
'[' ']'
| '[' comma_expression ']'
| operator_new_array_declarator '[' comma_expression ']'
;
operator_new_initializer_opt:
/* Nothing */
| '(' ')'
| '(' argument_expression_list ')'
;
cast_expression:
unary_expression
| '(' type_name ')' cast_expression
;
/* Following are C++, not ANSI C */
deallocation_expression:
cast_expression
| global_opt_scope_opt_delete deallocation_expression
| global_opt_scope_opt_delete '[' comma_expression ']' deallocation_expression /* archaic C++, what a concept */
| global_opt_scope_opt_delete '[' ']' deallocation_expression
;
/* Following are C++, not ANSI C */
global_opt_scope_opt_delete:
DELETE
| global_or_scope DELETE
;
/* Following are C++, not ANSI C */
point_member_expression:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -