1 /** 2 * Copyright: Copyright (c) 2017 Wojciech Szęszoł. All rights reserved. 3 * Authors: Wojciech Szęszoł 4 * Version: Initial created: October 05, 2017 5 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0) 6 */ 7 module dstep.translator.MacroParser; 8 9 import std.array; 10 import std.meta; 11 import std.traits; 12 import std.variant; 13 import std.stdio; 14 15 import clang.c.Index; 16 import clang.Cursor; 17 import clang.Token; 18 import clang.Type; 19 import clang.Util; 20 import clang.SourceLocation; 21 import clang.SourceRange; 22 23 enum bool isStringValue(alias T) = 24 is(typeof(T) : const char[]) && 25 !isAggregateType!(typeof(T)) && 26 !isStaticArray!(typeof(T)); 27 28 /** 29 * The accept family of functions parse tokens. In the case of successful parsing, 30 * the function advances the beginning of the tokens to the next token and returns true. 31 * 32 * The parsing is successful, if the first token in tokens is of the specified kind 33 * and its spelling matches one of the strings passed as Args. 34 * It assigns the spelling of the token to the spelling parameter. 35 */ 36 bool accept(Args...)(ref Token[] tokens, ref string spelling, TokenKind kind) 37 if (Args.length > 0 && allSatisfy!(isStringValue, Args)) 38 { 39 if (!tokens.empty && tokens.front.kind == kind) 40 { 41 foreach (arg; Args) 42 { 43 if (tokens.front.spelling == arg) 44 { 45 tokens = tokens[1 .. $]; 46 spelling = arg; 47 return true; 48 } 49 } 50 } 51 52 return false; 53 } 54 55 bool accept(ref Token[] tokens, ref string spelling, TokenKind kind) 56 { 57 if (!tokens.empty && tokens.front.kind == kind) 58 { 59 spelling = tokens.front.spelling; 60 tokens = tokens[1 .. $]; 61 return true; 62 } 63 64 return false; 65 } 66 67 bool accept(Args...)(ref Token[] tokens, TokenKind kind) 68 if (allSatisfy!(isStringValue, Args)) 69 { 70 if (!tokens.empty && tokens.front.kind == kind) 71 { 72 foreach (arg; Args) 73 { 74 if (tokens.front.spelling == arg) 75 { 76 tokens = tokens[1 .. $]; 77 return true; 78 } 79 } 80 } 81 82 return false; 83 } 84 85 bool accept(Args...)(ref Token[] tokens, ref string spelling) 86 if (Args.length > 0 && allSatisfy!(isStringValue, Args)) 87 { 88 if (!tokens.empty) 89 { 90 foreach (arg; Args) 91 { 92 if (tokens.front.spelling == arg) 93 { 94 tokens = tokens[1 .. $]; 95 spelling = arg; 96 return true; 97 } 98 } 99 } 100 101 return false; 102 } 103 104 bool acceptPunctuation(Args...)(ref Token[] tokens, ref string spelling) 105 if (allSatisfy!(isStringValue, Args)) 106 { 107 return accept!(Args)(tokens, spelling, TokenKind.punctuation); 108 } 109 110 bool acceptPunctuation(Args...)(ref Token[] tokens) 111 if (allSatisfy!(isStringValue, Args)) 112 { 113 return accept!(Args)(tokens, TokenKind.punctuation); 114 } 115 116 bool acceptIdentifier(ref Token[] tokens, ref string spelling) 117 { 118 return accept(tokens, spelling, TokenKind.identifier); 119 } 120 121 bool acceptLiteral(ref Token[] tokens, ref string spelling) 122 { 123 return accept(tokens, spelling, TokenKind.literal); 124 } 125 126 bool acceptKeyword(ref Token[] tokens, ref string spelling) 127 { 128 return accept(tokens, spelling, TokenKind.keyword); 129 } 130 131 bool acceptStringLiteral(ref Token[] tokens, ref string spelling) 132 { 133 import std..string : startsWith, endsWith; 134 135 if (!tokens.empty && tokens.front.kind == TokenKind.literal) 136 { 137 spelling = tokens.front.spelling; 138 139 if (!spelling.startsWith(`"`) || !spelling.endsWith(`"`)) 140 return false; 141 142 tokens = tokens[1 .. $]; 143 return true; 144 } 145 146 return false; 147 } 148 149 Expression parseLeftAssoc(ResultExpr, alias parseChild, Ops...)( 150 ref Token[] tokens, 151 Cursor[string] table, 152 bool defined) if (allSatisfy!(isStringValue, Ops)) 153 { 154 import std.traits; 155 import std.range; 156 157 auto local = tokens; 158 159 ReturnType!parseChild[] exprs = [ parseChild(local, table, defined) ]; 160 string[] ops = []; 161 162 if (!exprs[0].hasValue) 163 return Expression.init; 164 165 string op; 166 while (accept!(Ops)(local, op, TokenKind.punctuation)) 167 { 168 exprs ~= parseChild(local, table, defined); 169 170 if (!exprs[$ - 1].hasValue) 171 return Expression.init; 172 173 ops ~= op; 174 } 175 176 tokens = local; 177 178 if (exprs.length == 1) 179 return exprs[0]; 180 181 ResultExpr result = new ResultExpr; 182 result.left = exprs[0]; 183 result.right = exprs[1]; 184 result.operator = ops[0]; 185 186 foreach (expr, fop; zip(exprs[2 .. $], ops[1 .. $])) 187 { 188 ResultExpr parent = new ResultExpr; 189 parent.left = result; 190 parent.right = expr; 191 parent.operator = fop; 192 result = parent; 193 } 194 195 return Expression(result); 196 } 197 198 struct Identifier 199 { 200 string spelling; 201 202 string toString() 203 { 204 import std.format : format; 205 206 return format("Identifier(spelling = %s)", spelling); 207 } 208 } 209 210 struct TypeIdentifier 211 { 212 Type type; 213 } 214 215 struct Literal 216 { 217 string spelling; 218 219 this (string spelling) 220 { 221 this.spelling = spelling; 222 } 223 224 string toString() 225 { 226 import std.format : format; 227 228 return format("Literal(spelling = %s)", spelling); 229 } 230 } 231 232 struct StringLiteral 233 { 234 string spelling; 235 236 this (string spelling) 237 { 238 this.spelling = spelling; 239 } 240 241 string toString() 242 { 243 import std.format : format; 244 245 return format("Literal(spelling = %s)", spelling); 246 } 247 } 248 249 struct StringifyExpr 250 { 251 string spelling; 252 253 this (string spelling) 254 { 255 this.spelling = spelling; 256 } 257 258 string toString() 259 { 260 import std.format : format; 261 262 return format("StringifyExpr(spelling = %s)", spelling); 263 } 264 } 265 266 class StringConcat 267 { 268 Expression[] substrings; 269 270 this (Expression[] substrings) 271 { 272 this.substrings = substrings; 273 } 274 275 override string toString() 276 { 277 import std.format : format; 278 279 return format("StringConcat(substrings = %s)", substrings); 280 } 281 } 282 283 class TokenConcat 284 { 285 Expression[] subexprs; 286 287 this (Expression[] subexprs) 288 { 289 this.subexprs = subexprs; 290 } 291 292 override string toString() 293 { 294 import std.format : format; 295 296 return format("TokenConcat(subexprs = %s)", subexprs); 297 } 298 } 299 300 class IndexExpr 301 { 302 Expression subexpr; 303 Expression index; 304 305 override string toString() 306 { 307 import std.format : format; 308 309 return format("IndexExpr(subexpr = %s, index = %s)", subexpr, index); 310 } 311 } 312 313 class CallExpr 314 { 315 Expression expr; 316 Expression[] args; 317 318 override string toString() 319 { 320 import std.format : format; 321 322 return format("CallExpr(expr = %s, args = %s)", expr, args); 323 } 324 } 325 326 class DotExpr 327 { 328 Expression subexpr; 329 string identifier; 330 331 override string toString() 332 { 333 import std.format : format; 334 335 return format( 336 "DotExpr(subexpr = %s, identifier = %s)", 337 subexpr, 338 identifier); 339 } 340 } 341 342 class ArrowExpr : DotExpr 343 { 344 override string toString() 345 { 346 import std.format : format; 347 348 return format( 349 "ArrowExpr(subexpr = %s, identifier = %s)", 350 subexpr, 351 identifier); 352 } 353 } 354 355 class SubExpr 356 { 357 Expression subexpr; 358 359 this (Expression subexpr) 360 { 361 this.subexpr = subexpr; 362 } 363 364 override string toString() 365 { 366 import std.format : format; 367 368 return format("SubExpr(subexpr = %s)", subexpr); 369 } 370 } 371 372 class UnaryExpr 373 { 374 Expression subexpr; 375 string operator; 376 bool postfix = false; 377 378 override string toString() 379 { 380 import std.format : format; 381 382 return format( 383 "UnaryExpr(subexpr = %s, operator = %s)", 384 subexpr, 385 operator); 386 } 387 } 388 389 struct DefinedExpr 390 { 391 string identifier; 392 393 string toString() 394 { 395 import std.format : format; 396 397 return format("DefinedExpr(identifier = %s)", identifier); 398 } 399 } 400 401 struct SizeofType 402 { 403 Type type; 404 405 string toString() 406 { 407 import std.format : format; 408 409 return format("SizeofType(type = %s)", type); 410 } 411 } 412 413 class CastExpr 414 { 415 Type type; 416 Expression subexpr; 417 418 override string toString() 419 { 420 import std.format : format; 421 422 return format( 423 "CastExpr(typename = %s, subexpr = %s)", 424 type, 425 subexpr); 426 } 427 } 428 429 class BinaryExpr 430 { 431 Expression left; 432 Expression right; 433 string operator; 434 435 override string toString() 436 { 437 import std.format : format; 438 import std.range : retro; 439 import std.algorithm.searching : findSplit; 440 import std.array : array; 441 442 auto rname = findSplit(this.classinfo.name.retro, ".")[0].array; 443 444 return format( 445 "%s(left = %s, right = %s, operator = %s)", 446 rname.retro, 447 left, 448 right, 449 operator); 450 } 451 } 452 453 class MulExpr : BinaryExpr 454 { } 455 456 class AddExpr : BinaryExpr 457 { } 458 459 class SftExpr : BinaryExpr 460 { } 461 462 class RelExpr : BinaryExpr 463 { } 464 465 class EqlExpr : BinaryExpr 466 { } 467 468 class AndExpr : BinaryExpr 469 { } 470 471 class XorExpr : BinaryExpr 472 { } 473 474 class OrExpr : BinaryExpr 475 { } 476 477 class LogicalAndExpr : BinaryExpr 478 { } 479 480 class LogicalOrExpr : BinaryExpr 481 { } 482 483 class CondExpr 484 { 485 Expression expr; 486 Expression left; 487 Expression right; 488 489 override string toString() 490 { 491 import std.format : format; 492 import std.range : retro; 493 import std.algorithm.searching : findSplit; 494 import std.array : array; 495 496 auto rname = findSplit(this.classinfo.name.retro, ".")[0].array; 497 498 return format( 499 "CondExpr(expr = %s, left = %s, right = %s)", 500 expr, 501 left, 502 right); 503 } 504 } 505 506 alias Expression = Algebraic!( 507 Identifier, 508 TypeIdentifier, 509 Literal, 510 StringLiteral, 511 StringifyExpr, 512 StringConcat, 513 TokenConcat, 514 IndexExpr, 515 CallExpr, 516 DotExpr, 517 ArrowExpr, 518 SubExpr, 519 UnaryExpr, 520 DefinedExpr, 521 SizeofType, 522 CastExpr, 523 MulExpr, 524 AddExpr, 525 SftExpr, 526 RelExpr, 527 EqlExpr, 528 AndExpr, 529 XorExpr, 530 OrExpr, 531 LogicalAndExpr, 532 LogicalOrExpr, 533 CondExpr); 534 535 Expression debraced(Expression expression) 536 { 537 if (!expression.hasValue) 538 return expression; 539 540 auto subExpr = expression.peek!SubExpr(); 541 542 return subExpr !is null ? subExpr.subexpr : expression; 543 } 544 545 Expression braced(Expression expression) 546 { 547 if (!expression.hasValue) 548 return expression; 549 550 if (auto subExpr = expression.peek!Identifier()) 551 return expression; 552 else if (auto subExpr = expression.peek!Literal()) 553 return expression; 554 else if (auto subExpr = expression.peek!SubExpr()) 555 return expression; 556 else 557 return Expression(new SubExpr(expression)); 558 } 559 560 Expression parseStringConcat(ref Token[] tokens) 561 { 562 import std.array; 563 564 auto local = tokens; 565 566 Expression[] substrings; 567 568 while (true) 569 { 570 string spelling; 571 572 if (acceptStringLiteral(local, spelling)) 573 { 574 substrings ~= Expression(StringLiteral(spelling)); 575 } 576 else if (accept!("#")(local, TokenKind.punctuation)) 577 { 578 if (!accept(local, spelling, TokenKind.identifier)) 579 return Expression.init; 580 581 substrings ~= Expression(StringifyExpr(spelling)); 582 } 583 else 584 { 585 break; 586 } 587 } 588 589 if (substrings.length == 0) 590 return Expression.init; 591 592 tokens = local; 593 594 if (substrings.length == 1) 595 return substrings.front; 596 597 return Expression(new StringConcat(substrings)); 598 } 599 600 Expression parseTokenConcat(ref Token[] tokens) 601 { 602 Expression parseSubexpr(ref Token[] tokens) 603 { 604 string spelling; 605 606 if (acceptIdentifier(tokens, spelling)) 607 return Expression(Identifier(spelling)); 608 609 if (acceptLiteral(tokens, spelling)) 610 return Expression(Literal(spelling)); 611 612 return Expression.init; 613 } 614 615 auto local = tokens; 616 617 Expression[] subexprs; 618 auto first = parseSubexpr(local); 619 620 if (first.hasValue) 621 { 622 if (!acceptPunctuation!("##")(local)) 623 return Expression.init; 624 625 auto expr = parseSubexpr(local); 626 627 if (expr.hasValue) 628 { 629 subexprs ~= first; 630 subexprs ~= expr; 631 632 tokens = local; 633 634 while (acceptPunctuation!("##")(local)) 635 { 636 expr = parseSubexpr(local); 637 638 if (expr.hasValue) 639 { 640 subexprs ~= expr; 641 tokens = local; 642 } 643 else 644 { 645 break; 646 } 647 } 648 649 return Expression(new TokenConcat(subexprs)); 650 } 651 } 652 653 return Expression.init; 654 } 655 656 Expression parsePrimaryExpr(ref Token[] tokens, Cursor[string] table, bool defined) 657 { 658 string spelling; 659 660 auto type = parseTypeName(tokens, table); 661 662 if (type.isValid) 663 return Expression(TypeIdentifier(type)); 664 665 if (accept(tokens, spelling, TokenKind.identifier)) 666 return Expression(Identifier(spelling)); 667 668 auto local = tokens; 669 670 auto substrings = parseStringConcat(local); 671 672 if (substrings.hasValue) 673 { 674 tokens = local; 675 return substrings; 676 } 677 678 if (accept(local, spelling, TokenKind.literal)) 679 { 680 tokens = local; 681 return Expression(Literal(spelling)); 682 } 683 684 if (!accept!("(")(local, TokenKind.punctuation)) 685 return Expression.init; 686 687 auto subexpr = parseExpr(local, table, defined); 688 689 if (!subexpr.hasValue) 690 return Expression.init; 691 692 if (!accept!(")")(local, TokenKind.punctuation)) 693 return Expression.init; 694 695 tokens = local; 696 697 return Expression(new SubExpr(subexpr)); 698 } 699 700 Expression parseArg(ref Token[] tokens, Cursor[string] table, bool defined) 701 { 702 auto local = tokens; 703 704 auto expression = parseSftExpr(local, table, defined); 705 706 if (expression.hasValue) 707 { 708 tokens = local; 709 return expression; 710 } 711 712 auto type = parseTypeName(local, table); 713 714 if (type.isValid) 715 { 716 tokens = local; 717 expression = TypeIdentifier(type); 718 } 719 720 return expression; 721 } 722 723 Expression[] parseArgsList(ref Token[] tokens, Cursor[string] table, bool defined) 724 { 725 auto local = tokens; 726 727 Expression[] exprs = [ parseArg(local, table, defined) ]; 728 729 if (!exprs[0].hasValue) 730 return null; 731 732 while (true) 733 { 734 if (acceptPunctuation!(",")(local)) 735 { 736 Expression expr = parseArg(local, table, defined); 737 738 if (!expr.hasValue) 739 break; 740 741 exprs ~= expr; 742 } 743 else 744 { 745 break; 746 } 747 } 748 749 tokens = local; 750 751 return exprs; 752 } 753 754 Expression parsePostfixExpr(ref Token[] tokens, Cursor[string] table, bool defined) 755 { 756 auto local = tokens; 757 758 Expression expr = parsePrimaryExpr(local, table, defined); 759 760 if (!expr.hasValue) 761 return expr; 762 763 string spelling; 764 765 while (true) 766 { 767 if (acceptPunctuation!("[")(local)) 768 { 769 auto index = parseExpr(local, table, defined); 770 771 if (!index.hasValue) 772 break; 773 774 if (!acceptPunctuation!("]")(local)) 775 break; 776 777 IndexExpr subexpr = new IndexExpr; 778 subexpr.subexpr = expr; 779 subexpr.index = index; 780 expr = subexpr; 781 } 782 else if (acceptPunctuation!("(")(local)) 783 { 784 if (acceptPunctuation!(")")(local)) 785 { 786 CallExpr subexpr = new CallExpr; 787 subexpr.expr = expr; 788 subexpr.args = []; 789 expr = subexpr; 790 } 791 else 792 { 793 auto args = parseArgsList(local, table, defined); 794 795 if (args is null) 796 break; 797 798 if (!acceptPunctuation!(")")(local)) 799 break; 800 801 CallExpr subexpr = new CallExpr; 802 subexpr.expr = expr; 803 subexpr.args = args; 804 expr = subexpr; 805 } 806 } 807 else if (acceptPunctuation!(".")(local) && acceptIdentifier(local, spelling)) 808 { 809 DotExpr subexpr = new DotExpr; 810 subexpr.subexpr = expr; 811 subexpr.identifier = spelling; 812 expr = subexpr; 813 } 814 else if (acceptPunctuation!("->")(local) && acceptIdentifier(local, spelling)) 815 { 816 ArrowExpr subexpr = new ArrowExpr; 817 subexpr.subexpr = expr; 818 subexpr.identifier = spelling; 819 expr = subexpr; 820 } 821 else if (acceptPunctuation!("++", "--")(local, spelling)) 822 { 823 UnaryExpr subexpr = new UnaryExpr; 824 subexpr.subexpr = expr; 825 subexpr.operator = spelling; 826 subexpr.postfix = true; 827 expr = subexpr; 828 } 829 else 830 { 831 break; 832 } 833 } 834 835 tokens = local; 836 837 return expr; 838 } 839 840 Expression parseSizeofType(ref Token[] tokens, Cursor[string] table) 841 { 842 auto local = tokens; 843 844 if (acceptPunctuation!("(")(local)) 845 { 846 Type type = parseTypeName(local, table); 847 848 if (type.isValid && acceptPunctuation!(")")(local)) 849 { 850 SizeofType expr = SizeofType(); 851 expr.type = type; 852 tokens = local; 853 return Expression(expr); 854 } 855 } 856 857 return Expression.init; 858 } 859 860 Expression parseDefinedExpr(ref Token[] tokens) 861 { 862 auto local = tokens; 863 864 if (accept!("defined")(local, TokenKind.identifier)) 865 { 866 string spelling; 867 868 if (acceptIdentifier(local, spelling)) 869 { 870 auto expr = DefinedExpr(); 871 expr.identifier = spelling; 872 tokens = local; 873 return Expression(expr); 874 } 875 876 if (acceptPunctuation!("(")(local) && 877 acceptIdentifier(local, spelling) && 878 acceptPunctuation!(")")(local)) 879 { 880 auto expr = DefinedExpr(); 881 expr.identifier = spelling; 882 tokens = local; 883 return Expression(expr); 884 } 885 } 886 887 return Expression.init; 888 } 889 890 Expression parseUnaryExpr(ref Token[] tokens, Cursor[string] table, bool defined) 891 { 892 auto local = tokens; 893 894 string spelling; 895 896 if (accept!("++", "--")(local, spelling, TokenKind.punctuation)) 897 { 898 Expression subexpr = parseUnaryExpr(local, table, defined); 899 900 if (subexpr.hasValue) 901 { 902 UnaryExpr expr = new UnaryExpr; 903 expr.subexpr = subexpr; 904 expr.operator = spelling; 905 tokens = local; 906 return Expression(expr); 907 } 908 } 909 910 if (accept!("&", "*", "+", "-", "~", "!")(local, spelling, TokenKind.punctuation)) 911 { 912 Expression subexpr = parseCastExpr(local, table, defined); 913 914 if (subexpr.hasValue) 915 { 916 UnaryExpr expr = new UnaryExpr; 917 expr.subexpr = subexpr; 918 expr.operator = spelling; 919 tokens = local; 920 return Expression(expr); 921 } 922 } 923 924 if (accept!("sizeof")(local, spelling, TokenKind.keyword)) 925 { 926 auto sizeofExpr = parseSizeofType(local, table); 927 928 if (sizeofExpr.hasValue) 929 { 930 tokens = local; 931 return sizeofExpr; 932 } 933 934 Expression subexpr = parseUnaryExpr(local, table, defined); 935 936 if (subexpr.hasValue) 937 { 938 UnaryExpr expr = new UnaryExpr; 939 expr.subexpr = subexpr; 940 expr.operator = spelling; 941 tokens = local; 942 return Expression(expr); 943 } 944 } 945 946 if (defined) 947 { 948 auto expr = parseDefinedExpr(local); 949 950 if (expr.hasValue) 951 { 952 tokens = local; 953 return expr; 954 } 955 } 956 957 return parsePostfixExpr(tokens, table, defined); 958 } 959 960 Expression parseCastExpr(ref Token[] tokens, Cursor[string] table, bool defined) 961 { 962 auto local = tokens; 963 964 if (!accept!("(")(local, TokenKind.punctuation)) 965 return parseUnaryExpr(tokens, table, defined); 966 967 Type type = parseTypeName(local, table); 968 969 if (!type.isValid) 970 return parseUnaryExpr(tokens, table, defined); 971 972 if (!accept!(")")(local, TokenKind.punctuation)) 973 return parseUnaryExpr(tokens, table, defined); 974 975 auto subexpr = parseCastExpr(local, table, defined); 976 977 if (!subexpr.hasValue) 978 return parseUnaryExpr(tokens, table, defined); 979 980 tokens = local; 981 982 CastExpr result = new CastExpr; 983 result.type = type; 984 result.subexpr = subexpr; 985 986 return Expression(result); 987 } 988 989 alias parseMulExpr = parseLeftAssoc!(MulExpr, parseCastExpr, "*", "/", "%"); 990 alias parseAddExpr = parseLeftAssoc!(AddExpr, parseMulExpr, "+", "-"); 991 alias parseSftExpr = parseLeftAssoc!(SftExpr, parseAddExpr, "<<", ">>"); 992 alias parseRelExpr = parseLeftAssoc!(RelExpr, parseSftExpr, "<", ">", "<=", ">="); 993 alias parseEqlExpr = parseLeftAssoc!(EqlExpr, parseRelExpr, "==", "!="); 994 alias parseAndExpr = parseLeftAssoc!(AndExpr, parseEqlExpr, "&"); 995 alias parseXorExpr = parseLeftAssoc!(XorExpr, parseAndExpr, "^"); 996 alias parseOrExpr = parseLeftAssoc!(OrExpr, parseXorExpr, "|"); 997 alias parseLogicalAndExpr = parseLeftAssoc!(LogicalAndExpr, parseOrExpr, "&&"); 998 alias parseLogicalOrExpr = parseLeftAssoc!(LogicalOrExpr, parseLogicalAndExpr, "||"); 999 1000 Expression parseCondExpr(ref Token[] tokens, Cursor[string] table, bool defined) 1001 { 1002 auto local = tokens; 1003 1004 Expression expr = parseLogicalOrExpr(local, table, defined); 1005 1006 if (!expr.hasValue) 1007 return Expression.init; 1008 1009 tokens = local; 1010 1011 if (acceptPunctuation!("?")(local)) 1012 { 1013 Expression left = parseExpr(local, table, defined); 1014 1015 if (left.hasValue && acceptPunctuation!(":")(local)) 1016 { 1017 Expression right = parseCondExpr(local, table, defined); 1018 1019 if (right.hasValue) 1020 { 1021 CondExpr supexpr = new CondExpr; 1022 supexpr.expr = expr; 1023 supexpr.left = left; 1024 supexpr.right = right; 1025 expr = supexpr; 1026 1027 tokens = local; 1028 } 1029 } 1030 } 1031 1032 return expr; 1033 } 1034 1035 bool parseBasicSpecifier(ref Token[] tokens, ref string spelling, Cursor[string] table) 1036 { 1037 import std.meta : AliasSeq; 1038 1039 alias specifiers = AliasSeq!( 1040 "void", 1041 "char", 1042 "short", 1043 "int", 1044 "long", 1045 "float", 1046 "double", 1047 "signed", 1048 "unsigned", 1049 // "__complex__", TBD 1050 // "_Complex", TBD 1051 "bool", 1052 "_Bool"); 1053 1054 return accept!(specifiers)(tokens, spelling); 1055 } 1056 1057 bool parseRecordSpecifier(ref Token[] tokens, ref Type type, Cursor[string] table) 1058 { 1059 auto local = tokens; 1060 string spelling; 1061 string keywordType; 1062 1063 if (accept!("struct", "union")(local, keywordType, TokenKind.keyword) && 1064 acceptIdentifier(local, spelling)) 1065 { 1066 if (auto ptr = (keywordType ~ " " ~ spelling in table)) 1067 { 1068 type = ptr.type; 1069 tokens = local; 1070 return true; 1071 } 1072 } 1073 1074 return false; 1075 } 1076 1077 bool parseEnumSpecifier(ref Token[] tokens, ref Type type, Cursor[string] table) 1078 { 1079 auto local = tokens; 1080 string spelling; 1081 1082 if (acceptIdentifier(local, spelling)) 1083 { 1084 if (auto ptr = ("enum " ~ spelling in table)) 1085 { 1086 type = ptr.type; 1087 tokens = local; 1088 return true; 1089 } 1090 } 1091 1092 return false; 1093 } 1094 1095 bool parseTypedefName(ref Token[] tokens, ref Type type, Cursor[string] table) 1096 { 1097 auto local = tokens; 1098 string spelling; 1099 1100 if (acceptIdentifier(local, spelling)) 1101 { 1102 if (auto ptr = (spelling in table)) 1103 { 1104 type = Type.makeTypedef(spelling, ptr.type.canonical); 1105 1106 tokens = local; 1107 1108 return true; 1109 } 1110 } 1111 1112 return false; 1113 } 1114 1115 bool parseComplexSpecifier(ref Token[] tokens, ref Type type, Cursor[string] table) 1116 { 1117 return parseRecordSpecifier(tokens, type, table) || 1118 parseEnumSpecifier(tokens, type, table) || 1119 parseTypedefName(tokens, type, table); 1120 } 1121 1122 bool parseTypeQualifier(ref Token[] tokens, ref string spelling) 1123 { 1124 import std.meta : AliasSeq; 1125 1126 alias qualifiers = AliasSeq!( 1127 "const", 1128 "volatile", 1129 "_Atomic"); 1130 1131 return accept!(qualifiers)(tokens, spelling); 1132 } 1133 1134 bool parseSpecifierQualifierList( 1135 ref Token[] tokens, 1136 ref Type type, 1137 Cursor[string] table) 1138 { 1139 auto local = tokens; 1140 1141 Set!string specifiers; 1142 Set!string qualifiers; 1143 1144 while (true) 1145 { 1146 string spelling; 1147 1148 if (parseBasicSpecifier(local, spelling, table)) 1149 { 1150 if (type.isValid) 1151 return false; 1152 1153 if (specifiers.contains(spelling)) 1154 { 1155 if (spelling == "long") 1156 { 1157 if (specifiers.contains("__llong")) 1158 return false; 1159 else 1160 spelling = "__llong"; 1161 } 1162 else 1163 { 1164 return false; 1165 } 1166 } 1167 1168 specifiers.add(spelling); 1169 } 1170 else if (parseComplexSpecifier(local, type, table)) 1171 { 1172 if (specifiers.length != 0) 1173 return false; 1174 } 1175 else if (parseTypeQualifier(local, spelling)) 1176 { 1177 if (qualifiers.contains(spelling)) 1178 return false; 1179 1180 qualifiers.add(spelling); 1181 } 1182 else 1183 { 1184 break; 1185 } 1186 } 1187 1188 if (specifiers.length != 0) 1189 { 1190 if(!basicSpecifierListToType(type, specifiers)) 1191 return false; 1192 } 1193 1194 if (qualifiers.contains("const")) 1195 type.isConst = true; 1196 1197 if (qualifiers.contains("volatile")) 1198 type.isVolatile = true; 1199 1200 tokens = local; 1201 1202 return true; 1203 } 1204 1205 bool parseQualifierList( 1206 ref Token[] tokens, 1207 ref Type type) 1208 { 1209 auto local = tokens; 1210 1211 Set!string qualifiers; 1212 1213 while (true) 1214 { 1215 string spelling; 1216 1217 if (parseTypeQualifier(local, spelling)) 1218 { 1219 if (qualifiers.contains(spelling)) 1220 return false; 1221 1222 qualifiers.add(spelling); 1223 } 1224 else 1225 { 1226 break; 1227 } 1228 } 1229 1230 if (qualifiers.contains("const")) 1231 type.isConst = true; 1232 1233 if (qualifiers.contains("volatile")) 1234 type.isVolatile = true; 1235 1236 tokens = local; 1237 1238 return true; 1239 } 1240 1241 bool basicSpecifierListToType(ref Type type, Set!string specifiers) 1242 { 1243 if (specifiers.contains("void")) 1244 { 1245 if (specifiers.length != 1) 1246 return false; 1247 1248 type = Type(CXTypeKind.void_, "void"); 1249 return true; 1250 } 1251 1252 if (specifiers.contains("bool") || specifiers.contains("_Bool")) 1253 { 1254 if (specifiers.length != 1) 1255 return false; 1256 1257 type = Type(CXTypeKind.bool_, "bool"); 1258 return true; 1259 } 1260 1261 if (specifiers.contains("float")) 1262 { 1263 if (specifiers.length != 1) 1264 return false; 1265 1266 type = Type(CXTypeKind.float_, "float"); 1267 return true; 1268 } 1269 1270 if (specifiers.contains("double")) 1271 { 1272 if (specifiers.contains("long")) 1273 { 1274 if (specifiers.length != 2) 1275 return false; 1276 1277 type = Type(CXTypeKind.longDouble, "long double"); 1278 1279 return true; 1280 } 1281 1282 if (specifiers.length != 1) 1283 return false; 1284 1285 type = Type(CXTypeKind.double_, "double"); 1286 1287 return true; 1288 } 1289 1290 if ((specifiers.contains("signed") && specifiers.contains("unsigned")) || 1291 (specifiers.contains("char") && specifiers.contains("short")) || 1292 (specifiers.contains("char") && specifiers.contains("long")) || 1293 (specifiers.contains("char") && specifiers.contains("__llong")) || 1294 (specifiers.contains("short") && specifiers.contains("long")) || 1295 (specifiers.contains("short") && specifiers.contains("__llong"))) 1296 return false; 1297 1298 if (specifiers.contains("char")) 1299 { 1300 if (specifiers.contains("signed")) 1301 { 1302 if (specifiers.length != 2) 1303 return false; 1304 1305 type = Type(CXTypeKind.sChar, "signed char"); 1306 } 1307 else if (specifiers.contains("unsigned")) 1308 { 1309 if (specifiers.length != 2) 1310 return false; 1311 1312 type = Type(CXTypeKind.uChar, "unsigned char"); 1313 } 1314 else 1315 { 1316 if (specifiers.length != 1) 1317 return false; 1318 1319 type = Type(CXTypeKind.charS, "char"); 1320 } 1321 1322 return true; 1323 } 1324 1325 if (specifiers.contains("short")) 1326 { 1327 if (specifiers.contains("unsigned")) 1328 type = Type(CXTypeKind.uShort, "unsigned short"); 1329 else 1330 type = Type(CXTypeKind.short_, "short"); 1331 1332 return true; 1333 } 1334 1335 if (specifiers.contains("__llong")) 1336 { 1337 if (specifiers.contains("unsigned")) 1338 type = Type(CXTypeKind.uLongLong, "unsigned long long"); 1339 else 1340 type = Type(CXTypeKind.longLong, "long long"); 1341 1342 return true; 1343 } 1344 1345 if (specifiers.contains("long")) 1346 { 1347 if (specifiers.contains("unsigned")) 1348 type = Type(CXTypeKind.uLong, "unsigned long"); 1349 else 1350 type = Type(CXTypeKind.long_, "long"); 1351 1352 return true; 1353 } 1354 1355 if (specifiers.contains("int")) 1356 { 1357 if (specifiers.contains("unsigned")) 1358 type = Type(CXTypeKind.uInt, "unsigned int"); 1359 else 1360 type = Type(CXTypeKind.int_, "int"); 1361 1362 return true; 1363 } 1364 1365 if (specifiers.contains("unsigned")) 1366 { 1367 type = Type(CXTypeKind.uInt, "unsigned int"); 1368 return true; 1369 } 1370 1371 if (specifiers.contains("signed")) 1372 { 1373 type = Type(CXTypeKind.int_, "int"); 1374 return true; 1375 } 1376 1377 return false; 1378 } 1379 1380 bool parsePointer(ref Token[] tokens, ref Type type) 1381 { 1382 if (acceptPunctuation!("*")(tokens)) 1383 { 1384 type = Type.makePointer(type); 1385 1386 if (!parsePointer(tokens, type)) 1387 { 1388 if (parseQualifierList(tokens, type)) 1389 parsePointer(tokens, type); 1390 } 1391 1392 return true; 1393 } 1394 else 1395 { 1396 return false; 1397 } 1398 } 1399 1400 bool parseAbstractDeclarator(ref Token[] tokens, ref Type type, Cursor[string] table) 1401 { 1402 return parsePointer(tokens, type); 1403 } 1404 1405 Type parseTypeName(ref Token[] tokens, Cursor[string] table) 1406 { 1407 auto local = tokens; 1408 1409 Type type; 1410 1411 if (!parseSpecifierQualifierList(local, type, table)) 1412 return type; 1413 1414 parseAbstractDeclarator(local, type, table); 1415 1416 tokens = local; 1417 1418 return type; 1419 } 1420 1421 Expression parseExpr(ref Token[] tokens, Cursor[string] table, bool defined) 1422 { 1423 auto concatExpr = parseTokenConcat(tokens); 1424 1425 if (concatExpr.hasValue) 1426 return concatExpr; 1427 1428 auto condExpr = parseCondExpr(tokens, table, defined); 1429 1430 if (condExpr.hasValue) 1431 return condExpr; 1432 1433 return Expression.init; 1434 } 1435 1436 Expression parseExpr(ref Token[] tokens, bool defined) 1437 { 1438 Cursor[string] table; 1439 1440 return parseCondExpr(tokens, table, defined); 1441 } 1442 1443 Expression parseEnumMember(Token[] tokens, Cursor[string] table) 1444 { 1445 string member; 1446 1447 if (!acceptIdentifier(tokens, member)) 1448 return Expression.init; 1449 1450 if (!acceptPunctuation!("=")(tokens, member)) 1451 return Expression.init; 1452 1453 auto expression = parseExpr(tokens, table, false); 1454 1455 if (tokens.empty) 1456 return expression; 1457 else 1458 return Expression.init; 1459 } 1460 1461 string[] parseMacroParams(ref Token[] tokens) 1462 { 1463 auto local = tokens; 1464 1465 string[] params; 1466 1467 string param; 1468 1469 if (!accept(local, param, TokenKind.identifier)) 1470 return []; 1471 1472 params ~= param; 1473 1474 while (accept!(",")(local, TokenKind.punctuation)) 1475 { 1476 if (!accept(local, param, TokenKind.identifier)) 1477 return null; 1478 1479 params ~= param; 1480 } 1481 1482 tokens = local; 1483 1484 return params; 1485 } 1486 1487 class MacroDefinition 1488 { 1489 Cursor cursor; 1490 string spelling; 1491 string[] params; 1492 bool aliasOrConst; 1493 Expression expr; 1494 1495 override string toString() 1496 { 1497 import std.format : format; 1498 1499 return format( 1500 "MacroDefinition(spelling = %s, params = %s, aliasOrConst = %s, expr = %s)", 1501 spelling, 1502 params, 1503 aliasOrConst, 1504 expr); 1505 } 1506 1507 void dumpAST(ref Appender!string result, size_t indent) 1508 { 1509 import std.format; 1510 import std.array : replicate; 1511 import std..string : join; 1512 1513 result.put(" ".replicate(indent)); 1514 1515 if (aliasOrConst) 1516 formattedWrite(result, "MacroDefinition %s", spelling); 1517 else 1518 formattedWrite(result, "MacroDefinition %s(%s)", spelling, join(params, ", ")); 1519 } 1520 1521 string dumpAST() 1522 { 1523 auto result = Appender!string(); 1524 dumpAST(result, 0); 1525 return result.data; 1526 } 1527 } 1528 1529 MacroDefinition parseMacroDefinition( 1530 ref Token[] tokens, 1531 Cursor[string] table, 1532 bool defined = false) 1533 { 1534 auto local = tokens; 1535 1536 if (!accept!("#")(local, TokenKind.punctuation)) 1537 return null; 1538 1539 if (!accept!("define")(local, TokenKind.identifier)) 1540 return null; 1541 1542 MacroDefinition result = parsePartialMacroDefinition(local, table, defined); 1543 1544 if (result !is null) 1545 tokens = local; 1546 1547 return result; 1548 } 1549 1550 MacroDefinition parsePartialMacroDefinition( 1551 ref Token[] tokens, 1552 Cursor[string] table, 1553 bool defined = false) 1554 { 1555 auto local = tokens; 1556 1557 MacroDefinition result = new MacroDefinition; 1558 1559 if (!accept(local, result.spelling, TokenKind.identifier)) 1560 return null; 1561 1562 // Functional macros mustn't contain space before parentheses of parameter list. 1563 bool space = 1564 tokens.length > 2 && 1565 tokens[0].extent.end.offset == tokens[1].extent.start.offset; 1566 1567 if (space && accept!("(")(local, TokenKind.punctuation)) 1568 { 1569 if (!accept!(")")(local, TokenKind.punctuation)) 1570 { 1571 result.params = parseMacroParams(local); 1572 1573 if (!accept!(")")(local, TokenKind.punctuation)) 1574 return null; 1575 } 1576 } 1577 else 1578 { 1579 result.aliasOrConst = true; 1580 } 1581 1582 result.expr = parseExpr(local, table, defined); 1583 1584 if (!local.empty) 1585 { 1586 return null; 1587 } 1588 else 1589 { 1590 tokens = local; 1591 return result; 1592 } 1593 } 1594 1595 MacroDefinition[] parseMacroDefinitions(Range)( 1596 Range cursors, 1597 Cursor[string] types) 1598 { 1599 import std.algorithm; 1600 import std.array; 1601 1602 alias predicate = (Cursor cursor) => 1603 cursor.kind == CXCursorKind.macroDefinition; 1604 1605 auto definitions = cursors.filter!predicate(); 1606 1607 auto macroDefinitions = appender!(MacroDefinition[]); 1608 1609 foreach (definition; definitions) { 1610 auto tokens = definition.tokens; 1611 auto parsed = parsePartialMacroDefinition(tokens, types); 1612 1613 if (parsed !is null && parsed.expr.hasValue) 1614 { 1615 parsed.cursor = definition; 1616 macroDefinitions.put(parsed); 1617 1618 if (parsed.aliasOrConst) 1619 { 1620 auto debraced = parsed.expr.debraced; 1621 1622 if (debraced.peek!TypeIdentifier) 1623 types[parsed.spelling] = definition; 1624 } 1625 } 1626 } 1627 1628 return macroDefinitions.data; 1629 }