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