File: cxx.bnf

package info (click to toggle)
llvm-toolchain-15 1%3A15.0.6-4
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 1,554,644 kB
  • sloc: cpp: 5,922,452; ansic: 1,012,136; asm: 674,362; python: 191,568; objc: 73,855; f90: 42,327; lisp: 31,913; pascal: 11,973; javascript: 10,144; sh: 9,421; perl: 7,447; ml: 5,527; awk: 3,523; makefile: 2,520; xml: 885; cs: 573; fortran: 567
file content (776 lines) | stat: -rw-r--r-- 34,467 bytes parent folder | download
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
# This is a C++ grammar from the C++ standard [1].
#
# The grammar is a superset of the true grammar requring semantic constraints to
# resolve ambiguties. The grammar is context-free and ambiguous (beyond the
# limit of LR(k)). We use general parsing algorithm (e.g GLR) to handle the
# grammar and generate a transition table which is used to drive the parsing.
#
# It aims to align with the ISO C++ grammar as much as possible. We adjust it
# to fit the need for the grammar-based parser:
#  - attributes are omitted, which will be handled as comments;
#  - we don't allow nullable nonterminal symbols. There are few nullable
#    nonterminals in the spec grammar, they are adjusted to be non-nullable;
#  - the file merely describes the core C++ grammar. Preprocessor directives and
#    lexical conversions are omitted as we reuse clang's lexer and run a fake
#    preprocessor;
#  - grammar rules with the >> token are adjusted, the greatergreater token is
#    split into two > tokens, to make the GLR parser aware of nested templates
#    and right shift operator;
#
# Guidelines:
#   - nonterminals are lower_case; terminals (aka tokens) correspond to
#     clang::TokenKind, written as "IDENTIFIER", "USING", "::" etc;
#   - optional symbols are supported, with a _opt suffix;
#
# [1] https://isocpp.org/files/papers/N4860.pdf

# _ lists all the start-symbols which we support parsing.
#
# We list important nonterminals as start symbols, rather than doing it for all
# nonterminals by default, this reduces the number of states by 30% and LRTable
# actions by 16%.
_ := translation-unit
_ := statement-seq
_ := declaration-seq

# gram.key
typedef-name := IDENTIFIER
typedef-name := simple-template-id
namespace-name := IDENTIFIER
namespace-name := namespace-alias
namespace-alias := IDENTIFIER
class-name := IDENTIFIER
class-name := simple-template-id
enum-name := IDENTIFIER
template-name := IDENTIFIER

# gram.basic
#! Custom modifications to eliminate optional declaration-seq
translation-unit := declaration-seq
translation-unit := global-module-fragment_opt module-declaration declaration-seq_opt private-module-fragment_opt

