1------------------------------------------------------------------------------ 2-- -- 3-- GNAT COMPILER COMPONENTS -- 4-- -- 5-- P A R . T C H K -- 6-- -- 7-- B o d y -- 8-- -- 9-- Copyright (C) 1992-2018, Free Software Foundation, Inc. -- 10-- -- 11-- GNAT is free software; you can redistribute it and/or modify it under -- 12-- terms of the GNU General Public License as published by the Free Soft- -- 13-- ware Foundation; either version 3, or (at your option) any later ver- -- 14-- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- 15-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- 16-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- 17-- for more details. You should have received a copy of the GNU General -- 18-- Public License distributed with GNAT; see file COPYING3. If not, go to -- 19-- http://www.gnu.org/licenses for a complete copy of the license. -- 20-- -- 21-- GNAT was originally developed by the GNAT team at New York University. -- 22-- Extensive contributions were provided by Ada Core Technologies Inc. -- 23-- -- 24------------------------------------------------------------------------------ 25 26-- Token scan routines 27 28-- Error recovery: none of the T_xxx or TF_xxx routines raise Error_Resync 29 30separate (Par) 31package body Tchk is 32 33 type Position is (SC, BC, AP); 34 -- Specify position of error message (see Error_Msg_SC/BC/AP) 35 36 ----------------------- 37 -- Local Subprograms -- 38 ----------------------- 39 40 procedure Check_Token (T : Token_Type; P : Position); 41 pragma Inline (Check_Token); 42 -- Called by T_xx routines to check for reserved keyword token. P is the 43 -- position of the error message if the token is missing (see Wrong_Token) 44 45 procedure Wrong_Token (T : Token_Type; P : Position); 46 -- Called when scanning a reserved keyword when the keyword is not present. 47 -- T is the token type for the keyword, and P indicates the position to be 48 -- used to place a message relative to the current token if the keyword is 49 -- not located nearby. 50 51 ----------------- 52 -- Check_Token -- 53 ----------------- 54 55 procedure Check_Token (T : Token_Type; P : Position) is 56 begin 57 if Token = T then 58 Scan; 59 return; 60 else 61 Wrong_Token (T, P); 62 end if; 63 end Check_Token; 64 65 ------------- 66 -- T_Abort -- 67 ------------- 68 69 procedure T_Abort is 70 begin 71 Check_Token (Tok_Abort, SC); 72 end T_Abort; 73 74 ------------- 75 -- T_Arrow -- 76 ------------- 77 78 procedure T_Arrow is 79 begin 80 if Token = Tok_Arrow then 81 Scan; 82 83 -- A little recovery helper, accept then in place of => 84 85 elsif Token = Tok_Then then 86 Error_Msg_BC -- CODEFIX 87 ("|THEN should be ""='>"""); 88 Scan; -- past THEN used in place of => 89 90 elsif Token = Tok_Colon_Equal then 91 Error_Msg_SC -- CODEFIX 92 ("|"":="" should be ""='>"""); 93 Scan; -- past := used in place of => 94 95 else 96 Error_Msg_AP -- CODEFIX 97 ("missing ""='>"""); 98 end if; 99 end T_Arrow; 100 101 ---------- 102 -- T_At -- 103 ---------- 104 105 procedure T_At is 106 begin 107 Check_Token (Tok_At, SC); 108 end T_At; 109 110 ------------ 111 -- T_Body -- 112 ------------ 113 114 procedure T_Body is 115 begin 116 Check_Token (Tok_Body, BC); 117 end T_Body; 118 119 ----------- 120 -- T_Box -- 121 ----------- 122 123 procedure T_Box is 124 begin 125 if Token = Tok_Box then 126 Scan; 127 else 128 Error_Msg_AP -- CODEFIX 129 ("missing ""'<'>"""); 130 end if; 131 end T_Box; 132 133 ------------- 134 -- T_Colon -- 135 ------------- 136 137 procedure T_Colon is 138 begin 139 if Token = Tok_Colon then 140 Scan; 141 else 142 Error_Msg_AP -- CODEFIX 143 ("missing "":"""); 144 end if; 145 end T_Colon; 146 147 ------------------- 148 -- T_Colon_Equal -- 149 ------------------- 150 151 procedure T_Colon_Equal is 152 begin 153 if Token = Tok_Colon_Equal then 154 Scan; 155 156 elsif Token = Tok_Equal then 157 Error_Msg_SC -- CODEFIX 158 ("|""="" should be "":="""); 159 Scan; 160 161 elsif Token = Tok_Colon then 162 Error_Msg_SC -- CODEFIX 163 ("|"":"" should be "":="""); 164 Scan; 165 166 elsif Token = Tok_Is then 167 Error_Msg_SC -- CODEFIX 168 ("|IS should be "":="""); 169 Scan; 170 171 else 172 Error_Msg_AP -- CODEFIX 173 ("missing "":="""); 174 end if; 175 end T_Colon_Equal; 176 177 ------------- 178 -- T_Comma -- 179 ------------- 180 181 procedure T_Comma is 182 begin 183 if Token = Tok_Comma then 184 Scan; 185 186 else 187 if Token = Tok_Pragma then 188 P_Pragmas_Misplaced; 189 end if; 190 191 if Token = Tok_Comma then 192 Scan; 193 else 194 Error_Msg_AP -- CODEFIX 195 ("missing "","""); 196 end if; 197 end if; 198 199 if Token = Tok_Pragma then 200 P_Pragmas_Misplaced; 201 end if; 202 end T_Comma; 203 204 --------------- 205 -- T_Dot_Dot -- 206 --------------- 207 208 procedure T_Dot_Dot is 209 begin 210 if Token = Tok_Dot_Dot then 211 Scan; 212 else 213 Error_Msg_AP -- CODEFIX 214 ("missing "".."""); 215 end if; 216 end T_Dot_Dot; 217 218 ----------- 219 -- T_For -- 220 ----------- 221 222 procedure T_For is 223 begin 224 Check_Token (Tok_For, AP); 225 end T_For; 226 227 ----------------------- 228 -- T_Greater_Greater -- 229 ----------------------- 230 231 procedure T_Greater_Greater is 232 begin 233 if Token = Tok_Greater_Greater then 234 Scan; 235 else 236 Error_Msg_AP -- CODEFIX 237 ("missing ""'>'>"""); 238 end if; 239 end T_Greater_Greater; 240 241 ------------------ 242 -- T_Identifier -- 243 ------------------ 244 245 procedure T_Identifier is 246 begin 247 if Token = Tok_Identifier then 248 Scan; 249 elsif Token in Token_Class_Literal then 250 Error_Msg_SC ("identifier expected"); 251 Scan; 252 else 253 Error_Msg_AP ("identifier expected"); 254 end if; 255 end T_Identifier; 256 257 ---------- 258 -- T_In -- 259 ---------- 260 261 procedure T_In is 262 begin 263 Check_Token (Tok_In, AP); 264 end T_In; 265 266 ---------- 267 -- T_Is -- 268 ---------- 269 270 procedure T_Is is 271 begin 272 Ignore (Tok_Semicolon); 273 274 -- If we have IS scan past it 275 276 if Token = Tok_Is then 277 Scan; 278 279 -- And ignore any following semicolons 280 281 Ignore (Tok_Semicolon); 282 283 -- Allow OF, => or = to substitute for IS with complaint 284 285 elsif Token = Tok_Arrow then 286 Error_Msg_SC -- CODEFIX 287 ("|""=>"" should be IS"); 288 Scan; -- past => 289 290 elsif Token = Tok_Of then 291 Error_Msg_SC -- CODEFIX 292 ("|OF should be IS"); 293 Scan; -- past OF 294 295 elsif Token = Tok_Equal then 296 Error_Msg_SC -- CODEFIX 297 ("|""="" should be IS"); 298 Scan; -- past = 299 300 else 301 Wrong_Token (Tok_Is, AP); 302 end if; 303 304 -- Ignore extra IS keywords 305 306 while Token = Tok_Is loop 307 Error_Msg_SC -- CODEFIX 308 ("|extra IS ignored"); 309 Scan; 310 end loop; 311 end T_Is; 312 313 ------------------ 314 -- T_Left_Paren -- 315 ------------------ 316 317 procedure T_Left_Paren is 318 begin 319 if Token = Tok_Left_Paren then 320 Scan; 321 else 322 Error_Msg_AP -- CODEFIX 323 ("missing ""("""); 324 end if; 325 end T_Left_Paren; 326 327 ------------ 328 -- T_Loop -- 329 ------------ 330 331 procedure T_Loop is 332 begin 333 if Token = Tok_Do then 334 Error_Msg_SC -- CODEFIX 335 ("LOOP expected"); 336 Scan; 337 else 338 Check_Token (Tok_Loop, AP); 339 end if; 340 end T_Loop; 341 342 ----------- 343 -- T_Mod -- 344 ----------- 345 346 procedure T_Mod is 347 begin 348 Check_Token (Tok_Mod, AP); 349 end T_Mod; 350 351 ----------- 352 -- T_New -- 353 ----------- 354 355 procedure T_New is 356 begin 357 Check_Token (Tok_New, AP); 358 end T_New; 359 360 ---------- 361 -- T_Of -- 362 ---------- 363 364 procedure T_Of is 365 begin 366 Check_Token (Tok_Of, AP); 367 end T_Of; 368 369 ---------- 370 -- T_Or -- 371 ---------- 372 373 procedure T_Or is 374 begin 375 Check_Token (Tok_Or, AP); 376 end T_Or; 377 378 --------------- 379 -- T_Private -- 380 --------------- 381 382 procedure T_Private is 383 begin 384 Check_Token (Tok_Private, SC); 385 end T_Private; 386 387 ------------- 388 -- T_Range -- 389 ------------- 390 391 procedure T_Range is 392 begin 393 Check_Token (Tok_Range, AP); 394 end T_Range; 395 396 -------------- 397 -- T_Record -- 398 -------------- 399 400 procedure T_Record is 401 begin 402 Check_Token (Tok_Record, AP); 403 end T_Record; 404 405 ------------------- 406 -- T_Right_Paren -- 407 ------------------- 408 409 procedure T_Right_Paren is 410 begin 411 if Token = Tok_Right_Paren then 412 Scan; 413 else 414 Error_Msg_AP -- CODEFIX 415 ("|missing "")"""); 416 end if; 417 end T_Right_Paren; 418 419 ----------------- 420 -- T_Semicolon -- 421 ----------------- 422 423 procedure T_Semicolon is 424 begin 425 426 if Token = Tok_Semicolon then 427 Scan; 428 429 if Token = Tok_Semicolon then 430 Error_Msg_SC -- CODEFIX 431 ("|extra "";"" ignored"); 432 Scan; 433 end if; 434 435 return; 436 437 elsif Token = Tok_Colon then 438 Error_Msg_SC -- CODEFIX 439 ("|"":"" should be "";"""); 440 Scan; 441 return; 442 443 elsif Token = Tok_Comma then 444 Error_Msg_SC -- CODEFIX 445 ("|"","" should be "";"""); 446 Scan; 447 return; 448 449 elsif Token = Tok_Dot then 450 Error_Msg_SC -- CODEFIX 451 ("|""."" should be "";"""); 452 Scan; 453 return; 454 455 -- An interesting little case. If the previous token is a semicolon, 456 -- then there is no way that we can legitimately need another semicolon. 457 -- This could only arise in an situation where an error has already been 458 -- signalled. By simply ignoring the request for a semicolon in this 459 -- case, we avoid some spurious missing semicolon messages. 460 461 elsif Prev_Token = Tok_Semicolon then 462 return; 463 464 -- If the current token is | then this is a reasonable place to suggest 465 -- the possibility of a "C" confusion. 466 467 elsif Token = Tok_Vertical_Bar then 468 Error_Msg_SC -- CODEFIX 469 ("unexpected occurrence of ""'|"", did you mean OR'?"); 470 Resync_Past_Semicolon; 471 return; 472 473 -- Deal with pragma. If pragma is not at start of line, it is considered 474 -- misplaced otherwise we treat it as a normal missing semicolon case. 475 476 elsif Token = Tok_Pragma and then not Token_Is_At_Start_Of_Line then 477 P_Pragmas_Misplaced; 478 479 if Token = Tok_Semicolon then 480 Scan; 481 return; 482 end if; 483 end if; 484 485 -- If none of those tests return, we really have a missing semicolon 486 487 Error_Msg_AP -- CODEFIX 488 ("|missing "";"""); 489 return; 490 end T_Semicolon; 491 492 ------------ 493 -- T_Then -- 494 ------------ 495 496 procedure T_Then is 497 begin 498 Check_Token (Tok_Then, AP); 499 end T_Then; 500 501 ------------ 502 -- T_Type -- 503 ------------ 504 505 procedure T_Type is 506 begin 507 Check_Token (Tok_Type, BC); 508 end T_Type; 509 510 ----------- 511 -- T_Use -- 512 ----------- 513 514 procedure T_Use is 515 begin 516 Check_Token (Tok_Use, SC); 517 end T_Use; 518 519 ------------ 520 -- T_When -- 521 ------------ 522 523 procedure T_When is 524 begin 525 Check_Token (Tok_When, SC); 526 end T_When; 527 528 ------------ 529 -- T_With -- 530 ------------ 531 532 procedure T_With is 533 begin 534 Check_Token (Tok_With, BC); 535 end T_With; 536 537 -------------- 538 -- TF_Arrow -- 539 -------------- 540 541 procedure TF_Arrow is 542 Scan_State : Saved_Scan_State; 543 544 begin 545 if Token = Tok_Arrow then 546 Scan; -- skip arrow and we are done 547 548 elsif Token = Tok_Colon_Equal then 549 T_Arrow; -- Let T_Arrow give the message 550 551 else 552 T_Arrow; -- give missing arrow message 553 Save_Scan_State (Scan_State); -- at start of junk tokens 554 555 loop 556 if Prev_Token_Ptr < Current_Line_Start 557 or else Token = Tok_Semicolon 558 or else Token = Tok_EOF 559 then 560 Restore_Scan_State (Scan_State); -- to where we were 561 return; 562 end if; 563 564 Scan; -- continue search 565 566 if Token = Tok_Arrow then 567 Scan; -- past arrow 568 return; 569 end if; 570 end loop; 571 end if; 572 end TF_Arrow; 573 574 ----------- 575 -- TF_Is -- 576 ----------- 577 578 procedure TF_Is is 579 Scan_State : Saved_Scan_State; 580 581 begin 582 if Token = Tok_Is then 583 T_Is; -- past IS and we are done 584 585 -- Allow OF or => or = in place of IS (with error message) 586 587 elsif Token = Tok_Of 588 or else Token = Tok_Arrow 589 or else Token = Tok_Equal 590 then 591 T_Is; -- give missing IS message and skip bad token 592 593 else 594 T_Is; -- give missing IS message 595 Save_Scan_State (Scan_State); -- at start of junk tokens 596 597 loop 598 if Prev_Token_Ptr < Current_Line_Start 599 or else Token = Tok_Semicolon 600 or else Token = Tok_EOF 601 then 602 Restore_Scan_State (Scan_State); -- to where we were 603 return; 604 end if; 605 606 Scan; -- continue search 607 608 if Token = Tok_Is 609 or else Token = Tok_Of 610 or else Token = Tok_Arrow 611 then 612 Scan; -- past IS or OF or => 613 return; 614 end if; 615 end loop; 616 end if; 617 end TF_Is; 618 619 ------------- 620 -- TF_Loop -- 621 ------------- 622 623 procedure TF_Loop is 624 Scan_State : Saved_Scan_State; 625 626 begin 627 if Token = Tok_Loop then 628 Scan; -- past LOOP and we are done 629 630 -- Allow DO or THEN in place of LOOP 631 632 elsif Token = Tok_Then or else Token = Tok_Do then 633 T_Loop; -- give missing LOOP message 634 635 else 636 T_Loop; -- give missing LOOP message 637 Save_Scan_State (Scan_State); -- at start of junk tokens 638 639 loop 640 if Prev_Token_Ptr < Current_Line_Start 641 or else Token = Tok_Semicolon 642 or else Token = Tok_EOF 643 then 644 Restore_Scan_State (Scan_State); -- to where we were 645 return; 646 end if; 647 648 Scan; -- continue search 649 650 if Token = Tok_Loop or else Token = Tok_Then then 651 Scan; -- past loop or then (message already generated) 652 return; 653 end if; 654 end loop; 655 end if; 656 end TF_Loop; 657 658 -------------- 659 -- TF_Return-- 660 -------------- 661 662 procedure TF_Return is 663 Scan_State : Saved_Scan_State; 664 665 begin 666 if Token = Tok_Return then 667 Scan; -- skip RETURN and we are done 668 669 else 670 Error_Msg_SC -- CODEFIX 671 ("missing RETURN"); 672 Save_Scan_State (Scan_State); -- at start of junk tokens 673 674 loop 675 if Prev_Token_Ptr < Current_Line_Start 676 or else Token = Tok_Semicolon 677 or else Token = Tok_EOF 678 then 679 Restore_Scan_State (Scan_State); -- to where we were 680 return; 681 end if; 682 683 Scan; -- continue search 684 685 if Token = Tok_Return then 686 Scan; -- past RETURN 687 return; 688 end if; 689 end loop; 690 end if; 691 end TF_Return; 692 693 ------------------ 694 -- TF_Semicolon -- 695 ------------------ 696 697 procedure TF_Semicolon is 698 Scan_State : Saved_Scan_State; 699 700 begin 701 if Token = Tok_Semicolon then 702 T_Semicolon; 703 return; 704 705 -- An interesting little test here. If the previous token is a 706 -- semicolon, then there is no way that we can legitimately need 707 -- another semicolon. This could only arise in an error situation 708 -- where an error has already been signalled. By simply ignoring 709 -- the request for a semicolon in this case, we avoid some spurious 710 -- missing semicolon messages. 711 712 elsif Prev_Token = Tok_Semicolon then 713 return; 714 715 else 716 -- Deal with pragma. If pragma is not at start of line, it is 717 -- considered misplaced otherwise we treat it as a normal 718 -- missing semicolon case. 719 720 if Token = Tok_Pragma 721 and then not Token_Is_At_Start_Of_Line 722 then 723 P_Pragmas_Misplaced; 724 725 if Token = Tok_Semicolon then 726 T_Semicolon; 727 return; 728 end if; 729 end if; 730 731 -- Here we definitely have a missing semicolon, so give message 732 733 T_Semicolon; 734 735 -- Scan out junk on rest of line. Scan stops on END keyword, since 736 -- that seems to help avoid cascaded errors. 737 738 Save_Scan_State (Scan_State); -- at start of junk tokens 739 740 loop 741 if Prev_Token_Ptr < Current_Line_Start 742 or else Token = Tok_EOF 743 or else Token = Tok_End 744 then 745 Restore_Scan_State (Scan_State); -- to where we were 746 return; 747 end if; 748 749 Scan; -- continue search 750 751 if Token = Tok_Semicolon then 752 T_Semicolon; 753 return; 754 755 elsif Token in Token_Class_After_SM then 756 return; 757 end if; 758 end loop; 759 end if; 760 end TF_Semicolon; 761 762 ------------- 763 -- TF_Then -- 764 ------------- 765 766 procedure TF_Then is 767 Scan_State : Saved_Scan_State; 768 769 begin 770 if Token = Tok_Then then 771 Scan; -- past THEN and we are done 772 773 else 774 T_Then; -- give missing THEN message 775 Save_Scan_State (Scan_State); -- at start of junk tokens 776 777 loop 778 if Prev_Token_Ptr < Current_Line_Start 779 or else Token = Tok_Semicolon 780 or else Token = Tok_EOF 781 then 782 Restore_Scan_State (Scan_State); -- to where we were 783 return; 784 end if; 785 786 Scan; -- continue search 787 788 if Token = Tok_Then then 789 Scan; -- past THEN 790 return; 791 end if; 792 end loop; 793 end if; 794 end TF_Then; 795 796 ------------ 797 -- TF_Use -- 798 ------------ 799 800 procedure TF_Use is 801 Scan_State : Saved_Scan_State; 802 803 begin 804 if Token = Tok_Use then 805 Scan; -- past USE and we are done 806 807 else 808 T_Use; -- give USE expected message 809 Save_Scan_State (Scan_State); -- at start of junk tokens 810 811 loop 812 if Prev_Token_Ptr < Current_Line_Start 813 or else Token = Tok_Semicolon 814 or else Token = Tok_EOF 815 then 816 Restore_Scan_State (Scan_State); -- to where we were 817 return; 818 end if; 819 820 Scan; -- continue search 821 822 if Token = Tok_Use then 823 Scan; -- past use 824 return; 825 end if; 826 end loop; 827 end if; 828 end TF_Use; 829 830 ------------------ 831 -- U_Left_Paren -- 832 ------------------ 833 834 procedure U_Left_Paren is 835 begin 836 if Token = Tok_Left_Paren then 837 Scan; 838 else 839 Error_Msg_AP -- CODEFIX 840 ("missing ""(""!"); 841 end if; 842 end U_Left_Paren; 843 844 ------------------- 845 -- U_Right_Paren -- 846 ------------------- 847 848 procedure U_Right_Paren is 849 begin 850 if Token = Tok_Right_Paren then 851 Scan; 852 else 853 Error_Msg_AP -- CODEFIX 854 ("|missing "")""!"); 855 end if; 856 end U_Right_Paren; 857 858 ----------------- 859 -- Wrong_Token -- 860 ----------------- 861 862 procedure Wrong_Token (T : Token_Type; P : Position) is 863 Missing : constant String := "missing "; 864 Image : constant String := Token_Type'Image (T); 865 Tok_Name : constant String := Image (5 .. Image'Length); 866 M : constant String := Missing & Tok_Name; 867 868 begin 869 if Token = Tok_Semicolon then 870 Scan; 871 872 if Token = T then 873 Error_Msg_SP -- CODEFIX 874 ("|extra "";"" ignored"); 875 Scan; 876 else 877 Error_Msg_SP (M); 878 end if; 879 880 elsif Token = Tok_Comma then 881 Scan; 882 883 if Token = T then 884 Error_Msg_SP -- CODEFIX 885 ("|extra "","" ignored"); 886 Scan; 887 888 else 889 Error_Msg_SP (M); 890 end if; 891 892 else 893 case P is 894 when SC => Error_Msg_SC (M); 895 when BC => Error_Msg_BC (M); 896 when AP => Error_Msg_AP (M); 897 end case; 898 end if; 899 end Wrong_Token; 900 901end Tchk; 902