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