d: Merge upstream dmd 3982604c5, druntime bc58b1e9, phobos 12329adb6.
[official-gcc.git] / gcc / d / dmd / cparse.d
blobdfc45e0bc31ee76822783ab80b93e46ed7ec4f97
1 /**
2 * Takes a token stream from the lexer, and parses it into an abstract syntax tree.
4 * Specification: C11
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
14 module dmd.cparse;
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.common.outbuffer;
27 import dmd.root.rmem;
28 import dmd.root.rootobject;
29 import dmd.root.string;
30 import dmd.tokens;
32 /***********************************************************
34 final class CParser(AST) : Parser!AST
36 AST.Dsymbols* symbols; // symbols declared in current scope
38 bool addFuncName; /// add declaration of __func__ to function symbol table
40 extern (D) this(TARGET)(AST.Module _module, const(char)[] input, bool doDocComment,
41 const ref TARGET target)
43 super(_module, input, doDocComment);
45 //printf("CParser.this()\n");
46 mod = _module;
47 linkage = LINK.c;
48 Ccompile = true;
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;
55 // C `char` is always unsigned in ImportC
58 /********************************************
59 * Parse translation unit.
60 * C11 6.9
61 * translation-unit:
62 * external-declaration
63 * translation-unit external-declaration
65 * external-declaration:
66 * function-definition
67 * declaration
68 * Returns:
69 * array of Dsymbols that were declared
71 override AST.Dsymbols* parseModule()
73 //printf("cparseTranslationUnit()\n");
74 symbols = new AST.Dsymbols();
75 addBuiltinDeclarations();
76 while (1)
78 if (token.value == TOK.endOfFile)
80 // wrap the symbols in `extern (C) { symbols }`
81 auto wrap = new AST.Dsymbols();
82 auto ld = new AST.LinkDeclaration(token.loc, LINK.c, symbols);
83 wrap.push(ld);
85 return wrap;
88 cparseDeclaration(LVL.global);
92 /******************************************************************************/
93 /********************************* Statement Parser ***************************/
94 //{
96 /**********************
97 * C11 6.8
98 * statement:
99 * labeled-statement
100 * compound-statement
101 * expression-statement
102 * selection-statement
103 * iteration-statement
104 * jump-statement
106 * Params:
107 * flags = PSxxxx
108 * endPtr = store location of closing brace
109 * pEndloc = if { ... statements ... }, store location of closing brace, otherwise loc of last token of statement
110 * Returns:
111 * parsed statement
113 AST.Statement cparseStatement(int flags, const(char)** endPtr = null, Loc* pEndloc = null)
115 AST.Statement s;
116 const loc = token.loc;
118 //printf("cparseStatement()\n");
120 auto symbolsSave = symbols;
121 if (!(flags & (ParseStatementFlags.scope_ | ParseStatementFlags.curlyScope)))
122 symbols = new AST.Dsymbols();
124 switch (token.value)
126 case TOK.identifier:
127 /* A leading identifier can be a declaration, label, or expression.
128 * A quick check of the next token can disambiguate most cases.
130 switch (peekNext())
132 case TOK.colon:
134 // It's a label
135 auto ident = token.ident;
136 nextToken(); // advance to `:`
137 nextToken(); // advance past `:`
138 if (token.value == TOK.rightCurly)
139 s = null;
140 else if (token.value == TOK.leftCurly)
141 s = cparseStatement(ParseStatementFlags.curly | ParseStatementFlags.scope_);
142 else
143 s = cparseStatement(ParseStatementFlags.semiOk);
144 s = new AST.LabelStatement(loc, ident, s);
145 break;
148 case TOK.dot:
149 case TOK.arrow:
150 case TOK.plusPlus:
151 case TOK.minusMinus:
152 case TOK.leftBracket:
153 case TOK.question:
154 case TOK.assign:
155 case TOK.addAssign:
156 case TOK.minAssign:
157 case TOK.mulAssign:
158 case TOK.divAssign:
159 case TOK.modAssign:
160 case TOK.andAssign:
161 case TOK.orAssign:
162 case TOK.xorAssign:
163 case TOK.leftShiftAssign:
164 case TOK.rightShiftAssign:
165 goto Lexp;
167 case TOK.leftParenthesis:
169 /* If tokens look like a function call, assume it is one,
170 * As any type-name won't be resolved until semantic, this
171 * could be rewritten later.
173 auto tk = &token;
174 if (isFunctionCall(tk))
175 goto Lexp;
176 goto default;
179 default:
181 /* If tokens look like a declaration, assume it is one
183 auto tk = &token;
184 if (isCDeclaration(tk))
185 goto Ldeclaration;
186 goto Lexp;
189 break;
191 case TOK.int32Literal:
192 case TOK.uns32Literal:
193 case TOK.int64Literal:
194 case TOK.uns64Literal:
195 case TOK.int128Literal:
196 case TOK.uns128Literal:
197 case TOK.float32Literal:
198 case TOK.float64Literal:
199 case TOK.float80Literal:
200 case TOK.imaginary32Literal:
201 case TOK.imaginary64Literal:
202 case TOK.imaginary80Literal:
203 case TOK.leftParenthesis:
204 case TOK.and:
205 case TOK.mul:
206 case TOK.min:
207 case TOK.add:
208 case TOK.tilde:
209 case TOK.not:
210 case TOK.plusPlus:
211 case TOK.minusMinus:
212 case TOK.sizeof_:
213 Lexp:
214 auto exp = cparseExpression();
215 if (token.value == TOK.identifier && exp.op == EXP.identifier)
217 error("found `%s` when expecting `;` or `=`, did you mean `%s %s = %s`?", peek(&token).toChars(), exp.toChars(), token.toChars(), peek(peek(&token)).toChars());
218 nextToken();
220 else
221 check(TOK.semicolon, "statement");
222 s = new AST.ExpStatement(loc, exp);
223 break;
225 // type-specifiers
226 case TOK.void_:
227 case TOK.char_:
228 case TOK.int16:
229 case TOK.int32:
230 case TOK.int64:
231 case TOK.float32:
232 case TOK.float64:
233 case TOK.signed:
234 case TOK.unsigned:
235 case TOK._Bool:
236 //case TOK._Imaginary:
237 case TOK._Complex:
238 case TOK.struct_:
239 case TOK.union_:
240 case TOK.enum_:
242 // storage-class-specifiers
243 case TOK.typedef_:
244 case TOK.extern_:
245 case TOK.static_:
246 case TOK._Thread_local:
247 case TOK.auto_:
248 case TOK.register:
250 // function-specifiers
251 case TOK.inline:
252 case TOK._Noreturn:
254 // type-qualifiers
255 case TOK.const_:
256 case TOK.volatile:
257 case TOK.restrict:
259 // alignment-specifier
260 case TOK._Alignas:
262 // atomic-type-specifier or type_qualifier
263 case TOK._Atomic:
265 Ldeclaration:
267 cparseDeclaration(LVL.local);
268 if (symbols.length > 1)
270 auto as = new AST.Statements();
271 as.reserve(symbols.length);
272 foreach (d; (*symbols)[])
274 s = new AST.ExpStatement(loc, d);
275 as.push(s);
277 s = new AST.CompoundDeclarationStatement(loc, as);
278 symbols.setDim(0);
280 else if (symbols.length == 1)
282 auto d = (*symbols)[0];
283 s = new AST.ExpStatement(loc, d);
284 symbols.setDim(0);
286 else
287 s = new AST.ExpStatement(loc, cast(AST.Expression)null);
288 if (flags & ParseStatementFlags.scope_)
289 s = new AST.ScopeStatement(loc, s, token.loc);
290 break;
293 case TOK._Static_assert: // _Static_assert ( constant-expression, string-literal ) ;
294 s = new AST.StaticAssertStatement(cparseStaticAssert());
295 break;
297 case TOK.leftCurly:
299 /* C11 6.8.2
300 * compound-statement:
301 * { block-item-list (opt) }
303 * block-item-list:
304 * block-item
305 * block-item-list block-item
307 * block-item:
308 * declaration
309 * statement
311 nextToken();
312 auto statements = new AST.Statements();
313 while (token.value != TOK.rightCurly && token.value != TOK.endOfFile)
315 statements.push(cparseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope));
317 if (endPtr)
318 *endPtr = token.ptr;
319 endloc = token.loc;
320 if (pEndloc)
322 *pEndloc = token.loc;
323 pEndloc = null; // don't set it again
325 s = new AST.CompoundStatement(loc, statements);
326 if (flags & (ParseStatementFlags.scope_ | ParseStatementFlags.curlyScope))
327 s = new AST.ScopeStatement(loc, s, token.loc);
328 check(TOK.rightCurly, "compound statement");
329 break;
332 case TOK.while_:
334 nextToken();
335 check(TOK.leftParenthesis);
336 auto condition = cparseExpression();
337 check(TOK.rightParenthesis);
338 Loc endloc;
339 auto _body = cparseStatement(ParseStatementFlags.scope_, null, &endloc);
340 s = new AST.WhileStatement(loc, condition, _body, endloc, null);
341 break;
344 case TOK.semicolon:
345 /* C11 6.8.3 null statement
347 nextToken();
348 s = new AST.ExpStatement(loc, cast(AST.Expression)null);
349 break;
351 case TOK.do_:
353 nextToken();
354 auto _body = cparseStatement(ParseStatementFlags.scope_);
355 check(TOK.while_);
356 check(TOK.leftParenthesis);
357 auto condition = cparseExpression();
358 check(TOK.rightParenthesis);
359 check(TOK.semicolon, "terminating `;` required after do-while statement");
360 s = new AST.DoStatement(loc, _body, condition, token.loc);
361 break;
364 case TOK.for_:
366 AST.Statement _init;
367 AST.Expression condition;
368 AST.Expression increment;
370 nextToken();
371 check(TOK.leftParenthesis);
372 if (token.value == TOK.semicolon)
374 _init = null;
375 nextToken();
377 else
379 _init = cparseStatement(0);
381 if (token.value == TOK.semicolon)
383 condition = null;
384 nextToken();
386 else
388 condition = cparseExpression();
389 check(TOK.semicolon, "`for` condition");
391 if (token.value == TOK.rightParenthesis)
393 increment = null;
394 nextToken();
396 else
398 increment = cparseExpression();
399 check(TOK.rightParenthesis);
401 Loc endloc;
402 auto _body = cparseStatement(ParseStatementFlags.scope_, null, &endloc);
403 s = new AST.ForStatement(loc, _init, condition, increment, _body, endloc);
404 break;
407 case TOK.if_:
409 nextToken();
410 check(TOK.leftParenthesis);
411 auto condition = cparseExpression();
412 check(TOK.rightParenthesis);
413 auto ifbody = cparseStatement(ParseStatementFlags.scope_);
414 AST.Statement elsebody;
415 if (token.value == TOK.else_)
417 nextToken();
418 elsebody = cparseStatement(ParseStatementFlags.scope_);
420 else
421 elsebody = null;
422 if (condition && ifbody)
423 s = new AST.IfStatement(loc, null, condition, ifbody, elsebody, token.loc);
424 else
425 s = null; // don't propagate parsing errors
426 break;
429 case TOK.else_:
430 error("found `else` without a corresponding `if` statement");
431 goto Lerror;
433 case TOK.switch_:
435 nextToken();
436 check(TOK.leftParenthesis);
437 auto condition = cparseExpression();
438 check(TOK.rightParenthesis);
439 auto _body = cparseStatement(ParseStatementFlags.scope_);
440 s = new AST.SwitchStatement(loc, condition, _body, false);
441 break;
444 case TOK.case_:
447 nextToken();
448 auto exp = cparseAssignExp();
449 check(TOK.colon);
451 if (flags & ParseStatementFlags.curlyScope)
453 auto statements = new AST.Statements();
454 while (token.value != TOK.case_ && token.value != TOK.default_ && token.value != TOK.endOfFile && token.value != TOK.rightCurly)
456 auto cur = cparseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope);
457 statements.push(cur);
459 // https://issues.dlang.org/show_bug.cgi?id=21739
460 // Stop at the last break s.t. the following non-case statements are
461 // not merged into the current case. This can happen for
462 // case 1: ... break;
463 // debug { case 2: ... }
464 if (cur && cur.isBreakStatement())
465 break;
467 s = new AST.CompoundStatement(loc, statements);
469 else
471 s = cparseStatement(ParseStatementFlags.semi);
473 s = new AST.ScopeStatement(loc, s, token.loc);
474 s = new AST.CaseStatement(loc, exp, s);
475 break;
478 case TOK.default_:
480 nextToken();
481 check(TOK.colon);
483 if (flags & ParseStatementFlags.curlyScope)
485 auto statements = new AST.Statements();
486 while (token.value != TOK.case_ && token.value != TOK.default_ && token.value != TOK.endOfFile && token.value != TOK.rightCurly)
488 statements.push(cparseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope));
490 s = new AST.CompoundStatement(loc, statements);
492 else
493 s = cparseStatement(ParseStatementFlags.semi);
494 s = new AST.ScopeStatement(loc, s, token.loc);
495 s = new AST.DefaultStatement(loc, s);
496 break;
499 case TOK.return_:
501 /* return ;
502 * return expression ;
504 nextToken();
505 auto exp = token.value == TOK.semicolon ? null : cparseExpression();
506 check(TOK.semicolon, "`return` statement");
507 s = new AST.ReturnStatement(loc, exp);
508 break;
511 case TOK.break_:
512 nextToken();
513 check(TOK.semicolon, "`break` statement");
514 s = new AST.BreakStatement(loc, null);
515 break;
517 case TOK.continue_:
518 nextToken();
519 check(TOK.semicolon, "`continue` statement");
520 s = new AST.ContinueStatement(loc, null);
521 break;
523 case TOK.goto_:
525 Identifier ident;
526 nextToken();
527 if (token.value != TOK.identifier)
529 error("identifier expected following `goto`");
530 ident = null;
532 else
534 ident = token.ident;
535 nextToken();
537 s = new AST.GotoStatement(loc, ident);
538 check(TOK.semicolon, "`goto` statement");
539 break;
542 case TOK.asm_:
543 s = parseAsm();
544 break;
546 default:
547 error("found `%s` instead of statement", token.toChars());
548 goto Lerror;
550 Lerror:
551 panic();
552 if (token.value == TOK.semicolon)
553 nextToken();
554 s = null;
555 break;
557 if (pEndloc)
558 *pEndloc = prevloc;
559 symbols = symbolsSave;
560 return s;
564 /*******************************************************************************/
565 /********************************* Expression Parser ***************************/
568 /**************
569 * C11 6.5.17
570 * expression:
571 * assignment-expression
572 * expression , assignment-expression
574 AST.Expression cparseExpression()
576 auto loc = token.loc;
578 //printf("cparseExpression() loc = %d\n", loc.linnum);
579 auto e = cparseAssignExp();
580 while (token.value == TOK.comma)
582 nextToken();
583 auto e2 = cparseAssignExp();
584 e = new AST.CommaExp(loc, e, e2, false);
585 loc = token.loc;
587 return e;
591 /*********************
592 * C11 6.5.1
593 * primary-expression:
594 * identifier
595 * constant
596 * string-literal
597 * ( expression )
598 * generic-selection
600 AST.Expression cparsePrimaryExp()
602 AST.Expression e;
603 const loc = token.loc;
605 //printf("parsePrimaryExp(): loc = %d\n", loc.linnum);
606 switch (token.value)
608 case TOK.identifier:
609 if (token.ident is Id.__func__)
611 addFuncName = true; // implicitly declare __func__
613 e = new AST.IdentifierExp(loc, token.ident);
614 nextToken();
615 break;
617 case TOK.int32Literal:
618 e = new AST.IntegerExp(loc, token.intvalue, AST.Type.tint32);
619 nextToken();
620 break;
622 case TOK.uns32Literal:
623 e = new AST.IntegerExp(loc, token.unsvalue, AST.Type.tuns32);
624 nextToken();
625 break;
627 case TOK.int64Literal:
628 e = new AST.IntegerExp(loc, token.intvalue, AST.Type.tint64);
629 nextToken();
630 break;
632 case TOK.uns64Literal:
633 e = new AST.IntegerExp(loc, token.unsvalue, AST.Type.tuns64);
634 nextToken();
635 break;
637 case TOK.float32Literal:
638 e = new AST.RealExp(loc, token.floatvalue, AST.Type.tfloat32);
639 nextToken();
640 break;
642 case TOK.float64Literal:
643 e = new AST.RealExp(loc, token.floatvalue, AST.Type.tfloat64);
644 nextToken();
645 break;
647 case TOK.float80Literal:
648 e = new AST.RealExp(loc, token.floatvalue, AST.Type.tfloat80);
649 nextToken();
650 break;
652 case TOK.imaginary32Literal:
653 e = new AST.RealExp(loc, token.floatvalue, AST.Type.timaginary32);
654 nextToken();
655 break;
657 case TOK.imaginary64Literal:
658 e = new AST.RealExp(loc, token.floatvalue, AST.Type.timaginary64);
659 nextToken();
660 break;
662 case TOK.imaginary80Literal:
663 e = new AST.RealExp(loc, token.floatvalue, AST.Type.timaginary80);
664 nextToken();
665 break;
667 case TOK.string_:
669 // cat adjacent strings
670 auto s = token.ustring;
671 auto len = token.len;
672 auto postfix = token.postfix;
673 while (1)
675 nextToken();
676 if (token.value == TOK.string_)
678 if (token.postfix)
680 if (token.postfix != postfix)
681 error("mismatched string literal postfixes `'%c'` and `'%c'`", postfix, token.postfix);
682 postfix = token.postfix;
685 const len1 = len;
686 const len2 = token.len;
687 len = len1 + len2;
688 auto s2 = cast(char*)mem.xmalloc_noscan(len * char.sizeof);
689 memcpy(s2, s, len1 * char.sizeof);
690 memcpy(s2 + len1, token.ustring, len2 * char.sizeof);
691 s = s2;
693 else
694 break;
696 e = new AST.StringExp(loc, s[0 .. len], len, 1, postfix);
697 break;
700 case TOK.leftParenthesis:
701 nextToken();
702 e = cparseExpression();
703 check(TOK.rightParenthesis);
704 break;
706 case TOK._Generic:
707 e = cparseGenericSelection();
708 break;
710 default:
711 error("expression expected, not `%s`", token.toChars());
712 // Anything for e, as long as it's not NULL
713 e = new AST.IntegerExp(loc, 0, AST.Type.tint32);
714 nextToken();
715 break;
717 return e;
720 /*********************************
721 * C11 6.5.2
722 * postfix-expression:
723 * primary-expression
724 * postfix-expression [ expression ]
725 * postfix-expression ( argument-expression-list (opt) )
726 * postfix-expression . identifier
727 * postfix-expression -> identifier
728 * postfix-expression ++
729 * postfix-expression --
730 * ( type-name ) { initializer-list }
731 * ( type-name ) { initializer-list , }
733 * argument-expression-list:
734 * assignment-expression
735 * argument-expression-list , assignment-expression
737 private AST.Expression cparsePostfixExp(AST.Expression e)
739 e = cparsePrimaryExp();
740 return cparsePostfixOperators(e);
743 /********************************
744 * C11 6.5.2
745 * Parse a series of operators for a postfix expression after already parsing
746 * a primary-expression or compound literal expression.
747 * Params:
748 * e = parsed primary or compound literal expression
749 * Returns:
750 * parsed postfix expression
752 private AST.Expression cparsePostfixOperators(AST.Expression e)
754 while (1)
756 const loc = token.loc;
757 switch (token.value)
759 case TOK.dot:
760 nextToken();
761 if (token.value == TOK.identifier)
763 Identifier id = token.ident;
764 e = new AST.DotIdExp(loc, e, id);
765 break;
767 error("identifier expected following `.`, not `%s`", token.toChars());
768 break;
770 case TOK.arrow:
771 nextToken();
772 if (token.value == TOK.identifier)
774 Identifier id = token.ident;
775 auto die = new AST.DotIdExp(loc, e, id);
776 die.arrow = true;
777 e = die;
778 break;
780 error("identifier expected following `->`, not `%s`", token.toChars());
781 break;
783 case TOK.plusPlus:
784 e = new AST.PostExp(EXP.plusPlus, loc, e);
785 break;
787 case TOK.minusMinus:
788 e = new AST.PostExp(EXP.minusMinus, loc, e);
789 break;
791 case TOK.leftParenthesis:
792 e = new AST.CallExp(loc, e, cparseArguments());
793 continue;
795 case TOK.leftBracket:
797 // array dereferences:
798 // array[index]
799 AST.Expression index;
800 auto arguments = new AST.Expressions();
802 inBrackets++;
803 nextToken();
804 index = cparseAssignExp();
805 arguments.push(index);
806 check(TOK.rightBracket);
807 inBrackets--;
808 e = new AST.ArrayExp(loc, e, arguments);
809 continue;
811 default:
812 return e;
814 nextToken();
818 /************************
819 * C11 6.5.3
820 * unary-expression:
821 * postfix-expression
822 * ++ unary-expression
823 * -- unary-expression
824 * unary-operator cast-expression
825 * sizeof unary-expression
826 * sizeof ( type-name )
827 * _Alignof ( type-name )
829 * unary-operator:
830 * & * + - ~ !
832 private AST.Expression cparseUnaryExp()
834 AST.Expression e;
835 const loc = token.loc;
837 switch (token.value)
839 case TOK.plusPlus:
840 nextToken();
841 // Parse `++` as an unary operator so that cast expressions only give
842 // an error for being non-lvalues.
843 e = cparseCastExp();
844 e = new AST.PreExp(EXP.prePlusPlus, loc, e);
845 break;
847 case TOK.minusMinus:
848 nextToken();
849 // Parse `--` as an unary operator, same as prefix increment.
850 e = cparseCastExp();
851 e = new AST.PreExp(EXP.preMinusMinus, loc, e);
852 break;
854 case TOK.and:
855 nextToken();
856 e = cparseCastExp();
857 e = new AST.AddrExp(loc, e);
858 break;
860 case TOK.mul:
861 nextToken();
862 e = cparseCastExp();
863 e = new AST.PtrExp(loc, e);
864 break;
866 case TOK.min:
867 nextToken();
868 e = cparseCastExp();
869 e = new AST.NegExp(loc, e);
870 break;
872 case TOK.add:
873 nextToken();
874 e = cparseCastExp();
875 e = new AST.UAddExp(loc, e);
876 break;
878 case TOK.not:
879 nextToken();
880 e = cparseCastExp();
881 e = new AST.NotExp(loc, e);
882 break;
884 case TOK.tilde:
885 nextToken();
886 e = cparseCastExp();
887 e = new AST.ComExp(loc, e);
888 break;
890 case TOK.sizeof_:
892 nextToken();
893 if (token.value == TOK.leftParenthesis)
895 auto tk = peek(&token);
896 if (isTypeName(tk))
898 /* Expression may be either be requesting the sizeof a type-name
899 * or a compound literal, which requires checking whether
900 * the next token is leftCurly
902 nextToken();
903 auto t = cparseTypeName();
904 check(TOK.rightParenthesis);
905 if (token.value == TOK.leftCurly)
907 // ( type-name ) { initializer-list }
908 auto ci = cparseInitializer();
909 e = new AST.CompoundLiteralExp(loc, t, ci);
910 e = cparsePostfixOperators(e);
912 else
914 // ( type-name )
915 e = new AST.TypeExp(loc, t);
917 e = new AST.DotIdExp(loc, e, Id.__sizeof);
918 break;
921 e = cparseUnaryExp();
922 e = new AST.DotIdExp(loc, e, Id.__sizeof);
923 break;
926 case TOK._Alignof:
928 nextToken();
929 check(TOK.leftParenthesis);
930 auto t = cparseTypeName();
931 check(TOK.rightParenthesis);
932 e = new AST.TypeExp(loc, t);
933 e = new AST.DotIdExp(loc, e, Id.__xalignof);
934 break;
937 default:
938 e = cparsePostfixExp(e);
939 break;
941 assert(e);
942 return e;
945 /**************
946 * C11 6.5.4
947 * cast-expression
948 * unary-expression
949 * ( type-name ) cast-expression
951 private AST.Expression cparseCastExp()
953 if (token.value == TOK.leftParenthesis)
955 // If ( type-name )
956 auto pt = &token;
957 if (isCastExpression(pt))
959 // Expression may be either a cast or a compound literal, which
960 // requires checking whether the next token is leftCurly
961 const loc = token.loc;
962 nextToken();
963 auto t = cparseTypeName();
964 check(TOK.rightParenthesis);
965 pt = &token;
967 if (token.value == TOK.leftCurly)
969 // C11 6.5.2.5 ( type-name ) { initializer-list }
970 auto ci = cparseInitializer();
971 auto ce = new AST.CompoundLiteralExp(loc, t, ci);
972 return cparsePostfixOperators(ce);
974 else if (t.isTypeIdentifier() &&
975 token.value == TOK.leftParenthesis &&
976 !isCastExpression(pt))
978 /* this might actually be a function
979 * call that looks like `(a)(b)` or even `(a)(b,c)`
981 auto ie = new AST.IdentifierExp(loc, t.isTypeIdentifier().ident);
982 ie.parens = true; // disambiguate it from being a declaration
983 return new AST.CallExp(loc, ie, cparseArguments());
985 else
987 // ( type-name ) cast-expression
988 auto ce = cparseCastExp();
989 return new AST.CastExp(loc, ce, t);
993 return cparseUnaryExp();
996 /**************
997 * C11 6.5.5
998 * multiplicative-expression
999 * cast-expression
1000 * multiplicative-expression * cast-expression
1001 * multiplicative-expression / cast-expression
1002 * multiplicative-expression % cast-expression
1004 private AST.Expression cparseMulExp()
1006 const loc = token.loc;
1007 auto e = cparseCastExp();
1009 while (1)
1011 switch (token.value)
1013 case TOK.mul:
1014 nextToken();
1015 auto e2 = cparseCastExp();
1016 e = new AST.MulExp(loc, e, e2);
1017 continue;
1019 case TOK.div:
1020 nextToken();
1021 auto e2 = cparseCastExp();
1022 e = new AST.DivExp(loc, e, e2);
1023 continue;
1025 case TOK.mod:
1026 nextToken();
1027 auto e2 = cparseCastExp();
1028 e = new AST.ModExp(loc, e, e2);
1029 continue;
1031 default:
1032 break;
1034 break;
1036 return e;
1039 /**************
1040 * C11 6.5.6
1041 * additive-expression
1042 * multiplicative-expression
1043 * additive-expression + multiplicative-expression
1044 * additive-expression - multiplicative-expression
1046 private AST.Expression cparseAddExp()
1048 const loc = token.loc;
1049 auto e = cparseMulExp();
1051 while (1)
1053 switch (token.value)
1055 case TOK.add:
1056 nextToken();
1057 auto e2 = cparseMulExp();
1058 e = new AST.AddExp(loc, e, e2);
1059 continue;
1061 case TOK.min:
1062 nextToken();
1063 auto e2 = cparseMulExp();
1064 e = new AST.MinExp(loc, e, e2);
1065 continue;
1067 default:
1068 break;
1070 break;
1072 return e;
1075 /**************
1076 * C11 6.5.7
1077 * shift-expression
1078 * additive-expression
1079 * shift-expression << additive-expression
1080 * shift-expression >> additive-expression
1082 private AST.Expression cparseShiftExp()
1084 const loc = token.loc;
1085 auto e = cparseAddExp();
1087 while (1)
1089 switch (token.value)
1091 case TOK.leftShift:
1092 nextToken();
1093 auto e2 = cparseAddExp();
1094 e = new AST.ShlExp(loc, e, e2);
1095 continue;
1097 case TOK.rightShift:
1098 nextToken();
1099 auto e2 = cparseAddExp();
1100 e = new AST.ShrExp(loc, e, e2);
1101 continue;
1103 default:
1104 break;
1106 break;
1108 return e;
1111 /**************
1112 * C11 6.5.8
1113 * relational-expression
1114 * shift-expression
1115 * relational-expression < shift-expression
1116 * relational-expression > shift-expression
1117 * relational-expression <= shift-expression
1118 * relational-expression >= shift-expression
1120 private AST.Expression cparseRelationalExp()
1122 const loc = token.loc;
1124 auto e = cparseShiftExp();
1126 EXP op = EXP.reserved;
1127 switch (token.value)
1129 case TOK.lessThan: op = EXP.lessThan; goto Lcmp;
1130 case TOK.lessOrEqual: op = EXP.lessOrEqual; goto Lcmp;
1131 case TOK.greaterThan: op = EXP.greaterThan; goto Lcmp;
1132 case TOK.greaterOrEqual: op = EXP.greaterOrEqual; goto Lcmp;
1133 Lcmp:
1134 nextToken();
1135 auto e2 = cparseShiftExp();
1136 e = new AST.CmpExp(op, loc, e, e2);
1137 break;
1139 default:
1140 break;
1142 return e;
1145 /**************
1146 * C11 6.5.9
1147 * equality-expression
1148 * relational-expression
1149 * equality-expression == relational-expression
1150 * equality-expression != relational-expression
1152 private AST.Expression cparseEqualityExp()
1154 const loc = token.loc;
1156 auto e = cparseRelationalExp();
1158 EXP op = EXP.reserved;
1159 switch (token.value)
1161 case TOK.equal: op = EXP.equal; goto Lequal;
1162 case TOK.notEqual: op = EXP.notEqual; goto Lequal;
1163 Lequal:
1164 nextToken();
1165 auto e2 = cparseRelationalExp();
1166 e = new AST.EqualExp(op, loc, e, e2);
1167 break;
1169 default:
1170 break;
1172 return e;
1175 /**************
1176 * C11 6.5.10
1177 * AND-expression
1178 * equality-expression
1179 * AND-expression & equality-expression
1181 private AST.Expression cparseAndExp()
1183 Loc loc = token.loc;
1184 auto e = cparseEqualityExp();
1185 while (token.value == TOK.and)
1187 nextToken();
1188 auto e2 = cparseEqualityExp();
1189 e = new AST.AndExp(loc, e, e2);
1190 loc = token.loc;
1192 return e;
1195 /**************
1196 * C11 6.5.11
1197 * exclusive-OR-expression
1198 * AND-expression
1199 * exclusive-OR-expression ^ AND-expression
1201 private AST.Expression cparseXorExp()
1203 const loc = token.loc;
1205 auto e = cparseAndExp();
1206 while (token.value == TOK.xor)
1208 nextToken();
1209 auto e2 = cparseAndExp();
1210 e = new AST.XorExp(loc, e, e2);
1212 return e;
1215 /**************
1216 * C11 6.5.12
1217 * inclusive-OR-expression
1218 * exclusive-OR-expression
1219 * inclusive-OR-expression | exclusive-OR-expression
1221 private AST.Expression cparseOrExp()
1223 const loc = token.loc;
1225 auto e = cparseXorExp();
1226 while (token.value == TOK.or)
1228 nextToken();
1229 auto e2 = cparseXorExp();
1230 e = new AST.OrExp(loc, e, e2);
1232 return e;
1235 /**************
1236 * C11 6.5.13
1237 * logical-AND-expression
1238 * inclusive-OR-expression
1239 * logical-AND-expression && inclusive-OR-expression
1241 private AST.Expression cparseAndAndExp()
1243 const loc = token.loc;
1245 auto e = cparseOrExp();
1246 while (token.value == TOK.andAnd)
1248 nextToken();
1249 auto e2 = cparseOrExp();
1250 e = new AST.LogicalExp(loc, EXP.andAnd, e, e2);
1252 return e;
1255 /**************
1256 * C11 6.5.14
1257 * logical-OR-expression
1258 * logical-AND-expression
1259 * logical-OR-expression || logical-AND-expression
1261 private AST.Expression cparseOrOrExp()
1263 const loc = token.loc;
1265 auto e = cparseAndAndExp();
1266 while (token.value == TOK.orOr)
1268 nextToken();
1269 auto e2 = cparseAndAndExp();
1270 e = new AST.LogicalExp(loc, EXP.orOr, e, e2);
1272 return e;
1275 /**************
1276 * C11 6.5.15
1277 * conditional-expression:
1278 * logical-OR-expression
1279 * logical-OR-expression ? expression : conditional-expression
1281 private AST.Expression cparseCondExp()
1283 const loc = token.loc;
1285 auto e = cparseOrOrExp();
1286 if (token.value == TOK.question)
1288 nextToken();
1289 auto e1 = cparseExpression();
1290 check(TOK.colon);
1291 auto e2 = cparseCondExp();
1292 e = new AST.CondExp(loc, e, e1, e2);
1294 return e;
1297 /**************
1298 * C11 6.5.16
1299 * assignment-expression:
1300 * conditional-expression
1301 * unary-expression assignment-operator assignment-expression
1303 * assignment-operator:
1304 * = *= /= %= += -= <<= >>= &= ^= |=
1306 AST.Expression cparseAssignExp()
1308 AST.Expression e;
1309 e = cparseCondExp(); // constrain it to being unary-expression in semantic pass
1310 if (e is null)
1311 return e;
1313 const loc = token.loc;
1314 switch (token.value)
1316 case TOK.assign:
1317 nextToken();
1318 auto e2 = cparseAssignExp();
1319 e = new AST.AssignExp(loc, e, e2);
1320 break;
1322 case TOK.addAssign:
1323 nextToken();
1324 auto e2 = cparseAssignExp();
1325 e = new AST.AddAssignExp(loc, e, e2);
1326 break;
1328 case TOK.minAssign:
1329 nextToken();
1330 auto e2 = cparseAssignExp();
1331 e = new AST.MinAssignExp(loc, e, e2);
1332 break;
1334 case TOK.mulAssign:
1335 nextToken();
1336 auto e2 = cparseAssignExp();
1337 e = new AST.MulAssignExp(loc, e, e2);
1338 break;
1340 case TOK.divAssign:
1341 nextToken();
1342 auto e2 = cparseAssignExp();
1343 e = new AST.DivAssignExp(loc, e, e2);
1344 break;
1346 case TOK.modAssign:
1347 nextToken();
1348 auto e2 = cparseAssignExp();
1349 e = new AST.ModAssignExp(loc, e, e2);
1350 break;
1352 case TOK.andAssign:
1353 nextToken();
1354 auto e2 = cparseAssignExp();
1355 e = new AST.AndAssignExp(loc, e, e2);
1356 break;
1358 case TOK.orAssign:
1359 nextToken();
1360 auto e2 = cparseAssignExp();
1361 e = new AST.OrAssignExp(loc, e, e2);
1362 break;
1364 case TOK.xorAssign:
1365 nextToken();
1366 auto e2 = cparseAssignExp();
1367 e = new AST.XorAssignExp(loc, e, e2);
1368 break;
1370 case TOK.leftShiftAssign:
1371 nextToken();
1372 auto e2 = cparseAssignExp();
1373 e = new AST.ShlAssignExp(loc, e, e2);
1374 break;
1376 case TOK.rightShiftAssign:
1377 nextToken();
1378 auto e2 = cparseAssignExp();
1379 e = new AST.ShrAssignExp(loc, e, e2);
1380 break;
1382 default:
1383 break;
1386 return e;
1389 /***********************
1390 * C11 6.5.1.1
1391 * _Generic ( assignment-expression, generic-assoc-list )
1393 * generic-assoc-list:
1394 * generic-association
1395 * generic-assoc-list generic-association
1397 * generic-association:
1398 * type-name : assignment-expression
1399 * default : assignment-expression
1401 private AST.Expression cparseGenericSelection()
1403 const loc = token.loc;
1404 nextToken();
1405 check(TOK.leftParenthesis);
1406 auto cntlExp = cparseAssignExp();
1407 check(TOK.comma);
1408 auto types = new AST.Types();
1409 auto exps = new AST.Expressions();
1410 bool sawDefault;
1411 while (1)
1413 AST.Type t;
1414 if (token.value == TOK.default_)
1416 nextToken();
1417 if (sawDefault)
1418 error("only one `default` allowed in generic-assoc-list");
1419 sawDefault = true;
1420 t = null;
1422 else
1423 t = cparseTypeName();
1424 types.push(t);
1426 check(TOK.colon);
1427 auto e = cparseAssignExp();
1428 exps.push(e);
1429 if (token.value == TOK.rightParenthesis || token.value == TOK.endOfFile)
1430 break;
1431 check(TOK.comma);
1433 check(TOK.rightParenthesis);
1434 return new AST.GenericExp(loc, cntlExp, types, exps);
1437 /***********************
1438 * C11 6.6 Constant expressions
1439 * constant-expression:
1440 * conditional-expression
1442 private AST.Expression cparseConstantExp()
1444 return cparseAssignExp();
1448 /********************************************************************************/
1449 /********************************* Declaration Parser ***************************/
1452 /*************************************
1453 * C11 6.7
1454 * declaration:
1455 * declaration-specifiers init-declarator-list (opt) ;
1456 * static_assert-declaration
1458 * init-declarator-list:
1459 * init-declarator
1460 * init-declarator-list , init-declarator
1462 * init-declarator:
1463 * declarator
1464 * declarator = initializer
1466 * Params:
1467 * level = declaration context
1469 void cparseDeclaration(LVL level)
1471 //printf("cparseDeclaration(level = %d)\n", level);
1472 if (token.value == TOK._Static_assert)
1474 auto s = cparseStaticAssert();
1475 symbols.push(s);
1476 return;
1479 auto symbolsSave = symbols;
1480 Specifier specifier;
1481 specifier.packalign = this.packalign;
1482 auto tspec = cparseDeclarationSpecifiers(level, specifier);
1484 /* If a declarator does not follow, it is unnamed
1486 if (token.value == TOK.semicolon && tspec)
1488 nextToken();
1489 auto tt = tspec.isTypeTag();
1490 if (!tt ||
1491 !tt.id && (tt.tok == TOK.struct_ || tt.tok == TOK.union_))
1492 return; // legal but meaningless empty declaration, ignore it
1494 /* `struct tag;` and `struct tag { ... };`
1495 * always result in a declaration in the current scope
1497 auto stag = (tt.tok == TOK.struct_) ? new AST.StructDeclaration(tt.loc, tt.id, false) :
1498 (tt.tok == TOK.union_) ? new AST.UnionDeclaration(tt.loc, tt.id) :
1499 new AST.EnumDeclaration(tt.loc, tt.id, AST.Type.tint32);
1500 stag.members = tt.members;
1501 if (!symbols)
1502 symbols = new AST.Dsymbols();
1503 auto stags = applySpecifier(stag, specifier);
1504 symbols.push(stags);
1506 if (tt.tok == TOK.enum_)
1508 if (!tt.members)
1509 error(tt.loc, "`enum %s` has no members", stag.toChars());
1511 return;
1514 if (tspec && specifier.mod & MOD.xconst)
1516 tspec = toConst(tspec);
1517 specifier.mod = MOD.xnone; // 'used' it
1520 bool first = true;
1521 while (1)
1523 Identifier id;
1524 AST.Expression asmname;
1525 auto dt = cparseDeclarator(DTR.xdirect, tspec, id, specifier);
1526 if (!dt)
1528 panic();
1529 nextToken();
1530 break; // error recovery
1533 /* GNU Extensions
1534 * init-declarator:
1535 * declarator simple-asm-expr (opt) gnu-attributes (opt)
1536 * declarator simple-asm-expr (opt) gnu-attributes (opt) = initializer
1538 switch (token.value)
1540 case TOK.assign:
1541 case TOK.comma:
1542 case TOK.semicolon:
1543 case TOK.asm_:
1544 case TOK.__attribute__:
1545 /* This is a data definition, there cannot now be a
1546 * function definition.
1548 first = false;
1549 if (token.value == TOK.asm_)
1550 asmname = cparseSimpleAsmExpr();
1551 if (token.value == TOK.__attribute__)
1553 cparseGnuAttributes(specifier);
1554 if (token.value == TOK.leftCurly)
1556 error("attributes should be specified before the function definition");
1557 auto t = &token;
1558 if (skipBraces(t))
1560 token = *t;
1561 return;
1565 break;
1567 default:
1568 break;
1571 if (specifier.alignExps && dt.isTypeFunction())
1572 error("no alignment-specifier for function declaration"); // C11 6.7.5-2
1573 if (specifier.alignExps && specifier.scw == SCW.xregister)
1574 error("no alignment-specifier for `register` storage class"); // C11 6.7.5-2
1576 /* C11 6.9.1 Function Definitions
1577 * function-definition:
1578 * declaration-specifiers declarator declaration-list (opt) compound-statement
1580 * declaration-list:
1581 * declaration
1582 * declaration-list declaration
1584 auto t = &token;
1585 if (first && // first declarator
1586 id &&
1587 dt.isTypeFunction() && // function type not inherited from a typedef
1588 isDeclarationList(t) && // optional declaration-list
1589 level == LVL.global && // function definitions only at global scope
1590 t.value == TOK.leftCurly) // start of compound-statement
1592 auto s = cparseFunctionDefinition(id, dt.isTypeFunction(), specifier);
1593 symbols = symbolsSave;
1594 symbols.push(s);
1595 return;
1597 AST.Dsymbol s = null;
1598 symbols = symbolsSave;
1599 if (!symbols)
1600 symbols = new AST.Dsymbols; // lazilly create it
1602 if (level != LVL.global && !tspec && !specifier.scw && !specifier.mod)
1603 error("declaration-specifier-seq required");
1604 else if (specifier.scw == SCW.xtypedef)
1606 if (token.value == TOK.assign)
1607 error("no initializer for typedef declaration");
1608 if (specifier.alignExps)
1609 error("no alignment-specifier for typedef declaration"); // C11 6.7.5-2
1611 bool isalias = true;
1612 if (auto ts = dt.isTypeStruct())
1614 if (ts.sym.isAnonymous())
1616 // This is a typedef for an anonymous struct-or-union.
1617 // Directly set the ident for the struct-or-union.
1618 ts.sym.ident = id;
1619 isalias = false;
1622 else if (auto te = dt.isTypeEnum())
1624 if (te.sym.isAnonymous())
1626 // This is a typedef for an anonymous enum.
1627 te.sym.ident = id;
1628 isalias = false;
1631 if (isalias)
1632 s = new AST.AliasDeclaration(token.loc, id, dt);
1634 else if (id)
1636 if (level == LVL.prototype)
1637 break; // declared later as Parameter, not VarDeclaration
1639 if (dt.ty == AST.Tvoid)
1640 error("`void` has no value");
1642 AST.Initializer initializer;
1643 bool hasInitializer;
1644 if (token.value == TOK.assign)
1646 nextToken();
1647 hasInitializer = true;
1648 initializer = cparseInitializer();
1650 // declare the symbol
1651 assert(id);
1652 if (dt.isTypeFunction())
1654 if (hasInitializer)
1655 error("no initializer for function declaration");
1656 if (specifier.scw & SCW.x_Thread_local)
1657 error("functions cannot be `_Thread_local`"); // C11 6.7.1-4
1658 auto fd = new AST.FuncDeclaration(token.loc, Loc.initial, id, specifiersToSTC(level, specifier), dt, specifier.noreturn);
1659 s = fd;
1661 else
1663 // Give non-extern variables an implicit void initializer
1664 // if one has not been explicitly set.
1665 if (!hasInitializer && !(specifier.scw & SCW.xextern))
1666 initializer = new AST.VoidInitializer(token.loc);
1667 s = new AST.VarDeclaration(token.loc, dt, id, initializer, specifiersToSTC(level, specifier));
1670 if (s !is null)
1672 s = applySpecifier(s, specifier);
1673 if (level == LVL.local)
1675 // Wrap the declaration in `extern (C) { declaration }`
1676 // Necessary for function pointers, but harmless to apply to all.
1677 auto decls = new AST.Dsymbols(1);
1678 (*decls)[0] = s;
1679 s = new AST.LinkDeclaration(s.loc, linkage, decls);
1681 // Saw `asm("name")` in the function, type, or variable definition.
1682 // This maps directly to `pragma(mangle, "name")`
1683 if (asmname)
1685 auto args = new AST.Expressions(1);
1686 (*args)[0] = asmname;
1687 auto decls = new AST.Dsymbols(1);
1688 (*decls)[0] = s;
1689 s = new AST.PragmaDeclaration(asmname.loc, Id.mangle, args, decls);
1691 symbols.push(s);
1693 first = false;
1695 switch (token.value)
1697 case TOK.identifier:
1698 if (s)
1700 error("missing comma or semicolon after declaration of `%s`, found `%s` instead", s.toChars(), token.toChars());
1701 goto Lend;
1703 goto default;
1705 case TOK.semicolon:
1706 nextToken();
1707 return;
1709 case TOK.comma:
1710 if (!symbolsSave)
1711 symbolsSave = symbols;
1712 nextToken();
1713 break;
1715 default:
1716 error("`=`, `;` or `,` expected to end declaration instead of `%s`", token.toChars());
1717 Lend:
1718 while (token.value != TOK.semicolon && token.value != TOK.endOfFile)
1719 nextToken();
1720 nextToken();
1721 return;
1726 /***************************************
1727 * C11 Function Definitions
1728 * function-definition
1729 * declaration-specifiers declarator declaration-list (opt) compound-statement
1731 * declaration-list:
1732 * declaration
1733 * declaration-list declaration
1735 * It's already been parsed up to the declaration-list (opt).
1736 * Pick it up from there.
1737 * Params:
1738 * id = function identifier
1739 * ft = function type
1740 * specifier = function specifiers
1741 * Returns:
1742 * Dsymbol for the function
1744 AST.Dsymbol cparseFunctionDefinition(Identifier id, AST.TypeFunction ft, ref Specifier specifier)
1746 if (token.value != TOK.leftCurly) // if not start of a compound-statement
1748 // Do declaration-list
1751 cparseDeclaration(LVL.parameter);
1752 } while (token.value != TOK.leftCurly);
1754 /* Since there were declarations, the parameter-list must have been
1755 * an identifier-list.
1757 auto pl = ft.parameterList;
1758 pl.hasIdentifierList = true; // semantic needs to know to adjust parameter types
1759 if (pl.varargs != AST.VarArg.none && pl.length)
1760 error("function identifier-list cannot end with `...`");
1761 ft.parameterList.varargs = AST.VarArg.variadic; // but C11 allows extra arguments
1762 auto plLength = pl.length;
1763 if (symbols.length != plLength)
1764 error("%d identifiers does not match %d declarations", cast(int)plLength, cast(int)symbols.length);
1766 /* Transfer the types and storage classes from symbols[] to pl[]
1768 foreach (i; 0 .. plLength)
1770 auto p = pl[i]; // yes, quadratic
1772 // Convert typedef-identifier to identifier
1773 if (p.type)
1775 if (auto t = p.type.isTypeIdentifier())
1777 p.ident = t.ident;
1778 p.type = null;
1782 if (p.type || !(p.storageClass & STC.parameter))
1783 error("storage class and type are not allowed in identifier-list");
1784 foreach (s; (*symbols)[]) // yes, quadratic
1786 auto d = s.isDeclaration();
1787 if (d && p.ident == d.ident && d.type)
1789 p.type = d.type;
1790 p.storageClass = d.storage_class;
1791 d.type = null; // don't reuse
1792 break;
1795 if (!p.type)
1797 error("no declaration for identifier `%s`", p.ident.toChars());
1798 p.type = AST.Type.terror;
1803 addFuncName = false; // gets set to true if somebody references __func__ in this function
1804 const locFunc = token.loc;
1806 auto body = cparseStatement(ParseStatementFlags.curly); // don't start a new scope; continue with parameter scope
1807 auto fd = new AST.FuncDeclaration(locFunc, prevloc, id, specifiersToSTC(LVL.global, specifier), ft, specifier.noreturn);
1809 if (addFuncName)
1811 auto s = createFuncName(locFunc, id);
1812 body = new AST.CompoundStatement(locFunc, s, body);
1814 fd.fbody = body;
1816 // TODO add `symbols` to the function's local symbol table `sc2` in FuncDeclaration::semantic3()
1818 return fd;
1821 /***************************************
1822 * C11 Initialization
1823 * initializer:
1824 * assignment-expression
1825 * { initializer-list }
1826 * { initializer-list , }
1828 * initializer-list:
1829 * designation (opt) initializer
1830 * initializer-list , designation (opt) initializer
1832 * designation:
1833 * designator-list =
1835 * designator-list:
1836 * designator
1837 * designator-list designator
1839 * designator:
1840 * [ constant-expression ]
1841 * . identifier
1842 * Returns:
1843 * initializer
1845 AST.Initializer cparseInitializer()
1847 if (token.value != TOK.leftCurly)
1849 auto ae = cparseAssignExp(); // assignment-expression
1850 return new AST.ExpInitializer(token.loc, ae);
1852 nextToken();
1853 const loc = token.loc;
1855 /* Collect one or more `designation (opt) initializer`
1856 * into ci.initializerList, but lazily create ci
1858 AST.CInitializer ci;
1859 while (1)
1861 /* There can be 0 or more designators preceding an initializer.
1862 * Collect them in desigInit
1864 AST.DesigInit desigInit;
1865 while (1)
1867 if (token.value == TOK.leftBracket) // [ constant-expression ]
1869 nextToken();
1870 auto e = cparseConstantExp();
1871 check(TOK.rightBracket);
1872 if (!desigInit.designatorList)
1873 desigInit.designatorList = new AST.Designators;
1874 desigInit.designatorList.push(AST.Designator(e));
1876 else if (token.value == TOK.dot) // . identifier
1878 nextToken();
1879 if (token.value != TOK.identifier)
1881 error("identifier expected following `.` designator");
1882 break;
1884 if (!desigInit.designatorList)
1885 desigInit.designatorList = new AST.Designators;
1886 desigInit.designatorList.push(AST.Designator(token.ident));
1887 nextToken();
1889 else
1891 if (desigInit.designatorList)
1892 check(TOK.assign);
1893 break;
1897 desigInit.initializer = cparseInitializer();
1898 if (!ci)
1899 ci = new AST.CInitializer(loc);
1900 ci.initializerList.push(desigInit);
1901 if (token.value == TOK.comma)
1903 nextToken();
1904 if (token.value != TOK.rightCurly)
1905 continue;
1907 break;
1909 check(TOK.rightCurly);
1910 //printf("ci: %s\n", ci.toChars());
1911 return ci;
1914 /*************************************
1915 * C11 6.7
1916 * declaration-specifier:
1917 * storage-class-specifier declaration-specifiers (opt)
1918 * type-specifier declaration-specifiers (opt)
1919 * type-qualifier declaration-specifiers (opt)
1920 * function-specifier declaration-specifiers (opt)
1921 * alignment-specifier declaration-specifiers (opt)
1922 * Params:
1923 * level = declaration context
1924 * specifier = specifiers in and out
1925 * Returns:
1926 * resulting type, null if not specified
1928 private AST.Type cparseDeclarationSpecifiers(LVL level, ref Specifier specifier)
1930 enum TKW : uint
1932 xnone = 0,
1933 xchar = 1,
1934 xsigned = 2,
1935 xunsigned = 4,
1936 xshort = 8,
1937 xint = 0x10,
1938 xlong = 0x20,
1939 xllong = 0x40,
1940 xfloat = 0x80,
1941 xdouble = 0x100,
1942 xldouble = 0x200,
1943 xtag = 0x400,
1944 xident = 0x800,
1945 xvoid = 0x1000,
1946 xbool = 0x4000,
1947 ximaginary = 0x8000,
1948 xcomplex = 0x10000,
1949 x_Atomic = 0x20000,
1952 AST.Type t;
1953 Loc loc;
1954 //printf("parseDeclarationSpecifiers()\n");
1956 TKW tkw;
1957 SCW scw = specifier.scw & SCW.xtypedef;
1958 MOD mod;
1959 Identifier id;
1960 Identifier previd;
1962 Lwhile:
1963 while (1)
1965 //printf("token %s\n", token.toChars());
1966 TKW tkwx;
1967 SCW scwx;
1968 MOD modx;
1969 switch (token.value)
1971 // Storage class specifiers
1972 case TOK.static_: scwx = SCW.xstatic; break;
1973 case TOK.extern_: scwx = SCW.xextern; break;
1974 case TOK.auto_: scwx = SCW.xauto; break;
1975 case TOK.register: scwx = SCW.xregister; break;
1976 case TOK.typedef_: scwx = SCW.xtypedef; break;
1977 case TOK.inline: scwx = SCW.xinline; break;
1978 case TOK._Noreturn: scwx = SCW.x_Noreturn; break;
1979 case TOK._Thread_local: scwx = SCW.x_Thread_local; break;
1981 // Type qualifiers
1982 case TOK.const_: modx = MOD.xconst; break;
1983 case TOK.volatile: modx = MOD.xvolatile; break;
1984 case TOK.restrict: modx = MOD.xrestrict; break;
1986 // Type specifiers
1987 case TOK.char_: tkwx = TKW.xchar; break;
1988 case TOK.signed: tkwx = TKW.xsigned; break;
1989 case TOK.unsigned: tkwx = TKW.xunsigned; break;
1990 case TOK.int16: tkwx = TKW.xshort; break;
1991 case TOK.int32: tkwx = TKW.xint; break;
1992 case TOK.int64: tkwx = TKW.xlong; break;
1993 case TOK.float32: tkwx = TKW.xfloat; break;
1994 case TOK.float64: tkwx = TKW.xdouble; break;
1995 case TOK.void_: tkwx = TKW.xvoid; break;
1996 case TOK._Bool: tkwx = TKW.xbool; break;
1997 case TOK._Imaginary: tkwx = TKW.ximaginary; break;
1998 case TOK._Complex: tkwx = TKW.xcomplex; break;
2000 case TOK.identifier:
2001 tkwx = TKW.xident;
2002 id = token.ident;
2003 break;
2005 case TOK.struct_:
2006 case TOK.union_:
2008 const structOrUnion = token.value;
2009 const sloc = token.loc;
2010 nextToken();
2012 /* GNU Extensions
2013 * struct-or-union-specifier:
2014 * struct-or-union gnu-attributes (opt) identifier (opt) { struct-declaration-list } gnu-attributes (opt)
2015 * struct-or-union gnu-attribute (opt) identifier
2017 if (token.value == TOK.__attribute__)
2018 cparseGnuAttributes(specifier);
2020 t = cparseStruct(sloc, structOrUnion, symbols);
2021 tkwx = TKW.xtag;
2022 break;
2025 case TOK.enum_:
2026 t = cparseEnum(symbols);
2027 tkwx = TKW.xtag;
2028 break;
2030 case TOK._Atomic:
2032 // C11 6.7.2.4
2033 // type-specifier if followed by `( type-name )`
2034 auto tk = peek(&token);
2035 if (tk.value == TOK.leftParenthesis)
2037 tk = peek(tk);
2038 if (isTypeName(tk) && tk.value == TOK.rightParenthesis)
2040 nextToken();
2041 t = cparseTypeName();
2042 // TODO - implement the "atomic" part of t
2043 tkwx = TKW.x_Atomic;
2044 break;
2047 // C11 6.7.3 type-qualifier if not
2048 modx = MOD.x_Atomic;
2049 break;
2052 case TOK._Alignas:
2054 /* C11 6.7.5
2055 * _Alignas ( type-name )
2056 * _Alignas ( constant-expression )
2059 if (level & (LVL.parameter | LVL.prototype))
2060 error("no alignment-specifier for parameters"); // C11 6.7.5-2
2062 nextToken();
2063 check(TOK.leftParenthesis);
2064 AST.Expression exp;
2065 auto tk = &token;
2066 if (isTypeName(tk)) // _Alignas ( type-name )
2068 auto talign = cparseTypeName();
2069 /* Convert type to expression: `talign.alignof`
2071 auto e = new AST.TypeExp(loc, talign);
2072 exp = new AST.DotIdExp(loc, e, Id.__xalignof);
2074 else // _Alignas ( constant-expression )
2076 exp = cparseConstantExp();
2079 if (!specifier.alignExps)
2080 specifier.alignExps = new AST.Expressions(0);
2081 specifier.alignExps.push(exp);
2083 check(TOK.rightParenthesis);
2084 break;
2087 case TOK.__attribute__:
2089 /* GNU Extensions
2090 * declaration-specifiers:
2091 * gnu-attributes declaration-specifiers (opt)
2093 cparseGnuAttributes(specifier);
2094 break;
2097 default:
2098 break Lwhile;
2101 if (tkwx)
2103 if (tkw & TKW.xlong && tkwx & TKW.xlong)
2105 tkw &= ~TKW.xlong;
2106 tkwx = TKW.xllong;
2108 if (tkw && tkwx & TKW.xident)
2110 // 2nd identifier can't be a typedef
2111 break Lwhile; // leave parser on the identifier for the following declarator
2113 else if (tkwx & TKW.xident)
2115 // 1st identifier, save it for TypeIdentifier
2116 previd = id;
2118 if (tkw & TKW.xident && tkwx || // typedef-name followed by type-specifier
2119 tkw & tkwx) // duplicate type-specifiers
2121 error("illegal combination of type specifiers");
2122 tkwx = TKW.init;
2124 tkw |= tkwx;
2125 if (!(tkwx & TKW.xtag)) // if parser already advanced
2126 nextToken();
2127 continue;
2130 if (modx)
2132 mod |= modx;
2133 nextToken();
2134 continue;
2137 if (scwx)
2139 if (scw & scwx)
2140 error("duplicate storage class");
2141 scw |= scwx;
2142 const scw2 = scw & (SCW.xstatic | SCW.xextern | SCW.xauto | SCW.xregister | SCW.xtypedef);
2143 if (scw2 & (scw2 - 1) ||
2144 scw & (SCW.xauto | SCW.xregister) && scw & (SCW.xinline | SCW.x_Noreturn))
2146 error("conflicting storage class");
2147 scw &= ~scwx;
2149 if (level & (LVL.parameter | LVL.prototype) &&
2150 scw & ~SCW.xregister)
2152 error("only `register` storage class allowed for function parameters");
2153 scw &= ~scwx;
2155 if (level == LVL.global &&
2156 scw & (SCW.xauto | SCW.xregister))
2158 error("`auto` and `register` storage class not allowed for global");
2159 scw &= ~scwx;
2161 nextToken();
2162 continue;
2166 specifier.scw = scw;
2167 specifier.mod = mod;
2169 // Convert TKW bits to type t
2170 switch (tkw)
2172 case TKW.xnone: t = null; break;
2174 case TKW.xchar: t = AST.Type.tchar; break;
2175 case TKW.xsigned | TKW.xchar: t = AST.Type.tint8; break;
2176 case TKW.xunsigned | TKW.xchar: t = AST.Type.tuns8; break;
2178 case TKW.xshort:
2179 case TKW.xsigned | TKW.xshort:
2180 case TKW.xsigned | TKW.xshort | TKW.xint:
2181 case TKW.xshort | TKW.xint: t = AST.Type.tint16; break;
2183 case TKW.xunsigned | TKW.xshort | TKW.xint:
2184 case TKW.xunsigned | TKW.xshort: t = AST.Type.tuns16; break;
2186 case TKW.xint:
2187 case TKW.xsigned:
2188 case TKW.xsigned | TKW.xint: t = AST.Type.tint32; break;
2190 case TKW.xunsigned:
2191 case TKW.xunsigned | TKW.xint: t = AST.Type.tuns32; break;
2193 case TKW.xlong:
2194 case TKW.xsigned | TKW.xlong:
2195 case TKW.xsigned | TKW.xlong | TKW.xint:
2196 case TKW.xlong | TKW.xint: t = longsize == 4 ? AST.Type.tint32 : AST.Type.tint64; break;
2198 case TKW.xunsigned | TKW.xlong | TKW.xint:
2199 case TKW.xunsigned | TKW.xlong: t = longsize == 4 ? AST.Type.tuns32 : AST.Type.tuns64; break;
2201 case TKW.xllong:
2202 case TKW.xsigned | TKW.xllong:
2203 case TKW.xsigned | TKW.xllong | TKW.xint:
2204 case TKW.xllong | TKW.xint: t = AST.Type.tint64; break;
2206 case TKW.xunsigned | TKW.xllong | TKW.xint:
2207 case TKW.xunsigned | TKW.xllong: t = AST.Type.tuns64; break;
2209 case TKW.xvoid: t = AST.Type.tvoid; break;
2210 case TKW.xbool: t = AST.Type.tbool; break;
2212 case TKW.xfloat: t = AST.Type.tfloat32; break;
2213 case TKW.xdouble: t = AST.Type.tfloat64; break;
2214 case TKW.xlong | TKW.xdouble: t = realType(RTFlags.realfloat); break;
2216 case TKW.ximaginary | TKW.xfloat: t = AST.Type.timaginary32; break;
2217 case TKW.ximaginary | TKW.xdouble: t = AST.Type.timaginary64; break;
2218 case TKW.ximaginary | TKW.xlong | TKW.xdouble: t = realType(RTFlags.imaginary); break;
2220 case TKW.xcomplex | TKW.xfloat: t = AST.Type.tcomplex32; break;
2221 case TKW.xcomplex | TKW.xdouble: t = AST.Type.tcomplex64; break;
2222 case TKW.xcomplex | TKW.xlong | TKW.xdouble: t = realType(RTFlags.complex); break;
2224 case TKW.xident: t = new AST.TypeIdentifier(loc, previd);
2225 break;
2227 case TKW.xtag:
2228 break; // t is already set
2230 default:
2231 error("illegal type combination");
2232 t = AST.Type.terror;
2233 break;
2236 return t;
2239 /********************************
2240 * C11 6.7.6
2241 * Parse a declarator (including function definitions).
2242 * declarator:
2243 * pointer (opt) direct-declarator
2245 * direct-declarator :
2246 * identifier
2247 * ( declarator )
2248 * direct-declarator [ type-qualifier-list (opt) assignment-expression (opt) ]
2249 * direct-declarator [ static type-qualifier-list (opt) assignment-expression ]
2250 * direct-declarator [ type-qualifier-list static assignment-expression (opt) ]
2251 * direct-declarator [ type-qualifier-list (opt) * ]
2252 * direct-declarator ( parameter-type-list )
2253 * direct-declarator ( identifier-list (opt) )
2255 * pointer :
2256 * * type-qualifier-list (opt)
2257 * * type-qualifier-list (opt) pointer
2259 * type-qualifier-list :
2260 * type-qualifier
2261 * type-qualifier-list type-qualifier
2263 * parameter-type-list :
2264 * parameter-list
2265 * parameter-list , ...
2267 * parameter-list :
2268 * parameter-declaration
2269 * parameter-list , parameter-declaration
2271 * parameter-declaration :
2272 * declaration-specifiers declarator
2273 * declaration-specifiers abstract-declarator (opt)
2275 * identifier-list :
2276 * identifier
2277 * identifier-list , identifier
2279 * Params:
2280 * declarator = declarator kind
2281 * t = base type to start with
2282 * pident = set to Identifier if there is one, null if not
2283 * specifier = specifiers in and out
2284 * Returns:
2285 * type declared. If a TypeFunction is returned, this.symbols is the
2286 * symbol table for the parameter-type-list, which will contain any
2287 * declared struct, union or enum tags.
2289 private AST.Type cparseDeclarator(DTR declarator, AST.Type t,
2290 out Identifier pident, ref Specifier specifier)
2292 //printf("cparseDeclarator(%d)\n", declarator);
2293 AST.Types constTypes; // all the Types that will need `const` applied to them
2294 constTypes.setDim(0);
2296 AST.Type parseDecl(AST.Type t)
2298 AST.Type ts;
2299 while (1)
2301 switch (token.value)
2303 case TOK.identifier: // identifier
2304 //printf("identifier %s\n", token.ident.toChars());
2305 if (declarator == DTR.xabstract)
2306 error("identifier not allowed in abstract-declarator");
2307 pident = token.ident;
2308 ts = t;
2309 nextToken();
2310 break;
2312 case TOK.leftParenthesis: // ( declarator )
2313 /* like: T (*fp)();
2314 * T ((*fp))();
2316 nextToken();
2317 ts = parseDecl(t);
2318 check(TOK.rightParenthesis);
2319 break;
2321 case TOK.mul: // pointer
2322 t = new AST.TypePointer(t);
2323 nextToken();
2324 // add post fixes const/volatile/restrict/_Atomic
2325 const mod = cparseTypeQualifierList();
2326 if (mod & MOD.xconst)
2327 constTypes.push(t);
2328 if (token.value == TOK.__attribute__)
2329 cparseGnuAttributes(specifier);
2330 continue;
2332 default:
2333 if (declarator == DTR.xdirect)
2335 error("identifier or `(` expected"); // )
2336 panic();
2338 ts = t;
2339 break;
2341 break;
2344 // parse DeclaratorSuffixes
2345 while (1)
2347 /* Insert tx -> t into
2348 * ts -> ... -> t
2349 * so that
2350 * ts -> ... -> tx -> t
2352 static void insertTx(ref AST.Type ts, AST.Type tx, AST.Type t)
2354 AST.Type* pt;
2355 for (pt = &ts; *pt != t; pt = &(cast(AST.TypeNext)*pt).next)
2358 *pt = tx;
2361 switch (token.value)
2363 case TOK.leftBracket:
2365 // post [] syntax, pick up any leading type qualifiers, `static` and `*`
2366 AST.Type ta;
2367 nextToken();
2369 auto mod = cparseTypeQualifierList(); // const/volatile/restrict/_Atomic
2371 bool isStatic;
2372 bool isVLA;
2373 if (token.value == TOK.static_)
2375 isStatic = true; // `static`
2376 nextToken();
2377 if (!mod) // type qualifiers after `static`
2378 mod = cparseTypeQualifierList();
2380 else if (token.value == TOK.mul)
2382 if (peekNext() == TOK.rightBracket)
2384 isVLA = true; // `*`
2385 nextToken();
2389 if (isStatic || token.value != TOK.rightBracket)
2391 //printf("It's a static array\n");
2392 AST.Expression e = cparseAssignExp(); // [ expression ]
2393 ta = new AST.TypeSArray(t, e);
2395 else
2397 /* C11 6.7.6.2-4 An [ ] array is an incomplete array type
2399 ta = new AST.TypeSArray(t);
2401 check(TOK.rightBracket);
2403 // Issue errors for unsupported types.
2404 if (isVLA) // C11 6.7.6.2
2406 error("variable length arrays are not supported");
2408 if (isStatic) // C11 6.7.6.3
2410 error("static array parameters are not supported");
2412 if (declarator != DTR.xparameter)
2414 /* C11 6.7.6.2-4: '*' can only be used with function prototype scope.
2416 if (isVLA)
2417 error("variable length array used outside of function prototype");
2418 /* C11 6.7.6.2-1: type qualifiers and 'static' shall only appear
2419 * in a declaration of a function parameter with an array type.
2421 if (isStatic || mod)
2422 error("static or type qualifier used outside of function prototype");
2424 if (ts.isTypeSArray() || ts.isTypeDArray())
2426 /* C11 6.7.6.2-1: type qualifiers and 'static' shall only appear
2427 * in the outermost array type derivation.
2429 if (isStatic || mod)
2430 error("static or type qualifier used in non-outermost array type derivation");
2431 /* C11 6.7.6.2-1: the element type shall not be an incomplete or
2432 * function type.
2434 if (ta.isTypeSArray() && ta.isTypeSArray().isIncomplete() && !isVLA)
2435 error("array type has incomplete element type `%s`", ta.toChars());
2438 // Apply type qualifiers to the constructed type.
2439 if (mod & MOD.xconst) // ignore the other bits
2440 ta = toConst(ta);
2441 insertTx(ts, ta, t); // ts -> ... -> ta -> t
2442 continue;
2445 case TOK.leftParenthesis:
2447 // New symbol table for parameter-list
2448 auto symbolsSave = this.symbols;
2449 this.symbols = null;
2451 auto parameterList = cparseParameterList();
2452 AST.Type tf = new AST.TypeFunction(parameterList, t, linkage, 0);
2453 // tf = tf.addSTC(storageClass); // TODO
2454 insertTx(ts, tf, t); // ts -> ... -> tf -> t
2456 if (ts != tf)
2457 this.symbols = symbolsSave;
2458 break;
2461 default:
2462 break;
2464 break;
2466 return ts;
2469 t = parseDecl(t);
2471 /* Because const is transitive, cannot assemble types from
2472 * fragments. Instead, types to be annotated with const are put
2473 * in constTypes[], and a bottom up scan of t is done to apply
2474 * const
2476 if (constTypes.length)
2478 AST.Type constApply(AST.Type t)
2480 if (t.nextOf())
2482 auto tn = cast(AST.TypeNext)t; // t.nextOf() should return a ref instead of this
2483 tn.next = constApply(tn.next);
2485 foreach (tc; constTypes[])
2487 if (tc is t)
2489 return toConst(t);
2492 return t;
2495 t = constApply(t);
2498 //printf("result: %s\n", t.toChars());
2499 return t;
2502 /******************************
2503 * C11 6.7.3
2504 * type-qualifier:
2505 * const
2506 * restrict
2507 * volatile
2508 * _Atomic
2510 MOD cparseTypeQualifierList()
2512 MOD mod;
2513 while (1)
2515 switch (token.value)
2517 case TOK.const_: mod |= MOD.xconst; break;
2518 case TOK.volatile: mod |= MOD.xvolatile; break;
2519 case TOK.restrict: mod |= MOD.xrestrict; break;
2520 case TOK._Atomic: mod |= MOD.x_Atomic; break;
2522 default:
2523 return mod;
2525 nextToken();
2529 /***********************************
2530 * C11 6.7.7
2532 AST.Type cparseTypeName()
2534 Specifier specifier;
2535 specifier.packalign.setDefault();
2536 auto tspec = cparseSpecifierQualifierList(LVL.global, specifier);
2537 Identifier id;
2538 return cparseDeclarator(DTR.xabstract, tspec, id, specifier);
2541 /***********************************
2542 * C11 6.7.2.1
2543 * specifier-qualifier-list:
2544 * type-specifier specifier-qualifier-list (opt)
2545 * type-qualifier specifier-qualifier-list (opt)
2546 * Params:
2547 * level = declaration context
2548 * specifier = specifiers in and out
2549 * Returns:
2550 * resulting type, null if not specified
2552 AST.Type cparseSpecifierQualifierList(LVL level, ref Specifier specifier)
2554 auto t = cparseDeclarationSpecifiers(level, specifier);
2555 if (specifier.scw)
2556 error("storage class not allowed in specifier-qualified-list");
2557 return t;
2560 /***********************************
2561 * C11 6.7.6.3
2562 * ( parameter-type-list )
2563 * ( identifier-list (opt) )
2565 AST.ParameterList cparseParameterList()
2567 auto parameters = new AST.Parameters();
2568 AST.VarArg varargs = AST.VarArg.none;
2569 StorageClass varargsStc;
2571 check(TOK.leftParenthesis);
2572 if (token.value == TOK.void_ && peekNext() == TOK.rightParenthesis) // func(void)
2574 nextToken();
2575 nextToken();
2576 return AST.ParameterList(parameters, varargs, varargsStc);
2579 if (token.value == TOK.rightParenthesis) // func()
2581 nextToken();
2582 return AST.ParameterList(parameters, AST.VarArg.variadic, varargsStc);
2585 /* The check for identifier-list comes later,
2586 * when doing the trailing declaration-list (opt)
2588 while (1)
2590 if (token.value == TOK.rightParenthesis)
2591 break;
2592 if (token.value == TOK.dotDotDot)
2594 if (parameters.length == 0) // func(...)
2595 error("named parameter required before `...`");
2596 varargs = AST.VarArg.variadic; // C-style variadics
2597 nextToken();
2598 check(TOK.rightParenthesis);
2599 return AST.ParameterList(parameters, varargs, varargsStc);
2602 Specifier specifier;
2603 specifier.packalign.setDefault();
2604 auto tspec = cparseDeclarationSpecifiers(LVL.prototype, specifier);
2605 if (tspec && specifier.mod & MOD.xconst)
2607 tspec = toConst(tspec);
2608 specifier.mod = MOD.xnone; // 'used' it
2611 Identifier id;
2612 auto t = cparseDeclarator(DTR.xparameter, tspec, id, specifier);
2613 if (specifier.mod & MOD.xconst)
2614 t = toConst(t);
2615 auto param = new AST.Parameter(STC.parameter, t, id, null, null);
2616 parameters.push(param);
2617 if (token.value == TOK.rightParenthesis)
2618 break;
2619 check(TOK.comma);
2621 nextToken();
2622 return AST.ParameterList(parameters, varargs, varargsStc);
2625 /***********************************
2626 * C11 6.7.10
2627 * _Static_assert ( constant-expression , string-literal ) ;
2629 private AST.StaticAssert cparseStaticAssert()
2631 const loc = token.loc;
2633 //printf("cparseStaticAssert()\n");
2634 nextToken();
2635 check(TOK.leftParenthesis);
2636 auto exp = cparseConstantExp();
2637 check(TOK.comma);
2638 if (token.value != TOK.string_)
2639 error("string literal expected");
2640 auto msg = cparsePrimaryExp();
2641 check(TOK.rightParenthesis);
2642 check(TOK.semicolon);
2643 return new AST.StaticAssert(loc, exp, msg);
2646 /*************************
2647 * Collect argument list.
2648 * Parser is on opening parenthesis.
2649 * Returns:
2650 * the arguments
2652 private AST.Expressions* cparseArguments()
2654 nextToken();
2655 auto arguments = new AST.Expressions();
2656 while (token.value != TOK.rightParenthesis && token.value != TOK.endOfFile)
2658 auto arg = cparseAssignExp();
2659 arguments.push(arg);
2660 if (token.value != TOK.comma)
2661 break;
2663 nextToken(); // consume comma
2666 check(TOK.rightParenthesis);
2668 return arguments;
2671 /*************************
2672 * __declspec parser
2673 * https://docs.microsoft.com/en-us/cpp/cpp/declspec
2674 * decl-specifier:
2675 * __declspec ( extended-decl-modifier-seq )
2677 * extended-decl-modifier-seq:
2678 * extended-decl-modifier (opt)
2679 * extended-decl-modifier extended-decl-modifier-seq
2681 * extended-decl-modifier:
2682 * dllimport
2683 * dllexport
2685 private void cparseDeclspec()
2687 /* Check for dllexport, dllimport
2688 * Ignore the rest
2690 bool dllimport; // TODO implement
2691 bool dllexport; // TODO implement
2692 nextToken(); // move past __declspec
2693 check(TOK.leftParenthesis);
2694 while (1)
2696 if (token.value == TOK.rightParenthesis)
2698 nextToken();
2699 break;
2701 else if (token.value == TOK.endOfFile)
2702 break;
2703 else if (token.value == TOK.identifier)
2705 if (token.ident == Id.dllimport)
2707 dllimport = true;
2708 nextToken();
2710 else if (token.ident == Id.dllexport)
2712 dllexport = true;
2713 nextToken();
2715 else
2717 nextToken();
2718 if (token.value == TOK.leftParenthesis)
2719 cparseParens();
2722 else
2724 error("extended-decl-modifier expected");
2726 break;
2730 /*************************
2731 * Simple asm parser
2732 * https://gcc.gnu.org/onlinedocs/gcc/Asm-Labels.html
2733 * simple-asm-expr:
2734 * asm ( asm-string-literal )
2736 * asm-string-literal:
2737 * string-literal
2739 private AST.Expression cparseSimpleAsmExpr()
2741 nextToken(); // move past asm
2742 check(TOK.leftParenthesis);
2743 if (token.value != TOK.string_)
2744 error("string literal expected");
2745 auto label = cparsePrimaryExp();
2746 check(TOK.rightParenthesis);
2747 return label;
2750 /*************************
2751 * __attribute__ parser
2752 * https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html
2753 * gnu-attributes:
2754 * gnu-attributes gnu-attribute-specifier
2756 * gnu-attribute-specifier:
2757 * __attribute__ (( gnu-attribute-list ))
2759 * gnu-attribute-list:
2760 * gnu-attribute (opt)
2761 * gnu-attribute-list , gnu-attribute
2763 * Params:
2764 * specifier = filled in with the attribute(s)
2766 private void cparseGnuAttributes(ref Specifier specifier)
2768 while (token.value == TOK.__attribute__)
2770 nextToken(); // move past __attribute__
2771 check(TOK.leftParenthesis);
2772 check(TOK.leftParenthesis);
2774 if (token.value != TOK.rightParenthesis)
2776 while (1)
2778 cparseGnuAttribute(specifier);
2779 if (token.value != TOK.comma)
2780 break;
2781 nextToken();
2785 check(TOK.rightParenthesis);
2786 check(TOK.rightParenthesis);
2790 /*************************
2791 * Parse a single GNU attribute
2792 * gnu-attribute:
2793 * gnu-attribute-name
2794 * gnu-attribute-name ( identifier )
2795 * gnu-attribute-name ( identifier , expression-list )
2796 * gnu-attribute-name ( expression-list (opt) )
2798 * gnu-attribute-name:
2799 * keyword
2800 * identifier
2802 * expression-list:
2803 * constant-expression
2804 * expression-list , constant-expression
2806 * Params:
2807 * specifier = filled in with the attribute(s)
2809 private void cparseGnuAttribute(ref Specifier specifier)
2811 /* Check for dllimport, dllexport, vector_size(bytes)
2812 * Ignore the rest
2814 bool dllimport; // TODO implement
2815 bool dllexport; // TODO implement
2817 if (!isGnuAttributeName())
2818 return;
2820 if (token.value == TOK.identifier)
2822 if (token.ident == Id.dllimport)
2824 dllimport = true;
2825 nextToken();
2827 else if (token.ident == Id.dllexport)
2829 dllexport = true;
2830 nextToken();
2832 else if (token.ident == Id.noreturn)
2834 specifier.noreturn = true;
2835 nextToken();
2837 else if (token.ident == Id.vector_size)
2839 nextToken();
2840 check(TOK.leftParenthesis);
2841 cparseConstantExp(); // TODO implement
2842 check(TOK.rightParenthesis);
2844 else
2846 nextToken();
2847 if (token.value == TOK.leftParenthesis)
2848 cparseParens();
2851 else
2853 nextToken();
2854 if (token.value == TOK.leftParenthesis)
2855 cparseParens();
2859 /*************************
2860 * See if match for GNU attribute name, which may be any identifier,
2861 * storage-class-specifier, type-specifier, or type-qualifier.
2862 * Returns:
2863 * true if a valid GNU attribute name
2865 private bool isGnuAttributeName()
2867 switch (token.value)
2869 case TOK.identifier:
2870 case TOK.static_:
2871 case TOK.unsigned:
2872 case TOK.int64:
2873 case TOK.const_:
2874 case TOK.extern_:
2875 case TOK.register:
2876 case TOK.typedef_:
2877 case TOK.int16:
2878 case TOK.inline:
2879 case TOK._Noreturn:
2880 case TOK.volatile:
2881 case TOK.signed:
2882 case TOK.auto_:
2883 case TOK.restrict:
2884 case TOK._Complex:
2885 case TOK._Thread_local:
2886 case TOK.int32:
2887 case TOK.char_:
2888 case TOK.float32:
2889 case TOK.float64:
2890 case TOK.void_:
2891 case TOK._Bool:
2892 case TOK._Atomic:
2893 return true;
2895 default:
2896 return false;
2900 /***************************
2901 * Like skipParens(), but consume the tokens.
2903 private void cparseParens()
2905 check(TOK.leftParenthesis);
2906 int parens = 1;
2908 while (1)
2910 switch (token.value)
2912 case TOK.leftParenthesis:
2913 ++parens;
2914 break;
2916 case TOK.rightParenthesis:
2917 --parens;
2918 if (parens < 0)
2920 error("extra right parenthesis");
2921 return;
2923 if (parens == 0)
2925 nextToken();
2926 return;
2928 break;
2930 case TOK.endOfFile:
2931 error("end of file found before right parenthesis");
2932 return;
2934 default:
2935 break;
2937 nextToken();
2942 /******************************************************************************/
2943 /***************************** Struct & Enum Parser ***************************/
2946 /*************************************
2947 * C11 6.7.2.2
2948 * enum-specifier:
2949 * enum identifier (opt) { enumerator-list }
2950 * enum identifier (opt) { enumerator-list , }
2951 * enum identifier
2953 * enumerator-list:
2954 * enumerator
2955 * enumerator-list , enumerator
2957 * enumerator:
2958 * enumeration-constant
2959 * enumeration-constant = constant-expression
2961 * enumeration-constant:
2962 * identifier
2964 * Params:
2965 * symbols = symbols to add enum declaration to
2966 * Returns:
2967 * type of the enum
2969 private AST.Type cparseEnum(ref AST.Dsymbols* symbols)
2971 const loc = token.loc;
2972 nextToken();
2974 /* GNU Extensions
2975 * enum-specifier:
2976 * enum gnu-attributes (opt) identifier (opt) { enumerator-list } gnu-attributes (opt)
2977 * enum gnu-attributes (opt) identifier (opt) { enumerator-list , } gnu-attributes (opt)
2978 * enum gnu-attributes (opt) identifier
2980 Specifier specifier;
2981 specifier.packalign.setDefault();
2982 if (token.value == TOK.__attribute__)
2983 cparseGnuAttributes(specifier);
2985 Identifier tag;
2986 if (token.value == TOK.identifier)
2988 tag = token.ident;
2989 nextToken();
2992 AST.Dsymbols* members;
2993 if (token.value == TOK.leftCurly)
2995 nextToken();
2996 members = new AST.Dsymbols();
2998 if (token.value == TOK.rightCurly) // C11 6.7.2.2-1
3000 if (tag)
3001 error("no members for `enum %s`", tag.toChars());
3002 else
3003 error("no members for anonymous enum");
3006 while (token.value == TOK.identifier)
3008 auto ident = token.ident; // enumeration-constant
3009 nextToken();
3010 auto mloc = token.loc;
3012 if (token.value == TOK.__attribute__)
3014 /* gnu-attributes can appear here, but just scan and ignore them
3015 * https://gcc.gnu.org/onlinedocs/gcc/Enumerator-Attributes.html
3017 Specifier specifierx;
3018 specifierx.packalign.setDefault();
3019 cparseGnuAttributes(specifierx);
3022 AST.Expression value;
3023 if (token.value == TOK.assign)
3025 nextToken();
3026 value = cparseConstantExp();
3027 // TODO C11 6.7.2.2-2 value must fit into an int
3030 if (token.value == TOK.__attribute__)
3032 /* gnu-attributes can appear here, but just scan and ignore them
3033 * https://gcc.gnu.org/onlinedocs/gcc/Enumerator-Attributes.html
3035 Specifier specifierx;
3036 specifierx.packalign.setDefault();
3037 cparseGnuAttributes(specifierx);
3040 auto em = new AST.EnumMember(mloc, ident, value, null, 0, null, null);
3041 members.push(em);
3043 if (token.value == TOK.comma)
3045 nextToken();
3046 continue;
3048 break;
3050 check(TOK.rightCurly);
3052 /* GNU Extensions
3053 * Parse the postfix gnu-attributes (opt)
3055 if (token.value == TOK.__attribute__)
3056 cparseGnuAttributes(specifier);
3058 else if (!tag)
3059 error("missing `identifier` after `enum`");
3061 /* Need semantic information to determine if this is a declaration,
3062 * redeclaration, or reference to existing declaration.
3063 * Defer to the semantic() pass with a TypeTag.
3065 return new AST.TypeTag(loc, TOK.enum_, tag, members);
3068 /*************************************
3069 * C11 6.7.2.1
3070 * Parse struct and union specifiers.
3071 * Parser is advanced to the tag identifier or brace.
3072 * struct-or-union-specifier:
3073 * struct-or-union identifier (opt) { struct-declaration-list }
3074 * struct-or-union identifier
3076 * struct-or-union:
3077 * struct
3078 * union
3080 * struct-declaration-list:
3081 * struct-declaration
3082 * struct-declaration-list struct-declaration
3084 * Params:
3085 * loc = location of `struct` or `union`
3086 * structOrUnion = TOK.struct_ or TOK.union_
3087 * symbols = symbols to add struct-or-union declaration to
3088 * Returns:
3089 * type of the struct
3091 private AST.Type cparseStruct(Loc loc, TOK structOrUnion, ref AST.Dsymbols* symbols)
3093 Identifier tag;
3095 if (token.value == TOK.identifier)
3097 tag = token.ident;
3098 nextToken();
3101 AST.Dsymbols* members;
3102 if (token.value == TOK.leftCurly)
3104 nextToken();
3105 auto symbolsSave = symbols;
3106 symbols = new AST.Dsymbols();
3107 while (token.value != TOK.rightCurly)
3109 cparseStructDeclaration();
3111 if (token.value == TOK.endOfFile)
3112 break;
3114 members = symbols; // `members` will be non-null even with 0 members
3115 symbols = symbolsSave;
3116 check(TOK.rightCurly);
3118 if ((*members).length == 0) // C11 6.7.2.1-8
3120 /* allow empty structs as an extension
3121 * struct-declarator-list:
3122 * struct-declarator (opt)
3126 else if (!tag)
3127 error("missing tag `identifier` after `%s`", Token.toChars(structOrUnion));
3129 /* Need semantic information to determine if this is a declaration,
3130 * redeclaration, or reference to existing declaration.
3131 * Defer to the semantic() pass with a TypeTag.
3133 return new AST.TypeTag(loc, structOrUnion, tag, members);
3136 /*************************************
3137 * C11 6.7.2.1
3138 * Parse a struct declaration member.
3139 * struct-declaration:
3140 * specifier-qualifier-list struct-declarator-list (opt) ;
3141 * static_assert-declaration
3143 * struct-declarator-list:
3144 * struct-declarator
3145 * struct-declarator-list , struct-declarator
3147 * struct-declarator:
3148 * declarator
3149 * declarator (opt) : constant-expression
3151 void cparseStructDeclaration()
3153 //printf("cparseStructDeclaration()\n");
3154 if (token.value == TOK._Static_assert)
3156 auto s = cparseStaticAssert();
3157 symbols.push(s);
3158 return;
3161 auto symbolsSave = symbols;
3162 Specifier specifier;
3163 specifier.packalign = this.packalign;
3164 auto tspec = cparseSpecifierQualifierList(LVL.member, specifier);
3165 if (tspec && specifier.mod & MOD.xconst)
3167 tspec = toConst(tspec);
3168 specifier.mod = MOD.xnone; // 'used' it
3171 /* If a declarator does not follow, it is unnamed
3173 if (token.value == TOK.semicolon && tspec)
3175 nextToken();
3176 auto tt = tspec.isTypeTag();
3177 if (!tt)
3178 return; // legal but meaningless empty declaration
3180 /* If anonymous struct declaration
3181 * struct { ... members ... };
3182 * C11 6.7.2.1-13
3184 if (!tt.id && tt.members)
3186 /* members of anonymous struct are considered members of
3187 * the containing struct
3189 auto ad = new AST.AnonDeclaration(tt.loc, tt.tok == TOK.union_, tt.members);
3190 if (!symbols)
3191 symbols = new AST.Dsymbols();
3192 auto s = applySpecifier(ad, specifier);
3193 symbols.push(s);
3194 return;
3196 if (!tt.id && !tt.members)
3197 return; // already gave error in cparseStruct()
3199 /* `struct tag;` and `struct tag { ... };`
3200 * always result in a declaration in the current scope
3202 // TODO: merge in specifier
3203 auto stag = (tt.tok == TOK.struct_)
3204 ? new AST.StructDeclaration(tt.loc, tt.id, false)
3205 : new AST.UnionDeclaration(tt.loc, tt.id);
3206 stag.members = tt.members;
3207 if (!symbols)
3208 symbols = new AST.Dsymbols();
3209 auto s = applySpecifier(stag, specifier);
3210 symbols.push(s);
3211 return;
3214 while (1)
3216 Identifier id;
3217 AST.Type dt;
3218 if (token.value == TOK.colon)
3220 // C11 6.7.2.1-12 unnamed bit-field
3221 id = Identifier.generateAnonymousId("BitField");
3222 dt = tspec;
3224 else
3226 dt = cparseDeclarator(DTR.xdirect, tspec, id, specifier);
3227 if (!dt)
3229 panic();
3230 nextToken();
3231 break; // error recovery
3235 AST.Expression width;
3236 if (token.value == TOK.colon)
3238 // C11 6.7.2.1-10 bit-field
3239 nextToken();
3240 width = cparseConstantExp();
3243 /* GNU Extensions
3244 * struct-declarator:
3245 * declarator gnu-attributes (opt)
3246 * declarator (opt) : constant-expression gnu-attributes (opt)
3248 if (token.value == TOK.__attribute__)
3249 cparseGnuAttributes(specifier);
3251 AST.Dsymbol s = null;
3252 symbols = symbolsSave;
3253 if (!symbols)
3254 symbols = new AST.Dsymbols; // lazilly create it
3256 if (!tspec && !specifier.scw && !specifier.mod)
3257 error("specifier-qualifier-list required");
3258 else if (width)
3260 if (specifier.alignExps)
3261 error("no alignment-specifier for bit field declaration"); // C11 6.7.5-2
3262 s = new AST.BitFieldDeclaration(width.loc, dt, id, width);
3264 else if (id)
3266 if (dt.ty == AST.Tvoid)
3267 error("`void` has no value");
3269 // declare the symbol
3270 // Give member variables an implicit void initializer
3271 auto initializer = new AST.VoidInitializer(token.loc);
3272 s = new AST.VarDeclaration(token.loc, dt, id, initializer, specifiersToSTC(LVL.member, specifier));
3273 s = applySpecifier(s, specifier);
3275 if (s !is null)
3276 symbols.push(s);
3278 switch (token.value)
3280 case TOK.identifier:
3281 error("missing comma");
3282 goto default;
3284 case TOK.semicolon:
3285 nextToken();
3286 return;
3288 case TOK.comma:
3289 nextToken();
3290 break;
3292 default:
3293 error("`;` or `,` expected");
3294 while (token.value != TOK.semicolon && token.value != TOK.endOfFile)
3295 nextToken();
3296 nextToken();
3297 return;
3303 /******************************************************************************/
3304 /********************************* Lookahead Parser ***************************/
3307 /************************************
3308 * Determine if the scanner is sitting on the start of a declaration.
3309 * Params:
3310 * t = current token of the scanner
3311 * needId = flag with additional requirements for a declaration
3312 * endtok = ending token
3313 * pt = will be set ending token (if not null)
3314 * Returns:
3315 * true at start of a declaration
3317 private bool isCDeclaration(ref Token* pt)
3319 auto t = pt;
3320 //printf("isCDeclaration() %s\n", t.toChars());
3321 if (!isDeclarationSpecifiers(t))
3322 return false;
3324 while (1)
3326 if (t.value == TOK.semicolon)
3328 t = peek(t);
3329 pt = t;
3330 return true;
3332 if (!isCDeclarator(t, DTR.xdirect))
3333 return false;
3334 if (t.value == TOK.asm_)
3336 t = peek(t);
3337 if (t.value != TOK.leftParenthesis || !skipParens(t, &t))
3338 return false;
3340 if (t.value == TOK.__attribute__)
3342 t = peek(t);
3343 if (t.value != TOK.leftParenthesis || !skipParens(t, &t))
3344 return false;
3346 if (t.value == TOK.assign)
3348 t = peek(t);
3349 if (!isInitializer(t))
3350 return false;
3352 switch (t.value)
3354 case TOK.comma:
3355 t = peek(t);
3356 break;
3358 case TOK.semicolon:
3359 t = peek(t);
3360 pt = t;
3361 return true;
3363 default:
3364 return false;
3369 /********************************
3370 * See if match for initializer.
3371 * Params:
3372 * pt = starting token, updated to one past end of initializer if true
3373 * Returns:
3374 * true if initializer
3376 private bool isInitializer(ref Token* pt)
3378 //printf("isInitializer()\n");
3379 auto t = pt;
3381 if (t.value == TOK.leftCurly)
3383 if (!skipBraces(t))
3384 return false;
3385 pt = t;
3386 return true;
3389 // skip over assignment-expression, ending before comma or semiColon or EOF
3390 if (!isAssignmentExpression(t))
3391 return false;
3392 pt = t;
3393 return true;
3396 /********************************
3397 * See if match for:
3398 * postfix-expression ( argument-expression-list(opt) )
3399 * Params:
3400 * pt = starting token, updated to one past end of initializer if true
3401 * Returns:
3402 * true if function call
3404 private bool isFunctionCall(ref Token* pt)
3406 //printf("isFunctionCall()\n");
3407 auto t = pt;
3409 if (!isPrimaryExpression(t))
3410 return false;
3411 if (t.value != TOK.leftParenthesis)
3412 return false;
3413 t = peek(t);
3414 while (1)
3416 if (!isAssignmentExpression(t))
3417 return false;
3418 if (t.value == TOK.comma)
3420 t = peek(t);
3421 continue;
3423 if (t.value == TOK.rightParenthesis)
3425 t = peek(t);
3426 break;
3428 return false;
3430 if (t.value != TOK.semicolon)
3431 return false;
3432 pt = t;
3433 return true;
3436 /********************************
3437 * See if match for assignment-expression.
3438 * Params:
3439 * pt = starting token, updated to one past end of assignment-expression if true
3440 * Returns:
3441 * true if assignment-expression
3443 private bool isAssignmentExpression(ref Token* pt)
3445 auto t = pt;
3446 //printf("isAssignmentExpression() %s\n", t.toChars());
3448 /* This doesn't actually check for grammar matching an
3449 * assignment-expression. It just matches ( ) [ ] looking for
3450 * an ending token that would terminate one.
3452 bool any;
3453 while (1)
3455 switch (t.value)
3457 case TOK.comma:
3458 case TOK.semicolon:
3459 case TOK.rightParenthesis:
3460 case TOK.rightBracket:
3461 case TOK.endOfFile:
3462 if (!any)
3463 return false;
3464 break;
3466 case TOK.leftParenthesis:
3467 if (!skipParens(t, &t))
3468 return false;
3470 https://issues.dlang.org/show_bug.cgi?id=22267
3471 Fix issue 22267: If the parser encounters the following
3472 `identifier variableName = (expression);`
3473 the initializer is not identified as such since the parentheses
3474 cause the parser to keep walking indefinitely
3475 (whereas `(1) + 1` would not be affected.).
3477 any = true;
3478 continue;
3480 case TOK.leftBracket:
3481 if (!skipBrackets(t))
3482 return false;
3483 continue;
3485 case TOK.leftCurly:
3486 if (!skipBraces(t))
3487 return false;
3488 continue;
3490 default:
3491 any = true; // assume token was part of an a-e
3492 t = peek(t);
3493 continue;
3495 pt = t;
3496 return true;
3500 /********************************
3501 * See if match for constant-expression.
3502 * Params:
3503 * pt = starting token, updated to one past end of constant-expression if true
3504 * Returns:
3505 * true if constant-expression
3507 private bool isConstantExpression(ref Token* pt)
3509 return isAssignmentExpression(pt);
3512 /********************************
3513 * See if match for declaration-specifiers.
3514 * No errors are diagnosed.
3515 * Params:
3516 * pt = starting token, updated to one past end of declaration-specifiers if true
3517 * Returns:
3518 * true if declaration-specifiers
3520 private bool isDeclarationSpecifiers(ref Token* pt)
3522 //printf("isDeclarationSpecifiers()\n");
3524 auto t = pt;
3526 bool seenType;
3527 bool any;
3528 while (1)
3530 switch (t.value)
3532 // type-specifiers
3533 case TOK.void_:
3534 case TOK.char_:
3535 case TOK.int16:
3536 case TOK.int32:
3537 case TOK.int64:
3538 case TOK.float32:
3539 case TOK.float64:
3540 case TOK.signed:
3541 case TOK.unsigned:
3542 case TOK._Bool:
3543 //case TOK._Imaginary:
3544 case TOK._Complex:
3545 t = peek(t);
3546 seenType = true;
3547 any = true;
3548 continue;
3550 case TOK.identifier: // typedef-name
3551 if (!seenType)
3553 t = peek(t);
3554 seenType = true;
3555 any = true;
3556 continue;
3558 break;
3560 case TOK.struct_:
3561 case TOK.union_:
3562 case TOK.enum_:
3563 t = peek(t);
3564 if (t.value == TOK.identifier)
3566 t = peek(t);
3567 if (t.value == TOK.leftCurly)
3569 if (!skipBraces(t))
3570 return false;
3573 else if (t.value == TOK.leftCurly)
3575 if (!skipBraces(t))
3576 return false;
3578 else
3579 return false;
3580 any = true;
3581 continue;
3583 // storage-class-specifiers
3584 case TOK.typedef_:
3585 case TOK.extern_:
3586 case TOK.static_:
3587 case TOK._Thread_local:
3588 case TOK.auto_:
3589 case TOK.register:
3591 // function-specifiers
3592 case TOK.inline:
3593 case TOK._Noreturn:
3595 // type-qualifiers
3596 case TOK.const_:
3597 case TOK.volatile:
3598 case TOK.restrict:
3599 t = peek(t);
3600 any = true;
3601 continue;
3603 case TOK._Alignas: // alignment-specifier
3604 case TOK.__declspec: // decl-specifier
3605 case TOK.__attribute__: // attribute-specifier
3606 t = peek(t);
3607 if (!skipParens(t, &t))
3608 return false;
3609 any = true;
3610 continue;
3612 // either atomic-type-specifier or type_qualifier
3613 case TOK._Atomic: // TODO _Atomic ( type-name )
3614 t = peek(t);
3615 if (t.value == TOK.leftParenthesis) // maybe atomic-type-specifier
3617 auto tsave = t;
3618 t = peek(t);
3619 if (!isTypeName(t) || t.value != TOK.rightParenthesis)
3620 { // it's a type-qualifier
3621 t = tsave; // back up parser
3622 any = true;
3623 continue;
3625 t = peek(t); // move past right parenthesis of atomic-type-specifier
3627 any = true;
3628 continue;
3630 default:
3631 break;
3633 break;
3636 if (any)
3638 pt = t;
3639 return true;
3641 return false;
3644 /**************************************
3645 * See if declaration-list is present.
3646 * Returns:
3647 * true if declaration-list is present, even an empty one
3649 bool isDeclarationList(ref Token* pt)
3651 auto t = pt;
3652 while (1)
3654 if (t.value == TOK.leftCurly)
3656 pt = t;
3657 return true;
3659 if (!isCDeclaration(t))
3660 return false;
3664 /*******************************************
3665 * Skip braces.
3666 * Params:
3667 * pt = enters on left brace, set to token past right bracket on true
3668 * Returns:
3669 * true if successful
3671 private bool skipBraces(ref Token* pt)
3673 auto t = pt;
3674 if (t.value != TOK.leftCurly)
3675 return false;
3677 int braces = 0;
3679 while (1)
3681 switch (t.value)
3683 case TOK.leftCurly:
3684 ++braces;
3685 t = peek(t);
3686 continue;
3688 case TOK.rightCurly:
3689 --braces;
3690 if (braces == 0)
3692 pt = peek(t);
3693 return true;
3695 if (braces < 0)
3696 return false;
3698 t = peek(t);
3699 continue;
3701 case TOK.endOfFile:
3702 return false;
3704 default:
3705 t = peek(t);
3706 continue;
3711 /*******************************************
3712 * Skip brackets.
3713 * Params:
3714 * pt = enters on left bracket, set to token past right bracket on true
3715 * Returns:
3716 * true if successful
3718 private bool skipBrackets(ref Token* pt)
3720 auto t = pt;
3721 if (t.value != TOK.leftBracket)
3722 return false;
3724 int brackets = 0;
3726 while (1)
3728 switch (t.value)
3730 case TOK.leftBracket:
3731 ++brackets;
3732 t = peek(t);
3733 continue;
3735 case TOK.rightBracket:
3736 --brackets;
3737 if (brackets == 0)
3739 pt = peek(t);
3740 return true;
3742 if (brackets < 0)
3743 return false;
3745 t = peek(t);
3746 continue;
3748 case TOK.endOfFile:
3749 return false;
3751 default:
3752 t = peek(t);
3753 continue;
3758 /*********************************
3759 * Check to see if tokens starting with *pt form a declarator.
3760 * Params:
3761 * pt = pointer to starting token, updated to point past declarator if true is returned
3762 * declarator = declarator kind
3763 * Returns:
3764 * true if it does
3766 private bool isCDeclarator(ref Token* pt, DTR declarator)
3768 auto t = pt;
3769 while (1)
3771 if (t.value == TOK.mul) // pointer
3773 t = peek(t);
3774 if (!isTypeQualifierList(t))
3775 return false;
3777 else
3778 break;
3781 if (t.value == TOK.identifier)
3783 if (declarator == DTR.xabstract)
3784 return false;
3785 t = peek(t);
3787 else if (t.value == TOK.leftParenthesis)
3789 t = peek(t);
3790 if (!isCDeclarator(t, declarator))
3791 return false;
3792 if (t.value != TOK.rightParenthesis)
3793 return false;
3794 t = peek(t);
3796 else if (declarator == DTR.xdirect)
3798 return false;
3801 while (1)
3803 if (t.value == TOK.leftBracket)
3805 if (!skipBrackets(t))
3806 return false;
3808 else if (t.value == TOK.leftParenthesis)
3810 if (!skipParens(t, &t))
3811 return false;
3813 else
3814 break;
3816 pt = t;
3817 return true;
3820 /***************************
3821 * Is this the start of a type-qualifier-list?
3822 * (Can be empty.)
3823 * Params:
3824 * pt = first token; updated with past end of type-qualifier-list if true
3825 * Returns:
3826 * true if start of type-qualifier-list
3828 private bool isTypeQualifierList(ref Token* pt)
3830 auto t = pt;
3831 while (1)
3833 switch (t.value)
3835 case TOK.const_:
3836 case TOK.restrict:
3837 case TOK.volatile:
3838 case TOK._Atomic:
3839 t = peek(t);
3840 continue;
3842 default:
3843 break;
3845 break;
3847 pt = t;
3848 return true;
3851 /***************************
3852 * Is this the start of a type-name?
3853 * Params:
3854 * pt = first token; updated with past end of type-name if true
3855 * Returns:
3856 * true if start of type-name
3858 private bool isTypeName(ref Token* pt)
3860 auto t = pt;
3861 //printf("isTypeName() %s\n", t.toChars());
3862 if (!isSpecifierQualifierList(t))
3863 return false;
3864 if (!isCDeclarator(t, DTR.xabstract))
3865 return false;
3866 if (t.value != TOK.rightParenthesis)
3867 return false;
3868 pt = t;
3869 return true;
3872 /***************************
3873 * Is this the start of a specifier-qualifier-list?
3874 * Params:
3875 * pt = first token; updated with past end of specifier-qualifier-list if true
3876 * Returns:
3877 * true if start of specifier-qualifier-list
3879 private bool isSpecifierQualifierList(ref Token* pt)
3881 auto t = pt;
3882 bool result;
3883 while (1)
3885 switch (t.value)
3887 // Type Qualifiers
3888 case TOK.const_:
3889 case TOK.restrict:
3890 case TOK.volatile:
3892 // Type Specifiers
3893 case TOK.char_:
3894 case TOK.signed:
3895 case TOK.unsigned:
3896 case TOK.int16:
3897 case TOK.int32:
3898 case TOK.int64:
3899 case TOK.float32:
3900 case TOK.float64:
3901 case TOK.void_:
3902 case TOK._Bool:
3903 //case TOK._Imaginary: // ? missing in Spec
3904 case TOK._Complex:
3906 // typedef-name
3907 case TOK.identifier: // will not know until semantic if typedef
3908 t = peek(t);
3909 break;
3911 // struct-or-union-specifier
3912 // enum-specifier
3913 case TOK.struct_:
3914 case TOK.union_:
3915 case TOK.enum_:
3916 t = peek(t);
3917 if (t.value == TOK.identifier)
3919 t = peek(t);
3920 if (t.value == TOK.leftCurly)
3922 if (!skipBraces(t))
3923 return false;
3926 else if (t.value == TOK.leftCurly)
3928 if (!skipBraces(t))
3929 return false;
3931 else
3932 return false;
3933 break;
3935 // atomic-type-specifier
3936 case TOK._Atomic:
3937 t = peek(t);
3938 if (t.value != TOK.leftParenthesis ||
3939 !skipParens(t, &t))
3940 return false;
3941 break;
3943 default:
3944 if (result)
3945 pt = t;
3946 return result;
3948 result = true;
3952 /************************************
3953 * Looking at the leading left parenthesis, and determine if it is
3954 * either of the following:
3955 * ( type-name ) cast-expression
3956 * ( type-name ) { initializer-list }
3957 * as opposed to:
3958 * ( expression )
3959 * Params:
3960 * pt = starting token, updated to one past end of constant-expression if true
3961 * afterParenType = true if already seen ( type-name )
3962 * Returns:
3963 * true if matches ( type-name ) ...
3965 private bool isCastExpression(ref Token* pt, bool afterParenType = false)
3967 auto t = pt;
3968 switch (t.value)
3970 case TOK.leftParenthesis:
3971 auto tk = peek(t); // move past left parenthesis
3972 if (!isTypeName(tk) || tk.value != TOK.rightParenthesis)
3974 if (afterParenType)
3975 goto default; // could be ( type-name ) ( unary-expression )
3976 return false;
3978 tk = peek(tk); // move past right parenthesis
3980 if (tk.value == TOK.leftCurly)
3982 // ( type-name ) { initializer-list }
3983 if (!isInitializer(tk))
3984 return false;
3985 t = tk;
3986 break;
3989 if (tk.value == TOK.leftParenthesis && peek(tk).value == TOK.rightParenthesis)
3990 return false; // (type-name)() is not a cast (it might be a function call)
3992 if (!isCastExpression(tk, true))
3994 if (afterParenType) // could be ( type-name ) ( unary-expression )
3995 goto default; // where unary-expression also matched type-name
3996 return false;
3998 // ( type-name ) cast-expression
3999 t = tk;
4000 break;
4002 default:
4003 if (!afterParenType || !isUnaryExpression(t, afterParenType))
4004 return false;
4005 // if we've already seen ( type-name ), then this is a cast
4006 break;
4008 pt = t;
4009 return true;
4012 /********************************
4013 * See if match for unary-expression.
4014 * Params:
4015 * pt = starting token, updated to one past end of constant-expression if true
4016 * afterParenType = true if already seen ( type-name ) of a cast-expression
4017 * Returns:
4018 * true if unary-expression
4020 private bool isUnaryExpression(ref Token* pt, bool afterParenType = false)
4022 auto t = pt;
4023 switch (t.value)
4025 case TOK.plusPlus:
4026 case TOK.minusMinus:
4027 t = peek(t);
4028 if (!isUnaryExpression(t, afterParenType))
4029 return false;
4030 break;
4032 case TOK.and:
4033 case TOK.mul:
4034 case TOK.min:
4035 case TOK.add:
4036 case TOK.not:
4037 case TOK.tilde:
4038 t = peek(t);
4039 if (!isCastExpression(t, afterParenType))
4040 return false;
4041 break;
4043 case TOK.sizeof_:
4044 t = peek(t);
4045 if (t.value == TOK.leftParenthesis)
4047 auto tk = peek(t);
4048 if (isTypeName(tk))
4050 if (tk.value != TOK.rightParenthesis)
4051 return false;
4052 t = peek(tk);
4053 break;
4056 if (!isUnaryExpression(t, afterParenType))
4057 return false;
4058 break;
4060 case TOK._Alignof:
4061 t = peek(t);
4062 if (t.value != TOK.leftParenthesis)
4063 return false;
4064 t = peek(t);
4065 if (!isTypeName(t) || t.value != TOK.rightParenthesis)
4066 return false;
4067 break;
4069 default:
4070 // Compound literals are handled by cast and sizeof expressions,
4071 // so be content with just seeing a primary expression.
4072 if (!isPrimaryExpression(t))
4073 return false;
4074 break;
4076 pt = t;
4077 return true;
4080 /********************************
4081 * See if match for primary-expression.
4082 * Params:
4083 * pt = starting token, updated to one past end of constant-expression if true
4084 * Returns:
4085 * true if primary-expression
4087 private bool isPrimaryExpression(ref Token* pt)
4089 auto t = pt;
4090 switch (t.value)
4092 case TOK.identifier:
4093 case TOK.int32Literal:
4094 case TOK.uns32Literal:
4095 case TOK.int64Literal:
4096 case TOK.uns64Literal:
4097 case TOK.float32Literal:
4098 case TOK.float64Literal:
4099 case TOK.float80Literal:
4100 case TOK.imaginary32Literal:
4101 case TOK.imaginary64Literal:
4102 case TOK.imaginary80Literal:
4103 case TOK.string_:
4104 t = peek(t);
4105 break;
4107 case TOK.leftParenthesis:
4108 // ( expression )
4109 if (!skipParens(t, &t))
4110 return false;
4111 break;
4113 case TOK._Generic:
4114 t = peek(t);
4115 if (!skipParens(t, &t))
4116 return false;
4117 break;
4119 default:
4120 return false;
4122 pt = t;
4123 return true;
4127 /******************************************************************************/
4128 /********************************* More ***************************************/
4131 /**************
4132 * Declaration context
4134 enum LVL
4136 global = 1, /// global
4137 parameter = 2, /// function parameter (declarations for function identifier-list)
4138 prototype = 4, /// function prototype
4139 local = 8, /// local
4140 member = 0x10, /// struct member
4143 /// Types of declarator to parse
4144 enum DTR
4146 xdirect = 1, /// C11 6.7.6 direct-declarator
4147 xabstract = 2, /// C11 6.7.7 abstract-declarator
4148 xparameter = 3, /// parameter declarator may be either direct or abstract
4151 /// C11 6.7.1 Storage-class specifiers
4152 enum SCW : uint
4154 xnone = 0,
4155 xtypedef = 1,
4156 xextern = 2,
4157 xstatic = 4,
4158 x_Thread_local = 8,
4159 xauto = 0x10,
4160 xregister = 0x20,
4161 // C11 6.7.4 Function specifiers
4162 xinline = 0x40,
4163 x_Noreturn = 0x80,
4166 /// C11 6.7.3 Type qualifiers
4167 enum MOD : uint
4169 xnone = 0,
4170 xconst = 1,
4171 xvolatile = 2,
4172 xrestrict = 4,
4173 x_Atomic = 8,
4176 /**********************************
4177 * Aggregate for all the various specifiers
4179 struct Specifier
4181 bool noreturn; /// noreturn attribute
4182 SCW scw; /// storage-class specifiers
4183 MOD mod; /// type qualifiers
4184 AST.Expressions* alignExps; /// alignment
4185 structalign_t packalign; /// #pragma pack alignment value
4188 /***********************
4189 * Convert from C specifiers to D storage class
4190 * Params:
4191 * level = declaration context
4192 * specifier = specifiers, context, etc.
4193 * Returns:
4194 * corresponding D storage class
4196 StorageClass specifiersToSTC(LVL level, const ref Specifier specifier)
4198 StorageClass stc;
4199 if (specifier.scw & SCW.x_Thread_local)
4201 if (level == LVL.global)
4203 if (specifier.scw & SCW.xextern)
4204 stc = AST.STC.extern_;
4206 else if (level == LVL.local)
4208 if (specifier.scw & SCW.xextern)
4209 stc = AST.STC.extern_;
4210 else if (specifier.scw & SCW.xstatic)
4211 stc = AST.STC.static_;
4213 else if (level == LVL.member)
4215 if (specifier.scw & SCW.xextern)
4216 stc = AST.STC.extern_;
4217 else if (specifier.scw & SCW.xstatic)
4218 stc = AST.STC.static_;
4221 else
4223 if (level == LVL.global)
4225 if (specifier.scw & SCW.xextern)
4226 stc = AST.STC.extern_ | AST.STC.gshared;
4227 else if (specifier.scw & SCW.xstatic)
4228 stc = AST.STC.gshared | AST.STC.static_;
4229 else
4230 stc = AST.STC.gshared;
4232 else if (level == LVL.local)
4234 if (specifier.scw & SCW.xextern)
4235 stc = AST.STC.extern_ | AST.STC.gshared;
4236 else if (specifier.scw & SCW.xstatic)
4237 stc = AST.STC.gshared;
4239 else if (level == LVL.member)
4241 if (specifier.scw & SCW.xextern)
4242 stc = AST.STC.extern_ | AST.STC.gshared;
4243 else if (specifier.scw & SCW.xstatic)
4244 stc = AST.STC.gshared;
4247 return stc;
4250 /***********************
4251 * Return suitable D float type for C `long double`
4252 * Params:
4253 * flags = kind of float to return (real, imaginary, complex).
4254 * Returns:
4255 * corresponding D type
4257 private AST.Type realType(RTFlags flags)
4259 if (long_doublesize == AST.Type.tfloat80.size())
4261 // On GDC and LDC, D `real` types map to C `long double`, so never
4262 // return a double type when real.sizeof == double.sizeof.
4263 final switch (flags)
4265 case RTFlags.realfloat: return AST.Type.tfloat80;
4266 case RTFlags.imaginary: return AST.Type.timaginary80;
4267 case RTFlags.complex: return AST.Type.tcomplex80;
4270 else
4272 final switch (flags)
4274 case RTFlags.realfloat: return long_doublesize == 8 ? AST.Type.tfloat64 : AST.Type.tfloat80;
4275 case RTFlags.imaginary: return long_doublesize == 8 ? AST.Type.timaginary64 : AST.Type.timaginary80;
4276 case RTFlags.complex: return long_doublesize == 8 ? AST.Type.tcomplex64 : AST.Type.tcomplex80;
4281 /**************
4282 * Flags for realType
4284 private enum RTFlags
4286 realfloat,
4287 imaginary,
4288 complex,
4291 /********************
4292 * C11 6.4.2.2 Create declaration to predefine __func__
4293 * `static const char __func__[] = " function-name ";`
4294 * Params:
4295 * loc = location for this declaration
4296 * id = identifier of function
4297 * Returns:
4298 * statement representing the declaration of __func__
4300 private AST.Statement createFuncName(Loc loc, Identifier id)
4302 const fn = id.toString(); // function-name
4303 auto efn = new AST.StringExp(loc, fn, fn.length, 1, 'c');
4304 auto ifn = new AST.ExpInitializer(loc, efn);
4305 auto lenfn = new AST.IntegerExp(loc, fn.length + 1, AST.Type.tuns32); // +1 for terminating 0
4306 auto tfn = new AST.TypeSArray(AST.Type.tchar, lenfn);
4307 efn.type = tfn.immutableOf();
4308 efn.committed = 1;
4309 auto sfn = new AST.VarDeclaration(loc, tfn, Id.__func__, ifn, STC.gshared | STC.immutable_);
4310 auto e = new AST.DeclarationExp(loc, sfn);
4311 return new AST.ExpStatement(loc, e);
4314 /************************
4315 * After encountering an error, scan forward until a right brace or ; is found
4316 * or the end of the file.
4318 void panic()
4320 while (token.value != TOK.rightCurly && token.value != TOK.semicolon && token.value != TOK.endOfFile)
4321 nextToken();
4324 /**************************
4325 * Apply `const` to a type.
4326 * Params:
4327 * t = type to add const to
4328 * Returns:
4329 * resulting type
4331 private AST.Type toConst(AST.Type t)
4333 // `const` is always applied to the return type, not the
4334 // type function itself.
4335 if (auto tf = t.isTypeFunction())
4336 tf.next = tf.next.addSTC(STC.const_);
4337 else
4338 t = t.addSTC(STC.const_);
4339 return t;
4342 /***************************
4343 * Apply specifier to a Dsymbol.
4344 * Params:
4345 * s = Dsymbol
4346 * specifier = specifiers to apply
4347 * Returns:
4348 * Dsymbol with specifiers applied
4350 private AST.Dsymbol applySpecifier(AST.Dsymbol s, ref Specifier specifier)
4352 //printf("applySpecifier() %s\n", s.toChars());
4353 if (specifier.alignExps)
4355 //printf(" applying _Alignas %s, packalign %d\n", (*specifier.alignExps)[0].toChars(), cast(int)specifier.packalign);
4356 // Wrap declaration in an AlignDeclaration
4357 auto decls = new AST.Dsymbols(1);
4358 (*decls)[0] = s;
4359 s = new AST.AlignDeclaration(s.loc, specifier.alignExps, decls);
4361 else if (!specifier.packalign.isDefault())
4363 //printf(" applying packalign %d\n", cast(int)specifier.packalign);
4364 // Wrap #pragma pack in an AlignDeclaration
4365 auto decls = new AST.Dsymbols(1);
4366 (*decls)[0] = s;
4367 s = new AST.AlignDeclaration(s.loc, specifier.packalign, decls);
4369 return s;
4372 /***********************************
4373 * Add global target-dependent builtin declarations.
4375 private void addBuiltinDeclarations()
4377 void genBuiltinFunc(Identifier id, AST.VarArg va)
4379 auto tva_list = new AST.TypeIdentifier(Loc.initial, Id.builtin_va_list);
4380 auto parameters = new AST.Parameters();
4381 parameters.push(new AST.Parameter(STC.parameter | STC.ref_, tva_list, null, null, null));
4382 auto pl = AST.ParameterList(parameters, va, 0);
4383 auto tf = new AST.TypeFunction(pl, AST.Type.tvoid, LINK.c, 0);
4384 auto s = new AST.FuncDeclaration(Loc.initial, Loc.initial, id, AST.STC.static_, tf, false);
4385 symbols.push(s);
4388 /* void __builtin_va_start(__builtin_va_list, ...);
4389 * The second argument is supposed to be of any type, so fake it with the ...
4391 genBuiltinFunc(Id.builtin_va_start, AST.VarArg.variadic);
4393 /* void __builtin_va_end(__builtin_va_list);
4395 genBuiltinFunc(Id.builtin_va_end, AST.VarArg.none);
4397 /* struct __va_list_tag
4399 * uint, uint, void*, void*
4402 auto s = new AST.StructDeclaration(Loc.initial, Id.va_list_tag, false);
4403 symbols.push(s);