# gram.expr
# expr.prim
primary-expression := literal
primary-expression := THIS
primary-expression := ( expression )
primary-expression := id-expression
primary-expression := lambda-expression
primary-expression := fold-expression
primary-expression := requires-expression
id-expression := unqualified-id
id-expression := qualified-id
unqualified-id := IDENTIFIER
unqualified-id := operator-function-id
unqualified-id := conversion-function-id
unqualified-id := literal-operator-id
unqualified-id := ~ type-name
unqualified-id := ~ decltype-specifier
unqualified-id := template-id
qualified-id := nested-name-specifier TEMPLATE_opt unqualified-id
nested-name-specifier := ::
nested-name-specifier := type-name ::
nested-name-specifier := namespace-name ::
nested-name-specifier := decltype-specifier ::
nested-name-specifier := nested-name-specifier IDENTIFIER ::
nested-name-specifier := nested-name-specifier TEMPLATE_opt simple-template-id ::
lambda-expression := lambda-introducer lambda-declarator_opt compound-statement
lambda-expression := lambda-introducer < template-parameter-list > requires-clause_opt lambda-declarator_opt compound-statement
#! We allow a capture-default to appear anywhere in a capture-list.
# This simplifies the grammar and error recovery.
lambda-introducer := [ capture-list_opt ]
lambda-declarator := ( parameter-declaration-clause_opt ) decl-specifier-seq_opt noexcept-specifier_opt trailing-return-type_opt requires-clause_opt
capture-list := capture
capture-list := capture-list , capture
capture := capture-default
capture := simple-capture
capture := init-capture
capture-default := &
capture-default := =
simple-capture := IDENTIFIER ..._opt
simple-capture := & IDENTIFIER ..._opt
simple-capture := THIS
simple-capture := * THIS
init-capture := ..._opt IDENTIFIER initializer
init-capture := & ..._opt IDENTIFIER initializer
fold-expression := ( cast-expression fold-operator ... )
fold-expression := ( ... fold-operator cast-expression )
fold-expression := ( cast-expression fold-operator ... fold-operator cast-expression )
fold-operator := +
fold-operator := -
fold-operator := *
fold-operator := /
fold-operator := %
fold-operator := ^
fold-operator := |
fold-operator := <<
fold-operator := greatergreater
fold-operator := +=
fold-operator := -=
fold-operator := *=
fold-operator := /=
fold-operator := %=
fold-operator := ^=
fold-operator := &=
fold-operator := |=
fold-operator := <<=
fold-operator := >>=
fold-operator := =
fold-operator := ==
fold-operator := !=
fold-operator := <
fold-operator := >
fold-operator := <=
fold-operator := >=
fold-operator := &&
fold-operator := ||
fold-operator := ,
fold-operator := .*
fold-operator := ->*
requires-expression := REQUIRES requirement-parameter-list_opt requirement-body
requirement-parameter-list := ( parameter-declaration-clause_opt )
requirement-body := { requirement-seq }
requirement-seq := requirement
requirement-seq := requirement-seq requirement
requirement := simple-requirement
requirement := type-requirement
requirement := compound-requirement
requirement := nested-requirement
simple-requirement := expression ;
type-requirement := TYPENAME nested-name-specifier_opt type-name ;
compound-requirement := { expression } NOEXCEPT_opt return-type-requirement_opt ;
return-type-requirement := -> type-constraint
nested-requirement := REQUIRES constraint-expression ;
# expr.post
postfix-expression := primary-expression
postfix-expression := postfix-expression [ expr-or-braced-init-list ]
postfix-expression := postfix-expression ( expression-list_opt )
postfix-expression := simple-type-specifier ( expression-list_opt )
postfix-expression := typename-specifier ( expression-list_opt )
postfix-expression := simple-type-specifier braced-init-list
postfix-expression := postfix-expression . TEMPLATE_opt id-expression
postfix-expression := postfix-expression -> TEMPLATE_opt id-expression
postfix-expression := postfix-expression ++
postfix-expression := postfix-expression --
postfix-expression := DYNAMIC_CAST < type-id > ( expression )
postfix-expression := STATIC_CAST < type-id > ( expression )
postfix-expression := REINTERPRET_CAST < type-id > ( expression )
postfix-expression := CONST_CAST < type-id > ( expression )
postfix-expression := TYPEID ( expression )
postfix-expression := TYPEID ( type-id )
#! Standard defines expression-list in terms of initializer-list, but our
#  initializer-list allows designators.
expression-list := initializer-clause ..._opt
expression-list := expression-list , initializer-clause ..._opt
# expr.unary
unary-expression := postfix-expression
unary-expression := unary-operator cast-expression
unary-expression := ++ cast-expression
unary-expression := -- cast-expression
unary-expression := await-expression
unary-expression := SIZEOF unary-expression
unary-expression := SIZEOF ( type-id )
unary-expression := SIZEOF ... ( IDENTIFIER )
unary-expression := ALIGNOF ( type-id )
unary-expression := noexcept-expression
unary-expression := new-expression
unary-expression := delete-expression
unary-operator := *
unary-operator := &
unary-operator := +
unary-operator := -
unary-operator := !
unary-operator := ~
await-expression := CO_AWAIT cast-expression
noexcept-expression := NOEXCEPT ( expression )
new-expression := ::_opt NEW new-placement_opt new-type-id new-initializer_opt
new-expression := ::_opt NEW new-placement_opt ( type-id ) new-initializer_opt
new-placement := ( expression-list )
new-type-id := type-specifier-seq new-declarator_opt
new-declarator := ptr-operator new-declarator_opt
new-declarator := noptr-new-declarator
noptr-new-declarator := [ expression_opt ]
noptr-new-declarator := noptr-new-declarator [ constant-expression ]
new-initializer := ( expression-list_opt )
new-initializer := braced-init-list
delete-expression := ::_opt DELETE cast-expression
delete-expression := ::_opt DELETE [ ] cast-expression
cast-expression := unary-expression
cast-expression := ( type-id ) cast-expression
# expr.mptr.oper
pm-expression := cast-expression
pm-expression := pm-expression .* cast-expression
pm-expression := pm-expression ->* cast-expression
# expr.mul
multiplicative-expression := pm-expression
multiplicative-expression := multiplicative-expression * pm-expression
multiplicative-expression := multiplicative-expression / pm-expression
multiplicative-expression := multiplicative-expression % pm-expression
# expr.add
additive-expression := multiplicative-expression
additive-expression := additive-expression + multiplicative-expression
additive-expression := additive-expression - multiplicative-expression
# expr.shift
shift-expression := additive-expression
shift-expression := shift-expression << additive-expression
shift-expression := shift-expression greatergreater additive-expression
# expr.spaceship
compare-expression := shift-expression
compare-expression := compare-expression <=> shift-expression
# expr.rel
relational-expression := compare-expression
relational-expression := relational-expression < compare-expression
relational-expression := relational-expression > compare-expression
relational-expression := relational-expression <= compare-expression
relational-expression := relational-expression >= compare-expression
# expr.eq
equality-expression := relational-expression
equality-expression := equality-expression == relational-expression
equality-expression := equality-expression != relational-expression
# expr.bit.and
and-expression := equality-expression
and-expression := and-expression & equality-expression
# expr.xor
exclusive-or-expression := and-expression
exclusive-or-expression := exclusive-or-expression ^ and-expression
# expr.or
inclusive-or-expression := exclusive-or-expression
inclusive-or-expression := inclusive-or-expression | exclusive-or-expression
# expr.log.and
logical-and-expression := inclusive-or-expression
logical-and-expression := logical-and-expression && inclusive-or-expression
# expr.log.or
logical-or-expression := logical-and-expression
logical-or-expression := logical-or-expression || logical-and-expression
# expr.cond
conditional-expression := logical-or-expression
conditional-expression := logical-or-expression ? expression : assignment-expression
# expr.ass
yield-expression := CO_YIELD assignment-expression
yield-expression := CO_YIELD braced-init-list
throw-expression := THROW assignment-expression_opt
assignment-expression := conditional-expression
assignment-expression := yield-expression
assignment-expression := throw-expression
assignment-expression := logical-or-expression assignment-operator initializer-clause
assignment-operator := =
assignment-operator := *=
assignment-operator := /=
assignment-operator := %=
assignment-operator := +=
assignment-operator := -=
assignment-operator := >>=
assignment-operator := <<=
assignment-operator := &=
assignment-operator := ^=
assignment-operator := |=
# expr.comma
expression := assignment-expression
expression := expression , assignment-expression
# expr.const
constant-expression := conditional-expression

