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