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