# gram.stmt
statement := labeled-statement
statement := expression-statement
statement := compound-statement
statement := selection-statement
statement := iteration-statement
statement := jump-statement
statement := declaration-statement
statement := try-block
init-statement := expression-statement
init-statement := simple-declaration
condition := expression
condition := decl-specifier-seq declarator brace-or-equal-initializer
labeled-statement := IDENTIFIER : statement
labeled-statement := CASE constant-expression : statement
labeled-statement := DEFAULT : statement
expression-statement := expression_opt ;
compound-statement := { statement-seq_opt [recover=Brackets] }
statement-seq := statement
statement-seq := statement-seq statement
selection-statement := IF CONSTEXPR_opt ( init-statement_opt condition ) statement [guard]
selection-statement := IF CONSTEXPR_opt ( init-statement_opt condition ) statement ELSE statement
selection-statement := SWITCH ( init-statement_opt condition ) statement
iteration-statement := WHILE ( condition ) statement
iteration-statement := DO statement WHILE ( expression ) ;
iteration-statement := FOR ( init-statement condition_opt ; expression_opt ) statement
iteration-statement := FOR ( init-statement_opt for-range-declaration : for-range-initializer ) statement
for-range-declaration := decl-specifier-seq declarator
for-range-declaration := decl-specifier-seq ref-qualifier_opt [ identifier-list ]
for-range-initializer := expr-or-braced-init-list
jump-statement := BREAK ;
jump-statement := CONTINUE ;
jump-statement := RETURN expr-or-braced-init-list_opt ;
jump-statement := coroutine-return-statement
jump-statement := GOTO IDENTIFIER ;
coroutine-return-statement := CO_RETURN expr-or-braced-init-list_opt ;
declaration-statement := block-declaration

