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