-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcpp5.y
4200 lines (3430 loc) · 140 KB
/
cpp5.y
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
%{
/* Copyright (C) 1989-1991 James A. Roskind, All rights reserved.
This grammar was developed and written by James A. Roskind.
Copying of this grammar description, as a whole, is permitted
providing this notice is intact and applicable in all complete
copies. Translations as a whole to other parser generator input
languages (or grammar description languages) is permitted
provided that this notice is intact and applicable in all such
copies, along with a disclaimer that the contents are a
translation. The reproduction of derived text, such as modified
versions of this grammar, or the output of parser generators, is
permitted, provided the resulting work includes the copyright
notice "Portions Copyright (c) 1989, 1990 James A. Roskind".
Derived products, such as compilers, translators, browsers, etc.,
that use this grammar, must also provide the notice "Portions
Copyright (c) 1989, 1990 James A. Roskind" in a manner
appropriate to the utility, and in keeping with copyright law
(e.g.: EITHER displayed when first invoked/executed; OR displayed
continuously on display terminal; OR via placement in the object
code in form readable in a printout, with or near the title of
the work, or at the end of the file). No royalties, licenses or
commissions of any kind are required to copy this grammar, its
translations, or derivative products, when the copies are made in
compliance with this notice. Persons or corporations that do make
copies in compliance with this notice may charge whatever price
is agreeable to a buyer, for such copies or derivative works.
THIS GRAMMAR IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.
James A. Roskind
Independent Consultant
516 Latania Palm Drive
Indialantic FL, 32903
(407)729-4348
---end of copyright notice---
MOTIVATION-
My goal is to see software developers adopt this grammar as a
standard until such time as a better standard is accessible. The
only way to get it to become a standard, is to be sure that people
know that derivations are based on a specific work. The intent of
releasing this grammar is to provide a publicly accessible standard
grammar for C++. The intent of the copyright notice is to allow
arbitrary commercial and non-commercial use of the grammar, as long
as reference is given to the original standard. Without reference to
a specific standard, many alternative grammars would develop. By
referring to the standard, this grammar is given publicity, which
should lead to further use in compatible products and systems. The
benefits of such a standard to commercial products (browsers,
beautifiers, translators, compilers, ...) should be obvious to the
developers, in that other compatible products will emerge, and the
value of all conforming products will rise. Most developers are
aware of the value of acquiring a fairly complete grammar for a
language, and the copyright notice (and the resulting affiliation
with my work) should not be too high a price to pay. By copyrighting
this grammar, I have some minor control over what this standard is,
and I can (hopefully) keep it from degrading without my approval. I
will consistently attempt to provide upgraded grammars that are
compliant with the current art, and the ANSI C++ Committee
recommendation in particular. A developer is never prevented from
modifying the grammar to improve it in whatever way is seen fit.
There is also no restriction on the sale of copies, or derivative
works, providing the requests in the copyright notice are satisfied.
If you are not "copying" my work, but are rather only abstracting
some of the standard, an acknowledgment with references to such a
standard would be appreciated. Specifically, agreements with this
standard as to the resolution of otherwise ambiguous constructs,
should be noted.
Simply put: "make whatever use you would like of the grammar, but
include the ``portions Copyright ...'' as a reference to this
standard."
*/
/* Last modified 7/4/91, Version 2.0 */
/* File CPP5.Y is translated by YACC to Y.TAB.C */
/* ACKNOWLEDGMENT: Without Bjarne Stroustrup and his many co-workers
at Bell Labs, there would be no C++ Language for which to provide a
syntax description. Bjarne has also been especially helpful and open
in discussions, and by permitting me to review his texts prior to
their publication, allowed me a wonderful vantage point of clarity.
Without the effort expended by the ANSI C standardizing committee, I
would have been lost. Although the ANSI C standard does not include
a fully disambiguated syntax description, the committee has at least
provided most of the disambiguating rules in narratives. This C++
grammar is intended to be a superset of an ANSI C compatible grammar
that is provided in an related file.
Several reviewers have also recently critiqued this grammar, the
related C grammar, and or assisted in discussions during it's
preparation. These reviewers are certainly not responsible for the
errors I have committed here, but they are responsible for allowing
me to provide fewer errors. These colleagues include: Bruce
Blodgett, Mark Langley, Joe Fialli, Greg Perkins, Ron Guilmette, and
Eric Krohn. */
/* Required fixes from last release :
done: 0) Allow direct call to destructors
done: 1) Allow placement of declarations in labeled statements. The
easiest fix involves using a larger variance from the C grammar, and
simply making "statement" include declarations. Note that it should
also be legal for declarations to be in the branches of if
statements, as long as there is no other code in the block (I think).
Consider:
...
{
if (0 == a)
int b=5;
else
int c=4;
}
1) template support: Not done: pending syntax specification from
ANSI. (This looks like a major effort, as ANSI has decided to extend
the "TYPEDEFname"-feedback-to-the-lexer-hack to support template
names as a new kind of terminal token.)
2) exception handling: Not done: pending syntax specification from
ANSI (but it doesn't look hard)
done: 3) Support nested types, including identifier::name, where we
realize that identifier was a hidden type. Force the lexer to keep
pace in this situation. This will require an extension of the
yacc-lex feedback loop.
done: 4) Support nested types even when derivations are used in class
definitions.
5) Provide advanced tutorial on YACC conflicts: almost done in
documentation about machine generated documentation.
done: 6) Allow declaration specifiers to be left out of declarations
at file and structure scope so that operator conversion functions can
be declared and/or defined. Note that checking to see that it was a
function type that does not require declaration_specifiers is now a
constraint check, and not a syntax issue. Within function body
scopes, declaration specifiers are required, and this is critical to
distinguishing expressions.
*/
%}
/*
Interesting ambiguity:
Usually
typename ( typename2 ) ...
or
typename ( typename2 [4] ) ...
etc.
is a redeclaration of typename2.
Inside a structure elaboration, it is sometimes the declaration of a
constructor! Note, this only counts if typename IS the current
containing class name. (Note this can't conflict with ANSI C because
ANSI C would call it a redefinition, but claim it is semantically
illegal because you can't have a member declared the same type as the
containing struct!) Since the ambiguity is only reached when a ';' is
found, there is no problem with the fact that the semantic
interpretation is providing the true resolution. As currently
implemented, the constructor semantic actions must be able to process
an ordinary declaration. I may reverse this in the future, to ease
semantic implementation.
*/
/*
INTRO TO ANSI C GRAMMAR (provided in a separate file):
The refined grammar resolves several typedef ambiguities in the draft
proposed ANSI C standard syntax down to 1 shift/reduce conflict, as
reported by a YACC process. Note that the one shift reduce conflicts
is the traditional if-if-else conflict that is not resolved by the
grammar. This ambiguity can be removed using the method described in
the Dragon Book (2nd edition), but this does not appear worth the
effort.
There was quite a bit of effort made to reduce the conflicts to this
level, and an additional effort was made to make the grammar quite
similar to the C++ grammar being developed in parallel. Note that
this grammar resolves the following ANSI C ambiguities:
ANSI C section 3.5.6, "If the [typedef name] is redeclared at an
inner scope, the type specifiers shall not be omitted in the inner
declaration". Supplying type specifiers prevents consideration of T
as a typedef name in this grammar. Failure to supply type specifiers
forced the use of the TYPEDEFname as a type specifier. This is taken
to an (unnecessary) extreme by this implementation. The ambiguity is
only a problem with the first declarator in a declaration, but we
restrict ALL declarators whenever the users fails to use a
type_specifier.
ANSI C section 3.5.4.3, "In a parameter declaration, a single typedef
name in parentheses is taken to be an abstract declarator that
specifies a function with a single parameter, not as redundant
parentheses around the identifier". This is extended to cover the
following cases:
typedef float T;
int noo(const (T[5]));
int moo(const (T(int)));
...
Where again the '(' immediately to the left of 'T' is interpreted as
being the start of a parameter type list, and not as a redundant
paren around a redeclaration of T. Hence an equivalent code fragment
is:
typedef float T;
int noo(const int identifier1 (T identifier2 [5]));
int moo(const int identifier1 (T identifier2 (int identifier3)));
...
*/
%{
/*************** Includes and Defines *****************************/
#define YYDEBUG_LEXER_TEXT (yylval) /* our lexer loads this up each time.
We are telling the graphical debugger
where to find the spelling of the
tokens.*/
#define YYDEBUG 1 /* get the pretty debugging code to compile*/
#define YYSTYPE char * /* interface with flex: should be in header file */
/*************** Standard ytab.c continues here *********************/
%}
/*************************************************************************/
/* This group is used by the C/C++ language parser */
%token AUTO DOUBLE INT STRUCT
%token BREAK ELSE LONG SWITCH
%token CASE ENUM REGISTER TYPEDEF
%token CHAR EXTERN RETURN UNION
%token CONST FLOAT SHORT UNSIGNED
%token CONTINUE FOR SIGNED VOID
%token DEFAULT GOTO SIZEOF VOLATILE
%token DO IF STATIC WHILE
/* The following are used in C++ only. ANSI C would call these IDENTIFIERs */
%token NEW DELETE
%token THIS
%token OPERATOR
%token CLASS
%token PUBLIC PROTECTED PRIVATE
%token VIRTUAL FRIEND
%token INLINE OVERLOAD
/* ANSI C Grammar suggestions */
%token IDENTIFIER STRINGliteral
%token FLOATINGconstant INTEGERconstant CHARACTERconstant
%token OCTALconstant HEXconstant
/* New Lexical element, whereas ANSI C suggested non-terminal */
%token TYPEDEFname
/* Multi-Character operators */
%token ARROW /* -> */
%token ICR DECR /* ++ -- */
%token LSH RSH /* << >> */
%token LE GE EQ NE /* <= >= == != */
%token ANDAND OROR /* && || */
%token ELLIPSIS /* ... */
/* Following are used in C++, not ANSI C */
%token CLCL /* :: */
%token DOTstar ARROWstar/* .* ->* */
/* modifying assignment operators */
%token MULTassign DIVassign MODassign /* *= /= %= */
%token PLUSassign MINUSassign /* += -= */
%token LSHassign RSHassign /* <<= >>= */
%token ANDassign ERassign ORassign /* &= ^= |= */
/*************************************************************************/
%start translation_unit
/*************************************************************************/
%%
/*********************** CONSTANTS *********************************/
constant:
INTEGERconstant
| FLOATINGconstant
/* We are not including ENUMERATIONconstant here because we
are treating it like a variable with a type of "enumeration
constant". */
| OCTALconstant
| HEXconstant
| CHARACTERconstant
;
string_literal_list:
STRINGliteral
| string_literal_list STRINGliteral
;
/************************* EXPRESSIONS ********************************/
/* Note that I provide a "scope_opt_identifier" that *cannot*
begin with ::. This guarantees we have a viable declarator, and
helps to disambiguate :: based uses in the grammar. For example:
...
{
int (* ::b()); // must be an expression
int (T::b); // officially a declaration, which fails on constraint grounds
This *syntax* restriction reflects the current syntax in the ANSI
C++ Working Papers. This means that it is *incorrect* for
parsers to misparse the example:
int (* ::b()); // must be an expression
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:
'+'
| '-'
| '*'
| '/'
| '%'
| '^'
| '&'
| '|'
| '~'
| '!'
| '<'
| '>'
| LSH
| RSH
| 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:
deallocation_expression
| point_member_expression DOTstar deallocation_expression
| point_member_expression ARROWstar deallocation_expression
;
multiplicative_expression:
point_member_expression
| multiplicative_expression '*' point_member_expression
| multiplicative_expression '/' point_member_expression
| multiplicative_expression '%' point_member_expression
;
additive_expression:
multiplicative_expression
| additive_expression '+' multiplicative_expression
| additive_expression '-' multiplicative_expression
;
shift_expression:
additive_expression
| shift_expression LSH additive_expression
| shift_expression RSH additive_expression
;
relational_expression:
shift_expression
| relational_expression '<' shift_expression
| relational_expression '>' shift_expression
| relational_expression LE shift_expression
| relational_expression GE shift_expression
;
equality_expression:
relational_expression
| equality_expression EQ relational_expression
| equality_expression NE relational_expression
;
AND_expression:
equality_expression
| AND_expression '&' equality_expression
;
exclusive_OR_expression:
AND_expression
| exclusive_OR_expression '^' AND_expression
;
inclusive_OR_expression:
exclusive_OR_expression
| inclusive_OR_expression '|' exclusive_OR_expression
;
logical_AND_expression:
inclusive_OR_expression
| logical_AND_expression ANDAND inclusive_OR_expression
;
logical_OR_expression:
logical_AND_expression
| logical_OR_expression OROR logical_AND_expression
;
conditional_expression:
logical_OR_expression
| logical_OR_expression '?' comma_expression ':'
conditional_expression
;
assignment_expression:
conditional_expression
| unary_expression assignment_operator assignment_expression
;
assignment_operator:
'='
| MULTassign
| DIVassign
| MODassign
| PLUSassign
| MINUSassign
| LSHassign
| RSHassign
| ANDassign
| ERassign
| ORassign
;
comma_expression:
assignment_expression
| comma_expression ',' assignment_expression
;
constant_expression:
conditional_expression
;
/* The following was used for clarity */
comma_expression_opt:
/* Nothing */
| comma_expression
;
/******************************* DECLARATIONS *********************************/
/* The following are notably different from the ANSI C Standard
specified grammar, but are present in my ANSI C compatible
grammar. The changes were made to disambiguate typedefs presence
in declaration_specifiers (vs. in the declarator for
redefinition); to allow struct/union/enum/class tag declarations
without declarators, and to better reflect the parsing of
declarations (declarators must be combined with
declaration_specifiers ASAP, so that they can immediately become
visible in the current scope). */
declaration:
declaring_list ';'
| default_declaring_list ';'
| sue_declaration_specifier ';' { /* this is constraint error, as it
includes a storage class!?!*/ }
| sue_type_specifier ';'
| sue_type_specifier_elaboration ';'
;
/* Note that if a typedef were redeclared, then a declaration
specifier must be supplied (re: ANSI C spec). The following are
declarations wherein no declaration_specifier is supplied, and
hence the 'default' must be used. An example of this is
const a;
which by default, is the same as:
const int a;
`a' must NOT be a typedef in the above example. */
/* The presence of `{}' in the following rules indicates points
at which the symbol table MUST be updated so that the tokenizer
can IMMEDIATELY continue to maintain the proper distinction
between a TYPEDEFname and an IDENTIFIER. */
default_declaring_list: /* Can't redeclare typedef names */
declaration_qualifier_list identifier_declarator {} initializer_opt
| type_qualifier_list identifier_declarator {} initializer_opt
| default_declaring_list ',' identifier_declarator {} initializer_opt
| declaration_qualifier_list constructed_identifier_declarator
| type_qualifier_list constructed_identifier_declarator
| default_declaring_list ',' constructed_identifier_declarator
;
/* Note how type_qualifier_list is NOT used in the following
productions. Qualifiers are NOT sufficient to redefine
typedef-names (as prescribed by the ANSI C standard).*/
declaring_list:
declaration_specifier declarator {} initializer_opt
| type_specifier declarator {} initializer_opt
| basic_type_name declarator {} initializer_opt
| TYPEDEFname declarator {} initializer_opt
| global_or_scoped_typedefname declarator {} initializer_opt
| declaring_list ',' declarator {} initializer_opt
| declaration_specifier constructed_declarator
| type_specifier constructed_declarator
| basic_type_name constructed_declarator
| TYPEDEFname constructed_declarator
| global_or_scoped_typedefname constructed_declarator
| declaring_list ',' constructed_declarator
;
/* Declarators with parenthesized initializers present a big
problem. Typically a declarator that looks like: "*a(...)" is
supposed to bind FIRST to the "(...)", and then to the "*". This
binding presumes that the "(...)" stuff is a prototype. With
constructed declarators, we must (officially) finish the binding
to the "*" (finishing forming a good declarator) and THEN connect
with the argument list. Unfortunately, by the time we realize it
is an argument list (and not a prototype) we have pushed the
separate declarator tokens "*" and "a" onto the yacc stack
WITHOUT combining them. The solution is to use odd productions to
carry the incomplete declarator along with the "argument
expression list" back up the yacc stack. We would then actually
instantiate the symbol table after we have fully decorated the
symbol with all the leading "*" stuff. Actually, since we don't
have all the type information in one spot till we reduce to a
declaring_list, this delay is not a problem. Note that ordinary
initializers REQUIRE (ANSI C Standard) that the symbol be placed
into the symbol table BEFORE its initializer is read, but in the
case of parenthesized initializers, this is not possible (we
don't even know we have an initializer till have passed the
opening "(". ) */
constructed_declarator:
nonunary_constructed_identifier_declarator
| constructed_paren_typedef_declarator
| simple_paren_typedef_declarator '(' argument_expression_list ')'
| simple_paren_typedef_declarator postfixing_abstract_declarator
'(' argument_expression_list ')' /* constraint error */
| constructed_parameter_typedef_declarator
| asterisk_or_ampersand constructed_declarator
| unary_modifier constructed_declarator
;
constructed_paren_typedef_declarator:
'(' paren_typedef_declarator ')'
'(' argument_expression_list ')'
| '(' paren_typedef_declarator ')' postfixing_abstract_declarator
'(' argument_expression_list ')'
| '(' simple_paren_typedef_declarator postfixing_abstract_declarator ')'
'(' argument_expression_list ')'
| '(' TYPEDEFname postfixing_abstract_declarator ')'
'(' argument_expression_list ')'
;
constructed_parameter_typedef_declarator:
TYPEDEFname '(' argument_expression_list ')'
| TYPEDEFname postfixing_abstract_declarator
'(' argument_expression_list ')' /* constraint error */
| '(' clean_typedef_declarator ')'
'(' argument_expression_list ')'
| '(' clean_typedef_declarator ')' postfixing_abstract_declarator
'(' argument_expression_list ')'
;
constructed_identifier_declarator:
nonunary_constructed_identifier_declarator
| asterisk_or_ampersand constructed_identifier_declarator
| unary_modifier constructed_identifier_declarator
;
/* The following are restricted to NOT begin with any pointer
operators. This includes both "*" and "T::*" modifiers. Aside
from this restriction, the following would have been:
identifier_declarator '(' argument_expression_list ')' */
nonunary_constructed_identifier_declarator:
paren_identifier_declarator '(' argument_expression_list ')'
| paren_identifier_declarator postfixing_abstract_declarator
'(' argument_expression_list ')' /* constraint error*/
| '(' unary_identifier_declarator ')'
'(' argument_expression_list ')'
| '(' unary_identifier_declarator ')' postfixing_abstract_declarator
'(' argument_expression_list ')'
;
declaration_specifier:
basic_declaration_specifier /* Arithmetic or void */
| sue_declaration_specifier /* struct/union/enum/class */
| typedef_declaration_specifier /* typedef*/
;
type_specifier:
basic_type_specifier /* Arithmetic or void */
| sue_type_specifier /* Struct/Union/Enum/Class */
| sue_type_specifier_elaboration /* elaborated Struct/Union/Enum/Class */
| typedef_type_specifier /* Typedef */
;
declaration_qualifier_list: /* storage class and optional const/volatile */
storage_class
| type_qualifier_list storage_class
| declaration_qualifier_list declaration_qualifier
;
type_qualifier_list:
type_qualifier
| type_qualifier_list type_qualifier
;
declaration_qualifier:
storage_class
| type_qualifier /* const or volatile */
;
type_qualifier:
CONST
| VOLATILE
;
basic_declaration_specifier: /*Storage Class+Arithmetic or void*/
declaration_qualifier_list basic_type_name
| basic_type_specifier storage_class
| basic_type_name storage_class
| basic_declaration_specifier declaration_qualifier
| basic_declaration_specifier basic_type_name
;
basic_type_specifier:
type_qualifier_list basic_type_name /* Arithmetic or void */
| basic_type_name basic_type_name
| basic_type_name type_qualifier
| basic_type_specifier type_qualifier
| basic_type_specifier basic_type_name