# gram.dcl
declaration-seq := declaration
declaration-seq := declaration-seq declaration
declaration := block-declaration
declaration := nodeclspec-function-declaration
declaration := function-definition
declaration := template-declaration
declaration := deduction-guide
declaration := explicit-instantiation
declaration := explicit-specialization
declaration := export-declaration
declaration := linkage-specification
declaration := namespace-definition
declaration := empty-declaration
declaration := module-import-declaration
block-declaration := simple-declaration
block-declaration := asm-declaration
block-declaration := namespace-alias-definition
block-declaration := using-declaration
block-declaration := using-enum-declaration
block-declaration := using-directive
block-declaration := static_assert-declaration
block-declaration := alias-declaration
block-declaration := opaque-enum-declaration
nodeclspec-function-declaration := function-declarator ;
alias-declaration := USING IDENTIFIER = defining-type-id ;
simple-declaration := decl-specifier-seq init-declarator-list_opt ;
simple-declaration := decl-specifier-seq ref-qualifier_opt [ identifier-list ] initializer ;
static_assert-declaration := STATIC_ASSERT ( constant-expression ) ;
static_assert-declaration := STATIC_ASSERT ( constant-expression , string-literal ) ;
empty-declaration := ;
# dcl.spec
decl-specifier := storage-class-specifier
decl-specifier := defining-type-specifier
decl-specifier := function-specifier
decl-specifier := FRIEND
decl-specifier := TYPEDEF
decl-specifier := CONSTEXPR
decl-specifier := CONSTEVAL
decl-specifier := CONSTINIT
decl-specifier := INLINE
decl-specifier-seq := decl-specifier
decl-specifier-seq := decl-specifier decl-specifier-seq [guard]
storage-class-specifier := STATIC
storage-class-specifier := THREAD_LOCAL
storage-class-specifier := EXTERN
storage-class-specifier := MUTABLE
function-specifier := VIRTUAL
function-specifier := explicit-specifier
explicit-specifier := EXPLICIT ( constant-expression )
explicit-specifier := EXPLICIT
type-specifier := simple-type-specifier
type-specifier := elaborated-type-specifier
type-specifier := typename-specifier
type-specifier := cv-qualifier
type-specifier-seq := type-specifier
type-specifier-seq := type-specifier type-specifier-seq [guard]
defining-type-specifier := type-specifier
defining-type-specifier := class-specifier
defining-type-specifier := enum-specifier
defining-type-specifier-seq := defining-type-specifier
defining-type-specifier-seq := defining-type-specifier defining-type-specifier-seq [guard]
simple-type-specifier := nested-name-specifier_opt type-name
simple-type-specifier := nested-name-specifier TEMPLATE simple-template-id
simple-type-specifier := decltype-specifier
simple-type-specifier := placeholder-type-specifier
simple-type-specifier := nested-name-specifier_opt template-name
simple-type-specifier := builtin-type
builtin-type := CHAR
builtin-type := CHAR8_T
builtin-type := CHAR16_T
builtin-type := CHAR32_T
builtin-type := WCHAR_T
builtin-type := BOOL
simple-type-specifier := SHORT
builtin-type := INT
simple-type-specifier := LONG
simple-type-specifier := SIGNED
simple-type-specifier := UNSIGNED
builtin-type := FLOAT
builtin-type := DOUBLE
builtin-type := VOID
type-name := class-name
type-name := enum-name
type-name := typedef-name
elaborated-type-specifier := class-key nested-name-specifier_opt IDENTIFIER
elaborated-type-specifier := class-key simple-template-id
elaborated-type-specifier := class-key nested-name-specifier TEMPLATE_opt simple-template-id
elaborated-type-specifier := elaborated-enum-specifier
elaborated-enum-specifier := ENUM nested-name-specifier_opt IDENTIFIER
decltype-specifier := DECLTYPE ( expression )
placeholder-type-specifier := type-constraint_opt AUTO
placeholder-type-specifier := type-constraint_opt DECLTYPE ( AUTO )
init-declarator-list := init-declarator
init-declarator-list := init-declarator-list , init-declarator
#! The standard grammar allows:
#!   1) an initializer with any declarator, including a function declarator, this
#!      creates an ambiguity where a function definition is misparsed as a simple
#!      declaration;
#!   2) an function-body with any declarator, includeing a non-function
#!      declarator, this creates an ambiguity whwere a simple-declaration is
#!      misparsed as a function-definition;
#! We extend the standard declarator to function-declarator and non-function-declarator
#! to eliminate these false parses.
init-declarator := non-function-declarator initializer_opt
init-declarator := function-declarator requires-clause_opt
function-declarator := declarator [guard]
non-function-declarator := declarator [guard]
declarator := ptr-declarator
declarator := noptr-declarator parameters-and-qualifiers trailing-return-type
ptr-declarator := noptr-declarator
ptr-declarator := ptr-operator ptr-declarator
noptr-declarator := declarator-id
noptr-declarator := noptr-declarator parameters-and-qualifiers
noptr-declarator := noptr-declarator [ constant-expression_opt ]
noptr-declarator := ( ptr-declarator )
parameters-and-qualifiers := ( parameter-declaration-clause_opt [recover=Brackets] ) cv-qualifier-seq_opt ref-qualifier_opt noexcept-specifier_opt
trailing-return-type := -> type-id
ptr-operator := * cv-qualifier-seq_opt
ptr-operator := &
ptr-operator := &&
ptr-operator := nested-name-specifier * cv-qualifier-seq_opt
cv-qualifier-seq := cv-qualifier cv-qualifier-seq_opt
cv-qualifier := CONST
cv-qualifier := VOLATILE
ref-qualifier := &
ref-qualifier := &&
declarator-id := ..._opt id-expression
type-id := type-specifier-seq abstract-declarator_opt
defining-type-id := defining-type-specifier-seq abstract-declarator_opt
abstract-declarator := ptr-abstract-declarator
abstract-declarator := noptr-abstract-declarator_opt parameters-and-qualifiers trailing-return-type
abstract-declarator := abstract-pack-declarator
ptr-abstract-declarator := noptr-abstract-declarator
ptr-abstract-declarator := ptr-operator ptr-abstract-declarator_opt
noptr-abstract-declarator := noptr-abstract-declarator_opt parameters-and-qualifiers
noptr-abstract-declarator := noptr-abstract-declarator_opt [ constant-expression_opt ]
noptr-abstract-declarator := ( ptr-abstract-declarator )
abstract-pack-declarator := noptr-abstract-pack-declarator
abstract-pack-declarator := ptr-operator abstract-pack-declarator
noptr-abstract-pack-declarator := noptr-abstract-pack-declarator parameters-and-qualifiers
noptr-abstract-pack-declarator := noptr-abstract-pack-declarator [ constant-expression_opt ]
noptr-abstract-pack-declarator := ...
#! Custom modifications to avoid nullable clause.
parameter-declaration-clause := parameter-declaration-list
parameter-declaration-clause := parameter-declaration-list_opt ...
parameter-declaration-clause := parameter-declaration-list , ...
parameter-declaration-list := parameter-declaration
parameter-declaration-list := parameter-declaration-list , parameter-declaration
parameter-declaration := decl-specifier-seq declarator
parameter-declaration := decl-specifier-seq declarator = initializer-clause
parameter-declaration := decl-specifier-seq abstract-declarator_opt
parameter-declaration := decl-specifier-seq abstract-declarator_opt = initializer-clause
# dcl.init
initializer := brace-or-equal-initializer
initializer := ( expression-list )
brace-or-equal-initializer := = initializer-clause
brace-or-equal-initializer := braced-init-list
initializer-clause := assignment-expression
initializer-clause := braced-init-list
#! Allow mixed designated/non-designated init-list.
# This is standard C, and accepted by clang and others as an extension.
# FIXME: Decouple recovery from is-there-a-trailing-comma!
braced-init-list := { initializer-list [recover=Brackets] }
braced-init-list := { initializer-list , }
braced-init-list := { }
initializer-list := initializer-list-item
initializer-list := initializer-list , initializer-list-item
initializer-list-item := initializer-clause ..._opt
initializer-list-item := designator brace-or-equal-initializer ..._opt
designator := . IDENTIFIER
#! Array designators are legal in C, and a common extension in C++.
designator := [ expression ]
expr-or-braced-init-list := expression
expr-or-braced-init-list := braced-init-list
# dcl.fct
function-definition := decl-specifier-seq_opt function-declarator virt-specifier-seq_opt function-body
function-definition := decl-specifier-seq_opt function-declarator requires-clause function-body
function-body := ctor-initializer_opt compound-statement
function-body := function-try-block
function-body := = DEFAULT ;
function-body := = DELETE ;
# dcl.enum
enum-specifier := enum-head { enumerator-list_opt }
enum-specifier := enum-head { enumerator-list , }
enum-head := enum-key enum-head-name_opt enum-base_opt
enum-head-name := nested-name-specifier_opt IDENTIFIER
opaque-enum-declaration := enum-key enum-head-name enum-base_opt ;
enum-key := ENUM
enum-key := ENUM CLASS
enum-key := ENUM STRUCT
enum-base := : type-specifier-seq
enumerator-list := enumerator-definition
enumerator-list := enumerator-list , enumerator-definition
enumerator-definition := enumerator
enumerator-definition := enumerator = constant-expression
enumerator := IDENTIFIER
using-enum-declaration := USING elaborated-enum-specifier ;
# basic.namespace
namespace-definition := named-namespace-definition
namespace-definition := unnamed-namespace-definition
namespace-definition := nested-namespace-definition
named-namespace-definition := INLINE_opt NAMESPACE IDENTIFIER { namespace-body_opt }
unnamed-namespace-definition := INLINE_opt NAMESPACE { namespace-body_opt }
nested-namespace-definition := NAMESPACE enclosing-namespace-specifier :: INLINE_opt IDENTIFIER { namespace-body }
enclosing-namespace-specifier := IDENTIFIER
enclosing-namespace-specifier := enclosing-namespace-specifier :: INLINE_opt IDENTIFIER
#! Custom modification to avoid nullable namespace-body.
namespace-body := declaration-seq
namespace-alias-definition := NAMESPACE IDENTIFIER = qualified-namespace-specifier ;
qualified-namespace-specifier := nested-name-specifier_opt namespace-name
using-directive := USING NAMESPACE nested-name-specifier_opt namespace-name ;
using-declaration := USING using-declarator-list ;
using-declarator-list := using-declarator ..._opt
using-declarator-list := using-declarator-list , using-declarator ..._opt
using-declarator := TYPENAME_opt nested-name-specifier unqualified-id
# dcl.asm
asm-declaration := ASM ( string-literal ) ;
# dcl.link
linkage-specification := EXTERN string-literal { declaration-seq_opt }
linkage-specification := EXTERN string-literal declaration

