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