1 /**
2  * Takes a token stream from the lexer, and parses it into an abstract syntax tree.
3  *
4  * Specification: C11
5  *
6  * Copyright:   Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved
7  * Authors:     $(LINK2 https://www.digitalmars.com, Walter Bright)
8  * License:     $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/cparse.d, _cparse.d)
10  * Documentation:  https://dlang.org/phobos/dmd_cparse.html
11  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/cparse.d
12  */
13 
14 module dmd.cparse;
15 
16 import core.stdc.stdio;
17 import core.stdc.string : memcpy;
18 
19 import dmd.astenums;
20 import dmd.errorsink;
21 import dmd.id;
22 import dmd.identifier;
23 import dmd.lexer;
24 import dmd.location;
25 import dmd.parse;
26 import dmd.root.array;
27 import dmd.common.outbuffer;
28 import dmd.root.rmem;
29 import dmd.tokens;
30 
31 /***********************************************************
32  */
33 final class CParser(AST) : Parser!AST
34 {
35     AST.Dsymbols* symbols;      // symbols declared in current scope
36 
37     bool addFuncName;           /// add declaration of __func__ to function symbol table
38     bool importBuiltins;        /// seen use of C compiler builtins, so import __builtins;
39 
40     private
41     {
42         structalign_t packalign;        // current state of #pragma pack alignment
43 
44         // #pragma pack stack
45         Array!Identifier* records;      // identifers (or null)
46         Array!structalign_t* packs;     // parallel alignment values
47     }
48 
49     /* C cannot be parsed without determining if an identifier is a type or a variable.
50      * For expressions like `(T)-3`, is it a cast or a minus expression?
51      * It also occurs with `typedef int (F)(); F fun;`
52      * but to build the AST we need to distinguish `fun` being a function as opposed to a variable.
53      * To fix, build a symbol table for the typedefs.
54      * Symbol table of typedefs indexed by Identifier cast to void*.
55      * 1. if an identifier is a typedef, then it will return a non-null Type
56      * 2. if an identifier is not a typedef, then it will return null
57      */
58     Array!(void*) typedefTab;  /// Array of AST.Type[Identifier], typedef's indexed by Identifier
59 
60     /* This is passed in as a list of #define lines, as generated by the C preprocessor with the
61      * appropriate switch to emit them. We append to it any #define's and #undef's encountered in the source
62      * file, as cpp with the -dD embeds them in the preprocessed output file.
63      * Once the file is parsed, then the #define's are converted to D symbols and appended to the array
64      * of Dsymbols returned by parseModule().
65      */
66     OutBuffer* defines;
67 
68     extern (D) this(TARGET)(AST.Module _module, const(char)[] input, bool doDocComment,
69                             ErrorSink errorSink,
70                             const ref TARGET target, OutBuffer* defines, const CompileEnv* compileEnv) scope
71     {
72         const bool doUnittests = false;
73         super(_module, input, doDocComment, errorSink, compileEnv, doUnittests);
74 
75         //printf("CParser.this()\n");
76         mod = _module;
77         linkage = LINK.c;
78         Ccompile = true;
79         this.packalign.setDefault();
80         this.defines = defines;
81 
82         // Configure sizes for C `long`, `long double`, `wchar_t`, ...
83         this.boolsize = target.boolsize;
84         this.shortsize = target.shortsize;
85         this.intsize = target.intsize;
86         this.longsize = target.longsize;
87         this.long_longsize = target.long_longsize;
88         this.long_doublesize = target.long_doublesize;
89         this.wchar_tsize = target.wchar_tsize;
90 
91         // C `char` is always unsigned in ImportC
92     }
93 
94     /********************************************
95      * Parse translation unit.
96      * C11 6.9
97      * translation-unit:
98      *    external-declaration
99      *    translation-unit external-declaration
100      *
101      * external-declaration:
102      *    function-definition
103      *    declaration
104      * Returns:
105      *  array of Dsymbols that were declared
106      */
107     override AST.Dsymbols* parseModule()
108     {
109         //printf("cparseTranslationUnit()\n");
110         symbols = new AST.Dsymbols();
111         typedefTab.push(null);  // C11 6.2.1-3 symbol table for "file scope"
112         while (1)
113         {
114             if (token.value == TOK.endOfFile)
115             {
116                 addDefines();   // convert #define's to Dsymbols
117 
118                 // wrap the symbols in `extern (C) { symbols }`
119                 auto wrap = new AST.Dsymbols();
120                 auto ld = new AST.LinkDeclaration(token.loc, LINK.c, symbols);
121                 wrap.push(ld);
122 
123                 if (importBuiltins)
124                 {
125                     /* Seen references to C builtin functions.
126                      * Import their definitions
127                      */
128                     auto s = new AST.Import(Loc.initial, null, Id.builtins, null, false);
129                     wrap.push(s);
130                 }
131 
132                 // end of file scope
133                 typedefTab.pop();
134                 assert(typedefTab.length == 0);
135 
136                 return wrap;
137             }
138 
139             cparseDeclaration(LVL.global);
140         }
141     }
142 
143     /******************************************************************************/
144     /********************************* Statement Parser ***************************/
145     //{
146 
147     /**********************
148      * C11 6.8
149      * statement:
150      *    labeled-statement
151      *    compound-statement
152      *    expression-statement
153      *    selection-statement
154      *    iteration-statement
155      *    jump-statement
156      *
157      * Params:
158      *      flags = PSxxxx
159      *      endPtr = store location of closing brace
160      *      pEndloc = if { ... statements ... }, store location of closing brace, otherwise loc of last token of statement
161      * Returns:
162      *      parsed statement
163      */
164     AST.Statement cparseStatement(int flags, const(char)** endPtr = null, Loc* pEndloc = null)
165     {
166         AST.Statement s;
167         const loc = token.loc;
168 
169         //printf("cparseStatement()\n");
170 
171         const typedefTabLengthSave = typedefTab.length;
172         auto symbolsSave = symbols;
173         if (flags & ParseStatementFlags.scope_)
174         {
175             typedefTab.push(null);      // introduce new block scope
176         }
177 
178         if (!(flags & (ParseStatementFlags.scope_ | ParseStatementFlags.curlyScope)))
179         {
180             symbols = new AST.Dsymbols();
181         }
182 
183         switch (token.value)
184         {
185         case TOK.identifier:
186             /* A leading identifier can be a declaration, label, or expression.
187              * A quick check of the next token can disambiguate most cases.
188              */
189             switch (peekNext())
190             {
191                 case TOK.colon:
192                 {
193                     // It's a label
194                     auto ident = token.ident;
195                     nextToken();    // advance to `:`
196                     nextToken();    // advance past `:`
197                     if (token.value == TOK.rightCurly)
198                         s = null;
199                     else if (token.value == TOK.leftCurly)
200                         s = cparseStatement(ParseStatementFlags.curly | ParseStatementFlags.scope_);
201                     else
202                         s = cparseStatement(0);
203                     s = new AST.LabelStatement(loc, ident, s);
204                     break;
205                 }
206 
207                 case TOK.dot:
208                 case TOK.arrow:
209                 case TOK.plusPlus:
210                 case TOK.minusMinus:
211                 case TOK.leftBracket:
212                 case TOK.question:
213                 case TOK.assign:
214                 case TOK.addAssign:
215                 case TOK.minAssign:
216                 case TOK.mulAssign:
217                 case TOK.divAssign:
218                 case TOK.modAssign:
219                 case TOK.andAssign:
220                 case TOK.orAssign:
221                 case TOK.xorAssign:
222                 case TOK.leftShiftAssign:
223                 case TOK.rightShiftAssign:
224                     goto Lexp;
225 
226                 case TOK.leftParenthesis:
227                     if (auto pt = lookupTypedef(token.ident))
228                     {
229                         if (*pt)
230                             goto Ldeclaration;
231                     }
232                     goto Lexp;  // function call
233 
234                 default:
235                 {
236                     /* If tokens look like a declaration, assume it is one
237                      */
238                     auto tk = &token;
239                     if (isCDeclaration(tk))
240                         goto Ldeclaration;
241                     goto Lexp;
242                 }
243             }
244             break;
245 
246         case TOK.charLiteral:
247         case TOK.int32Literal:
248         case TOK.uns32Literal:
249         case TOK.int64Literal:
250         case TOK.uns64Literal:
251         case TOK.int128Literal:
252         case TOK.uns128Literal:
253         case TOK.float32Literal:
254         case TOK.float64Literal:
255         case TOK.float80Literal:
256         case TOK.imaginary32Literal:
257         case TOK.imaginary64Literal:
258         case TOK.imaginary80Literal:
259         case TOK.leftParenthesis:
260         case TOK.and:
261         case TOK.mul:
262         case TOK.min:
263         case TOK.add:
264         case TOK.tilde:
265         case TOK.not:
266         case TOK.plusPlus:
267         case TOK.minusMinus:
268         case TOK.sizeof_:
269         case TOK._Generic:
270         case TOK._assert:
271         Lexp:
272             auto exp = cparseExpression();
273             if (token.value == TOK.identifier && exp.op == EXP.identifier)
274             {
275                 error(token.loc, "found `%s` when expecting `;` or `=`, did you mean `%s %s = %s`?", peek(&token).toChars(), exp.toChars(), token.toChars(), peek(peek(&token)).toChars());
276                 nextToken();
277             }
278             else
279                 check(TOK.semicolon, "statement");
280             s = new AST.ExpStatement(loc, exp);
281             break;
282 
283         // type-specifiers
284         case TOK.void_:
285         case TOK.char_:
286         case TOK.int16:
287         case TOK.int32:
288         case TOK.int64:
289         case TOK.__int128:
290         case TOK.float32:
291         case TOK.float64:
292         case TOK.signed:
293         case TOK.unsigned:
294         case TOK._Bool:
295         //case TOK._Imaginary:
296         case TOK._Complex:
297         case TOK.struct_:
298         case TOK.union_:
299         case TOK.enum_:
300         case TOK.typeof_:
301 
302         // storage-class-specifiers
303         case TOK.typedef_:
304         case TOK.extern_:
305         case TOK.static_:
306         case TOK._Thread_local:
307         case TOK.__thread:
308         case TOK.auto_:
309         case TOK.register:
310 
311         // function-specifiers
312         case TOK.inline:
313         case TOK._Noreturn:
314 
315         // type-qualifiers
316         case TOK.const_:
317         case TOK..volatile:
318         case TOK.restrict:
319         case TOK.__stdcall:
320 
321         // alignment-specifier
322         case TOK._Alignas:
323 
324         // atomic-type-specifier or type_qualifier
325         case TOK._Atomic:
326 
327         Ldeclaration:
328         {
329             cparseDeclaration(LVL.local);
330             if (symbols.length > 1)
331             {
332                 auto as = new AST.Statements();
333                 as.reserve(symbols.length);
334                 foreach (d; (*symbols)[])
335                 {
336                     s = new AST.ExpStatement(loc, d);
337                     as.push(s);
338                 }
339                 s = new AST.CompoundDeclarationStatement(loc, as);
340                 symbols.setDim(0);
341             }
342             else if (symbols.length == 1)
343             {
344                 auto d = (*symbols)[0];
345                 s = new AST.ExpStatement(loc, d);
346                 symbols.setDim(0);
347             }
348             else
349                 s = new AST.ExpStatement(loc, cast(AST.Expression)null);
350             if (flags & ParseStatementFlags.scope_)
351                 s = new AST.ScopeStatement(loc, s, token.loc);
352             break;
353         }
354 
355         case TOK._Static_assert:        // _Static_assert ( constant-expression, string-literal ) ;
356             s = new AST.StaticAssertStatement(cparseStaticAssert());
357             break;
358 
359         case TOK.leftCurly:
360         {
361             /* C11 6.8.2
362              * compound-statement:
363              *    { block-item-list (opt) }
364              *
365              * block-item-list:
366              *    block-item
367              *    block-item-list block-item
368              *
369              * block-item:
370              *    declaration
371              *    statement
372              */
373             nextToken();
374             auto statements = new AST.Statements();
375             while (token.value != TOK.rightCurly && token.value != TOK.endOfFile)
376             {
377                 statements.push(cparseStatement(ParseStatementFlags.curlyScope));
378             }
379             if (endPtr)
380                 *endPtr = token.ptr;
381             endloc = token.loc;
382             if (pEndloc)
383             {
384                 *pEndloc = token.loc;
385                 pEndloc = null; // don't set it again
386             }
387             s = new AST.CompoundStatement(loc, statements);
388             if (flags & (ParseStatementFlags.scope_ | ParseStatementFlags.curlyScope))
389                 s = new AST.ScopeStatement(loc, s, token.loc);
390             check(TOK.rightCurly, "compound statement");
391             break;
392         }
393 
394         case TOK.while_:
395         {
396             nextToken();
397             check(TOK.leftParenthesis);
398             auto condition = cparseExpression();
399             check(TOK.rightParenthesis);
400             Loc endloc;
401             auto _body = cparseStatement(ParseStatementFlags.scope_, null, &endloc);
402             s = new AST.WhileStatement(loc, condition, _body, endloc, null);
403             break;
404         }
405 
406         case TOK.semicolon:
407             /* C11 6.8.3 null statement
408              */
409             nextToken();
410             s = new AST.ExpStatement(loc, cast(AST.Expression)null);
411             break;
412 
413         case TOK.do_:
414         {
415             nextToken();
416             auto _body = cparseStatement(ParseStatementFlags.scope_);
417             check(TOK.while_);
418             check(TOK.leftParenthesis);
419             auto condition = cparseExpression();
420             check(TOK.rightParenthesis);
421             check(TOK.semicolon, "terminating `;` required after do-while statement");
422             s = new AST.DoStatement(loc, _body, condition, token.loc);
423             break;
424         }
425 
426         case TOK.for_:
427         {
428             AST.Statement _init;
429             AST.Expression condition;
430             AST.Expression increment;
431 
432             nextToken();
433             check(TOK.leftParenthesis);
434             if (token.value == TOK.semicolon)
435             {
436                 _init = null;
437                 nextToken();
438             }
439             else
440             {
441                 _init = cparseStatement(0);
442             }
443             if (token.value == TOK.semicolon)
444             {
445                 condition = null;
446                 nextToken();
447             }
448             else
449             {
450                 condition = cparseExpression();
451                 check(TOK.semicolon, "`for` condition");
452             }
453             if (token.value == TOK.rightParenthesis)
454             {
455                 increment = null;
456                 nextToken();
457             }
458             else
459             {
460                 increment = cparseExpression();
461                 check(TOK.rightParenthesis);
462             }
463             Loc endloc;
464             auto _body = cparseStatement(ParseStatementFlags.scope_, null, &endloc);
465             s = new AST.ForStatement(loc, _init, condition, increment, _body, endloc);
466             break;
467         }
468 
469         case TOK.if_:
470         {
471             nextToken();
472             check(TOK.leftParenthesis);
473             auto condition = cparseExpression();
474             check(TOK.rightParenthesis);
475             auto ifbody = cparseStatement(ParseStatementFlags.scope_);
476             AST.Statement elsebody;
477             if (token.value == TOK.else_)
478             {
479                 nextToken();
480                 elsebody = cparseStatement(ParseStatementFlags.scope_);
481             }
482             else
483                 elsebody = null;
484             if (condition && ifbody)
485                 s = new AST.IfStatement(loc, null, condition, ifbody, elsebody, token.loc);
486             else
487                 s = null; // don't propagate parsing errors
488             break;
489         }
490 
491         case TOK.else_:
492             error("found `else` without a corresponding `if` statement");
493             goto Lerror;
494 
495         case TOK.switch_:
496         {
497             nextToken();
498             check(TOK.leftParenthesis);
499             auto condition = cparseExpression();
500             check(TOK.rightParenthesis);
501             auto _body = cparseStatement(ParseStatementFlags.scope_);
502             s = new AST.SwitchStatement(loc, condition, _body, false);
503             break;
504         }
505 
506         case TOK.case_:
507         {
508 
509             nextToken();
510             auto exp = cparseAssignExp();
511             AST.Expression expHigh;
512             if (token.value == TOK.dotDotDot)
513             {
514                 /* Case Ranges https://gcc.gnu.org/onlinedocs/gcc/Case-Ranges.html
515                  */
516                 nextToken();
517                 expHigh = cparseAssignExp();
518             }
519             check(TOK.colon);
520 
521             if (flags & ParseStatementFlags.curlyScope)
522             {
523                 auto statements = new AST.Statements();
524                 while (token.value != TOK.case_ && token.value != TOK.default_ && token.value != TOK.endOfFile && token.value != TOK.rightCurly)
525                 {
526                     auto cur = cparseStatement(ParseStatementFlags.curlyScope);
527                     statements.push(cur);
528 
529                     // https://issues.dlang.org/show_bug.cgi?id=21739
530                     // Stop at the last break s.t. the following non-case statements are
531                     // not merged into the current case. This can happen for
532                     // case 1: ... break;
533                     // debug { case 2: ... }
534                     if (cur && cur.isBreakStatement())
535                         break;
536                 }
537                 s = new AST.CompoundStatement(loc, statements);
538             }
539             else
540             {
541                 s = cparseStatement(0);
542             }
543             s = new AST.ScopeStatement(loc, s, token.loc);
544             if (expHigh)
545                 s = new AST.CaseRangeStatement(loc, exp, expHigh, s);
546             else
547                 s = new AST.CaseStatement(loc, exp, s);
548             break;
549         }
550 
551         case TOK.default_:
552         {
553             nextToken();
554             check(TOK.colon);
555 
556             if (flags & ParseStatementFlags.curlyScope)
557             {
558                 auto statements = new AST.Statements();
559                 while (token.value != TOK.case_ && token.value != TOK.default_ && token.value != TOK.endOfFile && token.value != TOK.rightCurly)
560                 {
561                     statements.push(cparseStatement(ParseStatementFlags.curlyScope));
562                 }
563                 s = new AST.CompoundStatement(loc, statements);
564             }
565             else
566                 s = cparseStatement(0);
567             s = new AST.ScopeStatement(loc, s, token.loc);
568             s = new AST.DefaultStatement(loc, s);
569             break;
570         }
571 
572         case TOK.return_:
573         {
574             /*  return ;
575              *  return expression ;
576              */
577             nextToken();
578             auto exp = token.value == TOK.semicolon ? null : cparseExpression();
579             check(TOK.semicolon, "`return` statement");
580             s = new AST.ReturnStatement(loc, exp);
581             break;
582         }
583 
584         case TOK.break_:
585             nextToken();
586             check(TOK.semicolon, "`break` statement");
587             s = new AST.BreakStatement(loc, null);
588             break;
589 
590         case TOK.continue_:
591             nextToken();
592             check(TOK.semicolon, "`continue` statement");
593             s = new AST.ContinueStatement(loc, null);
594             break;
595 
596         case TOK.goto_:
597         {
598             Identifier ident;
599             nextToken();
600             if (token.value != TOK.identifier)
601             {
602                 error("identifier expected following `goto`");
603                 ident = null;
604             }
605             else
606             {
607                 ident = token.ident;
608                 nextToken();
609             }
610             s = new AST.GotoStatement(loc, ident);
611             check(TOK.semicolon, "`goto` statement");
612             break;
613         }
614 
615         case TOK.asm_:
616             switch (peekNext())
617             {
618                 case TOK.goto_:
619                 case TOK.inline:
620                 case TOK..volatile:
621                 case TOK.leftParenthesis:
622                     s = cparseGnuAsm();
623                     break;
624 
625                 default:
626                     // ImportC extensions: parse as a D asm block.
627                     s = parseAsm();
628                     break;
629             }
630             break;
631 
632         default:
633             error("found `%s` instead of statement", token.toChars());
634             goto Lerror;
635 
636         Lerror:
637             panic();
638             if (token.value == TOK.semicolon)
639                 nextToken();
640             s = null;
641             break;
642         }
643         if (pEndloc)
644             *pEndloc = prevloc;
645         symbols = symbolsSave;
646         typedefTab.setDim(typedefTabLengthSave);
647         return s;
648     }
649 
650     //}
651     /*******************************************************************************/
652     /********************************* Expression Parser ***************************/
653     //{
654 
655     /**************
656      * C11 6.5.17
657      * expression:
658      *  assignment-expression
659      *  expression , assignment-expression
660      */
661     AST.Expression cparseExpression()
662     {
663         auto loc = token.loc;
664 
665         //printf("cparseExpression() loc = %d\n", loc.linnum);
666         auto e = cparseAssignExp();
667         while (token.value == TOK.comma)
668         {
669             nextToken();
670             auto e2 = cparseAssignExp();
671             e = new AST.CommaExp(loc, e, e2, false);
672             loc = token.loc;
673         }
674         return e;
675     }
676 
677 
678     /*********************
679      * C11 6.5.1
680      * primary-expression:
681      *    identifier
682      *    constant
683      *    string-literal
684      *    ( expression )
685      *    generic-selection
686      *    __builtin_va_arg(assign_expression, type)
687      */
688     AST.Expression cparsePrimaryExp()
689     {
690         AST.Expression e;
691         const loc = token.loc;
692 
693         //printf("parsePrimaryExp(): loc = %d\n", loc.linnum);
694         switch (token.value)
695         {
696         case TOK.identifier:
697             const id = token.ident.toString();
698             if (id.length > 2 && id[0] == '_' && id[1] == '_')  // leading double underscore
699             {
700                 if (token.ident is Id.__func__)
701                 {
702                     addFuncName = true;     // implicitly declare __func__
703                 }
704                 else if (token.ident is Id.builtin_va_arg)
705                 {
706                     e = cparseBuiltin_va_arg();
707                     break;
708                 }
709                 else
710                     importBuiltins = true;  // probably one of those compiler extensions
711             }
712             e = new AST.IdentifierExp(loc, token.ident);
713             nextToken();
714             break;
715 
716         case TOK.charLiteral:
717         case TOK.int32Literal:
718             e = new AST.IntegerExp(loc, token.intvalue, AST.Type.tint32);
719             nextToken();
720             break;
721 
722         case TOK.uns32Literal:
723             e = new AST.IntegerExp(loc, token.unsvalue, AST.Type.tuns32);
724             nextToken();
725             break;
726 
727         case TOK.int64Literal:
728             e = new AST.IntegerExp(loc, token.intvalue, AST.Type.tint64);
729             nextToken();
730             break;
731 
732         case TOK.uns64Literal:
733             e = new AST.IntegerExp(loc, token.unsvalue, AST.Type.tuns64);
734             nextToken();
735             break;
736 
737         case TOK.float32Literal:
738             e = new AST.RealExp(loc, token.floatvalue, AST.Type.tfloat32);
739             nextToken();
740             break;
741 
742         case TOK.float64Literal:
743             e = new AST.RealExp(loc, token.floatvalue, AST.Type.tfloat64);
744             nextToken();
745             break;
746 
747         case TOK.float80Literal:
748             e = new AST.RealExp(loc, token.floatvalue, AST.Type.tfloat80);
749             nextToken();
750             break;
751 
752         case TOK.imaginary32Literal:
753             e = new AST.RealExp(loc, token.floatvalue, AST.Type.timaginary32);
754             nextToken();
755             break;
756 
757         case TOK.imaginary64Literal:
758             e = new AST.RealExp(loc, token.floatvalue, AST.Type.timaginary64);
759             nextToken();
760             break;
761 
762         case TOK.imaginary80Literal:
763             e = new AST.RealExp(loc, token.floatvalue, AST.Type.timaginary80);
764             nextToken();
765             break;
766 
767         case TOK.string_:
768         {
769             // cat adjacent strings
770             auto s = token.ustring;
771             auto len = token.len;
772             auto postfix = token.postfix;
773             while (1)
774             {
775                 nextToken();
776                 if (token.value == TOK.string_)
777                 {
778                     if (token.postfix)
779                     {
780                         if (token.postfix != postfix)
781                             error(token.loc, "mismatched string literal postfixes `'%c'` and `'%c'`", postfix, token.postfix);
782                         postfix = token.postfix;
783                     }
784 
785                     const len1 = len;
786                     const len2 = token.len;
787                     len = len1 + len2;
788                     auto s2 = cast(char*)mem.xmalloc_noscan(len * char.sizeof);
789                     memcpy(s2, s, len1 * char.sizeof);
790                     memcpy(s2 + len1, token.ustring, len2 * char.sizeof);
791                     s = s2;
792                 }
793                 else
794                     break;
795             }
796             e = new AST.StringExp(loc, s[0 .. len], len, 1, postfix);
797             break;
798         }
799 
800         case TOK.leftParenthesis:
801             nextToken();
802             if (token.value == TOK.leftCurly)
803                 e = cparseStatementExpression();        // gcc extension
804             else
805                 e = cparseExpression();
806             check(TOK.rightParenthesis);
807             break;
808 
809         case TOK._Generic:
810             e = cparseGenericSelection();
811             break;
812 
813         case TOK._assert:  // __check(assign-exp) extension
814             nextToken();
815             check(TOK.leftParenthesis, "`__check`");
816             e = parseAssignExp();
817             check(TOK.rightParenthesis);
818             e = new AST.AssertExp(loc, e, null);
819             break;
820 
821         default:
822             error("expression expected, not `%s`", token.toChars());
823             // Anything for e, as long as it's not NULL
824             e = new AST.IntegerExp(loc, 0, AST.Type.tint32);
825             nextToken();
826             break;
827         }
828         return e;
829     }
830 
831     /*********************************
832      * C11 6.5.2
833      * postfix-expression:
834      *    primary-expression
835      *    postfix-expression [ expression ]
836      *    postfix-expression ( argument-expression-list (opt) )
837      *    postfix-expression . identifier
838      *    postfix-expression -> identifier
839      *    postfix-expression ++
840      *    postfix-expression --
841      *    ( type-name ) { initializer-list }
842      *    ( type-name ) { initializer-list , }
843      *
844      * argument-expression-list:
845      *    assignment-expression
846      *    argument-expression-list , assignment-expression
847      */
848     private AST.Expression cparsePostfixExp(AST.Expression e)
849     {
850         e = cparsePrimaryExp();
851         return cparsePostfixOperators(e);
852     }
853 
854     /********************************
855      * C11 6.5.2
856      * Parse a series of operators for a postfix expression after already parsing
857      * a primary-expression or compound literal expression.
858      * Params:
859      *      e = parsed primary or compound literal expression
860      * Returns:
861      *      parsed postfix expression
862      */
863     private AST.Expression cparsePostfixOperators(AST.Expression e)
864     {
865         while (1)
866         {
867             const loc = token.loc;
868             switch (token.value)
869             {
870             case TOK.dot:
871                 nextToken();
872                 if (token.value == TOK.identifier)
873                 {
874                     Identifier id = token.ident;
875                     e = new AST.DotIdExp(loc, e, id);
876                     break;
877                 }
878                 error("identifier expected following `.`, not `%s`", token.toChars());
879                 break;
880 
881             case TOK.arrow:
882                 nextToken();
883                 if (token.value == TOK.identifier)
884                 {
885                     Identifier id = token.ident;
886                     auto die = new AST.DotIdExp(loc, e, id);
887                     die.arrow = true;
888                     e = die;
889                     break;
890                 }
891                 error("identifier expected following `->`, not `%s`", token.toChars());
892                 break;
893 
894             case TOK.plusPlus:
895                 e = new AST.PostExp(EXP.plusPlus, loc, e);
896                 break;
897 
898             case TOK.minusMinus:
899                 e = new AST.PostExp(EXP.minusMinus, loc, e);
900                 break;
901 
902             case TOK.leftParenthesis:
903                 e = new AST.CallExp(loc, e, cparseArguments());
904                 continue;
905 
906             case TOK.leftBracket:
907                 {
908                     // array dereferences:
909                     //      array[index]
910                     AST.Expression index;
911                     auto arguments = new AST.Expressions();
912 
913                     inBrackets++;
914                     nextToken();
915                     index = cparseAssignExp();
916                     arguments.push(index);
917                     check(TOK.rightBracket);
918                     inBrackets--;
919                     e = new AST.ArrayExp(loc, e, arguments);
920                     continue;
921                 }
922             default:
923                 return e;
924             }
925             nextToken();
926         }
927     }
928 
929     /************************
930      * C11 6.5.3
931      * unary-expression:
932      *    postfix-expression
933      *    ++ unary-expression
934      *    -- unary-expression
935      *    unary-operator cast-expression
936      *    sizeof unary-expression
937      *    sizeof ( type-name )
938      *    _Alignof ( type-name )
939      *
940      * unary-operator:
941      *    & * + - ~ !
942      */
943     private AST.Expression cparseUnaryExp()
944     {
945         AST.Expression e;
946         const loc = token.loc;
947 
948         switch (token.value)
949         {
950         case TOK.plusPlus:
951             nextToken();
952             // Parse `++` as an unary operator so that cast expressions only give
953             // an error for being non-lvalues.
954             e = cparseCastExp();
955             e = new AST.PreExp(EXP.prePlusPlus, loc, e);
956             break;
957 
958         case TOK.minusMinus:
959             nextToken();
960             // Parse `--` as an unary operator, same as prefix increment.
961             e = cparseCastExp();
962             e = new AST.PreExp(EXP.preMinusMinus, loc, e);
963             break;
964 
965         case TOK.and:
966             nextToken();
967             e = cparseCastExp();
968             e = new AST.AddrExp(loc, e);
969             break;
970 
971         case TOK.mul:
972             nextToken();
973             e = cparseCastExp();
974             e = new AST.PtrExp(loc, e);
975             break;
976 
977         case TOK.min:
978             nextToken();
979             e = cparseCastExp();
980             e = new AST.NegExp(loc, e);
981             break;
982 
983         case TOK.add:
984             nextToken();
985             e = cparseCastExp();
986             e = new AST.UAddExp(loc, e);
987             break;
988 
989         case TOK.not:
990             nextToken();
991             e = cparseCastExp();
992             e = new AST.NotExp(loc, e);
993             break;
994 
995         case TOK.tilde:
996             nextToken();
997             e = cparseCastExp();
998             e = new AST.ComExp(loc, e);
999             break;
1000 
1001         case TOK.sizeof_:
1002         {
1003             nextToken();
1004             if (token.value == TOK.leftParenthesis)
1005             {
1006                 auto tk = peek(&token);
1007                 if (isTypeName(tk))
1008                 {
1009                     /* Expression may be either be requesting the sizeof a type-name
1010                      * or a compound literal, which requires checking whether
1011                      * the next token is leftCurly
1012                      */
1013                     nextToken();
1014                     auto t = cparseTypeName();
1015                     check(TOK.rightParenthesis);
1016                     if (token.value == TOK.leftCurly)
1017                     {
1018                         // ( type-name ) { initializer-list }
1019                         auto ci = cparseInitializer();
1020                         e = new AST.CompoundLiteralExp(loc, t, ci);
1021                         e = cparsePostfixOperators(e);
1022                     }
1023                     else
1024                     {
1025                         // ( type-name )
1026                         e = new AST.TypeExp(loc, t);
1027                     }
1028                 }
1029                 else
1030                 {
1031                     // must be an expression
1032                     e = cparseUnaryExp();
1033                 }
1034             }
1035             else
1036             {
1037                 //C11 6.5.3
1038                 e = cparseUnaryExp();
1039             }
1040 
1041             e = new AST.DotIdExp(loc, e, Id.__sizeof);
1042             break;
1043         }
1044 
1045         case TOK._Alignof:
1046         {
1047             nextToken();
1048             check(TOK.leftParenthesis);
1049             auto t = cparseTypeName();
1050             check(TOK.rightParenthesis);
1051             e = new AST.TypeExp(loc, t);
1052             e = new AST.DotIdExp(loc, e, Id.__xalignof);
1053             break;
1054         }
1055 
1056         default:
1057             e = cparsePostfixExp(e);
1058             break;
1059         }
1060         assert(e);
1061         return e;
1062     }
1063 
1064     /**************
1065      * C11 6.5.4
1066      * cast-expression
1067      *    unary-expression
1068      *    ( type-name ) cast-expression
1069      */
1070     private AST.Expression cparseCastExp()
1071     {
1072         if (token.value == TOK.leftParenthesis)
1073         {
1074             //printf("cparseCastExp()\n");
1075             auto tk = peek(&token);
1076             bool iscast;
1077             bool isexp;
1078             if (tk.value == TOK.identifier)
1079             {
1080                 iscast = isTypedef(tk.ident);
1081                 isexp = !iscast;
1082             }
1083             if (isexp)
1084             {
1085                 // ( identifier ) is an expression
1086                 return cparseUnaryExp();
1087             }
1088 
1089             // If ( type-name )
1090             auto pt = &token;
1091 
1092             if (isCastExpression(pt))
1093             {
1094                 // Expression may be either a cast or a compound literal, which
1095                 // requires checking whether the next token is leftCurly
1096                 const loc = token.loc;
1097                 nextToken();
1098                 auto t = cparseTypeName();
1099                 check(TOK.rightParenthesis);
1100                 pt = &token;
1101 
1102                 if (token.value == TOK.leftCurly)
1103                 {
1104                     // C11 6.5.2.5 ( type-name ) { initializer-list }
1105                     auto ci = cparseInitializer();
1106                     auto ce = new AST.CompoundLiteralExp(loc, t, ci);
1107                     return cparsePostfixOperators(ce);
1108                 }
1109 
1110                 if (iscast)
1111                 {
1112                     // ( type-name ) cast-expression
1113                     auto ce = cparseCastExp();
1114                     return new AST.CastExp(loc, ce, t);
1115                 }
1116 
1117                 if (t.isTypeIdentifier() &&
1118                     isexp &&
1119                     token.value == TOK.leftParenthesis &&
1120                     !isCastExpression(pt))
1121                 {
1122                     /* (t)(...)... might be a cast expression or a function call,
1123                      * with different grammars: a cast would be cparseCastExp(),
1124                      * a function call would be cparsePostfixExp(CallExp(cparseArguments())).
1125                      * We can't know until t is known. So, parse it as a function call
1126                      * and let semantic() rewrite the AST as a CastExp if it turns out
1127                      * to be a type.
1128                      */
1129                     auto ie = new AST.IdentifierExp(loc, t.isTypeIdentifier().ident);
1130                     ie.parens = true;    // let semantic know it might be a CastExp
1131                     AST.Expression e = new AST.CallExp(loc, ie, cparseArguments());
1132                     return cparsePostfixOperators(e);
1133                 }
1134 
1135                 // ( type-name ) cast-expression
1136                 auto ce = cparseCastExp();
1137                 return new AST.CastExp(loc, ce, t);
1138             }
1139         }
1140         return cparseUnaryExp();
1141     }
1142 
1143     /**************
1144      * C11 6.5.5
1145      * multiplicative-expression
1146      *    cast-expression
1147      *    multiplicative-expression * cast-expression
1148      *    multiplicative-expression / cast-expression
1149      *    multiplicative-expression % cast-expression
1150      */
1151     private AST.Expression cparseMulExp()
1152     {
1153         const loc = token.loc;
1154         auto e = cparseCastExp();
1155 
1156         while (1)
1157         {
1158             switch (token.value)
1159             {
1160             case TOK.mul:
1161                 nextToken();
1162                 auto e2 = cparseCastExp();
1163                 e = new AST.MulExp(loc, e, e2);
1164                 continue;
1165 
1166             case TOK.div:
1167                 nextToken();
1168                 auto e2 = cparseCastExp();
1169                 e = new AST.DivExp(loc, e, e2);
1170                 continue;
1171 
1172             case TOK.mod:
1173                 nextToken();
1174                 auto e2 = cparseCastExp();
1175                 e = new AST.ModExp(loc, e, e2);
1176                 continue;
1177 
1178             default:
1179                 break;
1180             }
1181             break;
1182         }
1183         return e;
1184     }
1185 
1186     /**************
1187      * C11 6.5.6
1188      * additive-expression
1189      *    multiplicative-expression
1190      *    additive-expression + multiplicative-expression
1191      *    additive-expression - multiplicative-expression
1192      */
1193     private AST.Expression cparseAddExp()
1194     {
1195         const loc = token.loc;
1196         auto e = cparseMulExp();
1197 
1198         while (1)
1199         {
1200             switch (token.value)
1201             {
1202             case TOK.add:
1203                 nextToken();
1204                 auto e2 = cparseMulExp();
1205                 e = new AST.AddExp(loc, e, e2);
1206                 continue;
1207 
1208             case TOK.min:
1209                 nextToken();
1210                 auto e2 = cparseMulExp();
1211                 e = new AST.MinExp(loc, e, e2);
1212                 continue;
1213 
1214             default:
1215                 break;
1216             }
1217             break;
1218         }
1219         return e;
1220     }
1221 
1222     /**************
1223      * C11 6.5.7
1224      * shift-expression
1225      *    additive-expression
1226      *    shift-expression << additive-expression
1227      *    shift-expression >> additive-expression
1228      */
1229     private AST.Expression cparseShiftExp()
1230     {
1231         const loc = token.loc;
1232         auto e = cparseAddExp();
1233 
1234         while (1)
1235         {
1236             switch (token.value)
1237             {
1238             case TOK.leftShift:
1239                 nextToken();
1240                 auto e2 = cparseAddExp();
1241                 e = new AST.ShlExp(loc, e, e2);
1242                 continue;
1243 
1244             case TOK.rightShift:
1245                 nextToken();
1246                 auto e2 = cparseAddExp();
1247                 e = new AST.ShrExp(loc, e, e2);
1248                 continue;
1249 
1250             default:
1251                 break;
1252             }
1253             break;
1254         }
1255         return e;
1256     }
1257 
1258     /**************
1259      * C11 6.5.8
1260      * relational-expression
1261      *    shift-expression
1262      *    relational-expression < shift-expression
1263      *    relational-expression > shift-expression
1264      *    relational-expression <= shift-expression
1265      *    relational-expression >= shift-expression
1266      */
1267     private AST.Expression cparseRelationalExp()
1268     {
1269         const loc = token.loc;
1270 
1271         auto e = cparseShiftExp();
1272 
1273         EXP op = EXP.reserved;
1274         switch (token.value)
1275         {
1276         case TOK.lessThan:       op = EXP.lessThan; goto Lcmp;
1277         case TOK.lessOrEqual:    op = EXP.lessOrEqual; goto Lcmp;
1278         case TOK.greaterThan:    op = EXP.greaterThan; goto Lcmp;
1279         case TOK.greaterOrEqual: op = EXP.greaterOrEqual; goto Lcmp;
1280         Lcmp:
1281             nextToken();
1282             auto e2 = cparseShiftExp();
1283             e = new AST.CmpExp(op, loc, e, e2);
1284             break;
1285 
1286         default:
1287             break;
1288         }
1289         return e;
1290     }
1291 
1292     /**************
1293      * C11 6.5.9
1294      * equality-expression
1295      *    relational-expression
1296      *    equality-expression == relational-expression
1297      *    equality-expression != relational-expression
1298      */
1299     private AST.Expression cparseEqualityExp()
1300     {
1301         const loc = token.loc;
1302 
1303         auto e = cparseRelationalExp();
1304 
1305         EXP op = EXP.reserved;
1306         switch (token.value)
1307         {
1308         case TOK.equal:         op = EXP.equal;    goto Lequal;
1309         case TOK.notEqual:      op = EXP.notEqual; goto Lequal;
1310         Lequal:
1311             nextToken();
1312             auto e2 = cparseRelationalExp();
1313             e = new AST.EqualExp(op, loc, e, e2);
1314             break;
1315 
1316         default:
1317             break;
1318         }
1319         return e;
1320     }
1321 
1322     /**************
1323      * C11 6.5.10
1324      * AND-expression
1325      *    equality-expression
1326      *    AND-expression & equality-expression
1327      */
1328     private AST.Expression cparseAndExp()
1329     {
1330         Loc loc = token.loc;
1331         auto e = cparseEqualityExp();
1332         while (token.value == TOK.and)
1333         {
1334             nextToken();
1335             auto e2 = cparseEqualityExp();
1336             e = new AST.AndExp(loc, e, e2);
1337             loc = token.loc;
1338         }
1339         return e;
1340     }
1341 
1342     /**************
1343      * C11 6.5.11
1344      * exclusive-OR-expression
1345      *    AND-expression
1346      *    exclusive-OR-expression ^ AND-expression
1347      */
1348     private AST.Expression cparseXorExp()
1349     {
1350         const loc = token.loc;
1351 
1352         auto e = cparseAndExp();
1353         while (token.value == TOK.xor)
1354         {
1355             nextToken();
1356             auto e2 = cparseAndExp();
1357             e = new AST.XorExp(loc, e, e2);
1358         }
1359         return e;
1360     }
1361 
1362     /**************
1363      * C11 6.5.12
1364      * inclusive-OR-expression
1365      *    exclusive-OR-expression
1366      *    inclusive-OR-expression | exclusive-OR-expression
1367      */
1368     private AST.Expression cparseOrExp()
1369     {
1370         const loc = token.loc;
1371 
1372         auto e = cparseXorExp();
1373         while (token.value == TOK.or)
1374         {
1375             nextToken();
1376             auto e2 = cparseXorExp();
1377             e = new AST.OrExp(loc, e, e2);
1378         }
1379         return e;
1380     }
1381 
1382     /**************
1383      * C11 6.5.13
1384      * logical-AND-expression
1385      *    inclusive-OR-expression
1386      *    logical-AND-expression && inclusive-OR-expression
1387      */
1388     private AST.Expression cparseAndAndExp()
1389     {
1390         const loc = token.loc;
1391 
1392         auto e = cparseOrExp();
1393         while (token.value == TOK.andAnd)
1394         {
1395             nextToken();
1396             auto e2 = cparseOrExp();
1397             e = new AST.LogicalExp(loc, EXP.andAnd, e, e2);
1398         }
1399         return e;
1400     }
1401 
1402     /**************
1403      * C11 6.5.14
1404      * logical-OR-expression
1405      *    logical-AND-expression
1406      *    logical-OR-expression || logical-AND-expression
1407      */
1408     private AST.Expression cparseOrOrExp()
1409     {
1410         const loc = token.loc;
1411 
1412         auto e = cparseAndAndExp();
1413         while (token.value == TOK.orOr)
1414         {
1415             nextToken();
1416             auto e2 = cparseAndAndExp();
1417             e = new AST.LogicalExp(loc, EXP.orOr, e, e2);
1418         }
1419         return e;
1420     }
1421 
1422     /**************
1423      * C11 6.5.15
1424      * conditional-expression:
1425      *    logical-OR-expression
1426      *    logical-OR-expression ? expression : conditional-expression
1427      */
1428     private AST.Expression cparseCondExp()
1429     {
1430         const loc = token.loc;
1431 
1432         auto e = cparseOrOrExp();
1433         if (token.value == TOK.question)
1434         {
1435             nextToken();
1436             auto e1 = cparseExpression();
1437             check(TOK.colon);
1438             auto e2 = cparseCondExp();
1439             e = new AST.CondExp(loc, e, e1, e2);
1440         }
1441         return e;
1442     }
1443 
1444     /**************
1445      * C11 6.5.16
1446      * assignment-expression:
1447      *    conditional-expression
1448      *    unary-expression assignment-operator assignment-expression
1449      *
1450      * assignment-operator:
1451      *    = *= /= %= += -= <<= >>= &= ^= |=
1452      */
1453     AST.Expression cparseAssignExp()
1454     {
1455         AST.Expression e;
1456         e = cparseCondExp(); // constrain it to being unary-expression in semantic pass
1457         if (e is null)
1458             return e;
1459 
1460         const loc = token.loc;
1461         switch (token.value)
1462         {
1463         case TOK.assign:
1464             nextToken();
1465             auto e2 = cparseAssignExp();
1466             e = new AST.AssignExp(loc, e, e2);
1467             break;
1468 
1469         case TOK.addAssign:
1470             nextToken();
1471             auto e2 = cparseAssignExp();
1472             e = new AST.AddAssignExp(loc, e, e2);
1473             break;
1474 
1475         case TOK.minAssign:
1476             nextToken();
1477             auto e2 = cparseAssignExp();
1478             e = new AST.MinAssignExp(loc, e, e2);
1479             break;
1480 
1481         case TOK.mulAssign:
1482             nextToken();
1483             auto e2 = cparseAssignExp();
1484             e = new AST.MulAssignExp(loc, e, e2);
1485             break;
1486 
1487         case TOK.divAssign:
1488             nextToken();
1489             auto e2 = cparseAssignExp();
1490             e = new AST.DivAssignExp(loc, e, e2);
1491             break;
1492 
1493         case TOK.modAssign:
1494             nextToken();
1495             auto e2 = cparseAssignExp();
1496             e = new AST.ModAssignExp(loc, e, e2);
1497             break;
1498 
1499         case TOK.andAssign:
1500             nextToken();
1501             auto e2 = cparseAssignExp();
1502             e = new AST.AndAssignExp(loc, e, e2);
1503             break;
1504 
1505         case TOK.orAssign:
1506             nextToken();
1507             auto e2 = cparseAssignExp();
1508             e = new AST.OrAssignExp(loc, e, e2);
1509             break;
1510 
1511         case TOK.xorAssign:
1512             nextToken();
1513             auto e2 = cparseAssignExp();
1514             e = new AST.XorAssignExp(loc, e, e2);
1515             break;
1516 
1517         case TOK.leftShiftAssign:
1518             nextToken();
1519             auto e2 = cparseAssignExp();
1520             e = new AST.ShlAssignExp(loc, e, e2);
1521             break;
1522 
1523         case TOK.rightShiftAssign:
1524             nextToken();
1525             auto e2 = cparseAssignExp();
1526             e = new AST.ShrAssignExp(loc, e, e2);
1527             break;
1528 
1529         default:
1530             break;
1531         }
1532 
1533         return e;
1534     }
1535 
1536     /***********************
1537      * C11 6.5.1.1
1538      * _Generic ( assignment-expression, generic-assoc-list )
1539      *
1540      * generic-assoc-list:
1541      *   generic-association
1542      *   generic-assoc-list generic-association
1543      *
1544      * generic-association:
1545      *   type-name : assignment-expression
1546      *   default : assignment-expression
1547      */
1548     private AST.Expression cparseGenericSelection()
1549     {
1550         const loc = token.loc;
1551         nextToken();
1552         check(TOK.leftParenthesis);
1553         auto cntlExp = cparseAssignExp();
1554         check(TOK.comma);
1555         auto types = new AST.Types();
1556         auto exps = new AST.Expressions();
1557         bool sawDefault;
1558         while (1)
1559         {
1560             AST.Type t;
1561             if (token.value == TOK.default_)
1562             {
1563                 nextToken();
1564                 if (sawDefault)
1565                     error("only one `default` allowed in generic-assoc-list");
1566                 sawDefault = true;
1567                 t = null;
1568             }
1569             else
1570                 t = cparseTypeName();
1571             types.push(t);
1572 
1573             check(TOK.colon);
1574             auto e = cparseAssignExp();
1575             exps.push(e);
1576             if (token.value == TOK.rightParenthesis || token.value == TOK.endOfFile)
1577                 break;
1578             check(TOK.comma);
1579         }
1580         check(TOK.rightParenthesis);
1581         return new AST.GenericExp(loc, cntlExp, types, exps);
1582     }
1583 
1584     /***********************
1585      * C11 6.6 Constant expressions
1586      * constant-expression:
1587      *   conditional-expression
1588      */
1589     private AST.Expression cparseConstantExp()
1590     {
1591         return cparseAssignExp();
1592     }
1593 
1594     /*****************************
1595      * gcc extension:
1596      *    type __builtin_va_arg(assign-expression, type)
1597      * Rewrite as `va_arg` template from `core.stdc.stdarg`:
1598      *    va_arg!(type)(assign-expression);
1599      * Lexer is on `__builtin_va_arg`
1600      */
1601     private AST.Expression cparseBuiltin_va_arg()
1602     {
1603         importBuiltins = true;  // need core.stdc.stdarg
1604 
1605         nextToken();
1606         check(TOK.leftParenthesis);
1607 
1608         auto arguments = new AST.Expressions();
1609         auto arg = cparseAssignExp();
1610         arguments.push(arg);
1611 
1612         check(TOK.comma);
1613 
1614         auto t = cparseTypeName();
1615         auto tiargs = new AST.Objects();
1616         tiargs.push(t);
1617 
1618         const loc = loc;
1619         auto ti = new AST.TemplateInstance(loc, Id.va_arg, tiargs);
1620         auto tie = new AST.ScopeExp(loc, ti);
1621 
1622         AST.Expression e = new AST.CallExp(loc, tie, arguments);
1623 
1624         check(TOK.rightParenthesis);
1625         return e;
1626     }
1627 
1628     /*****************************
1629      * gcc extension: https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html
1630      * Represent as a function literal, then call the function literal.
1631      * Parser is on opening curly brace.
1632      */
1633     private AST.Expression cparseStatementExpression()
1634     {
1635         AST.ParameterList parameterList;
1636         StorageClass stc = 0;
1637         const loc = token.loc;
1638         typedefTab.push(null);
1639         auto fbody = cparseStatement(ParseStatementFlags.scope_);
1640         typedefTab.pop();                                        // end of function scope
1641 
1642         // Rewrite last ExpStatement (if there is one) as a ReturnStatement
1643         auto ss = fbody.isScopeStatement();
1644         auto cs = ss.statement.isCompoundStatement();
1645         assert(cs);
1646         if (const len = (*cs.statements).length)
1647         {
1648             auto s = (*cs.statements)[len - 1];
1649             if (auto es = s.isExpStatement())
1650                 (*cs.statements)[len - 1] = new AST.ReturnStatement(es.loc, es.exp);
1651         }
1652 
1653         auto tf = new AST.TypeFunction(parameterList, null, LINK.d, stc);
1654         auto fd = new AST.FuncLiteralDeclaration(loc, token.loc, tf, TOK.delegate_, null, null, 0);
1655         fd.fbody = fbody;
1656 
1657         auto fe = new AST.FuncExp(loc, fd);
1658         auto args = new AST.Expressions();
1659         auto e = new AST.CallExp(loc, fe, args);   // call the function literal
1660         return e;
1661     }
1662 
1663     //}
1664     /********************************************************************************/
1665     /********************************* Declaration Parser ***************************/
1666     //{
1667 
1668     /*************************************
1669      * C11 6.7
1670      * declaration:
1671      *    declaration-specifiers init-declarator-list (opt) ;
1672      *    static_assert-declaration
1673      *
1674      * init-declarator-list:
1675      *    init-declarator
1676      *    init-declarator-list , init-declarator
1677      *
1678      * init-declarator:
1679      *    declarator
1680      *    declarator = initializer
1681      *
1682      * Params:
1683      *    level = declaration context
1684      */
1685     void cparseDeclaration(LVL level)
1686     {
1687         //printf("cparseDeclaration(level = %d)\n", level);
1688         if (token.value == TOK._Static_assert)
1689         {
1690             auto s = cparseStaticAssert();
1691             symbols.push(s);
1692             return;
1693         }
1694 
1695         if (token.value == TOK.__pragma)
1696         {
1697             uupragmaDirective(scanloc);
1698             return;
1699         }
1700 
1701         if (token.value == TOK._import) // import declaration extension
1702         {
1703             auto a = parseImport();
1704             if (a && a.length)
1705                 symbols.append(a);
1706             return;
1707         }
1708 
1709         const typedefTabLengthSave = typedefTab.length;
1710         auto symbolsSave = symbols;
1711         Specifier specifier;
1712         specifier.packalign = this.packalign;
1713         auto tspec = cparseDeclarationSpecifiers(level, specifier);
1714 
1715         AST.Dsymbol declareTag(AST.TypeTag tt, ref Specifier specifier)
1716         {
1717             /* `struct tag;` and `struct tag { ... };`
1718              * always result in a declaration in the current scope
1719              */
1720             auto stag = (tt.tok == TOK.struct_) ? new AST.StructDeclaration(tt.loc, tt.id, false) :
1721                         (tt.tok == TOK.union_)  ? new AST.UnionDeclaration(tt.loc, tt.id) :
1722                                                   new AST.EnumDeclaration(tt.loc, tt.id, tt.base);
1723             if (!tt.packalign.isUnknown())
1724             {
1725                 // saw `struct __declspec(align(N)) Tag ...`
1726                 auto st = stag.isStructDeclaration();
1727                 st.alignment = tt.packalign;
1728             }
1729             stag.members = tt.members;
1730             tt.members = null;
1731             if (!symbols)
1732                 symbols = new AST.Dsymbols();
1733             auto stags = applySpecifier(stag, specifier);
1734             symbols.push(stags);
1735             return stags;
1736         }
1737 
1738         /* If a declarator does not follow, it is unnamed
1739          */
1740         if (token.value == TOK.semicolon)
1741         {
1742             if (!tspec)
1743             {
1744                 nextToken();
1745                 return;         // accept empty declaration as an extension
1746             }
1747 
1748             if (auto ti = tspec.isTypeIdentifier())
1749             {
1750                 // C11 6.7.2-2
1751                 error("type-specifier missing for declaration of `%s`", ti.ident.toChars());
1752                 nextToken();
1753                 return;
1754             }
1755 
1756             nextToken();
1757             auto tt = tspec.isTypeTag();
1758             if (!tt ||
1759                 !tt.id && (tt.tok == TOK.struct_ || tt.tok == TOK.union_))
1760                 return; // legal but meaningless empty declaration, ignore it
1761 
1762             auto stags = declareTag(tt, specifier);
1763 
1764             if (0 && tt.tok == TOK.enum_)    // C11 proscribes enums with no members, but we allow it
1765             {
1766                 if (!tt.members)
1767                     error(tt.loc, "`enum %s` has no members", stags.toChars());
1768             }
1769             return;
1770         }
1771 
1772         if (!tspec)
1773         {
1774             error("no type for declarator before `%s`", token.toChars());
1775             panic();
1776             nextToken();
1777             return;
1778         }
1779 
1780         if (tspec && specifier.mod & MOD.xconst)
1781         {
1782             tspec = toConst(tspec);
1783             specifier.mod &= ~MOD.xnone;          // 'used' it
1784         }
1785 
1786         void scanPastSemicolon()
1787         {
1788             while (token.value != TOK.semicolon && token.value != TOK.endOfFile)
1789                 nextToken();
1790             nextToken();
1791         }
1792 
1793         if (token.value == TOK.assign && tspec && tspec.isTypeIdentifier())
1794         {
1795             /* C11 6.7.2-2
1796              * Special check for `const b = 1;` because some compilers allow it
1797              */
1798             error("type-specifier omitted for declaration of `%s`", tspec.isTypeIdentifier().ident.toChars());
1799             return scanPastSemicolon();
1800         }
1801 
1802         bool first = true;
1803         while (1)
1804         {
1805             Identifier id;
1806             AST.StringExp asmName;
1807             auto dt = cparseDeclarator(DTR.xdirect, tspec, id, specifier);
1808             if (!dt)
1809             {
1810                 panic();
1811                 nextToken();
1812                 break;          // error recovery
1813             }
1814 
1815             /* GNU Extensions
1816              * init-declarator:
1817              *    declarator simple-asm-expr (opt) gnu-attributes (opt)
1818              *    declarator simple-asm-expr (opt) gnu-attributes (opt) = initializer
1819              */
1820             switch (token.value)
1821             {
1822                 case TOK.assign:
1823                 case TOK.comma:
1824                 case TOK.semicolon:
1825                 case TOK.asm_:
1826                 case TOK.__attribute__:
1827                     if (token.value == TOK.asm_)
1828                         asmName = cparseGnuAsmLabel();
1829                     if (token.value == TOK.__attribute__)
1830                     {
1831                         cparseGnuAttributes(specifier);
1832                         if (token.value == TOK.leftCurly)
1833                             break;              // function definition
1834                     }
1835                     /* This is a data definition, there cannot now be a
1836                      * function definition.
1837                      */
1838                     first = false;
1839                     break;
1840 
1841                 default:
1842                     break;
1843             }
1844 
1845             if (specifier.alignExps && dt.isTypeFunction())
1846                 error("no alignment-specifier for function declaration"); // C11 6.7.5-2
1847             if (specifier.alignExps && specifier.scw == SCW.xregister)
1848                 error("no alignment-specifier for `register` storage class"); // C11 6.7.5-2
1849 
1850             /* C11 6.9.1 Function Definitions
1851              * function-definition:
1852              *   declaration-specifiers declarator declaration-list (opt) compound-statement
1853              *
1854              * declaration-list:
1855              *    declaration
1856              *    declaration-list declaration
1857              */
1858             auto t = &token;
1859             if (first &&                   // first declarator
1860                 id &&
1861                 dt.isTypeFunction() &&     // function type not inherited from a typedef
1862                 isDeclarationList(t) &&    // optional declaration-list
1863                 level == LVL.global &&     // function definitions only at global scope
1864                 t.value == TOK.leftCurly)  // start of compound-statement
1865             {
1866                 auto s = cparseFunctionDefinition(id, dt.isTypeFunction(), specifier);
1867                 typedefTab.setDim(typedefTabLengthSave);
1868                 symbols = symbolsSave;
1869                 symbols.push(s);
1870                 return;
1871             }
1872             AST.Dsymbol s = null;
1873             typedefTab.setDim(typedefTabLengthSave);
1874             symbols = symbolsSave;
1875             if (!symbols)
1876                 symbols = new AST.Dsymbols;     // lazilly create it
1877 
1878             if (level != LVL.global && !tspec && !specifier.scw && !specifier.mod)
1879                 error("declaration-specifier-seq required");
1880             else if (specifier.scw == SCW.xtypedef)
1881             {
1882                 if (token.value == TOK.assign)
1883                     error("no initializer for typedef declaration");
1884                 if (specifier.alignExps)
1885                     error("no alignment-specifier for typedef declaration"); // C11 6.7.5-2
1886 
1887                 bool isalias = true;
1888                 if (auto ts = dt.isTypeStruct())
1889                 {
1890                     if (ts.sym.isAnonymous())
1891                     {
1892                         // This is a typedef for an anonymous struct-or-union.
1893                         // Directly set the ident for the struct-or-union.
1894                         ts.sym.ident = id;
1895                         isalias = false;
1896                     }
1897                 }
1898                 else if (auto te = dt.isTypeEnum())
1899                 {
1900                     if (te.sym.isAnonymous())
1901                     {
1902                         // This is a typedef for an anonymous enum.
1903                         te.sym.ident = id;
1904                         isalias = false;
1905                     }
1906                 }
1907                 else if (auto tt = dt.isTypeTag())
1908                 {
1909                     if (tt.id || tt.tok == TOK.enum_)
1910                     {
1911                         if (!tt.id && id)
1912                             tt.id = id;
1913                         Specifier spec;
1914                         auto stag = declareTag(tt, spec);
1915                         if (tt.tok == TOK.enum_)
1916                         {
1917                             isalias = false;
1918                             s = new AST.AliasDeclaration(token.loc, id, stag);
1919                         }
1920                     }
1921                 }
1922                 if (isalias)
1923                     s = new AST.AliasDeclaration(token.loc, id, dt);
1924                 insertTypedefToTypedefTab(id, dt);       // remember typedefs
1925             }
1926             else if (id)
1927             {
1928                 if (auto tt = dt.isTypeTag())
1929                 {
1930                     if (tt.members && (tt.id || tt.tok == TOK.enum_))
1931                     {
1932                         Specifier spec;
1933                         declareTag(tt, spec);
1934                     }
1935                 }
1936 
1937                 if (level == LVL.prototype)
1938                     break;      // declared later as Parameter, not VarDeclaration
1939 
1940                 if (dt.ty == AST.Tvoid)
1941                     error("`void` has no value");
1942 
1943                 AST.Initializer initializer;
1944                 bool hasInitializer;
1945                 if (token.value == TOK.assign)
1946                 {
1947                     nextToken();
1948                     hasInitializer = true;
1949                     initializer = cparseInitializer();
1950                 }
1951                 // declare the symbol
1952                 assert(id);
1953 
1954                 if (isFunctionTypedef(dt))
1955                 {
1956                     if (hasInitializer)
1957                         error("no initializer for function declaration");
1958                     if (specifier.scw & SCW.x_Thread_local)
1959                         error("functions cannot be `_Thread_local`"); // C11 6.7.1-4
1960                     auto fd = new AST.FuncDeclaration(token.loc, Loc.initial, id, specifiersToSTC(level, specifier), dt, specifier.noreturn);
1961                     specifiersToFuncDeclaration(fd, specifier);
1962                     s = fd;
1963                 }
1964                 else
1965                 {
1966                     // Give non-extern variables an implicit void initializer
1967                     // if one has not been explicitly set.
1968                     if (!hasInitializer &&
1969                         !(specifier.scw & (SCW.xextern | SCW.xstatic | SCW.x_Thread_local) || level == LVL.global))
1970                         initializer = new AST.VoidInitializer(token.loc);
1971                     auto vd = new AST.VarDeclaration(token.loc, dt, id, initializer, specifiersToSTC(level, specifier));
1972                     specifiersToVarDeclaration(vd, specifier);
1973                     s = vd;
1974                 }
1975                 if (level != LVL.global)
1976                     insertIdToTypedefTab(id);   // non-typedef declarations can hide typedefs in outer scopes
1977             }
1978             if (s !is null)
1979             {
1980                 // Saw `asm("name")` in the function, type, or variable definition.
1981                 // This is equivalent to `pragma(mangle, "name")` in D
1982                 if (asmName)
1983                 {
1984                     /*
1985                     https://issues.dlang.org/show_bug.cgi?id=23012
1986                     Ideally this would be translated to a pragma(mangle)
1987                     decl. This is not possible because ImportC symbols are
1988                     (currently) merged before semantic analysis is performed,
1989                     so the pragma(mangle) never effects any change on the declarations
1990                     it pertains too.
1991 
1992                     Writing to mangleOverride directly avoids this, and is possible
1993                     because C only a StringExp is allowed unlike a full fat pragma(mangle)
1994                     which is more liberal.
1995                     */
1996                     if (auto p = s.isDeclaration())
1997                     {
1998                         auto str = asmName.peekString();
1999                         p.mangleOverride = str;
2000 //                      p.adFlags |= AST.VarDeclaration.nounderscore;
2001                         p.adFlags |= 4; // cannot get above line to compile on Ubuntu
2002                     }
2003                 }
2004                 s = applySpecifier(s, specifier);
2005                 if (level == LVL.local)
2006                 {
2007                     // Wrap the declaration in `extern (C) { declaration }`
2008                     // Necessary for function pointers, but harmless to apply to all.
2009                     auto decls = new AST.Dsymbols(1);
2010                     (*decls)[0] = s;
2011                     s = new AST.LinkDeclaration(s.loc, linkage, decls);
2012                 }
2013                 symbols.push(s);
2014             }
2015             first = false;
2016 
2017             switch (token.value)
2018             {
2019                 case TOK.identifier:
2020                     if (s)
2021                     {
2022                         error(token.loc, "missing comma or semicolon after declaration of `%s`, found `%s` instead", s.toChars(), token.toChars());
2023                         goto Lend;
2024                     }
2025                     goto default;
2026 
2027                 case TOK.semicolon:
2028                     nextToken();
2029                     return;
2030 
2031                 case TOK.comma:
2032                     if (!symbolsSave)
2033                         symbolsSave = symbols;
2034                     nextToken();
2035                     break;
2036 
2037                 default:
2038                     error("`=`, `;` or `,` expected to end declaration instead of `%s`", token.toChars());
2039                 Lend:
2040                     return scanPastSemicolon();
2041             }
2042         }
2043     }
2044 
2045     /***************************************
2046      * C11 Function Definitions
2047      * function-definition
2048      *    declaration-specifiers declarator declaration-list (opt) compound-statement
2049      *
2050      * declaration-list:
2051      *    declaration
2052      *    declaration-list declaration
2053      *
2054      * It's already been parsed up to the declaration-list (opt).
2055      * Pick it up from there.
2056      * Params:
2057      *    id = function identifier
2058      *    ft = function type
2059      *    specifier = function specifiers
2060      * Returns:
2061      *  Dsymbol for the function
2062      */
2063     AST.Dsymbol cparseFunctionDefinition(Identifier id, AST.TypeFunction ft, ref Specifier specifier)
2064     {
2065         /* Start function scope
2066          */
2067         typedefTab.push(null);
2068 
2069         if (token.value != TOK.leftCurly)       // if not start of a compound-statement
2070         {
2071             // Do declaration-list
2072             do
2073             {
2074                 cparseDeclaration(LVL.parameter);
2075             } while (token.value != TOK.leftCurly);
2076 
2077             /* Since there were declarations, the parameter-list must have been
2078              * an identifier-list.
2079              */
2080             ft.parameterList.hasIdentifierList = true;        // semantic needs to know to adjust parameter types
2081             auto pl = ft.parameterList;
2082             if (pl.varargs != AST.VarArg.none && pl.length)
2083                 error("function identifier-list cannot end with `...`");
2084             ft.parameterList.varargs = AST.VarArg.KRvariadic;   // but C11 allows extra arguments
2085             auto plLength = pl.length;
2086             if (symbols.length != plLength)
2087                 error(token.loc, "%d identifiers does not match %d declarations", cast(int)plLength, cast(int)symbols.length);
2088 
2089             /* Transfer the types and storage classes from symbols[] to pl[]
2090              */
2091             foreach (i; 0 .. plLength)
2092             {
2093                 auto p = pl[i];  // yes, quadratic
2094 
2095                 // Convert typedef-identifier to identifier
2096                 if (p.type)
2097                 {
2098                     if (auto t = p.type.isTypeIdentifier())
2099                     {
2100                         p.ident = t.ident;
2101                         p.type = null;
2102                     }
2103                 }
2104 
2105                 if (p.type || !(p.storageClass & STC.parameter))
2106                     error("storage class and type are not allowed in identifier-list");
2107                 foreach (s; (*symbols)[]) // yes, quadratic
2108                 {
2109                     auto ad = s.isAttribDeclaration();
2110                     if (ad)
2111                         s = (*ad.decl)[0];      // AlignDeclaration wrapping the declaration
2112 
2113                     auto d = s.isDeclaration();
2114                     if (d && p.ident == d.ident && d.type)
2115                     {
2116                         p.type = d.type;
2117                         p.storageClass = d.storage_class;
2118                         d.type = null; // don't reuse
2119                         break;
2120                     }
2121                 }
2122                 if (!p.type)
2123                 {
2124                     error("no declaration for identifier `%s`", p.ident.toChars());
2125                     p.type = AST.Type.terror;
2126                 }
2127             }
2128         }
2129 
2130         addFuncName = false;    // gets set to true if somebody references __func__ in this function
2131         const locFunc = token.loc;
2132 
2133         auto body = cparseStatement(ParseStatementFlags.curly);  // don't start a new scope; continue with parameter scope
2134         typedefTab.pop();                                        // end of function scope
2135 
2136         auto fd = new AST.FuncDeclaration(locFunc, prevloc, id, specifiersToSTC(LVL.global, specifier), ft, specifier.noreturn);
2137         specifiersToFuncDeclaration(fd, specifier);
2138 
2139         if (addFuncName)
2140         {
2141             auto s = createFuncName(locFunc, id);
2142             body = new AST.CompoundStatement(locFunc, s, body);
2143         }
2144         fd.fbody = body;
2145 
2146         // TODO add `symbols` to the function's local symbol table `sc2` in FuncDeclaration::semantic3()
2147 
2148         return fd;
2149     }
2150 
2151     /***************************************
2152      * C11 Initialization
2153      * initializer:
2154      *    assignment-expression
2155      *    { initializer-list }
2156      *    { initializer-list , }
2157      *
2158      * initializer-list:
2159      *    designation (opt) initializer
2160      *    initializer-list , designation (opt) initializer
2161      *
2162      * designation:
2163      *    designator-list =
2164      *
2165      * designator-list:
2166      *    designator
2167      *    designator-list designator
2168      *
2169      * designator:
2170      *    [ constant-expression ]
2171      *    . identifier
2172      * Returns:
2173      *    initializer
2174      */
2175     AST.Initializer cparseInitializer()
2176     {
2177         if (token.value != TOK.leftCurly)
2178         {
2179             auto ae = cparseAssignExp();        // assignment-expression
2180             return new AST.ExpInitializer(token.loc, ae);
2181         }
2182         nextToken();
2183         const loc = token.loc;
2184 
2185         /* Collect one or more `designation (opt) initializer`
2186          * into ci.initializerList, but lazily create ci
2187          */
2188         AST.CInitializer ci;
2189         while (1)
2190         {
2191             /* There can be 0 or more designators preceding an initializer.
2192              * Collect them in desigInit
2193              */
2194             AST.DesigInit desigInit;
2195             while (1)
2196             {
2197                 if (token.value == TOK.leftBracket)     // [ constant-expression ]
2198                 {
2199                     nextToken();
2200                     auto e = cparseConstantExp();
2201                     check(TOK.rightBracket);
2202                     if (!desigInit.designatorList)
2203                         desigInit.designatorList = new AST.Designators;
2204                     desigInit.designatorList.push(AST.Designator(e));
2205                 }
2206                 else if (token.value == TOK.dot)        // . identifier
2207                 {
2208                     nextToken();
2209                     if (token.value != TOK.identifier)
2210                     {
2211                         error("identifier expected following `.` designator");
2212                         break;
2213                     }
2214                     if (!desigInit.designatorList)
2215                         desigInit.designatorList = new AST.Designators;
2216                     desigInit.designatorList.push(AST.Designator(token.ident));
2217                     nextToken();
2218                 }
2219                 else
2220                 {
2221                     if (desigInit.designatorList)
2222                         check(TOK.assign);
2223                     break;
2224                 }
2225             }
2226 
2227             desigInit.initializer = cparseInitializer();
2228             if (!ci)
2229                 ci = new AST.CInitializer(loc);
2230             ci.initializerList.push(desigInit);
2231             if (token.value == TOK.comma)
2232             {
2233                 nextToken();
2234                 if (token.value != TOK.rightCurly)
2235                     continue;
2236             }
2237             break;
2238         }
2239         check(TOK.rightCurly);
2240         //printf("ci: %s\n", ci.toChars());
2241         return ci;
2242     }
2243 
2244     /*************************************
2245      * C11 6.7
2246      * declaration-specifier:
2247      *    storage-class-specifier declaration-specifiers (opt)
2248      *    type-specifier declaration-specifiers (opt)
2249      *    type-qualifier declaration-specifiers (opt)
2250      *    function-specifier declaration-specifiers (opt)
2251      *    alignment-specifier declaration-specifiers (opt)
2252      * Params:
2253      *  level = declaration context
2254      *  specifier = specifiers in and out
2255      * Returns:
2256      *  resulting type, null if not specified
2257      */
2258     private AST.Type cparseDeclarationSpecifiers(LVL level, ref Specifier specifier)
2259     {
2260         enum TKW : uint
2261         {
2262             xnone      = 0,
2263             xchar      = 1,
2264             xsigned    = 2,
2265             xunsigned  = 4,
2266             xshort     = 8,
2267             xint       = 0x10,
2268             xlong      = 0x20,
2269             xllong     = 0x40,
2270             xfloat     = 0x80,
2271             xdouble    = 0x100,
2272             xldouble   = 0x200,
2273             xtag       = 0x400,
2274             xident     = 0x800,
2275             xvoid      = 0x1000,
2276             xbool      = 0x4000,
2277             ximaginary = 0x8000,
2278             xcomplex   = 0x10000,
2279             x_Atomic   = 0x20000,
2280             xint128    = 0x40000,
2281         }
2282 
2283         AST.Type t;
2284         Loc loc;
2285         //printf("parseDeclarationSpecifiers()\n");
2286 
2287         TKW tkw;
2288         SCW scw = specifier.scw & SCW.xtypedef;
2289         MOD mod;
2290         Identifier id;
2291         Identifier previd;
2292 
2293     Lwhile:
2294         while (1)
2295         {
2296             //printf("token %s\n", token.toChars());
2297             TKW tkwx;
2298             SCW scwx;
2299             MOD modx;
2300             switch (token.value)
2301             {
2302                 // Storage class specifiers
2303                 case TOK.static_:    scwx = SCW.xstatic;    break;
2304                 case TOK.extern_:    scwx = SCW.xextern;    break;
2305                 case TOK.auto_:      scwx = SCW.xauto;      break;
2306                 case TOK.register:   scwx = SCW.xregister;  break;
2307                 case TOK.typedef_:   scwx = SCW.xtypedef;   break;
2308                 case TOK.inline:     scwx = SCW.xinline;    break;
2309                 case TOK._Noreturn:  scwx = SCW.x_Noreturn; break;
2310                 case TOK.__thread:
2311                 case TOK._Thread_local: scwx = SCW.x_Thread_local; break;
2312 
2313                 // Type qualifiers
2314                 case TOK.const_:     modx = MOD.xconst;     break;
2315                 case TOK..volatile:   modx = MOD.xvolatile;  break;
2316                 case TOK.restrict:   modx = MOD.xrestrict;  break;
2317                 case TOK.__stdcall:  modx = MOD.x__stdcall; break;
2318 
2319                 // Type specifiers
2320                 case TOK.char_:      tkwx = TKW.xchar;      break;
2321                 case TOK.signed:     tkwx = TKW.xsigned;    break;
2322                 case TOK.unsigned:   tkwx = TKW.xunsigned;  break;
2323                 case TOK.int16:      tkwx = TKW.xshort;     break;
2324                 case TOK.int32:      tkwx = TKW.xint;       break;
2325                 case TOK.int64:      tkwx = TKW.xlong;      break;
2326                 case TOK.__int128:   tkwx = TKW.xint128;    break;
2327                 case TOK.float32:    tkwx = TKW.xfloat;     break;
2328                 case TOK.float64:    tkwx = TKW.xdouble;    break;
2329                 case TOK.void_:      tkwx = TKW.xvoid;      break;
2330                 case TOK._Bool:      tkwx = TKW.xbool;      break;
2331                 case TOK._Imaginary: tkwx = TKW.ximaginary; break;
2332                 case TOK._Complex:   tkwx = TKW.xcomplex;   break;
2333 
2334                 case TOK.identifier:
2335                     tkwx = TKW.xident;
2336                     id = token.ident;
2337                     break;
2338 
2339                 case TOK.struct_:
2340                 case TOK.union_:
2341                 {
2342                     const structOrUnion = token.value;
2343                     const sloc = token.loc;
2344                     nextToken();
2345 
2346                     Specifier tagSpecifier;
2347 
2348                     /* GNU Extensions
2349                      * struct-or-union-specifier:
2350                      *    struct-or-union gnu-attributes (opt) identifier (opt) { struct-declaration-list } gnu-attributes (opt)
2351                      *    struct-or-union gnu-attribute (opt) identifier
2352                      */
2353                     while (1)
2354                     {
2355                         if (token.value == TOK.__attribute__)
2356                             cparseGnuAttributes(tagSpecifier);
2357                         else if (token.value == TOK.__declspec)
2358                             cparseDeclspec(tagSpecifier);
2359                         else
2360                             break;
2361                     }
2362                     t = cparseStruct(sloc, structOrUnion, tagSpecifier.packalign, symbols);
2363                     tkwx = TKW.xtag;
2364                     break;
2365                 }
2366 
2367                 case TOK.enum_:
2368                     t = cparseEnum(symbols);
2369                     tkwx = TKW.xtag;
2370                     break;
2371 
2372                 case TOK._Atomic:
2373                 {
2374                     // C11 6.7.2.4
2375                     // type-specifier if followed by `( type-name )`
2376                     auto tk = peek(&token);
2377                     if (tk.value == TOK.leftParenthesis)
2378                     {
2379                         tk = peek(tk);
2380                         if (isTypeName(tk) && tk.value == TOK.rightParenthesis)
2381                         {
2382                             nextToken();
2383                             nextToken();
2384                             t = cparseTypeName();
2385                             tkwx = TKW.x_Atomic;
2386                             break;
2387                         }
2388                     }
2389                     // C11 6.7.3 type-qualifier if not
2390                     modx = MOD.x_Atomic;
2391                     break;
2392                 }
2393 
2394                 case TOK._Alignas:
2395                 {
2396                     /* C11 6.7.5
2397                      * _Alignas ( type-name )
2398                      * _Alignas ( constant-expression )
2399                      */
2400 
2401                     if (level & (LVL.parameter | LVL.prototype))
2402                         error("no alignment-specifier for parameters"); // C11 6.7.5-2
2403 
2404                     nextToken();
2405                     check(TOK.leftParenthesis);
2406                     AST.Expression exp;
2407                     auto tk = &token;
2408                     if (isTypeName(tk))  // _Alignas ( type-name )
2409                     {
2410                         auto talign = cparseTypeName();
2411                         /* Convert type to expression: `talign.alignof`
2412                          */
2413                         auto e = new AST.TypeExp(loc, talign);
2414                         exp = new AST.DotIdExp(loc, e, Id.__xalignof);
2415                     }
2416                     else  // _Alignas ( constant-expression )
2417                     {
2418                         exp = cparseConstantExp();
2419                     }
2420 
2421                     if (!specifier.alignExps)
2422                         specifier.alignExps = new AST.Expressions(0);
2423                     specifier.alignExps.push(exp);
2424 
2425                     check(TOK.rightParenthesis);
2426                     break;
2427                 }
2428 
2429                 case TOK.__attribute__:
2430                 {
2431                     /* GNU Extensions
2432                      * declaration-specifiers:
2433                      *    gnu-attributes declaration-specifiers (opt)
2434                      */
2435                     cparseGnuAttributes(specifier);
2436                     break;
2437                 }
2438 
2439                 case TOK.__declspec:
2440                 {
2441                     /* Microsoft extension
2442                      */
2443                     cparseDeclspec(specifier);
2444                     break;
2445                 }
2446 
2447                 case TOK.typeof_:
2448                 {
2449                     nextToken();
2450                     check(TOK.leftParenthesis);
2451 
2452                     auto tk = &token;
2453                     AST.Expression e;
2454                     if (isTypeName(tk))
2455                         e = new AST.TypeExp(loc, cparseTypeName());
2456                     else
2457                         e = cparseExpression();
2458                     t = new AST.TypeTypeof(loc, e);
2459 
2460                     if(token.value == TOK.rightParenthesis)
2461                         nextToken();
2462                     else
2463                     {
2464                         t = AST.Type.terror;
2465                         error("`typeof` operator expects an expression or type name in parentheses");
2466 
2467                         // skipParens et. al expect to be on the opening parenthesis
2468                         int parens;
2469                         loop: while(1)
2470                         {
2471                             switch(token.value)
2472                             {
2473                                 case TOK.leftParenthesis:
2474                                     parens++;
2475                                     break;
2476                                 case TOK.rightParenthesis:
2477                                     parens--;
2478                                     if(parens < 0)
2479                                         goto case;
2480                                     break;
2481                                 case TOK.endOfFile:
2482                                     break loop;
2483                                 default:
2484                             }
2485                             nextToken();
2486                         }
2487                     }
2488 
2489                     tkwx = TKW.xtag;
2490                     break;
2491                 }
2492 
2493                 default:
2494                     break Lwhile;
2495             }
2496 
2497             if (tkwx)
2498             {
2499                 if (tkw & TKW.xlong && tkwx & TKW.xlong)
2500                 {
2501                     tkw &= ~TKW.xlong;
2502                     tkwx = TKW.xllong;
2503                 }
2504                 if (tkw && tkwx & TKW.xident)
2505                 {
2506                     // 2nd identifier can't be a typedef
2507                     break Lwhile; // leave parser on the identifier for the following declarator
2508                 }
2509                 else if (tkwx & TKW.xident)
2510                 {
2511                     // 1st identifier, save it for TypeIdentifier
2512                     previd = id;
2513                 }
2514                 if (tkw & TKW.xident && tkwx ||  // typedef-name followed by type-specifier
2515                     tkw & tkwx)                  // duplicate type-specifiers
2516                 {
2517                     error("illegal combination of type specifiers");
2518                     tkwx = TKW.init;
2519                 }
2520                 tkw |= tkwx;
2521                 if (!(tkwx & TKW.xtag)) // if parser already advanced
2522                     nextToken();
2523                 continue;
2524             }
2525 
2526             if (modx)
2527             {
2528                 mod |= modx;
2529                 nextToken();
2530                 continue;
2531             }
2532 
2533             if (scwx)
2534             {
2535                 if (scw & scwx)
2536                     error("duplicate storage class");
2537                 scw |= scwx;
2538                 // C11 6.7.1-2 At most one storage-class may be given, except that
2539                 // _Thread_local may appear with static or extern.
2540                 const scw2 = scw & (SCW.xstatic | SCW.xextern | SCW.xauto | SCW.xregister | SCW.xtypedef);
2541                 if (scw2 & (scw2 - 1) ||
2542                     scw & (SCW.x_Thread_local) && scw & (SCW.xauto | SCW.xregister | SCW.xtypedef))
2543                 {
2544                     error("multiple storage classes in declaration specifiers");
2545                     scw &= ~scwx;
2546                 }
2547                 if (level == LVL.local &&
2548                     scw & (SCW.x_Thread_local) && scw & (SCW.xinline | SCW.x_Noreturn))
2549                 {
2550                     error("`inline` and `_Noreturn` function specifiers not allowed for `_Thread_local`");
2551                     scw &= ~scwx;
2552                 }
2553                 if (level == LVL.local &&
2554                     scw & (SCW.x_Thread_local) && !(scw & (SCW.xstatic | SCW.xextern)))
2555                 {
2556                     error("`_Thread_local` in block scope must be accompanied with `static` or `extern`"); // C11 6.7.1-3
2557                     scw &= ~scwx;
2558                 }
2559                 if (level & (LVL.parameter | LVL.prototype) &&
2560                     scw & ~SCW.xregister)
2561                 {
2562                     error("only `register` storage class allowed for function parameters");
2563                     scw &= ~scwx;
2564                 }
2565                 if (level == LVL.global &&
2566                     scw & (SCW.xauto | SCW.xregister))
2567                 {
2568                     error("`auto` and `register` storage class not allowed for global");
2569                     scw &= ~scwx;
2570                 }
2571                 nextToken();
2572                 continue;
2573             }
2574         }
2575 
2576         specifier.scw = scw;
2577         specifier.mod = mod;
2578 
2579         // Convert TKW bits to type t
2580         switch (tkw)
2581         {
2582             case TKW.xnone:                     t = null; break;
2583 
2584             case TKW.xchar:                     t = AST.Type.tchar; break;
2585             case TKW.xsigned | TKW.xchar:       t = AST.Type.tint8; break;
2586             case TKW.xunsigned | TKW.xchar:     t = AST.Type.tuns8; break;
2587 
2588             case TKW.xshort:
2589             case TKW.xsigned | TKW.xshort:
2590             case TKW.xsigned | TKW.xshort | TKW.xint:
2591             case TKW.xshort | TKW.xint:         t = integerTypeForSize(shortsize); break;
2592 
2593             case TKW.xunsigned | TKW.xshort | TKW.xint:
2594             case TKW.xunsigned | TKW.xshort:    t = unsignedTypeForSize(shortsize); break;
2595 
2596             case TKW.xint:
2597             case TKW.xsigned:
2598             case TKW.xsigned | TKW.xint:        t = integerTypeForSize(intsize); break;
2599 
2600             case TKW.xunsigned:
2601             case TKW.xunsigned | TKW.xint:      t = unsignedTypeForSize(intsize); break;
2602 
2603             case TKW.xlong:
2604             case TKW.xsigned | TKW.xlong:
2605             case TKW.xsigned | TKW.xlong | TKW.xint:
2606             case TKW.xlong | TKW.xint:          t = integerTypeForSize(longsize); break;
2607 
2608             case TKW.xunsigned | TKW.xlong | TKW.xint:
2609             case TKW.xunsigned | TKW.xlong:     t = unsignedTypeForSize(longsize); break;
2610 
2611             case TKW.xllong:
2612             case TKW.xsigned | TKW.xllong:
2613             case TKW.xsigned | TKW.xllong | TKW.xint:
2614             case TKW.xllong | TKW.xint:          t = integerTypeForSize(long_longsize); break;
2615 
2616             case TKW.xunsigned | TKW.xllong | TKW.xint:
2617             case TKW.xunsigned | TKW.xllong:     t = unsignedTypeForSize(long_longsize); break;
2618 
2619             case TKW.xint128:
2620             case TKW.xsigned | TKW.xint128:     t = integerTypeForSize(16); break;
2621 
2622             case TKW.xunsigned | TKW.xint128:   t = unsignedTypeForSize(16); break;
2623 
2624             case TKW.xvoid:                     t = AST.Type.tvoid; break;
2625             case TKW.xbool:                     t = boolsize == 1 ? AST.Type.tbool : integerTypeForSize(boolsize); break;
2626 
2627             case TKW.xfloat:                    t = AST.Type.tfloat32; break;
2628             case TKW.xdouble:                   t = AST.Type.tfloat64; break;
2629             case TKW.xlong | TKW.xdouble:       t = realType(RTFlags.realfloat); break;
2630 
2631             case TKW.ximaginary | TKW.xfloat:              t = AST.Type.timaginary32; break;
2632             case TKW.ximaginary | TKW.xdouble:             t = AST.Type.timaginary64; break;
2633             case TKW.ximaginary | TKW.xlong | TKW.xdouble: t = realType(RTFlags.imaginary); break;
2634 
2635             case TKW.xcomplex | TKW.xfloat:                t = AST.Type.tcomplex32; break;
2636             case TKW.xcomplex | TKW.xdouble:               t = AST.Type.tcomplex64; break;
2637             case TKW.xcomplex | TKW.xlong | TKW.xdouble:   t = realType(RTFlags.complex); break;
2638 
2639             case TKW.xident:
2640             {
2641                 const idx = previd.toString();
2642                 if (idx.length > 2 && idx[0] == '_' && idx[1] == '_')  // leading double underscore
2643                     importBuiltins = true;  // probably one of those compiler extensions
2644                 t = null;
2645 
2646                 /* Punch through to what the typedef is, to support things like:
2647                  *  typedef T* T;
2648                  */
2649                 auto pt = lookupTypedef(previd);
2650                 if (pt && *pt)      // if previd is a known typedef
2651                     t = *pt;
2652 
2653                 if (!t)
2654                     t = new AST.TypeIdentifier(loc, previd);
2655                 break;
2656             }
2657 
2658             case TKW.xtag:
2659             case TKW.x_Atomic:  // no atomics for you
2660                 break;          // t is already set
2661 
2662             default:
2663                 error("illegal type combination");
2664                 t = AST.Type.terror;
2665                 break;
2666         }
2667 
2668         return t;
2669     }
2670 
2671     /********************************
2672      * C11 6.7.6
2673      * Parse a declarator (including function definitions).
2674      * declarator:
2675      *    pointer (opt) direct-declarator
2676      *
2677      * direct-declarator :
2678      *    identifier
2679      *    ( declarator )
2680      *    direct-declarator [ type-qualifier-list (opt) assignment-expression (opt) ]
2681      *    direct-declarator [ static type-qualifier-list (opt) assignment-expression ]
2682      *    direct-declarator [ type-qualifier-list static assignment-expression (opt) ]
2683      *    direct-declarator [ type-qualifier-list (opt) * ]
2684      *    direct-declarator ( parameter-type-list )
2685      *    direct-declarator ( identifier-list (opt) )
2686      *
2687      * pointer :
2688      *    * type-qualifier-list (opt)
2689      *    * type-qualifier-list (opt) pointer
2690      *
2691      * type-qualifier-list :
2692      *    type-qualifier
2693      *    type-qualifier-list type-qualifier
2694      *
2695      * parameter-type-list :
2696      *    parameter-list
2697      *    parameter-list , ...
2698      *
2699      * parameter-list :
2700      *    parameter-declaration
2701      *    parameter-list , parameter-declaration
2702      *
2703      * parameter-declaration :
2704      *    declaration-specifiers declarator
2705      *    declaration-specifiers abstract-declarator (opt)
2706      *
2707      * identifier-list :
2708      *    identifier
2709      *    identifier-list , identifier
2710      *
2711      * Params:
2712      *  declarator   = declarator kind
2713      *  t            = base type to start with
2714      *  pident       = set to Identifier if there is one, null if not
2715      *  specifier    = specifiers in and out
2716      * Returns:
2717      *  type declared. If a TypeFunction is returned, this.symbols is the
2718      *  symbol table for the parameter-type-list, which will contain any
2719      *  declared struct, union or enum tags.
2720      */
2721     private AST.Type cparseDeclarator(DTR declarator, AST.Type t,
2722         out Identifier pident, ref Specifier specifier)
2723     {
2724         //printf("cparseDeclarator(%d, %p)\n", declarator, t);
2725         AST.Types constTypes; // all the Types that will need `const` applied to them
2726 
2727         AST.Type parseDecl(AST.Type t)
2728         {
2729             AST.Type ts;
2730             while (1)
2731             {
2732                 switch (token.value)
2733                 {
2734                 case TOK.identifier:        // identifier
2735                     //printf("identifier %s\n", token.ident.toChars());
2736                     if (declarator == DTR.xabstract)
2737                         error("identifier not allowed in abstract-declarator");
2738                     pident = token.ident;
2739                     ts = t;
2740                     nextToken();
2741                     break;
2742 
2743                 case TOK.leftParenthesis:   // ( declarator )
2744                     /* like: T (*fp)();
2745                      *       T ((*fp))();
2746                      */
2747                     nextToken();
2748 
2749                     if (token.value == TOK.__stdcall) // T (__stdcall*fp)();
2750                     {
2751                         specifier.mod |= MOD.x__stdcall;
2752                         nextToken();
2753                     }
2754 
2755                     ts = parseDecl(t);
2756                     check(TOK.rightParenthesis);
2757                     break;
2758 
2759                 case TOK.mul:               // pointer
2760                     t = new AST.TypePointer(t);
2761                     nextToken();
2762                     // add post fixes const/volatile/restrict/_Atomic
2763                     const mod = cparseTypeQualifierList();
2764                     if (mod & MOD.xconst)
2765                         constTypes.push(t);
2766                     if (token.value == TOK.__attribute__)
2767                         cparseGnuAttributes(specifier);
2768                     continue;
2769 
2770                 default:
2771                     if (declarator == DTR.xdirect)
2772                     {
2773                         if (!t || t.isTypeIdentifier())
2774                         {
2775                             // const arr[1];
2776                             error("no type-specifier for declarator");
2777                             t = AST.Type.tint32;
2778                         }
2779                         else
2780                             error("identifier or `(` expected"); // )
2781                         panic();
2782                     }
2783                     ts = t;
2784                     break;
2785                 }
2786                 break;
2787             }
2788 
2789             // parse DeclaratorSuffixes
2790             while (1)
2791             {
2792                 /* Insert tx -> t into
2793                  *   ts -> ... -> t
2794                  * so that
2795                  *   ts -> ... -> tx -> t
2796                  */
2797                 static void insertTx(ref AST.Type ts, AST.Type tx, AST.Type t)
2798                 {
2799                     AST.Type* pt;
2800                     for (pt = &ts; *pt != t; pt = &(cast(AST.TypeNext)*pt).next)
2801                     {
2802                     }
2803                     *pt = tx;
2804                 }
2805 
2806                 switch (token.value)
2807                 {
2808                     case TOK.leftBracket:
2809                     {
2810                         // post [] syntax, pick up any leading type qualifiers, `static` and `*`
2811                         AST.Type ta;
2812                         nextToken();
2813 
2814                         auto mod = cparseTypeQualifierList();   // const/volatile/restrict/_Atomic
2815 
2816                         bool isStatic;
2817                         bool isVLA;
2818                         if (token.value == TOK.static_)
2819                         {
2820                             isStatic = true;    // `static`
2821                             nextToken();
2822                             if (!mod)           // type qualifiers after `static`
2823                                 mod = cparseTypeQualifierList();
2824                         }
2825                         else if (token.value == TOK.mul)
2826                         {
2827                             if (peekNext() == TOK.rightBracket)
2828                             {
2829                                 isVLA = true;   // `*`
2830                                 nextToken();
2831                             }
2832                         }
2833 
2834                         if (isStatic || token.value != TOK.rightBracket)
2835                         {
2836                             //printf("It's a static array\n");
2837                             AST.Expression e = cparseAssignExp(); // [ expression ]
2838                             ta = new AST.TypeSArray(t, e);
2839                         }
2840                         else
2841                         {
2842                             /* C11 6.7.6.2-4 An [ ] array is an incomplete array type
2843                              */
2844                             ta = new AST.TypeSArray(t);
2845                         }
2846                         check(TOK.rightBracket);
2847 
2848                         // Issue errors for unsupported types.
2849                         if (isVLA) // C11 6.7.6.2
2850                         {
2851                             error("variable length arrays are not supported");
2852                         }
2853                         if (isStatic) // C11 6.7.6.3
2854                         {
2855                             error("static array parameters are not supported");
2856                         }
2857                         if (declarator != DTR.xparameter)
2858                         {
2859                             /* C11 6.7.6.2-4: '*' can only be used with function prototype scope.
2860                              */
2861                             if (isVLA)
2862                                 error("variable length array used outside of function prototype");
2863                             /* C11 6.7.6.2-1: type qualifiers and 'static' shall only appear
2864                              * in a declaration of a function parameter with an array type.
2865                              */
2866                             if (isStatic || mod)
2867                                 error("static or type qualifier used outside of function prototype");
2868                         }
2869                         if (ts.isTypeSArray() || ts.isTypeDArray())
2870                         {
2871                             /* C11 6.7.6.2-1: type qualifiers and 'static' shall only appear
2872                              * in the outermost array type derivation.
2873                              */
2874                             if (isStatic || mod)
2875                                 error("static or type qualifier used in non-outermost array type derivation");
2876                             /* C11 6.7.6.2-1: the element type shall not be an incomplete or
2877                              * function type.
2878                              */
2879                             if (ta.isTypeSArray() && ta.isTypeSArray().isIncomplete() && !isVLA)
2880                                 error("array type has incomplete element type `%s`", ta.toChars());
2881                         }
2882 
2883                         // Apply type qualifiers to the constructed type.
2884                         if (mod & MOD.xconst) // ignore the other bits
2885                             ta = toConst(ta);
2886                         insertTx(ts, ta, t);  // ts -> ... -> ta -> t
2887                         continue;
2888                     }
2889 
2890                     case TOK.leftParenthesis:
2891                     {
2892                         // New symbol table for parameter-list
2893                         auto symbolsSave = this.symbols;
2894                         this.symbols = null;
2895 
2896                         auto parameterList = cparseParameterList();
2897                         const lkg = specifier.mod & MOD.x__stdcall ? LINK.windows : linkage;
2898                         StorageClass stc = specifier._nothrow ? STC.nothrow_ : 0;
2899                         if (specifier._pure)
2900                             stc |= STC.pure_;
2901                         AST.Type tf = new AST.TypeFunction(parameterList, t, lkg, stc);
2902     //                  tf = tf.addSTC(storageClass);  // TODO
2903                         insertTx(ts, tf, t);  // ts -> ... -> tf -> t
2904 
2905                         if (ts != tf)
2906                             this.symbols = symbolsSave;
2907                         break;
2908                     }
2909 
2910                     default:
2911                         break;
2912                 }
2913                 break;
2914             }
2915             return ts;
2916         }
2917 
2918         t = parseDecl(t);
2919 
2920         /* Because const is transitive, cannot assemble types from
2921          * fragments. Instead, types to be annotated with const are put
2922          * in constTypes[], and a bottom up scan of t is done to apply
2923          * const
2924          */
2925         if (constTypes.length)
2926         {
2927             AST.Type constApply(AST.Type t)
2928             {
2929                 if (t.nextOf())
2930                 {
2931                     auto tn = cast(AST.TypeNext)t; // t.nextOf() should return a ref instead of this
2932                     tn.next = constApply(tn.next);
2933                 }
2934                 foreach (tc; constTypes[])
2935                 {
2936                     if (tc is t)
2937                     {
2938                         return toConst(t);
2939                     }
2940                 }
2941                 return t;
2942             }
2943 
2944             if (declarator == DTR.xparameter &&
2945                 t.isTypePointer())
2946             {
2947                 /* Because there are instances in .h files of "const pointer to mutable",
2948                  * skip applying transitive `const`
2949                  * https://issues.dlang.org/show_bug.cgi?id=22534
2950                  */
2951                 auto tn = cast(AST.TypeNext)t;
2952                 tn.next = constApply(tn.next);
2953             }
2954             else
2955                 t = constApply(t);
2956         }
2957 
2958         //printf("result: %s\n", t.toChars());
2959         return t;
2960     }
2961 
2962     /******************************
2963      * C11 6.7.3
2964      * type-qualifier:
2965      *    const
2966      *    restrict
2967      *    volatile
2968      *    _Atomic
2969      *    __stdcall
2970      */
2971     MOD cparseTypeQualifierList()
2972     {
2973         MOD mod;
2974         while (1)
2975         {
2976             switch (token.value)
2977             {
2978                 case TOK.const_:     mod |= MOD.xconst;     break;
2979                 case TOK..volatile:   mod |= MOD.xvolatile;  break;
2980                 case TOK.restrict:   mod |= MOD.xrestrict;  break;
2981                 case TOK._Atomic:    mod |= MOD.x_Atomic;   break;
2982                 case TOK.__stdcall:  mod |= MOD.x__stdcall; break;
2983 
2984                 default:
2985                     return mod;
2986             }
2987             nextToken();
2988         }
2989     }
2990 
2991     /***********************************
2992      * C11 6.7.7
2993      */
2994     AST.Type cparseTypeName()
2995     {
2996         Specifier specifier;
2997         specifier.packalign.setDefault();
2998         auto tspec = cparseSpecifierQualifierList(LVL.global, specifier);
2999         if (!tspec)
3000         {
3001             error("type-specifier is missing");
3002             tspec = AST.Type.tint32;
3003         }
3004         if (tspec && specifier.mod & MOD.xconst)
3005         {
3006             tspec = toConst(tspec);
3007             specifier.mod = MOD.xnone;      // 'used' it
3008         }
3009         Identifier id;
3010         return cparseDeclarator(DTR.xabstract, tspec, id, specifier);
3011     }
3012 
3013     /***********************************
3014      * C11 6.7.2.1
3015      * specifier-qualifier-list:
3016      *    type-specifier specifier-qualifier-list (opt)
3017      *    type-qualifier specifier-qualifier-list (opt)
3018      * Params:
3019      *  level = declaration context
3020      *  specifier = specifiers in and out
3021      * Returns:
3022      *  resulting type, null if not specified
3023      */
3024     AST.Type cparseSpecifierQualifierList(LVL level, ref Specifier specifier)
3025     {
3026         auto t = cparseDeclarationSpecifiers(level, specifier);
3027         if (specifier.scw)
3028             error("storage class not allowed in specifier-qualified-list");
3029         return t;
3030     }
3031 
3032     /***********************************
3033      * C11 6.7.6.3
3034      * ( parameter-type-list )
3035      * ( identifier-list (opt) )
3036      */
3037     AST.ParameterList cparseParameterList()
3038     {
3039         auto parameters = new AST.Parameters();
3040         AST.VarArg varargs = AST.VarArg.none;
3041         StorageClass varargsStc;
3042 
3043         check(TOK.leftParenthesis);
3044         if (token.value == TOK.void_ && peekNext() == TOK.rightParenthesis) // func(void)
3045         {
3046             nextToken();
3047             nextToken();
3048             return AST.ParameterList(parameters, varargs, varargsStc);
3049         }
3050 
3051         if (token.value == TOK.rightParenthesis)        // func()
3052         {
3053             nextToken();
3054             return AST.ParameterList(parameters, AST.VarArg.KRvariadic, varargsStc);
3055         }
3056 
3057         /* Create function prototype scope
3058          */
3059         typedefTab.push(null);
3060 
3061         AST.ParameterList finish()
3062         {
3063             typedefTab.pop();
3064             return AST.ParameterList(parameters, varargs, varargsStc);
3065         }
3066 
3067         /* The check for identifier-list comes later,
3068          * when doing the trailing declaration-list (opt)
3069          */
3070         while (1)
3071         {
3072             if (token.value == TOK.rightParenthesis)
3073                 break;
3074             if (token.value == TOK.dotDotDot)
3075             {
3076                 if (parameters.length == 0)     // func(...)
3077                     error("named parameter required before `...`");
3078                 importBuiltins = true;          // will need __va_list_tag
3079                 varargs = AST.VarArg.variadic;  // C-style variadics
3080                 nextToken();
3081                 check(TOK.rightParenthesis);
3082                 return finish();
3083             }
3084 
3085             Specifier specifier;
3086             specifier.packalign.setDefault();
3087             auto tspec = cparseDeclarationSpecifiers(LVL.prototype, specifier);
3088             if (!tspec)
3089             {
3090                 error("no type-specifier for parameter");
3091                 tspec = AST.Type.tint32;
3092             }
3093 
3094             if (specifier.mod & MOD.xconst)
3095             {
3096                 if ((token.value == TOK.rightParenthesis || token.value == TOK.comma) &&
3097                     tspec.isTypeIdentifier())
3098                     error("type-specifier omitted for parameter `%s`", tspec.isTypeIdentifier().ident.toChars());
3099 
3100                 tspec = toConst(tspec);
3101                 specifier.mod = MOD.xnone;      // 'used' it
3102             }
3103 
3104             Identifier id;
3105             auto t = cparseDeclarator(DTR.xparameter, tspec, id, specifier);
3106             if (token.value == TOK.__attribute__)
3107                 cparseGnuAttributes(specifier);
3108             if (specifier.mod & MOD.xconst)
3109                 t = toConst(t);
3110             auto param = new AST.Parameter(specifiersToSTC(LVL.parameter, specifier),
3111                                            t, id, null, null);
3112             parameters.push(param);
3113             if (token.value == TOK.rightParenthesis || token.value == TOK.endOfFile)
3114                 break;
3115             check(TOK.comma);
3116         }
3117         check(TOK.rightParenthesis);
3118         return finish();
3119     }
3120 
3121     /***********************************
3122      * C11 6.7.10
3123      * _Static_assert ( constant-expression , string-literal ) ;
3124      */
3125     private AST.StaticAssert cparseStaticAssert()
3126     {
3127         const loc = token.loc;
3128 
3129         //printf("cparseStaticAssert()\n");
3130         nextToken();
3131         check(TOK.leftParenthesis);
3132         auto exp = cparseConstantExp();
3133         check(TOK.comma);
3134         if (token.value != TOK.string_)
3135             error("string literal expected");
3136         auto msg = cparsePrimaryExp();
3137         check(TOK.rightParenthesis);
3138         check(TOK.semicolon);
3139         return new AST.StaticAssert(loc, exp, msg);
3140     }
3141 
3142     /*************************
3143      * Collect argument list.
3144      * Parser is on opening parenthesis.
3145      * Returns:
3146      *    the arguments
3147      */
3148     private AST.Expressions* cparseArguments()
3149     {
3150         nextToken();
3151         auto arguments = new AST.Expressions();
3152         while (token.value != TOK.rightParenthesis && token.value != TOK.endOfFile)
3153         {
3154             auto arg = cparseAssignExp();
3155             arguments.push(arg);
3156             if (token.value != TOK.comma)
3157                 break;
3158 
3159             nextToken(); // consume comma
3160         }
3161 
3162         check(TOK.rightParenthesis);
3163 
3164         return arguments;
3165     }
3166 
3167     /*************************
3168      * __declspec parser
3169      * https://docs.microsoft.com/en-us/cpp/cpp/declspec
3170      * decl-specifier:
3171      *    __declspec ( extended-decl-modifier-seq )
3172      *
3173      * extended-decl-modifier-seq:
3174      *    extended-decl-modifier (opt)
3175      *    extended-decl-modifier extended-decl-modifier-seq
3176      *
3177      * extended-decl-modifier:
3178      *    align(number)
3179      *    deprecated(depMsg)
3180      *    dllimport
3181      *    dllexport
3182      *    naked
3183      *    noinline
3184      *    noreturn
3185      *    nothrow
3186      *    thread
3187      * Params:
3188      *  specifier = filled in with the attribute(s)
3189      */
3190     private void cparseDeclspec(ref Specifier specifier)
3191     {
3192         //printf("cparseDeclspec()\n");
3193         /* Check for dllexport, dllimport
3194          * Ignore the rest
3195          */
3196         nextToken();     // move past __declspec
3197         check(TOK.leftParenthesis);
3198         while (1)
3199         {
3200             if (token.value == TOK.rightParenthesis)
3201             {
3202                 nextToken();
3203                 break;
3204             }
3205             else if (token.value == TOK.endOfFile)
3206                 break;
3207             else if (token.value == TOK.identifier)
3208             {
3209                 if (token.ident == Id.dllimport)
3210                 {
3211                     specifier.dllimport = true;
3212                     nextToken();
3213                 }
3214                 else if (token.ident == Id.dllexport)
3215                 {
3216                     specifier.dllexport = true;
3217                     nextToken();
3218                 }
3219                 else if (token.ident == Id.naked)
3220                 {
3221                     specifier.naked = true;
3222                     nextToken();
3223                 }
3224                 else if (token.ident == Id.noinline)
3225                 {
3226                     specifier.scw |= SCW.xnoinline;
3227                     nextToken();
3228                 }
3229                 else if (token.ident == Id.noreturn)
3230                 {
3231                     specifier.noreturn = true;
3232                     nextToken();
3233                 }
3234                 else if (token.ident == Id._nothrow)
3235                 {
3236                     specifier._nothrow = true;
3237                     nextToken();
3238                 }
3239                 else if (token.ident == Id.thread)
3240                 {
3241                     specifier.scw |= SCW.x_Thread_local;
3242                     nextToken();
3243                 }
3244                 else if (token.ident == Id._align)
3245                 {
3246                     // Microsoft spec is very imprecise as to how this actually works
3247                     nextToken();
3248                     check(TOK.leftParenthesis);
3249                     if (token.value == TOK.int32Literal)
3250                     {
3251                         const n = token.unsvalue;
3252                         if (n < 1 || n & (n - 1) || 8192 < n)
3253                             error("__decspec(align(%lld)) must be an integer positive power of 2 and be <= 8,192", cast(ulong)n);
3254                         specifier.packalign.set(cast(uint)n);
3255                         specifier.packalign.setPack(true);
3256                         nextToken();
3257                     }
3258                     else
3259                     {
3260                         error("alignment value expected, not `%s`", token.toChars());
3261                         nextToken();
3262                     }
3263 
3264                     check(TOK.rightParenthesis);
3265                 }
3266                 else if (token.ident == Id._deprecated)
3267                 {
3268                     specifier._deprecated = true;
3269                     nextToken();
3270                     if (token.value == TOK.leftParenthesis)  // optional deprecation message
3271                     {
3272                         nextToken();
3273                         specifier.depMsg = cparseExpression();
3274                         check(TOK.rightParenthesis);
3275                     }
3276                 }
3277                 else
3278                 {
3279                     nextToken();
3280                     if (token.value == TOK.leftParenthesis)
3281                         cparseParens();
3282                 }
3283             }
3284             else if (token.value == TOK.restrict) // ImportC assigns no semantics to `restrict`, so just ignore the keyword.
3285                 nextToken();
3286             else
3287             {
3288                 error("extended-decl-modifier expected");
3289                 break;
3290             }
3291         }
3292     }
3293 
3294     /*************************
3295      * Parser for asm label. It appears after the declarator, and has apparently
3296      * nothing to do with inline assembler.
3297      * https://gcc.gnu.org/onlinedocs/gcc/Asm-Labels.html
3298      * simple-asm-expr:
3299      *   asm ( asm-string-literal )
3300      *
3301      * asm-string-literal:
3302      *   string-literal
3303      */
3304     private AST.StringExp cparseGnuAsmLabel()
3305     {
3306         nextToken();     // move past asm
3307         check(TOK.leftParenthesis);
3308         if (token.value != TOK.string_)
3309             error("string literal expected for Asm Label, not `%s`", token.toChars());
3310         auto label = cparsePrimaryExp();
3311         check(TOK.rightParenthesis);
3312         return cast(AST.StringExp) label;
3313     }
3314 
3315     /********************
3316      * Parse C inline assembler statement in Gnu format.
3317      * https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
3318      *   asm asm-qualifiers ( AssemblerTemplate : OutputOperands : InputOperands : Clobbers : GotoLabels )
3319      * Current token is on the `asm`.
3320      * Returns:
3321      *   inline assembler expression as a Statement
3322      */
3323     private AST.Statement cparseGnuAsm()
3324     {
3325         // Defer parsing of AsmStatements until semantic processing.
3326         const loc = token.loc;
3327 
3328         nextToken();
3329 
3330         // Consume all asm-qualifiers. As a future optimization, we could record
3331         // the `inline` and `volatile` storage classes against the statement.
3332         while (token.value == TOK.goto_ ||
3333                token.value == TOK.inline ||
3334                token.value == TOK..volatile)
3335             nextToken();
3336 
3337         check(TOK.leftParenthesis);
3338         if (token.value != TOK.string_)
3339             error("string literal expected for Assembler Template, not `%s`", token.toChars());
3340         Token* toklist = null;
3341         Token** ptoklist = &toklist;
3342         //Identifier label = null;
3343         auto statements = new AST.Statements();
3344 
3345         int parens;
3346         while (1)
3347         {
3348             switch (token.value)
3349             {
3350                 case TOK.leftParenthesis:
3351                     ++parens;
3352                     goto default;
3353 
3354                 case TOK.rightParenthesis:
3355                     --parens;
3356                     if (parens >= 0)
3357                         goto default;
3358                     break;
3359 
3360                 case TOK.semicolon:
3361                     error("matching `)` expected, not `;`");
3362                     break;
3363 
3364                 case TOK.endOfFile:
3365                     /* ( */
3366                     error("matching `)` expected, not end of file");
3367                     break;
3368 
3369                 case TOK.colonColon:  // treat as two separate : tokens for iasmgcc
3370                     *ptoklist = allocateToken();
3371                     memcpy(*ptoklist, &token, Token.sizeof);
3372                     (*ptoklist).value = TOK.colon;
3373                     ptoklist = &(*ptoklist).next;
3374 
3375                     *ptoklist = allocateToken();
3376                     memcpy(*ptoklist, &token, Token.sizeof);
3377                     (*ptoklist).value = TOK.colon;
3378                     ptoklist = &(*ptoklist).next;
3379 
3380                     *ptoklist = null;
3381                     nextToken();
3382                     continue;
3383 
3384                 default:
3385                     *ptoklist = allocateToken();
3386                     memcpy(*ptoklist, &token, Token.sizeof);
3387                     ptoklist = &(*ptoklist).next;
3388                     *ptoklist = null;
3389                     nextToken();
3390                     continue;
3391             }
3392             if (toklist)
3393             {
3394                 // Create AsmStatement from list of tokens we've saved
3395                 AST.Statement s = new AST.AsmStatement(token.loc, toklist);
3396                 statements.push(s);
3397             }
3398             break;
3399         }
3400         nextToken();
3401         auto s = new AST.CompoundAsmStatement(loc, statements, 0);
3402         return s;
3403     }
3404 
3405     /*************************
3406      * __attribute__ parser
3407      * https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html
3408      * gnu-attributes:
3409      *   gnu-attributes gnu-attribute-specifier
3410      *
3411      * gnu-attribute-specifier:
3412      *    __attribute__ (( gnu-attribute-list ))
3413      *
3414      * gnu-attribute-list:
3415      *    gnu-attribute (opt)
3416      *    gnu-attribute-list , gnu-attribute
3417      *
3418      * Params:
3419      *  specifier = filled in with the attribute(s)
3420      */
3421     private void cparseGnuAttributes(ref Specifier specifier)
3422     {
3423         while (token.value == TOK.__attribute__)
3424         {
3425             nextToken();     // move past __attribute__
3426             check(TOK.leftParenthesis);
3427             check(TOK.leftParenthesis);
3428 
3429             if (token.value != TOK.rightParenthesis)
3430             {
3431                 while (1)
3432                 {
3433                     cparseGnuAttribute(specifier);
3434                     if (token.value != TOK.comma)
3435                         break;
3436                     nextToken();
3437                 }
3438             }
3439 
3440             check(TOK.rightParenthesis);
3441             check(TOK.rightParenthesis);
3442         }
3443     }
3444 
3445     /*************************
3446      * Parse a single GNU attribute
3447      * gnu-attribute:
3448      *    gnu-attribute-name
3449      *    gnu-attribute-name ( identifier )
3450      *    gnu-attribute-name ( identifier , expression-list )
3451      *    gnu-attribute-name ( expression-list (opt) )
3452      *
3453      * gnu-attribute-name:
3454      *    keyword
3455      *    identifier
3456      *
3457      * expression-list:
3458      *    constant-expression
3459      *    expression-list , constant-expression
3460      *
3461      * Params:
3462      *  specifier = filled in with the attribute(s)
3463      */
3464     private void cparseGnuAttribute(ref Specifier specifier)
3465     {
3466         /* Check for dllimport, dllexport, naked, noreturn, vector_size(bytes)
3467          * Ignore the rest
3468          */
3469         if (!isGnuAttributeName())
3470             return;
3471 
3472         if (token.value == TOK.identifier)
3473         {
3474             if (token.ident == Id.aligned)
3475             {
3476                 nextToken();
3477                 if (token.value == TOK.leftParenthesis)
3478                 {
3479                     nextToken();
3480                     if (token.value == TOK.int32Literal)
3481                     {
3482                         const n = token.unsvalue;
3483                         if (n < 1 || n & (n - 1) || ushort.max < n)
3484                             error("__attribute__((aligned(%lld))) must be an integer positive power of 2 and be <= 32,768", cast(ulong)n);
3485                         specifier.packalign.set(cast(uint)n);
3486                         specifier.packalign.setPack(true);
3487                         nextToken();
3488                     }
3489                     else
3490                     {
3491                         error("alignment value expected, not `%s`", token.toChars());
3492                         nextToken();
3493                     }
3494 
3495                     check(TOK.rightParenthesis);
3496                 }
3497                 /* ignore __attribute__((aligned)), which sets the alignment to the largest value for any data
3498                  * type on the target machine. It's the opposite of __attribute__((packed))
3499                  */
3500             }
3501             else if (token.ident == Id.always_inline) // https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html
3502             {
3503                 specifier.scw |= SCW.xinline;
3504                 nextToken();
3505             }
3506             else if (token.ident == Id._deprecated)
3507             {
3508                 specifier._deprecated = true;
3509                 nextToken();
3510                 if (token.value == TOK.leftParenthesis)  // optional deprecation message
3511                 {
3512                     nextToken();
3513                     specifier.depMsg = cparseExpression();
3514                     check(TOK.rightParenthesis);
3515                 }
3516             }
3517             else if (token.ident == Id.dllimport)
3518             {
3519                 specifier.dllimport = true;
3520                 nextToken();
3521             }
3522             else if (token.ident == Id.dllexport)
3523             {
3524                 specifier.dllexport = true;
3525                 nextToken();
3526             }
3527             else if (token.ident == Id.naked)
3528             {
3529                 specifier.naked = true;
3530                 nextToken();
3531             }
3532             else if (token.ident == Id.noinline)
3533             {
3534                 specifier.scw |= SCW.xnoinline;
3535                 nextToken();
3536             }
3537             else if (token.ident == Id.noreturn)
3538             {
3539                 specifier.noreturn = true;
3540                 nextToken();
3541             }
3542             else if (token.ident == Id._nothrow)
3543             {
3544                 specifier._nothrow = true;
3545                 nextToken();
3546             }
3547             else if (token.ident == Id._pure)
3548             {
3549                 specifier._pure = true;
3550                 nextToken();
3551             }
3552             else if (token.ident == Id.vector_size)
3553             {
3554                 nextToken();
3555                 check(TOK.leftParenthesis);
3556                 cparseConstantExp();  // TODO implement
3557                 check(TOK.rightParenthesis);
3558             }
3559             else
3560             {
3561                 nextToken();
3562                 if (token.value == TOK.leftParenthesis)
3563                     cparseParens();
3564             }
3565         }
3566         else
3567         {
3568             nextToken();
3569             if (token.value == TOK.leftParenthesis)
3570                 cparseParens();
3571         }
3572     }
3573 
3574     /*************************
3575      * See if match for GNU attribute name, which may be any identifier,
3576      * storage-class-specifier, type-specifier, or type-qualifier.
3577      * Returns:
3578      *  true if a valid GNU attribute name
3579      */
3580     private bool isGnuAttributeName()
3581     {
3582         switch (token.value)
3583         {
3584             case TOK.identifier:
3585             case TOK.static_:
3586             case TOK.unsigned:
3587             case TOK.int64:
3588             case TOK.const_:
3589             case TOK.extern_:
3590             case TOK.register:
3591             case TOK.typedef_:
3592             case TOK.int16:
3593             case TOK.inline:
3594             case TOK._Noreturn:
3595             case TOK..volatile:
3596             case TOK.signed:
3597             case TOK.auto_:
3598             case TOK.restrict:
3599             case TOK._Complex:
3600             case TOK._Thread_local:
3601             case TOK.int32:
3602             case TOK.__int128:
3603             case TOK.char_:
3604             case TOK.float32:
3605             case TOK.float64:
3606             case TOK.void_:
3607             case TOK._Bool:
3608             case TOK._Atomic:
3609                 return true;
3610 
3611             default:
3612                 return false;
3613         }
3614     }
3615 
3616     /***************************
3617      * Like skipParens(), but consume the tokens.
3618      */
3619     private void cparseParens()
3620     {
3621         check(TOK.leftParenthesis);
3622         int parens = 1;
3623 
3624         while (1)
3625         {
3626             switch (token.value)
3627             {
3628                 case TOK.leftParenthesis:
3629                     ++parens;
3630                     break;
3631 
3632                 case TOK.rightParenthesis:
3633                     --parens;
3634                     if (parens < 0)
3635                     {
3636                         error("extra right parenthesis");
3637                         return;
3638                     }
3639                     if (parens == 0)
3640                     {
3641                         nextToken();
3642                         return;
3643                     }
3644                     break;
3645 
3646                 case TOK.endOfFile:
3647                     error("end of file found before right parenthesis");
3648                     return;
3649 
3650                 default:
3651                     break;
3652             }
3653             nextToken();
3654         }
3655     }
3656 
3657     //}
3658     /******************************************************************************/
3659     /***************************** Struct & Enum Parser ***************************/
3660     //{
3661 
3662     /*************************************
3663      * C11 6.7.2.2
3664      * enum-specifier:
3665      *    enum identifier (opt) { enumerator-list }
3666      *    enum identifier (opt) { enumerator-list , }
3667      *    enum identifier
3668      *
3669      * enumerator-list:
3670      *    enumerator
3671      *    enumerator-list , enumerator
3672      *
3673      * enumerator:
3674      *    enumeration-constant
3675      *    enumeration-constant = constant-expression
3676      *
3677      * enumeration-constant:
3678      *    identifier
3679      *
3680      * Params:
3681      *  symbols = symbols to add enum declaration to
3682      * Returns:
3683      *  type of the enum
3684      */
3685     private AST.Type cparseEnum(ref AST.Dsymbols* symbols)
3686     {
3687         const loc = token.loc;
3688         nextToken();
3689 
3690         /* GNU Extensions
3691          * enum-specifier:
3692          *    enum gnu-attributes (opt) identifier (opt) { enumerator-list } gnu-attributes (opt)
3693          *    enum gnu-attributes (opt) identifier (opt) { enumerator-list , } gnu-attributes (opt)
3694          *    enum gnu-attributes (opt) identifier
3695          */
3696         Specifier specifier;
3697         specifier.packalign.setDefault();
3698         if (token.value == TOK.__attribute__)
3699             cparseGnuAttributes(specifier);
3700 
3701         Identifier tag;
3702         if (token.value == TOK.identifier)
3703         {
3704             tag = token.ident;
3705             nextToken();
3706         }
3707 
3708         /* clang extension: add optional base type after the identifier
3709          * https://en.cppreference.com/w/cpp/language/enum
3710          *   enum Identifier : Type
3711          */
3712         //AST.Type base = AST.Type.tint32;  // C11 6.7.2.2-4 implementation defined default base type
3713         AST.Type base = null;               // C23 says base type is determined by enum member values
3714         if (token.value == TOK.colon)
3715         {
3716             nextToken();
3717             base = cparseTypeName();
3718         }
3719 
3720         AST.Dsymbols* members;
3721         if (token.value == TOK.leftCurly)
3722         {
3723             nextToken();
3724             members = new AST.Dsymbols();
3725 
3726             if (token.value == TOK.rightCurly)  // C11 6.7.2.2-1
3727             {
3728                 if (tag)
3729                     error("no members for `enum %s`", tag.toChars());
3730                 else
3731                     error("no members for anonymous enum");
3732             }
3733 
3734             while (token.value == TOK.identifier)
3735             {
3736                 auto ident = token.ident;  // enumeration-constant
3737                 nextToken();
3738                 auto mloc = token.loc;
3739 
3740                 if (token.value == TOK.__attribute__)
3741                 {
3742                     /* gnu-attributes can appear here, but just scan and ignore them
3743                      * https://gcc.gnu.org/onlinedocs/gcc/Enumerator-Attributes.html
3744                      */
3745                     Specifier specifierx;
3746                     specifierx.packalign.setDefault();
3747                     cparseGnuAttributes(specifierx);
3748                 }
3749 
3750                 AST.Expression value;
3751                 if (token.value == TOK.assign)
3752                 {
3753                     nextToken();
3754                     value = cparseConstantExp();
3755                     // TODO C11 6.7.2.2-2 value must fit into an int
3756                 }
3757 
3758                 if (token.value == TOK.__attribute__)
3759                 {
3760                     /* gnu-attributes can appear here, but just scan and ignore them
3761                      * https://gcc.gnu.org/onlinedocs/gcc/Enumerator-Attributes.html
3762                      */
3763                     Specifier specifierx;
3764                     specifierx.packalign.setDefault();
3765                     cparseGnuAttributes(specifierx);
3766                 }
3767 
3768                 auto em = new AST.EnumMember(mloc, ident, value, null, 0, null, null);
3769                 members.push(em);
3770 
3771                 if (token.value == TOK.comma)
3772                 {
3773                     nextToken();
3774                     continue;
3775                 }
3776                 break;
3777             }
3778             check(TOK.rightCurly);
3779 
3780             /* GNU Extensions
3781              * Parse the postfix gnu-attributes (opt)
3782              */
3783             if (token.value == TOK.__attribute__)
3784                 cparseGnuAttributes(specifier);
3785         }
3786         else if (!tag)
3787             error("missing `identifier` after `enum`");
3788 
3789         /* Need semantic information to determine if this is a declaration,
3790          * redeclaration, or reference to existing declaration.
3791          * Defer to the semantic() pass with a TypeTag.
3792          */
3793         return new AST.TypeTag(loc, TOK.enum_, tag, structalign_t.init, base, members);
3794     }
3795 
3796     /*************************************
3797      * C11 6.7.2.1
3798      * Parse struct and union specifiers.
3799      * Parser is advanced to the tag identifier or brace.
3800      * struct-or-union-specifier:
3801      *    struct-or-union identifier (opt) { struct-declaration-list }
3802      *    struct-or-union identifier
3803      *
3804      * struct-or-union:
3805      *    struct
3806      *    union
3807      *
3808      * struct-declaration-list:
3809      *    struct-declaration
3810      *    struct-declaration-list struct-declaration
3811      *
3812      * Params:
3813      *  loc = location of `struct` or `union`
3814      *  structOrUnion = TOK.struct_ or TOK.union_
3815      *  packalign = alignment to use for struct members
3816      *  symbols = symbols to add struct-or-union declaration to
3817      * Returns:
3818      *  type of the struct
3819      */
3820     private AST.Type cparseStruct(Loc loc, TOK structOrUnion, structalign_t packalign, ref AST.Dsymbols* symbols)
3821     {
3822         Identifier tag;
3823 
3824         if (token.value == TOK.identifier)
3825         {
3826             tag = token.ident;
3827             nextToken();
3828         }
3829 
3830         AST.Dsymbols* members;
3831         if (token.value == TOK.leftCurly)
3832         {
3833             nextToken();
3834             members = new AST.Dsymbols();          // so `members` will be non-null even with 0 members
3835             while (token.value != TOK.rightCurly)
3836             {
3837                 cparseStructDeclaration(members);
3838 
3839                 if (token.value == TOK.endOfFile)
3840                     break;
3841             }
3842             check(TOK.rightCurly);
3843 
3844             if ((*members).length == 0) // C11 6.7.2.1-8
3845             {
3846                 /* allow empty structs as an extension
3847                  *  struct-declarator-list:
3848                  *    struct-declarator (opt)
3849                  */
3850             }
3851         }
3852         else if (!tag)
3853             error("missing tag `identifier` after `%s`", Token.toChars(structOrUnion));
3854 
3855         /* Need semantic information to determine if this is a declaration,
3856          * redeclaration, or reference to existing declaration.
3857          * Defer to the semantic() pass with a TypeTag.
3858          */
3859         return new AST.TypeTag(loc, structOrUnion, tag, packalign, null, members);
3860     }
3861 
3862     /*************************************
3863      * C11 6.7.2.1
3864      * Parse a struct declaration member.
3865      * struct-declaration:
3866      *    specifier-qualifier-list struct-declarator-list (opt) ;
3867      *    static_assert-declaration
3868      *
3869      * struct-declarator-list:
3870      *    struct-declarator
3871      *    struct-declarator-list , struct-declarator
3872      *
3873      * struct-declarator:
3874      *    declarator
3875      *    declarator (opt) : constant-expression
3876      * Params:
3877      *    members = where to put the fields (members)
3878      */
3879     void cparseStructDeclaration(AST.Dsymbols* members)
3880     {
3881         //printf("cparseStructDeclaration()\n");
3882         if (token.value == TOK._Static_assert)
3883         {
3884             auto s = cparseStaticAssert();
3885             members.push(s);
3886             return;
3887         }
3888 
3889         Specifier specifier;
3890         specifier.packalign = this.packalign;
3891         auto tspec = cparseSpecifierQualifierList(LVL.member, specifier);
3892         if (!tspec)
3893         {
3894             error("no type-specifier for struct member");
3895             tspec = AST.Type.tint32;
3896         }
3897         if (specifier.mod & MOD.xconst)
3898         {
3899             tspec = toConst(tspec);
3900             specifier.mod = MOD.xnone;          // 'used' it
3901         }
3902 
3903         /* If a declarator does not follow, it is unnamed
3904          */
3905         if (token.value == TOK.semicolon && tspec)
3906         {
3907             nextToken();
3908             auto tt = tspec.isTypeTag();
3909             if (!tt)
3910             {
3911                 if (auto ti = tspec.isTypeIdentifier())
3912                 {
3913                     error("type-specifier omitted before declaration of `%s`", ti.ident.toChars());
3914                 }
3915                 return; // legal but meaningless empty declaration
3916             }
3917 
3918             /* If anonymous struct declaration
3919              *   struct { ... members ... };
3920              * C11 6.7.2.1-13
3921              */
3922             if (!tt.id && tt.members)
3923             {
3924                 /* members of anonymous struct are considered members of
3925                  * the containing struct
3926                  */
3927                 auto ad = new AST.AnonDeclaration(tt.loc, tt.tok == TOK.union_, tt.members);
3928                 auto s = applySpecifier(ad, specifier);
3929                 members.push(s);
3930                 return;
3931             }
3932             if (!tt.id && !tt.members)
3933                 return; // already gave error in cparseStruct()
3934 
3935             /* `struct tag;` and `struct tag { ... };`
3936              * always result in a declaration in the current scope
3937              */
3938             // TODO: merge in specifier
3939             auto stag = (tt.tok == TOK.struct_)
3940                 ? new AST.StructDeclaration(tt.loc, tt.id, false)
3941                 : new AST.UnionDeclaration(tt.loc, tt.id);
3942             stag.members = tt.members;
3943             if (!symbols)
3944                 symbols = new AST.Dsymbols();
3945             auto s = applySpecifier(stag, specifier);
3946             symbols.push(s);
3947             return;
3948         }
3949 
3950         while (1)
3951         {
3952             Identifier id;
3953             AST.Type dt;
3954             if (token.value == TOK.colon)
3955             {
3956                 if (auto ti = tspec.isTypeIdentifier())
3957                 {
3958                     error("type-specifier omitted before bit field declaration of `%s`", ti.ident.toChars());
3959                     tspec = AST.Type.tint32;
3960                 }
3961 
3962                 // C11 6.7.2.1-12 unnamed bit-field
3963                 id = Identifier.generateAnonymousId("BitField");
3964                 dt = tspec;
3965             }
3966             else
3967             {
3968                 dt = cparseDeclarator(DTR.xdirect, tspec, id, specifier);
3969                 if (!dt)
3970                 {
3971                     panic();
3972                     nextToken();
3973                     break;          // error recovery
3974                 }
3975             }
3976 
3977             AST.Expression width;
3978             if (token.value == TOK.colon)
3979             {
3980                 // C11 6.7.2.1-10 bit-field
3981                 nextToken();
3982                 width = cparseConstantExp();
3983             }
3984 
3985             /* GNU Extensions
3986              * struct-declarator:
3987              *    declarator gnu-attributes (opt)
3988              *    declarator (opt) : constant-expression gnu-attributes (opt)
3989              */
3990             if (token.value == TOK.__attribute__)
3991                 cparseGnuAttributes(specifier);
3992 
3993             if (!tspec && !specifier.scw && !specifier.mod)
3994                 error("specifier-qualifier-list required");
3995             else if (width)
3996             {
3997                 if (specifier.alignExps)
3998                     error("no alignment-specifier for bit field declaration"); // C11 6.7.5-2
3999                 auto s = new AST.BitFieldDeclaration(width.loc, dt, id, width);
4000                 members.push(s);
4001             }
4002             else if (id)
4003             {
4004                 if (dt.ty == AST.Tvoid)
4005                     error("`void` has no value");
4006 
4007                 // declare the symbol
4008                 // Give member variables an implicit void initializer
4009                 auto initializer = new AST.VoidInitializer(token.loc);
4010                 AST.Dsymbol s = new AST.VarDeclaration(token.loc, dt, id, initializer, specifiersToSTC(LVL.member, specifier));
4011                 s = applySpecifier(s, specifier);
4012                 members.push(s);
4013             }
4014 
4015             switch (token.value)
4016             {
4017                 case TOK.identifier:
4018                     error("missing comma");
4019                     goto default;
4020 
4021                 case TOK.semicolon:
4022                     nextToken();
4023                     return;
4024 
4025                 case TOK.comma:
4026                     nextToken();
4027                     break;
4028 
4029                 default:
4030                     error("`;` or `,` expected");
4031                     while (token.value != TOK.semicolon && token.value != TOK.endOfFile)
4032                         nextToken();
4033                     nextToken();
4034                     return;
4035             }
4036         }
4037     }
4038 
4039     //}
4040     /******************************************************************************/
4041     /********************************* Lookahead Parser ***************************/
4042     //{
4043 
4044     /************************************
4045      * Determine if the scanner is sitting on the start of a declaration.
4046      * Params:
4047      *      t       = current token of the scanner
4048      *      needId  = flag with additional requirements for a declaration
4049      *      endtok  = ending token
4050      *      pt      = will be set ending token (if not null)
4051      * Returns:
4052      *      true at start of a declaration
4053      */
4054     private bool isCDeclaration(ref Token* pt)
4055     {
4056         auto t = pt;
4057         //printf("isCDeclaration() %s\n", t.toChars());
4058         if (!isDeclarationSpecifiers(t))
4059             return false;
4060 
4061         while (1)
4062         {
4063             if (t.value == TOK.semicolon)
4064             {
4065                 t = peek(t);
4066                 pt = t;
4067                 return true;
4068             }
4069             if (!isCDeclarator(t, DTR.xdirect))
4070                 return false;
4071             if (t.value == TOK.asm_)
4072             {
4073                 t = peek(t);
4074                 if (t.value != TOK.leftParenthesis || !skipParens(t, &t))
4075                     return false;
4076             }
4077             if (t.value == TOK.__attribute__)
4078             {
4079                 t = peek(t);
4080                 if (t.value != TOK.leftParenthesis || !skipParens(t, &t))
4081                     return false;
4082             }
4083             if (t.value == TOK.assign)
4084             {
4085                 t = peek(t);
4086                 if (!isInitializer(t))
4087                     return false;
4088             }
4089             switch (t.value)
4090             {
4091                 case TOK.comma:
4092                     t = peek(t);
4093                     break;
4094 
4095                 case TOK.semicolon:
4096                     t = peek(t);
4097                     pt = t;
4098                     return true;
4099 
4100                 default:
4101                     return false;
4102             }
4103         }
4104     }
4105 
4106     /********************************
4107      * See if match for initializer.
4108      * Params:
4109      *  pt = starting token, updated to one past end of initializer if true
4110      * Returns:
4111      *  true if initializer
4112      */
4113     private bool isInitializer(ref Token* pt)
4114     {
4115         //printf("isInitializer()\n");
4116         auto t = pt;
4117 
4118         if (t.value == TOK.leftCurly)
4119         {
4120             if (!skipBraces(t))
4121                 return false;
4122             pt = t;
4123             return true;
4124         }
4125 
4126         // skip over assignment-expression, ending before comma or semiColon or EOF
4127         if (!isAssignmentExpression(t))
4128             return false;
4129         pt = t;
4130         return true;
4131     }
4132 
4133     /********************************
4134      * See if match for:
4135      *    postfix-expression ( argument-expression-list(opt) )
4136      * Params:
4137      *  pt = starting token, updated to one past end of initializer if true
4138      * Returns:
4139      *  true if function call
4140      */
4141     private bool isFunctionCall(ref Token* pt)
4142     {
4143         //printf("isFunctionCall()\n");
4144         auto t = pt;
4145 
4146         if (!isPrimaryExpression(t))
4147             return false;
4148         if (t.value != TOK.leftParenthesis)
4149             return false;
4150         t = peek(t);
4151         while (1)
4152         {
4153             if (!isAssignmentExpression(t))
4154                 return false;
4155             if (t.value == TOK.comma)
4156             {
4157                 t = peek(t);
4158                 continue;
4159             }
4160             if (t.value == TOK.rightParenthesis)
4161             {
4162                 t = peek(t);
4163                 break;
4164             }
4165             return false;
4166         }
4167         if (t.value != TOK.semicolon)
4168             return false;
4169         pt = t;
4170         return true;
4171     }
4172 
4173     /********************************
4174      * See if match for assignment-expression.
4175      * Params:
4176      *  pt = starting token, updated to one past end of assignment-expression if true
4177      * Returns:
4178      *  true if assignment-expression
4179      */
4180     private bool isAssignmentExpression(ref Token* pt)
4181     {
4182         auto t = pt;
4183         //printf("isAssignmentExpression() %s\n", t.toChars());
4184 
4185         /* This doesn't actually check for grammar matching an
4186          * assignment-expression. It just matches ( ) [ ] looking for
4187          * an ending token that would terminate one.
4188          */
4189         bool any;
4190         while (1)
4191         {
4192             switch (t.value)
4193             {
4194                 case TOK.comma:
4195                 case TOK.semicolon:
4196                 case TOK.rightParenthesis:
4197                 case TOK.rightBracket:
4198                 case TOK.endOfFile:
4199                     if (!any)
4200                         return false;
4201                     break;
4202 
4203                 case TOK.leftParenthesis:
4204                     if (!skipParens(t, &t))
4205                         return false;
4206                     /*
4207                         https://issues.dlang.org/show_bug.cgi?id=22267
4208                         Fix issue 22267: If the parser encounters the following
4209                             `identifier variableName = (expression);`
4210                         the initializer is not identified as such since the parentheses
4211                         cause the parser to keep walking indefinitely
4212                         (whereas `(1) + 1` would not be affected.).
4213                     */
4214                     any = true;
4215                     continue;
4216 
4217                 case TOK.leftBracket:
4218                     if (!skipBrackets(t))
4219                         return false;
4220                     continue;
4221 
4222                 case TOK.leftCurly:
4223                     if (!skipBraces(t))
4224                         return false;
4225                     continue;
4226 
4227                 default:
4228                     any = true;   // assume token was part of an a-e
4229                     t = peek(t);
4230                     continue;
4231             }
4232             pt = t;
4233             return true;
4234         }
4235     }
4236 
4237     /********************************
4238      * See if match for constant-expression.
4239      * Params:
4240      *  pt = starting token, updated to one past end of constant-expression if true
4241      * Returns:
4242      *  true if constant-expression
4243      */
4244     private bool isConstantExpression(ref Token* pt)
4245     {
4246         return isAssignmentExpression(pt);
4247     }
4248 
4249     /********************************
4250      * See if match for declaration-specifiers.
4251      * No errors are diagnosed.
4252      * Params:
4253      *  pt = starting token, updated to one past end of declaration-specifiers if true
4254      * Returns:
4255      *  true if declaration-specifiers
4256      */
4257     private bool isDeclarationSpecifiers(ref Token* pt)
4258     {
4259         //printf("isDeclarationSpecifiers()\n");
4260 
4261         auto t = pt;
4262 
4263         bool seenType;
4264         bool any;
4265         while (1)
4266         {
4267             switch (t.value)
4268             {
4269                 // type-specifiers
4270                 case TOK.void_:
4271                 case TOK.char_:
4272                 case TOK.int16:
4273                 case TOK.int32:
4274                 case TOK.int64:
4275                 case TOK.__int128:
4276                 case TOK.float32:
4277                 case TOK.float64:
4278                 case TOK.signed:
4279                 case TOK.unsigned:
4280                 case TOK._Bool:
4281                 //case TOK._Imaginary:
4282                 case TOK._Complex:
4283                     t = peek(t);
4284                     seenType = true;
4285                     any = true;
4286                     continue;
4287 
4288                 case TOK.identifier: // typedef-name
4289                     if (!seenType)
4290                     {
4291                         t = peek(t);
4292                         seenType = true;
4293                         any = true;
4294                         continue;
4295                     }
4296                     break;
4297 
4298                 case TOK.struct_:
4299                 case TOK.union_:
4300                 case TOK.enum_:
4301                     t = peek(t);
4302                     if (t.value == TOK.__attribute__ ||
4303                         t.value == TOK.__declspec)
4304                     {
4305                         t = peek(t);
4306                         if (!skipParens(t, &t))
4307                             return false;
4308                     }
4309                     if (t.value == TOK.identifier)
4310                     {
4311                         t = peek(t);
4312                         if (t.value == TOK.leftCurly)
4313                         {
4314                             if (!skipBraces(t))
4315                                 return false;
4316                         }
4317                     }
4318                     else if (t.value == TOK.leftCurly)
4319                     {
4320                         if (!skipBraces(t))
4321                             return false;
4322                     }
4323                     else
4324                         return false;
4325                     any = true;
4326                     continue;
4327 
4328                 // storage-class-specifiers
4329                 case TOK.typedef_:
4330                 case TOK.extern_:
4331                 case TOK.static_:
4332                 case TOK.__thread:
4333                 case TOK._Thread_local:
4334                 case TOK.auto_:
4335                 case TOK.register:
4336 
4337                 // function-specifiers
4338                 case TOK.inline:
4339                 case TOK._Noreturn:
4340 
4341                 // type-qualifiers
4342                 case TOK.const_:
4343                 case TOK..volatile:
4344                 case TOK.restrict:
4345                 case TOK.__stdcall:
4346                     t = peek(t);
4347                     any = true;
4348                     continue;
4349 
4350                 case TOK._Alignas:      // alignment-specifier
4351                 case TOK.__declspec:    // decl-specifier
4352                 case TOK.__attribute__: // attribute-specifier
4353                     t = peek(t);
4354                     if (!skipParens(t, &t))
4355                         return false;
4356                     any = true;
4357                     continue;
4358 
4359                 // either atomic-type-specifier or type_qualifier
4360                 case TOK._Atomic:  // TODO _Atomic ( type-name )
4361                     t = peek(t);
4362                     if (t.value == TOK.leftParenthesis) // maybe atomic-type-specifier
4363                     {
4364                         auto tsave = t;
4365                         t = peek(t);
4366                         if (!isTypeName(t) || t.value != TOK.rightParenthesis)
4367                         {   // it's a type-qualifier
4368                             t = tsave;  // back up parser
4369                             any = true;
4370                             continue;
4371                         }
4372                         t = peek(t);    // move past right parenthesis of atomic-type-specifier
4373                     }
4374                     any = true;
4375                     continue;
4376 
4377                 default:
4378                     break;
4379             }
4380             break;
4381         }
4382 
4383         if (any)
4384         {
4385             pt = t;
4386             return true;
4387         }
4388         return false;
4389     }
4390 
4391     /**************************************
4392      * See if declaration-list is present.
4393      * Returns:
4394      *    true if declaration-list is present, even an empty one
4395      */
4396     bool isDeclarationList(ref Token* pt)
4397     {
4398         auto t = pt;
4399         while (1)
4400         {
4401             if (t.value == TOK.leftCurly)
4402             {
4403                 pt = t;
4404                 return true;
4405             }
4406             if (!isCDeclaration(t))
4407                 return false;
4408         }
4409     }
4410 
4411     /*******************************************
4412      * Skip braces.
4413      * Params:
4414      *      pt = enters on left brace, set to token past right bracket on true
4415      * Returns:
4416      *      true if successful
4417      */
4418     private bool skipBraces(ref Token* pt)
4419     {
4420         auto t = pt;
4421         if (t.value != TOK.leftCurly)
4422             return false;
4423 
4424         int braces = 0;
4425 
4426         while (1)
4427         {
4428             switch (t.value)
4429             {
4430                 case TOK.leftCurly:
4431                     ++braces;
4432                     t = peek(t);
4433                     continue;
4434 
4435                 case TOK.rightCurly:
4436                     --braces;
4437                     if (braces == 0)
4438                     {
4439                         pt = peek(t);
4440                         return true;
4441                     }
4442                     if (braces < 0)
4443                         return false;
4444 
4445                     t = peek(t);
4446                     continue;
4447 
4448                 case TOK.endOfFile:
4449                     return false;
4450 
4451                 default:
4452                     t = peek(t);
4453                     continue;
4454             }
4455         }
4456     }
4457 
4458     /*******************************************
4459      * Skip brackets.
4460      * Params:
4461      *      pt = enters on left bracket, set to token past right bracket on true
4462      * Returns:
4463      *      true if successful
4464      */
4465     private bool skipBrackets(ref Token* pt)
4466     {
4467         auto t = pt;
4468         if (t.value != TOK.leftBracket)
4469             return false;
4470 
4471         int brackets = 0;
4472 
4473         while (1)
4474         {
4475             switch (t.value)
4476             {
4477                 case TOK.leftBracket:
4478                     ++brackets;
4479                     t = peek(t);
4480                     continue;
4481 
4482                 case TOK.rightBracket:
4483                     --brackets;
4484                     if (brackets == 0)
4485                     {
4486                         pt = peek(t);
4487                         return true;
4488                     }
4489                     if (brackets < 0)
4490                         return false;
4491 
4492                     t = peek(t);
4493                     continue;
4494 
4495                 case TOK.endOfFile:
4496                     return false;
4497 
4498                 default:
4499                     t = peek(t);
4500                     continue;
4501             }
4502         }
4503     }
4504 
4505     /*********************************
4506      * Check to see if tokens starting with *pt form a declarator.
4507      * Params:
4508      *  pt = pointer to starting token, updated to point past declarator if true is returned
4509      *  declarator = declarator kind
4510      * Returns:
4511      *  true if it does
4512      */
4513     private bool isCDeclarator(ref Token* pt, DTR declarator)
4514     {
4515         auto t = pt;
4516         while (1)
4517         {
4518             if (t.value == TOK.mul)     // pointer
4519             {
4520                 t = peek(t);
4521                 if (!isTypeQualifierList(t))
4522                     return false;
4523             }
4524             else
4525                 break;
4526         }
4527 
4528         if (t.value == TOK.identifier)
4529         {
4530             if (declarator == DTR.xabstract)
4531                 return false;
4532             t = peek(t);
4533         }
4534         else if (t.value == TOK.leftParenthesis)
4535         {
4536             t = peek(t);
4537             if (!isCDeclarator(t, declarator))
4538                 return false;
4539             if (t.value != TOK.rightParenthesis)
4540                 return false;
4541             t = peek(t);
4542         }
4543         else if (declarator == DTR.xdirect)
4544         {
4545             return false;
4546         }
4547 
4548         while (1)
4549         {
4550             if (t.value == TOK.leftBracket)
4551             {
4552                 if (!skipBrackets(t))
4553                     return false;
4554             }
4555             else if (t.value == TOK.leftParenthesis)
4556             {
4557                 if (!skipParens(t, &t))
4558                     return false;
4559             }
4560             else
4561                 break;
4562         }
4563         pt = t;
4564         return true;
4565     }
4566 
4567     /***************************
4568      * Is this the start of a type-qualifier-list?
4569      * (Can be empty.)
4570      * Params:
4571      *  pt = first token; updated with past end of type-qualifier-list if true
4572      * Returns:
4573      *  true if start of type-qualifier-list
4574      */
4575     private bool isTypeQualifierList(ref Token* pt)
4576     {
4577         auto t = pt;
4578         while (1)
4579         {
4580             switch (t.value)
4581             {
4582                 case TOK.const_:
4583                 case TOK.restrict:
4584                 case TOK..volatile:
4585                 case TOK._Atomic:
4586                 case TOK.__stdcall:
4587                     t = peek(t);
4588                     continue;
4589 
4590                 default:
4591                     break;
4592             }
4593             break;
4594         }
4595         pt = t;
4596         return true;
4597     }
4598 
4599     /***************************
4600      * Is this the start of a type-name?
4601      * Params:
4602      *  pt = first token; updated with past end of type-name if true
4603      * Returns:
4604      *  true if start of type-name
4605      */
4606     private bool isTypeName(ref Token* pt)
4607     {
4608         auto t = pt;
4609         //printf("isTypeName() %s\n", t.toChars());
4610         if (!isSpecifierQualifierList(t))
4611             return false;
4612         if (!isCDeclarator(t, DTR.xabstract))
4613             return false;
4614         if (t.value != TOK.rightParenthesis)
4615             return false;
4616         pt = t;
4617         return true;
4618     }
4619 
4620     /***************************
4621      * Is this the start of a specifier-qualifier-list?
4622      * Params:
4623      *  pt = first token; updated with past end of specifier-qualifier-list if true
4624      * Returns:
4625      *  true if start of specifier-qualifier-list
4626      */
4627     private bool isSpecifierQualifierList(ref Token* pt)
4628     {
4629         auto t = pt;
4630         bool result;
4631         while (1)
4632         {
4633             switch (t.value)
4634             {
4635                 // Type Qualifiers
4636                 case TOK.const_:
4637                 case TOK.restrict:
4638                 case TOK..volatile:
4639                 case TOK.__stdcall:
4640 
4641                 // Type Specifiers
4642                 case TOK.char_:
4643                 case TOK.signed:
4644                 case TOK.unsigned:
4645                 case TOK.int16:
4646                 case TOK.int32:
4647                 case TOK.int64:
4648                 case TOK.__int128:
4649                 case TOK.float32:
4650                 case TOK.float64:
4651                 case TOK.void_:
4652                 case TOK._Bool:
4653                 //case TOK._Imaginary: // ? missing in Spec
4654                 case TOK._Complex:
4655                     t = peek(t);
4656                     break;
4657 
4658                 case TOK.identifier:
4659                     // Use typedef table to disambiguate
4660                     if (isTypedef(t.ident))
4661                     {
4662                         t = peek(t);
4663                         break;
4664                     }
4665                     else
4666                     {
4667                         return false;
4668                     }
4669 
4670                 // struct-or-union-specifier
4671                 // enum-specifier
4672                 case TOK.struct_:
4673                 case TOK.union_:
4674                 case TOK.enum_:
4675                     t = peek(t);
4676                     if (t.value == TOK.identifier)
4677                     {
4678                         t = peek(t);
4679                         if (t.value == TOK.leftCurly)
4680                         {
4681                             if (!skipBraces(t))
4682                                 return false;
4683                         }
4684                     }
4685                     else if (t.value == TOK.leftCurly)
4686                     {
4687                         if (!skipBraces(t))
4688                             return false;
4689                     }
4690                     else
4691                         return false;
4692                     break;
4693 
4694                 // atomic-type-specifier
4695                 case TOK._Atomic:
4696                 case TOK.typeof_:
4697                     t = peek(t);
4698                     if (t.value != TOK.leftParenthesis ||
4699                         !skipParens(t, &t))
4700                         return false;
4701                     break;
4702 
4703                 default:
4704                     if (result)
4705                         pt = t;
4706                     return result;
4707             }
4708             result = true;
4709         }
4710     }
4711 
4712     /************************************
4713      * Looking at the leading left parenthesis, and determine if it is
4714      * either of the following:
4715      *    ( type-name ) cast-expression
4716      *    ( type-name ) { initializer-list }
4717      * as opposed to:
4718      *    ( expression )
4719      * Params:
4720      *    pt = starting token, updated to one past end of constant-expression if true
4721      *    afterParenType = true if already seen `( type-name )`
4722      * Returns:
4723      *    true if matches ( type-name ) ...
4724      */
4725     private bool isCastExpression(ref Token* pt, bool afterParenType = false)
4726     {
4727         enum log = false;
4728         if (log) printf("isCastExpression(tk: `%s`, afterParenType: %d)\n", token.toChars(pt.value), afterParenType);
4729         auto t = pt;
4730         switch (t.value)
4731         {
4732             case TOK.leftParenthesis:
4733                 auto tk = peek(t);  // move past left parenthesis
4734                 if (!isTypeName(tk) || tk.value != TOK.rightParenthesis)
4735                 {
4736                     if (afterParenType)
4737                         goto default; // could be ( type-name ) ( unary-expression )
4738                     return false;
4739                 }
4740                 tk = peek(tk);  // move past right parenthesis
4741 
4742                 if (tk.value == TOK.leftCurly)
4743                 {
4744                     // ( type-name ) { initializer-list }
4745                     if (!isInitializer(tk))
4746                     {
4747                         return false;
4748                     }
4749                     t = tk;
4750                     break;
4751                 }
4752 
4753                 if (tk.value == TOK.leftParenthesis && peek(tk).value == TOK.rightParenthesis)
4754                 {
4755                     return false;    // (type-name)() is not a cast (it might be a function call)
4756                 }
4757 
4758                 if (!isCastExpression(tk, true))
4759                 {
4760                     if (afterParenType) // could be ( type-name ) ( unary-expression )
4761                         goto default;   // where unary-expression also matched type-name
4762                     return true;
4763                 }
4764                 // ( type-name ) cast-expression
4765                 t = tk;
4766                 break;
4767 
4768             default:
4769                 if (!afterParenType || !isUnaryExpression(t, afterParenType))
4770                 {
4771                     return false;
4772                 }
4773                 // if we've already seen ( type-name ), then this is a cast
4774                 break;
4775         }
4776         pt = t;
4777         if (log) printf("isCastExpression true\n");
4778         return true;
4779     }
4780 
4781     /********************************
4782      * See if match for unary-expression.
4783      * Params:
4784      *    pt = starting token, updated to one past end of constant-expression if true
4785      *    afterParenType = true if already seen ( type-name ) of a cast-expression
4786      * Returns:
4787      *    true if unary-expression
4788      */
4789     private bool isUnaryExpression(ref Token* pt, bool afterParenType = false)
4790     {
4791         auto t = pt;
4792         switch (t.value)
4793         {
4794             case TOK.plusPlus:
4795             case TOK.minusMinus:
4796                 t = peek(t);
4797                 if (!isUnaryExpression(t, afterParenType))
4798                     return false;
4799                 break;
4800 
4801             case TOK.and:
4802             case TOK.mul:
4803             case TOK.min:
4804             case TOK.add:
4805             case TOK.not:
4806             case TOK.tilde:
4807                 t = peek(t);
4808                 if (!isCastExpression(t, afterParenType))
4809                     return false;
4810                 break;
4811 
4812             case TOK.sizeof_:
4813                 t = peek(t);
4814                 if (t.value == TOK.leftParenthesis)
4815                 {
4816                     auto tk = peek(t);
4817                     if (isTypeName(tk))
4818                     {
4819                         if (tk.value != TOK.rightParenthesis)
4820                             return false;
4821                         t = peek(tk);
4822                         break;
4823                     }
4824                 }
4825                 if (!isUnaryExpression(t, afterParenType))
4826                     return false;
4827                 break;
4828 
4829             case TOK._Alignof:
4830                 t = peek(t);
4831                 if (t.value != TOK.leftParenthesis)
4832                     return false;
4833                 t = peek(t);
4834                 if (!isTypeName(t) || t.value != TOK.rightParenthesis)
4835                     return false;
4836                 break;
4837 
4838             default:
4839                 // Compound literals are handled by cast and sizeof expressions,
4840                 // so be content with just seeing a primary expression.
4841                 if (!isPrimaryExpression(t))
4842                     return false;
4843                 break;
4844         }
4845         pt = t;
4846         return true;
4847     }
4848 
4849     /********************************
4850      * See if match for primary-expression.
4851      * Params:
4852      *    pt = starting token, updated to one past end of constant-expression if true
4853      * Returns:
4854      *    true if primary-expression
4855      */
4856     private bool isPrimaryExpression(ref Token* pt)
4857     {
4858         auto t = pt;
4859         switch (t.value)
4860         {
4861             case TOK.identifier:
4862             case TOK.charLiteral:
4863             case TOK.int32Literal:
4864             case TOK.uns32Literal:
4865             case TOK.int64Literal:
4866             case TOK.uns64Literal:
4867             case TOK.float32Literal:
4868             case TOK.float64Literal:
4869             case TOK.float80Literal:
4870             case TOK.imaginary32Literal:
4871             case TOK.imaginary64Literal:
4872             case TOK.imaginary80Literal:
4873             case TOK.string_:
4874                 t = peek(t);
4875                 break;
4876 
4877             case TOK.leftParenthesis:
4878                 // ( expression )
4879                 if (!skipParens(t, &t))
4880                     return false;
4881                 break;
4882 
4883             case TOK._Generic:
4884                 t = peek(t);
4885                 if (!skipParens(t, &t))
4886                     return false;
4887                 break;
4888 
4889             default:
4890                 return false;
4891         }
4892         pt = t;
4893         return true;
4894     }
4895 
4896     //}
4897     /******************************************************************************/
4898     /********************************* More ***************************************/
4899     //{
4900 
4901     /**************
4902      * Declaration context
4903      */
4904     enum LVL
4905     {
4906         global    = 1,    /// global
4907         parameter = 2,    /// function parameter (declarations for function identifier-list)
4908         prototype = 4,    /// function prototype
4909         local     = 8,    /// local
4910         member    = 0x10, /// struct member
4911     }
4912 
4913     /// Types of declarator to parse
4914     enum DTR
4915     {
4916         xdirect    = 1, /// C11 6.7.6 direct-declarator
4917         xabstract  = 2, /// C11 6.7.7 abstract-declarator
4918         xparameter = 3, /// parameter declarator may be either direct or abstract
4919     }
4920 
4921     /// C11 6.7.1 Storage-class specifiers
4922     enum SCW : uint
4923     {
4924         xnone      = 0,
4925         xtypedef   = 1,
4926         xextern    = 2,
4927         xstatic    = 4,
4928         x_Thread_local = 8,
4929         xauto      = 0x10,
4930         xregister  = 0x20,
4931         // C11 6.7.4 Function specifiers
4932         xinline    = 0x40,
4933         x_Noreturn = 0x80,
4934 
4935         xnoinline  = 0x100,
4936     }
4937 
4938     /// C11 6.7.3 Type qualifiers
4939     enum MOD : uint
4940     {
4941         xnone     = 0,
4942         xconst    = 1,
4943         xvolatile = 2,
4944         xrestrict = 4,
4945         x_Atomic  = 8,
4946         x__stdcall = 0x10, // Windows linkage extension
4947     }
4948 
4949     /**********************************
4950      * Aggregate for all the various specifiers
4951      */
4952     struct Specifier
4953     {
4954         bool noreturn;  /// noreturn attribute
4955         bool naked;     /// naked attribute
4956         bool _nothrow;  /// nothrow attribute
4957         bool _pure;     /// pure attribute
4958         bool dllimport; /// dllimport attribute
4959         bool dllexport; /// dllexport attribute
4960         bool _deprecated;       /// deprecated attribute
4961         AST.Expression depMsg;  /// deprecated message
4962 
4963         SCW scw;        /// storage-class specifiers
4964         MOD mod;        /// type qualifiers
4965         AST.Expressions*  alignExps;  /// alignment
4966         structalign_t packalign;  /// #pragma pack alignment value
4967     }
4968 
4969     /***********************
4970      * Convert from C specifiers to D storage class
4971      * Params:
4972      *  level = declaration context
4973      *  specifier = specifiers, context, etc.
4974      * Returns:
4975      *  corresponding D storage class
4976      */
4977     StorageClass specifiersToSTC(LVL level, const ref Specifier specifier)
4978     {
4979         StorageClass stc;
4980         if (specifier.scw & SCW.x_Thread_local)
4981         {
4982             if (level == LVL.global)
4983             {
4984                 if (specifier.scw & SCW.xextern)
4985                     stc = AST.STC.extern_;
4986                 else if (specifier.scw & SCW.xstatic)
4987                     stc = AST.STC.static_;
4988             }
4989             else if (level == LVL.local)
4990             {
4991                 if (specifier.scw & SCW.xextern)
4992                     stc = AST.STC.extern_;
4993                 else if (specifier.scw & SCW.xstatic)
4994                     stc = AST.STC.static_;
4995             }
4996             else if (level == LVL.member)
4997             {
4998                 if (specifier.scw & SCW.xextern)
4999                     stc = AST.STC.extern_;
5000                 else if (specifier.scw & SCW.xstatic)
5001                     stc = AST.STC.static_;
5002             }
5003         }
5004         else
5005         {
5006             if (level == LVL.global)
5007             {
5008                 if (specifier.scw & SCW.xextern)
5009                     stc = AST.STC.extern_ | AST.STC.gshared;
5010                 else if (specifier.scw & SCW.xstatic)
5011                     stc = AST.STC.gshared | AST.STC.static_;
5012                 else
5013                     stc = AST.STC.gshared;
5014             }
5015             else if (level == LVL.local)
5016             {
5017                 if (specifier.scw & SCW.xextern)
5018                     stc = AST.STC.extern_ | AST.STC.gshared;
5019                 else if (specifier.scw & SCW.xstatic)
5020                     stc = AST.STC.gshared;
5021                 else if (specifier.scw & SCW.xregister)
5022                     stc = AST.STC.register;
5023             }
5024             else if (level == LVL.parameter)
5025             {
5026                 if (specifier.scw & SCW.xregister)
5027                     stc = AST.STC.register | AST.STC.parameter;
5028                 else
5029                     stc = AST.STC.parameter;
5030             }
5031             else if (level == LVL.member)
5032             {
5033                 if (specifier.scw & SCW.xextern)
5034                     stc = AST.STC.extern_ | AST.STC.gshared;
5035                 else if (specifier.scw & SCW.xstatic)
5036                     stc = AST.STC.gshared;
5037             }
5038         }
5039         if (specifier._deprecated && !specifier.depMsg)
5040             stc |= AST.STC.deprecated_;
5041         return stc;
5042     }
5043 
5044     /***********************
5045      * Add attributes from Specifier to function
5046      * Params:
5047      *  fd = function to apply them to
5048      *  specifier = specifiers
5049      */
5050     void specifiersToFuncDeclaration(AST.FuncDeclaration fd, const ref Specifier specifier)
5051     {
5052         fd.isNaked = specifier.naked;
5053         fd.dllImport = specifier.dllimport;
5054         fd.dllExport = specifier.dllexport;
5055 
5056         if (specifier.scw & SCW.xnoinline)
5057             fd.inlining = PINLINE.never;
5058         else if (specifier.scw & SCW.xinline)
5059             fd.inlining = PINLINE.always;
5060     }
5061 
5062     /***********************
5063      * Add attributes from Specifier to variable
5064      * Params:
5065      *  vd = function to apply them to
5066      *  specifier = specifiers
5067      */
5068     void specifiersToVarDeclaration(AST.VarDeclaration vd, const ref Specifier specifier)
5069     {
5070         vd.dllImport = specifier.dllimport;
5071         vd.dllExport = specifier.dllexport;
5072     }
5073 
5074     /***********************
5075      * Return suitable signed integer type for the given size
5076      * Params:
5077      *  size = size of type
5078      * Returns:
5079      *  corresponding signed D integer type
5080      */
5081     private AST.Type integerTypeForSize(ubyte size)
5082     {
5083         if (size <= 1)
5084             return AST.Type.tint8;
5085         if (size <= 2)
5086             return AST.Type.tint16;
5087         if (size <= 4)
5088             return AST.Type.tint32;
5089         if (size <= 8)
5090             return AST.Type.tint64;
5091         if (size == 16)
5092         {
5093             error("__int128 not supported");
5094             return AST.Type.terror;
5095         }
5096         error("unsupported integer type");
5097         return AST.Type.terror;
5098     }
5099 
5100     /***********************
5101      * Return suitable unsigned integer type for the given size
5102      * Params:
5103      *  size = size of type
5104      * Returns:
5105      *  corresponding unsigned D integer type
5106      */
5107     private AST.Type unsignedTypeForSize(ubyte size)
5108     {
5109         if (size <= 1)
5110             return AST.Type.tuns8;
5111         if (size <= 2)
5112             return AST.Type.tuns16;
5113         if (size <= 4)
5114             return AST.Type.tuns32;
5115         if (size <= 8)
5116             return AST.Type.tuns64;
5117         if (size == 16)
5118         {
5119             error("unsigned __int128 not supported");
5120             return AST.Type.terror;
5121         }
5122         error("unsupported integer type");
5123         return AST.Type.terror;
5124     }
5125 
5126     /***********************
5127      * Return suitable D float type for C `long double`
5128      * Params:
5129      *  flags = kind of float to return (real, imaginary, complex).
5130      * Returns:
5131      *  corresponding D type
5132      */
5133     private AST.Type realType(RTFlags flags)
5134     {
5135         if (long_doublesize == AST.Type.tfloat80.size())
5136         {
5137             // On GDC and LDC, D `real` types map to C `long double`, so never
5138             // return a double type when real.sizeof == double.sizeof.
5139             final switch (flags)
5140             {
5141                 case RTFlags.realfloat: return AST.Type.tfloat80;
5142                 case RTFlags.imaginary: return AST.Type.timaginary80;
5143                 case RTFlags.complex:   return AST.Type.tcomplex80;
5144             }
5145         }
5146         else
5147         {
5148             final switch (flags)
5149             {
5150                 case RTFlags.realfloat: return long_doublesize == 8 ? AST.Type.tfloat64 : AST.Type.tfloat80;
5151                 case RTFlags.imaginary: return long_doublesize == 8 ? AST.Type.timaginary64 : AST.Type.timaginary80;
5152                 case RTFlags.complex:   return long_doublesize == 8 ? AST.Type.tcomplex64 : AST.Type.tcomplex80;
5153             }
5154         }
5155     }
5156 
5157     /**************
5158      * Flags for realType
5159      */
5160     private enum RTFlags
5161     {
5162         realfloat,
5163         imaginary,
5164         complex,
5165     }
5166 
5167     /********************
5168      * C11 6.4.2.2 Create declaration to predefine __func__
5169      *    `static const char __func__[] = " function-name ";`
5170      * Params:
5171      *    loc = location for this declaration
5172      *    id = identifier of function
5173      * Returns:
5174      *    statement representing the declaration of __func__
5175      */
5176     private AST.Statement createFuncName(Loc loc, Identifier id)
5177     {
5178         const fn = id.toString();  // function-name
5179         auto efn = new AST.StringExp(loc, fn, fn.length, 1, 'c');
5180         auto ifn = new AST.ExpInitializer(loc, efn);
5181         auto lenfn = new AST.IntegerExp(loc, fn.length + 1, AST.Type.tuns32); // +1 for terminating 0
5182         auto tfn = new AST.TypeSArray(AST.Type.tchar, lenfn);
5183         efn.type = tfn.immutableOf();
5184         efn.committed = true;
5185         auto sfn = new AST.VarDeclaration(loc, tfn, Id.__func__, ifn, STC.gshared | STC.immutable_);
5186         auto e = new AST.DeclarationExp(loc, sfn);
5187         return new AST.ExpStatement(loc, e);
5188     }
5189 
5190     /************************
5191      * After encountering an error, scan forward until a right brace or ; is found
5192      * or the end of the file.
5193      */
5194     void panic()
5195     {
5196         while (token.value != TOK.rightCurly && token.value != TOK.semicolon && token.value != TOK.endOfFile)
5197             nextToken();
5198     }
5199 
5200     /**************************
5201      * Apply `const` to a type.
5202      * Params:
5203      *    t = type to add const to
5204      * Returns:
5205      *    resulting type
5206      */
5207     private AST.Type toConst(AST.Type t)
5208     {
5209         // `const` is always applied to the return type, not the
5210         // type function itself.
5211         if (auto tf = t.isTypeFunction())
5212             tf.next = tf.next.addSTC(STC.const_);
5213         else if (auto tt = t.isTypeTag())
5214             tt.mod |= MODFlags.const_;
5215         else
5216         {
5217             /* Ignore const if the result would be const pointer to mutable
5218              */
5219             auto tn = t.nextOf();
5220             if (!tn || tn.isConst())
5221                 t = t.addSTC(STC.const_);
5222         }
5223         return t;
5224     }
5225 
5226     /***************************
5227      * Apply specifier to a Dsymbol.
5228      * Params:
5229      *  s = Dsymbol
5230      *  specifier = specifiers to apply
5231      * Returns:
5232      *  Dsymbol with specifiers applied
5233      */
5234     private AST.Dsymbol applySpecifier(AST.Dsymbol s, ref Specifier specifier)
5235     {
5236         //printf("applySpecifier() %s\n", s.toChars());
5237         if (specifier._deprecated)
5238         {
5239             if (specifier.depMsg)
5240             {
5241                 // Wrap declaration in a DeprecatedDeclaration
5242                 auto decls = new AST.Dsymbols(1);
5243                 (*decls)[0] = s;
5244                 s = new AST.DeprecatedDeclaration(specifier.depMsg, decls);
5245             }
5246         }
5247 
5248         if (specifier.alignExps)
5249         {
5250             //printf("  applying _Alignas %s, packalign %d\n", (*specifier.alignExps)[0].toChars(), cast(int)specifier.packalign);
5251             // Wrap declaration in an AlignDeclaration
5252             auto decls = new AST.Dsymbols(1);
5253             (*decls)[0] = s;
5254             s = new AST.AlignDeclaration(s.loc, specifier.alignExps, decls);
5255         }
5256         else if (!specifier.packalign.isDefault())
5257         {
5258             //printf("  applying packalign %d\n", cast(int)specifier.packalign);
5259             // Wrap #pragma pack in an AlignDeclaration
5260             auto decls = new AST.Dsymbols(1);
5261             (*decls)[0] = s;
5262             s = new AST.AlignDeclaration(s.loc, specifier.packalign, decls);
5263         }
5264         return s;
5265     }
5266 
5267     //}
5268 
5269     /******************************************************************************/
5270     /************************** typedefTab symbol table ***************************/
5271     //{
5272 
5273     /********************************
5274      * Determines if type t is a function type.
5275      * Params:
5276      *  t = type to test
5277      * Returns:
5278      *  true if it represents a function
5279      */
5280     bool isFunctionTypedef(AST.Type t)
5281     {
5282         //printf("isFunctionTypedef() %s\n", t.toChars());
5283         if (t.isTypeFunction())
5284             return true;
5285         if (auto tid = t.isTypeIdentifier())
5286         {
5287             auto pt = lookupTypedef(tid.ident);
5288             if (pt && *pt)
5289             {
5290                 return (*pt).isTypeFunction() !is null;
5291             }
5292         }
5293         return false;
5294     }
5295 
5296     /********************************
5297      * Determine if `id` is a symbol for a Typedef.
5298      * Params:
5299      *  id = possible typedef
5300      * Returns:
5301      *  true if id is a Type
5302      */
5303     bool isTypedef(Identifier id)
5304     {
5305         auto pt = lookupTypedef(id);
5306         return (pt && *pt);
5307     }
5308 
5309     /*******************************
5310      * Add `id` to typedefTab[], but only if it will mask an existing typedef.
5311      * Params: id = identifier for non-typedef symbol
5312      */
5313     void insertIdToTypedefTab(Identifier id)
5314     {
5315         //printf("insertIdToTypedefTab(id: %s) level %d\n", id.toChars(), cast(int)typedefTab.length - 1);
5316         if (isTypedef(id))  // if existing typedef
5317         {
5318             /* Add id as null, so we can later distinguish it from a non-null typedef
5319              */
5320             auto tab = cast(void*[void*])(typedefTab[$ - 1]);
5321             tab[cast(void*)id] = cast(void*)null;
5322         }
5323     }
5324 
5325     /*******************************
5326      * Add `id` to typedefTab[]
5327      * Params:
5328      *  id = identifier for typedef symbol
5329      *  t = type of the typedef symbol
5330      */
5331     void insertTypedefToTypedefTab(Identifier id, AST.Type t)
5332     {
5333         //printf("insertTypedefToTypedefTab(id: %s, t: %s) level %d\n", id.toChars(), t ? t.toChars() : "null".ptr, cast(int)typedefTab.length - 1);
5334         if (auto tid = t.isTypeIdentifier())
5335         {
5336             // Try to resolve the TypeIdentifier to its type
5337             auto pt = lookupTypedef(tid.ident);
5338             if (pt && *pt)
5339                 t = *pt;
5340         }
5341         auto tab = cast(void*[void*])(typedefTab[$ - 1]);
5342         tab[cast(void*)id] = cast(void*)t;
5343         typedefTab[$ - 1] = cast(void*)tab;
5344     }
5345 
5346     /*********************************
5347      * Lookup id in typedefTab[].
5348      * Returns:
5349      *  if not found, then null.
5350      *  if found, then Type*. Deferencing it will yield null if it is not
5351      *  a typedef, and a type if it is a typedef.
5352      */
5353     AST.Type* lookupTypedef(Identifier id)
5354     {
5355         foreach_reverse (tab; typedefTab[])
5356         {
5357             if (auto pt = cast(void*)id in cast(void*[void*])tab)
5358             {
5359                 return cast(AST.Type*)pt;
5360             }
5361         }
5362         return null; // not found
5363     }
5364 
5365     //}
5366 
5367     /******************************************************************************/
5368     /********************************* Directive Parser ***************************/
5369     //{
5370 
5371     override bool parseSpecialTokenSequence()
5372     {
5373         Token n;
5374         scan(&n);
5375         if (n.value == TOK.int32Literal)
5376         {
5377             poundLine(n, true);
5378             return true;
5379         }
5380         if (n.value == TOK.identifier)
5381         {
5382             if (n.ident == Id.line)
5383             {
5384                 poundLine(n, false);
5385                 return true;
5386             }
5387             else if (defines && (n.ident == Id.define || n.ident == Id.undef))
5388             {
5389                 /* Append this line to `defines`.
5390                  * Not canonicalizing it - assume it already is
5391                  */
5392                 defines.writeByte('#');
5393                 defines.writestring(n.ident.toString());
5394                 skipToNextLine(defines);
5395                 defines.writeByte('\n');
5396                 return true;
5397             }
5398             else if (n.ident == Id.__pragma)
5399             {
5400                 pragmaDirective(scanloc);
5401                 return true;
5402             }
5403         }
5404         if (n.ident != Id.undef)
5405             error("C preprocessor directive `#%s` is not supported", n.toChars());
5406         return false;
5407     }
5408 
5409     /*********************************************
5410      * VC __pragma
5411      * https://docs.microsoft.com/en-us/cpp/preprocessor/pragma-directives-and-the-pragma-keyword?view=msvc-170
5412      * Scanner is on the `__pragma`
5413      * Params:
5414      *  startloc = location to use for error messages
5415      */
5416     private void uupragmaDirective(const ref Loc startloc)
5417     {
5418         const loc = startloc;
5419         nextToken();
5420         if (token.value != TOK.leftParenthesis)
5421         {
5422             error(loc, "left parenthesis expected to follow `__pragma`");
5423             return;
5424         }
5425         nextToken();
5426         if (token.value == TOK.identifier && token.ident == Id.pack)
5427             pragmaPack(startloc, false);
5428         else
5429             error(loc, "unrecognized __pragma");
5430         if (token.value != TOK.rightParenthesis)
5431         {
5432             error(loc, "right parenthesis expected to close `__pragma(...)`");
5433             return;
5434         }
5435         nextToken();
5436     }
5437 
5438     /*********************************************
5439      * C11 6.10.6 Pragma directive
5440      * # pragma pp-tokens(opt) new-line
5441      * The C preprocessor sometimes leaves pragma directives in
5442      * the preprocessed output. Ignore them.
5443      * Upon return, p is at start of next line.
5444      */
5445     private void pragmaDirective(const ref Loc loc)
5446     {
5447         Token n;
5448         scan(&n);
5449         if (n.value == TOK.identifier && n.ident == Id.pack)
5450             return pragmaPack(loc, true);
5451         if (n.value != TOK.endOfLine)
5452             skipToNextLine();
5453     }
5454 
5455     /*********
5456      * # pragma pack
5457      * https://gcc.gnu.org/onlinedocs/gcc-4.4.4/gcc/Structure_002dPacking-Pragmas.html
5458      * https://docs.microsoft.com/en-us/cpp/preprocessor/pack
5459      * Scanner is on the `pack`
5460      * Params:
5461      *  startloc = location to use for error messages
5462      *  useScan = use scan() to retrieve next token, instead of nextToken()
5463      */
5464     private void pragmaPack(const ref Loc startloc, bool useScan)
5465     {
5466         const loc = startloc;
5467 
5468         /* Pull tokens from scan() or nextToken()
5469          */
5470         void scan(Token* t)
5471         {
5472             if (useScan)
5473             {
5474                 Lexer.scan(t);
5475             }
5476             else
5477             {
5478                 nextToken();
5479                 *t = token;
5480             }
5481         }
5482 
5483         Token n;
5484         scan(&n);
5485         if (n.value != TOK.leftParenthesis)
5486         {
5487             error(loc, "left parenthesis expected to follow `#pragma pack`");
5488             if (n.value != TOK.endOfLine)
5489                 skipToNextLine();
5490             return;
5491         }
5492 
5493         void closingParen()
5494         {
5495             if (n.value != TOK.rightParenthesis)
5496             {
5497                 error(loc, "right parenthesis expected to close `#pragma pack(`");
5498             }
5499             if (n.value != TOK.endOfLine)
5500                 skipToNextLine();
5501         }
5502 
5503         void setPackAlign(ref const Token t)
5504         {
5505             const n = t.unsvalue;
5506             if (n < 1 || n & (n - 1) || ushort.max < n)
5507                 error(loc, "pack must be an integer positive power of 2, not 0x%llx", cast(ulong)n);
5508             packalign.set(cast(uint)n);
5509             packalign.setPack(true);
5510         }
5511 
5512         scan(&n);
5513 
5514         if (!records)
5515         {
5516             records = new Array!Identifier;
5517             packs = new Array!structalign_t;
5518         }
5519 
5520         /* # pragma pack ( show )
5521          */
5522         if (n.value == TOK.identifier && n.ident == Id.show)
5523         {
5524             if (packalign.isDefault())
5525                 eSink.warning(startloc, "current pack attribute is default");
5526             else
5527                 eSink.warning(startloc, "current pack attribute is %d", packalign.get());
5528             scan(&n);
5529             return closingParen();
5530         }
5531         /* # pragma pack ( push )
5532          * # pragma pack ( push , identifier )
5533          * # pragma pack ( push , integer )
5534          * # pragma pack ( push , identifier , integer )
5535          */
5536         if (n.value == TOK.identifier && n.ident == Id.push)
5537         {
5538             scan(&n);
5539             Identifier record = null;
5540             if (n.value == TOK.comma)
5541             {
5542                 scan(&n);
5543                 if (n.value == TOK.identifier)
5544                 {
5545                     record = n.ident;
5546                     scan(&n);
5547                     if (n.value == TOK.comma)
5548                     {
5549                         scan(&n);
5550                         if (n.value == TOK.int32Literal)
5551                         {
5552                             setPackAlign(n);
5553                             scan(&n);
5554                         }
5555                         else
5556                             error(loc, "alignment value expected, not `%s`", n.toChars());
5557                     }
5558                 }
5559                 else if (n.value == TOK.int32Literal)
5560                 {
5561                     setPackAlign(n);
5562                     scan(&n);
5563                 }
5564                 else
5565                     error(loc, "alignment value expected, not `%s`", n.toChars());
5566             }
5567             this.records.push(record);
5568             this.packs.push(packalign);
5569             return closingParen();
5570         }
5571         /* # pragma pack ( pop )
5572          * # pragma pack ( pop PopList )
5573          * PopList :
5574          *    , IdentifierOrInteger
5575          *    , IdentifierOrInteger PopList
5576          * IdentifierOrInteger:
5577          *      identifier
5578          *      integer
5579          */
5580         if (n.value == TOK.identifier && n.ident == Id.pop)
5581         {
5582             scan(&n);
5583             size_t len = this.records.length;
5584             if (n.value == TOK.rightParenthesis) // #pragma pack ( pop )
5585             {
5586                 if (len == 0)   // nothing to pop
5587                     return closingParen();
5588 
5589                 this.records.setDim(len - 1);
5590                 this.packs.setDim(len - 1);
5591                 if (len == 1)   // stack is now empty
5592                     packalign.setDefault();
5593                 else
5594                     packalign = (*this.packs)[len - 1];
5595                 return closingParen();
5596             }
5597             while (n.value == TOK.comma)        // #pragma pack ( pop ,
5598             {
5599                 scan(&n);
5600                 if (n.value == TOK.identifier)
5601                 {
5602                     /* pragma pack(pop, identifier
5603                      * Pop until identifier is found, pop that one too, and set
5604                      * alignment to the new top of the stack.
5605                      * If identifier is not found, do nothing.
5606                      */
5607                     for ( ; len; --len)
5608                     {
5609                         if ((*this.records)[len - 1] == n.ident)
5610                         {
5611                             this.records.setDim(len - 1);
5612                             this.packs.setDim(len - 1);
5613                             if (len > 1)
5614                                 packalign = (*this.packs)[len - 2];
5615                             else
5616                                 packalign.setDefault(); // stack empty, use default
5617                             break;
5618                         }
5619                     }
5620                     scan(&n);
5621                 }
5622                 else if (n.value == TOK.int32Literal)
5623                 {
5624                     setPackAlign(n);
5625                     scan(&n);
5626                 }
5627                 else
5628                 {
5629                     error(loc, "identifier or alignment value expected following `#pragma pack(pop,` not `%s`", n.toChars());
5630                     scan(&n);
5631                 }
5632             }
5633             return closingParen();
5634         }
5635         /* # pragma pack ( integer )
5636          * Sets alignment to integer
5637          */
5638         if (n.value == TOK.int32Literal)
5639         {
5640             setPackAlign(n);
5641             scan(&n);
5642             return closingParen();
5643         }
5644         /* # pragma pack ( )
5645          * Sets alignment to default
5646          */
5647         if (n.value == TOK.rightParenthesis)
5648         {
5649             packalign.setDefault();
5650             return closingParen();
5651         }
5652 
5653         error(loc, "unrecognized `#pragma pack(%s)`", n.toChars());
5654         if (n.value != TOK.endOfLine)
5655             skipToNextLine();
5656     }
5657 
5658     //}
5659 
5660     /******************************************************************************/
5661     /********************************* #define Parser *****************************/
5662     //{
5663 
5664     /**
5665      * Go through the #define's in the defines buffer and see what we can convert
5666      * to Dsymbols, which are then appended to symbols[]
5667      */
5668     void addDefines()
5669     {
5670         if (!defines || defines.length < 10)  // minimum length of a #define line
5671             return;
5672         OutBuffer* buf = defines;
5673         defines = null;                 // prevent skipToNextLine() and parseSpecialTokenSequence()
5674                                         // from appending to slice[]
5675         const length = buf.length;
5676         buf.writeByte(0);
5677         auto slice = buf.peekChars()[0 .. length];
5678         resetDefineLines(slice);                // reset lexer
5679 
5680         const(char)* endp = &slice[length - 7];
5681 
5682         size_t[void*] defineTab;    // hash table of #define's turned into Symbol's
5683                                     // indexed by Identifier, returns index into symbols[]
5684                                     // The memory for this is leaked
5685 
5686         void addVar(AST.VarDeclaration v)
5687         {
5688             //printf("addVar() %s\n", v.toChars());
5689             v.isCmacro(true);           // mark it as coming from a C #define
5690             /* If it's already defined, replace the earlier
5691              * definition
5692              */
5693             if (size_t* pd = cast(void*)v.ident in defineTab)
5694             {
5695                 //printf("replacing %s\n", v.toChars());
5696                 (*symbols)[*pd] = v;
5697                 return;
5698             }
5699             defineTab[cast(void*)v.ident] = symbols.length;
5700             symbols.push(v);
5701         }
5702 
5703         Token n;
5704 
5705         while (p < endp)
5706         {
5707             if (p[0 .. 7] == "#define")
5708             {
5709                 p += 7;
5710                 scan(&n);
5711                 //printf("%s\n", n.toChars());
5712                 if (n.value == TOK.identifier)
5713                 {
5714                     auto id = n.ident;
5715                     scan(&n);
5716 
5717                     AST.Type t;
5718 
5719                     switch (n.value)
5720                     {
5721                         case TOK.endOfLine:     // #define identifier
5722                             nextDefineLine();
5723                             continue;
5724 
5725                         case TOK.int32Literal:
5726                         case TOK.charLiteral:       t = AST.Type.tint32;    goto Linteger;
5727                         case TOK.uns32Literal:      t = AST.Type.tuns32;    goto Linteger;
5728                         case TOK.int64Literal:      t = AST.Type.tint64;    goto Linteger;
5729                         case TOK.uns64Literal:      t = AST.Type.tuns64;    goto Linteger;
5730 
5731                         Linteger:
5732                             const intvalue = n.intvalue;
5733                             scan(&n);
5734                             if (n.value == TOK.endOfLine)
5735                             {
5736                                 /* Declare manifest constant:
5737                                  *  enum id = intvalue;
5738                                  */
5739                                 AST.Expression e = new AST.IntegerExp(scanloc, intvalue, t);
5740                                 auto v = new AST.VarDeclaration(scanloc, t, id, new AST.ExpInitializer(scanloc, e), STC.manifest);
5741                                 addVar(v);
5742                                 nextDefineLine();
5743                                 continue;
5744                             }
5745                             break;
5746 
5747                         case TOK.float32Literal:      t = AST.Type.tfloat32;     goto Lfloat;
5748                         case TOK.float64Literal:      t = AST.Type.tfloat64;     goto Lfloat;
5749                         case TOK.float80Literal:      t = AST.Type.tfloat80;     goto Lfloat;
5750                         case TOK.imaginary32Literal:  t = AST.Type.timaginary32; goto Lfloat;
5751                         case TOK.imaginary64Literal:  t = AST.Type.timaginary64; goto Lfloat;
5752                         case TOK.imaginary80Literal:  t = AST.Type.timaginary80; goto Lfloat;
5753 
5754                         Lfloat:
5755                             const floatvalue = n.floatvalue;
5756                             scan(&n);
5757                             if (n.value == TOK.endOfLine)
5758                             {
5759                                 /* Declare manifest constant:
5760                                  *  enum id = floatvalue;
5761                                  */
5762                                 AST.Expression e = new AST.RealExp(scanloc, floatvalue, t);
5763                                 auto v = new AST.VarDeclaration(scanloc, t, id, new AST.ExpInitializer(scanloc, e), STC.manifest);
5764                                 addVar(v);
5765                                 nextDefineLine();
5766                                 continue;
5767                             }
5768                             break;
5769 
5770                         case TOK.string_:
5771                             const str = n.ustring;
5772                             const len = n.len;
5773                             const postfix = n.postfix;
5774                             scan(&n);
5775                             if (n.value == TOK.endOfLine)
5776                             {
5777                                 /* Declare manifest constant:
5778                                  *  enum id = "string";
5779                                  */
5780                                 AST.Expression e = new AST.StringExp(scanloc, str[0 .. len], len, 1, postfix);
5781                                 auto v = new AST.VarDeclaration(scanloc, null, id, new AST.ExpInitializer(scanloc, e), STC.manifest);
5782                                 addVar(v);
5783                                 nextDefineLine();
5784                                 continue;
5785                             }
5786                             break;
5787 
5788                         default:
5789                             break;
5790                     }
5791                 }
5792                 skipToNextLine();
5793             }
5794             else
5795             {
5796                 scan(&n);
5797                 if (n.value != TOK.endOfLine)
5798                 {
5799                     skipToNextLine();
5800                 }
5801             }
5802             nextDefineLine();
5803         }
5804 
5805         defines = buf;
5806     }
5807 
5808     //}
5809 }