# gram.module
module-declaration := export-keyword_opt module-keyword module-name module-partition_opt ;
module-name := module-name-qualifier_opt IDENTIFIER
module-partition := : module-name-qualifier_opt IDENTIFIER
module-name-qualifier := IDENTIFIER .
module-name-qualifier := module-name-qualifier IDENTIFIER .
export-declaration := EXPORT declaration
export-declaration := EXPORT { declaration-seq_opt }
export-declaration := export-keyword module-import-declaration
module-import-declaration := import-keyword module-name ;
module-import-declaration := import-keyword module-partition ;
# FIXME: we don't have header-name in the grammar. Handle these in PP?
# module-import-declaration := import-keyword header-name ;
global-module-fragment := module-keyword ; declaration-seq_opt
private-module-fragment := module-keyword : PRIVATE ; declaration-seq_opt

# gram.class
class-specifier := class-head { member-specification_opt [recover=Brackets] }
class-head := class-key class-head-name class-virt-specifier_opt base-clause_opt
class-head := class-key base-clause_opt
class-head-name := nested-name-specifier_opt class-name
class-virt-specifier := contextual-final
class-key := CLASS
class-key := STRUCT
class-key := UNION
member-specification := member-declaration member-specification_opt
member-specification := access-specifier : member-specification_opt
member-declaration := decl-specifier-seq_opt member-declarator-list_opt ;
member-declaration := function-definition
member-declaration := using-declaration
member-declaration := using-enum-declaration
member-declaration := static_assert-declaration
member-declaration := template-declaration
member-declaration := explicit-specialization
member-declaration := deduction-guide
member-declaration := alias-declaration
member-declaration := opaque-enum-declaration
member-declaration := empty-declaration
member-declarator-list := member-declarator
member-declarator-list := member-declarator-list , member-declarator
member-declarator := declarator virt-specifier-seq_opt pure-specifier_opt
member-declarator := declarator requires-clause
member-declarator := declarator brace-or-equal-initializer
member-declarator := IDENTIFIER_opt : constant-expression brace-or-equal-initializer_opt
virt-specifier-seq := virt-specifier
virt-specifier-seq := virt-specifier-seq virt-specifier
virt-specifier := contextual-override
virt-specifier := contextual-final
pure-specifier := = contextual-zero
conversion-function-id := OPERATOR conversion-type-id
conversion-type-id := type-specifier-seq conversion-declarator_opt
conversion-declarator := ptr-operator conversion-declarator_opt
base-clause := : base-specifier-list
base-specifier-list := base-specifier ..._opt
base-specifier-list := base-specifier-list , base-specifier ..._opt
base-specifier := class-or-decltype
base-specifier := VIRTUAL access-specifier_opt class-or-decltype
base-specifier := access-specifier VIRTUAL_opt class-or-decltype
class-or-decltype := nested-name-specifier_opt type-name
class-or-decltype := nested-name-specifier TEMPLATE simple-template-id
class-or-decltype := decltype-specifier
access-specifier := PRIVATE
access-specifier := PROTECTED
access-specifier := PUBLIC
ctor-initializer := : mem-initializer-list
mem-initializer-list := mem-initializer ..._opt
mem-initializer-list := mem-initializer-list , mem-initializer ..._opt
mem-initializer := mem-initializer-id ( expression-list_opt )
mem-initializer := mem-initializer-id braced-init-list
mem-initializer-id := class-or-decltype
mem-initializer-id := IDENTIFIER

# gram.over
operator-function-id := OPERATOR operator-name
operator-name := NEW
operator-name := DELETE
operator-name := NEW [ ]
operator-name := DELETE [ ]
operator-name := CO_AWAIT
operator-name := ( )
operator-name := [ ]
operator-name := ->
operator-name := ->*
operator-name := ~
operator-name := !
operator-name := +
operator-name := -
operator-name := *
operator-name := /
operator-name := %
operator-name := ^
operator-name := &
operator-name := |
operator-name := =
operator-name := +=
operator-name := -=
operator-name := *=
operator-name := /=
operator-name := %=
operator-name := ^=
operator-name := &=
operator-name := |=
operator-name := ==
operator-name := !=
operator-name := <
operator-name := >
operator-name := <=
operator-name := >=
operator-name := <=>
operator-name := ^^
operator-name := ||
operator-name := <<
operator-name := greatergreater
operator-name := <<=
operator-name := >>=
operator-name := ++
operator-name := --
operator-name := ,
literal-operator-id := OPERATOR string-literal IDENTIFIER
literal-operator-id := OPERATOR user-defined-string-literal

# gram.temp
template-declaration := template-head declaration
template-declaration := template-head concept-definition
template-head := TEMPLATE < template-parameter-list > requires-clause_opt
template-parameter-list := template-parameter
template-parameter-list := template-parameter-list , template-parameter
requires-clause := REQUIRES constraint-logical-or-expression
constraint-logical-or-expression := constraint-logical-and-expression
constraint-logical-or-expression := constraint-logical-or-expression || constraint-logical-and-expression
constraint-logical-and-expression := primary-expression
constraint-logical-and-expression := constraint-logical-and-expression && primary-expression
template-parameter := type-parameter
template-parameter := parameter-declaration
type-parameter := type-parameter-key ..._opt IDENTIFIER_opt
type-parameter := type-parameter-key IDENTIFIER_opt = type-id
type-parameter := type-constraint ..._opt IDENTIFIER_opt
type-parameter := type-constraint IDENTIFIER_opt = type-id
type-parameter := template-head type-parameter-key ..._opt IDENTIFIER_opt
type-parameter := template-head type-parameter-key IDENTIFIER_opt = id-expression
type-parameter-key := CLASS
type-parameter-key := TYPENAME
type-constraint := nested-name-specifier_opt concept-name
type-constraint := nested-name-specifier_opt concept-name < template-argument-list_opt >
simple-template-id := template-name < template-argument-list_opt >
template-id := simple-template-id
template-id := operator-function-id < template-argument-list_opt >
template-id := literal-operator-id < template-argument-list_opt >
template-argument-list := template-argument ..._opt
template-argument-list := template-argument-list , template-argument ..._opt
template-argument := constant-expression
template-argument := type-id
template-argument := id-expression
constraint-expression := logical-or-expression
deduction-guide := explicit-specifier_opt template-name ( parameter-declaration-list_opt ) -> simple-template-id ;
concept-definition := CONCEPT concept-name = constraint-expression ;
concept-name := IDENTIFIER
typename-specifier := TYPENAME nested-name-specifier IDENTIFIER
typename-specifier := TYPENAME nested-name-specifier TEMPLATE_opt simple-template-id
explicit-instantiation := EXTERN_opt TEMPLATE declaration
explicit-specialization := TEMPLATE < > declaration

# gram.except
try-block := TRY compound-statement handler-seq
function-try-block := TRY ctor-initializer_opt compound-statement handler-seq
handler-seq := handler handler-seq_opt
handler := CATCH ( exception-declaration ) compound-statement
exception-declaration := type-specifier-seq declarator
exception-declaration := type-specifier-seq abstract-declarator_opt
noexcept-specifier := NOEXCEPT ( constant-expression )
noexcept-specifier := NOEXCEPT

# gram.cpp
identifier-list := IDENTIFIER
identifier-list := identifier-list , IDENTIFIER

# gram.lex
#! As we use clang lexer, most of lexical symbols are not needed, we only add
#! needed literals.
literal := integer-literal
literal := character-literal
literal := floating-point-literal
literal := string-literal
literal := boolean-literal
literal := pointer-literal
literal := user-defined-literal
integer-literal := NUMERIC_CONSTANT [guard]
character-literal := CHAR_CONSTANT [guard]
character-literal := WIDE_CHAR_CONSTANT [guard]
character-literal := UTF8_CHAR_CONSTANT [guard]
character-literal := UTF16_CHAR_CONSTANT [guard]
character-literal := UTF32_CHAR_CONSTANT [guard]
floating-point-literal := NUMERIC_CONSTANT [guard]
string-literal-chunk := STRING_LITERAL [guard]
string-literal-chunk := WIDE_STRING_LITERAL [guard]
string-literal-chunk := UTF8_STRING_LITERAL [guard]
string-literal-chunk := UTF16_STRING_LITERAL [guard]
string-literal-chunk := UTF32_STRING_LITERAL [guard]
#! Technically, string concatenation happens at phase 6 which is before parsing,
#! so it doesn't belong to the grammar. However, we extend the grammar to
#! support it, to make the pseudoparser fully functional on practical code.
string-literal := string-literal-chunk
string-literal := string-literal string-literal-chunk
user-defined-literal := user-defined-integer-literal
user-defined-literal := user-defined-floating-point-literal
user-defined-literal := user-defined-string-literal
user-defined-literal := user-defined-character-literal
user-defined-integer-literal := NUMERIC_CONSTANT [guard]
user-defined-string-literal-chunk := STRING_LITERAL [guard]
user-defined-string-literal-chunk := WIDE_STRING_LITERAL [guard]
user-defined-string-literal-chunk := UTF8_STRING_LITERAL [guard]
user-defined-string-literal-chunk := UTF16_STRING_LITERAL [guard]
user-defined-string-literal-chunk := UTF32_STRING_LITERAL [guard]
user-defined-string-literal := user-defined-string-literal-chunk
user-defined-string-literal := string-literal-chunk user-defined-string-literal
user-defined-string-literal := user-defined-string-literal string-literal-chunk
user-defined-floating-point-literal := NUMERIC_CONSTANT [guard]
user-defined-character-literal := CHAR_CONSTANT [guard]
user-defined-character-literal := WIDE_CHAR_CONSTANT [guard]
user-defined-character-literal := UTF8_CHAR_CONSTANT [guard]
user-defined-character-literal := UTF16_CHAR_CONSTANT [guard]
user-defined-character-literal := UTF32_CHAR_CONSTANT [guard]
boolean-literal := FALSE
boolean-literal := TRUE
pointer-literal := NULLPTR

#! Contextual keywords -- clang lexer always lexes them as identifier tokens.
#! Placeholders for literal text in the grammar that lex as other things.
contextual-override := IDENTIFIER [guard]
contextual-final := IDENTIFIER [guard]
contextual-zero := NUMERIC_CONSTANT [guard]
module-keyword := IDENTIFIER [guard]
import-keyword := IDENTIFIER [guard]
export-keyword := IDENTIFIER [guard]

#! greatergreater token -- clang lexer always lexes it as a single token, we
#! split it into two tokens to make the GLR parser aware of the nested-template
#! case.
greatergreater := > >

#! C++ predefined identifier, __func__ [dcl.fct.def.general] p8
#! FIXME: add other (MSVC, GNU extension) predefined identifiers.
primary-expression := predefined-expression
predefined-expression := __FUNC__