1------------------------------------------------------------------------------ 2-- -- 3-- GNAT COMPILER COMPONENTS -- 4-- -- 5-- S I N P U T -- 6-- -- 7-- B o d y -- 8-- -- 9-- Copyright (C) 1992-2021, 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 26pragma Style_Checks (All_Checks); 27-- Subprograms not all in alpha order 28 29with Atree; use Atree; 30with Debug; use Debug; 31with Opt; use Opt; 32with Output; use Output; 33with Scans; use Scans; 34with Sinfo; use Sinfo; 35with Sinfo.Nodes; use Sinfo.Nodes; 36with Widechar; use Widechar; 37 38with GNAT.Byte_Order_Mark; use GNAT.Byte_Order_Mark; 39 40with System.Storage_Elements; 41with System.Memory; 42with System.WCh_Con; use System.WCh_Con; 43 44with Unchecked_Conversion; 45with Unchecked_Deallocation; 46 47package body Sinput is 48 49 use ASCII, System; 50 51 -- Routines to support conversion between types Lines_Table_Ptr, 52 -- Logical_Lines_Table_Ptr and System.Address. 53 54 pragma Warnings (Off); 55 -- These unchecked conversions are aliasing safe, since they are never 56 -- used to construct improperly aliased pointer values. 57 58 function To_Address is 59 new Unchecked_Conversion (Lines_Table_Ptr, Address); 60 61 function To_Address is 62 new Unchecked_Conversion (Logical_Lines_Table_Ptr, Address); 63 64 function To_Pointer is 65 new Unchecked_Conversion (Address, Lines_Table_Ptr); 66 67 function To_Pointer is 68 new Unchecked_Conversion (Address, Logical_Lines_Table_Ptr); 69 70 pragma Warnings (On); 71 72 ----------------------------- 73 -- Source_File_Index_Table -- 74 ----------------------------- 75 76 -- The Get_Source_File_Index function is called very frequently. Earlier 77 -- versions cached a single entry, but then reverted to a serial search, 78 -- and this proved to be a significant source of inefficiency. We then 79 -- switched to using a table with a start point followed by a serial 80 -- search. Now we make sure source buffers are on a reasonable boundary 81 -- (see Types.Source_Align), and we can just use a direct look up in the 82 -- following table. 83 84 -- Note that this array is pretty large, but in most operating systems 85 -- it will not be allocated in physical memory unless it is actually used. 86 87 Source_File_Index_Table : 88 array (Int range 0 .. 1 + (Int'Last / Source_Align)) of Source_File_Index; 89 90 --------------------------- 91 -- Add_Line_Tables_Entry -- 92 --------------------------- 93 94 procedure Add_Line_Tables_Entry 95 (S : in out Source_File_Record; 96 P : Source_Ptr) 97 is 98 LL : Physical_Line_Number; 99 100 begin 101 -- Reallocate the lines tables if necessary 102 103 -- Note: the reason we do not use the normal Table package 104 -- mechanism is that we have several of these tables. We could 105 -- use the new GNAT.Dynamic_Tables package and that would probably 106 -- be a good idea ??? 107 108 if S.Last_Source_Line = S.Lines_Table_Max then 109 Alloc_Line_Tables 110 (S, 111 Int (S.Last_Source_Line) * 112 ((100 + Alloc.Lines_Increment) / 100)); 113 114 if Debug_Flag_D then 115 Write_Str ("--> Reallocating lines table, size = "); 116 Write_Int (Int (S.Lines_Table_Max)); 117 Write_Eol; 118 end if; 119 end if; 120 121 S.Last_Source_Line := S.Last_Source_Line + 1; 122 LL := S.Last_Source_Line; 123 124 S.Lines_Table (LL) := P; 125 126 -- Deal with setting new entry in logical lines table if one is 127 -- present. Note that there is always space (because the call to 128 -- Alloc_Line_Tables makes sure both tables are the same length), 129 130 if S.Logical_Lines_Table /= null then 131 132 -- We can always set the entry from the previous one, because 133 -- the processing for a Source_Reference pragma ensures that 134 -- at least one entry following the pragma is set up correctly. 135 136 S.Logical_Lines_Table (LL) := S.Logical_Lines_Table (LL - 1) + 1; 137 end if; 138 end Add_Line_Tables_Entry; 139 140 ----------------------- 141 -- Alloc_Line_Tables -- 142 ----------------------- 143 144 procedure Alloc_Line_Tables 145 (S : in out Source_File_Record; 146 New_Max : Nat) 147 is 148 subtype size_t is Memory.size_t; 149 150 New_Table : Lines_Table_Ptr; 151 152 New_Logical_Table : Logical_Lines_Table_Ptr; 153 154 New_Size : constant size_t := 155 size_t (New_Max * Lines_Table_Type'Component_Size / 156 Storage_Unit); 157 158 begin 159 if S.Lines_Table = null then 160 New_Table := To_Pointer (Memory.Alloc (New_Size)); 161 162 else 163 New_Table := 164 To_Pointer (Memory.Realloc (To_Address (S.Lines_Table), New_Size)); 165 end if; 166 167 if New_Table = null then 168 raise Storage_Error; 169 else 170 S.Lines_Table := New_Table; 171 S.Lines_Table_Max := Physical_Line_Number (New_Max); 172 end if; 173 174 if S.Num_SRef_Pragmas /= 0 then 175 if S.Logical_Lines_Table = null then 176 New_Logical_Table := To_Pointer (Memory.Alloc (New_Size)); 177 else 178 New_Logical_Table := To_Pointer 179 (Memory.Realloc (To_Address (S.Logical_Lines_Table), New_Size)); 180 end if; 181 182 if New_Logical_Table = null then 183 raise Storage_Error; 184 else 185 S.Logical_Lines_Table := New_Logical_Table; 186 end if; 187 end if; 188 end Alloc_Line_Tables; 189 190 ----------------- 191 -- Backup_Line -- 192 ----------------- 193 194 procedure Backup_Line (P : in out Source_Ptr) is 195 Sindex : constant Source_File_Index := Get_Source_File_Index (P); 196 Src : constant Source_Buffer_Ptr := 197 Source_File.Table (Sindex).Source_Text; 198 Sfirst : constant Source_Ptr := 199 Source_File.Table (Sindex).Source_First; 200 201 begin 202 P := P - 1; 203 204 if P = Sfirst then 205 return; 206 end if; 207 208 if Src (P) = CR then 209 if Src (P - 1) = LF then 210 P := P - 1; 211 end if; 212 213 else -- Src (P) = LF 214 if Src (P - 1) = CR then 215 P := P - 1; 216 end if; 217 end if; 218 219 -- Now find first character of the previous line 220 221 while P > Sfirst 222 and then Src (P - 1) /= LF 223 and then Src (P - 1) /= CR 224 loop 225 P := P - 1; 226 end loop; 227 end Backup_Line; 228 229 --------------------------- 230 -- Build_Location_String -- 231 --------------------------- 232 233 procedure Build_Location_String 234 (Buf : in out Bounded_String; 235 Loc : Source_Ptr) 236 is 237 Ptr : Source_Ptr := Loc; 238 239 begin 240 -- Loop through instantiations 241 242 loop 243 Append (Buf, Reference_Name (Get_Source_File_Index (Ptr))); 244 Append (Buf, ':'); 245 Append (Buf, Nat (Get_Logical_Line_Number (Ptr))); 246 247 Ptr := Instantiation_Location (Ptr); 248 exit when Ptr = No_Location; 249 Append (Buf, " instantiated at "); 250 end loop; 251 end Build_Location_String; 252 253 function Build_Location_String (Loc : Source_Ptr) return String is 254 Buf : Bounded_String; 255 begin 256 Build_Location_String (Buf, Loc); 257 return +Buf; 258 end Build_Location_String; 259 260 ------------------- 261 -- Check_For_BOM -- 262 ------------------- 263 264 procedure Check_For_BOM is 265 BOM : BOM_Kind; 266 Len : Natural; 267 Tst : String (1 .. 5); 268 C : Character; 269 270 begin 271 for J in 1 .. 5 loop 272 C := Source (Scan_Ptr + Source_Ptr (J) - 1); 273 274 -- Definitely no BOM if EOF character marks either end of file, or 275 -- an illegal non-BOM character if not at the end of file. 276 277 if C = EOF then 278 return; 279 end if; 280 281 Tst (J) := C; 282 end loop; 283 284 Read_BOM (Tst, Len, BOM, XML_Support => False); 285 286 case BOM is 287 when UTF8_All => 288 Scan_Ptr := Scan_Ptr + Source_Ptr (Len); 289 First_Non_Blank_Location := Scan_Ptr; 290 Current_Line_Start := Scan_Ptr; 291 Wide_Character_Encoding_Method := WCEM_UTF8; 292 Upper_Half_Encoding := True; 293 294 when UTF16_BE 295 | UTF16_LE 296 => 297 Set_Standard_Error; 298 Write_Line ("UTF-16 encoding format not recognized"); 299 Set_Standard_Output; 300 raise Unrecoverable_Error; 301 302 when UTF32_BE 303 | UTF32_LE 304 => 305 Set_Standard_Error; 306 Write_Line ("UTF-32 encoding format not recognized"); 307 Set_Standard_Output; 308 raise Unrecoverable_Error; 309 310 when Unknown => 311 null; 312 313 when others => 314 raise Program_Error; 315 end case; 316 end Check_For_BOM; 317 318 ----------------------------- 319 -- Clear_Source_File_Table -- 320 ----------------------------- 321 322 procedure Free is new Unchecked_Deallocation 323 (Lines_Table_Type, Lines_Table_Ptr); 324 325 procedure Free is new Unchecked_Deallocation 326 (Logical_Lines_Table_Type, Logical_Lines_Table_Ptr); 327 328 procedure Clear_Source_File_Table is 329 begin 330 for X in 1 .. Source_File.Last loop 331 declare 332 S : Source_File_Record renames Source_File.Table (X); 333 begin 334 if S.Instance = No_Instance_Id then 335 Free_Source_Buffer (S.Source_Text); 336 else 337 Free_Dope (S.Source_Text'Address); 338 S.Source_Text := null; 339 end if; 340 341 Free (S.Lines_Table); 342 Free (S.Logical_Lines_Table); 343 end; 344 end loop; 345 346 Source_File.Free; 347 Sinput.Initialize; 348 end Clear_Source_File_Table; 349 350 --------------------------------- 351 -- Comes_From_Inherited_Pragma -- 352 --------------------------------- 353 354 function Comes_From_Inherited_Pragma (S : Source_Ptr) return Boolean is 355 SIE : Source_File_Record renames 356 Source_File.Table (Get_Source_File_Index (S)); 357 begin 358 return SIE.Inherited_Pragma; 359 end Comes_From_Inherited_Pragma; 360 361 ----------------------------- 362 -- Comes_From_Inlined_Body -- 363 ----------------------------- 364 365 function Comes_From_Inlined_Body (S : Source_Ptr) return Boolean is 366 SIE : Source_File_Record renames 367 Source_File.Table (Get_Source_File_Index (S)); 368 begin 369 return SIE.Inlined_Body; 370 end Comes_From_Inlined_Body; 371 372 ------------------------ 373 -- Free_Source_Buffer -- 374 ------------------------ 375 376 procedure Free_Source_Buffer (Src : in out Source_Buffer_Ptr) is 377 -- Unchecked_Deallocation doesn't work for access-to-constant; we need 378 -- to first Unchecked_Convert to access-to-variable. 379 380 function To_Source_Buffer_Ptr_Var is new 381 Unchecked_Conversion (Source_Buffer_Ptr, Source_Buffer_Ptr_Var); 382 383 Temp : Source_Buffer_Ptr_Var := To_Source_Buffer_Ptr_Var (Src); 384 385 procedure Free_Ptr is new 386 Unchecked_Deallocation (Source_Buffer, Source_Buffer_Ptr_Var); 387 begin 388 Free_Ptr (Temp); 389 Src := null; 390 end Free_Source_Buffer; 391 392 ----------------------- 393 -- Get_Column_Number -- 394 ----------------------- 395 396 function Get_Column_Number (P : Source_Ptr) return Column_Number is 397 S : Source_Ptr; 398 C : Column_Number; 399 Sindex : Source_File_Index; 400 Src : Source_Buffer_Ptr; 401 402 begin 403 -- If the input source pointer is not a meaningful value then return 404 -- at once with column number 1. This can happen for a file not found 405 -- condition for a file loaded indirectly by RTE, and also perhaps on 406 -- some unknown internal error conditions. In either case we certainly 407 -- don't want to blow up. 408 409 if P < 1 then 410 return 1; 411 412 else 413 Sindex := Get_Source_File_Index (P); 414 Src := Source_File.Table (Sindex).Source_Text; 415 S := Line_Start (P); 416 C := 1; 417 418 while S < P loop 419 if Src (S) = HT then 420 C := (C - 1) / 8 * 8 + (8 + 1); 421 S := S + 1; 422 423 -- Deal with wide character case, but don't include brackets 424 -- notation in this circuit, since we know that this will 425 -- display unencoded (no one encodes brackets notation). 426 427 elsif Src (S) /= '[' and then Is_Start_Of_Wide_Char (Src, S) then 428 C := C + 1; 429 Skip_Wide (Src, S); 430 431 -- Normal (non-wide) character case or brackets sequence 432 433 else 434 C := C + 1; 435 S := S + 1; 436 end if; 437 end loop; 438 439 return C; 440 end if; 441 end Get_Column_Number; 442 443 ----------------------------- 444 -- Get_Logical_Line_Number -- 445 ----------------------------- 446 447 function Get_Logical_Line_Number 448 (P : Source_Ptr) return Logical_Line_Number 449 is 450 SFR : Source_File_Record 451 renames Source_File.Table (Get_Source_File_Index (P)); 452 453 L : constant Physical_Line_Number := Get_Physical_Line_Number (P); 454 455 begin 456 if SFR.Num_SRef_Pragmas = 0 then 457 return Logical_Line_Number (L); 458 else 459 return SFR.Logical_Lines_Table (L); 460 end if; 461 end Get_Logical_Line_Number; 462 463 --------------------------------- 464 -- Get_Logical_Line_Number_Img -- 465 --------------------------------- 466 467 function Get_Logical_Line_Number_Img 468 (P : Source_Ptr) return String 469 is 470 begin 471 Name_Len := 0; 472 Add_Nat_To_Name_Buffer (Nat (Get_Logical_Line_Number (P))); 473 return Name_Buffer (1 .. Name_Len); 474 end Get_Logical_Line_Number_Img; 475 476 ------------------------------ 477 -- Get_Physical_Line_Number -- 478 ------------------------------ 479 480 function Get_Physical_Line_Number 481 (P : Source_Ptr) return Physical_Line_Number 482 is 483 Sfile : Source_File_Index; 484 Table : Lines_Table_Ptr; 485 Lo : Physical_Line_Number; 486 Hi : Physical_Line_Number; 487 Mid : Physical_Line_Number; 488 Loc : Source_Ptr; 489 490 begin 491 -- If the input source pointer is not a meaningful value then return 492 -- at once with line number 1. This can happen for a file not found 493 -- condition for a file loaded indirectly by RTE, and also perhaps on 494 -- some unknown internal error conditions. In either case we certainly 495 -- don't want to blow up. 496 497 if P < 1 then 498 return 1; 499 500 -- Otherwise we can do the binary search 501 502 else 503 Sfile := Get_Source_File_Index (P); 504 Loc := P + Source_File.Table (Sfile).Sloc_Adjust; 505 Table := Source_File.Table (Sfile).Lines_Table; 506 Lo := 1; 507 Hi := Source_File.Table (Sfile).Last_Source_Line; 508 509 loop 510 Mid := (Lo + Hi) / 2; 511 512 if Loc < Table (Mid) then 513 Hi := Mid - 1; 514 515 else -- Loc >= Table (Mid) 516 517 if Mid = Hi or else 518 Loc < Table (Mid + 1) 519 then 520 return Mid; 521 else 522 Lo := Mid + 1; 523 end if; 524 525 end if; 526 527 end loop; 528 end if; 529 end Get_Physical_Line_Number; 530 531 --------------------------- 532 -- Get_Source_File_Index -- 533 --------------------------- 534 535 function Get_Source_File_Index (S : Source_Ptr) return Source_File_Index is 536 Result : Source_File_Index; 537 538 procedure Assertions; 539 -- Assert various properties of the result 540 541 procedure Assertions is 542 543 -- ???The old version using zero-origin array indexing without array 544 -- bounds checks returned 1 (i.e. system.ads) for these special 545 -- locations, presumably by accident. We are mimicing that here. 546 547 Special : constant Boolean := 548 S = No_Location 549 or else S = Standard_Location 550 or else S = Standard_ASCII_Location 551 or else S = System_Location; 552 553 pragma Assert ((S > No_Location) xor Special); 554 pragma Assert (Result in Source_File.First .. Source_File.Last); 555 556 SFR : Source_File_Record renames Source_File.Table (Result); 557 558 begin 559 -- SFR.Source_Text = null if and only if this is the SFR for a debug 560 -- output file (*.dg), and that file is under construction. S can be 561 -- slightly past Source_Last in that case because we haven't updated 562 -- Source_Last. 563 564 if Null_Source_Buffer_Ptr (SFR.Source_Text) then 565 pragma Assert (S >= SFR.Source_First); null; 566 else 567 pragma Assert (SFR.Source_Text'First = SFR.Source_First); 568 pragma Assert (SFR.Source_Text'Last = SFR.Source_Last); 569 570 if not Special then 571 pragma Assert (S in SFR.Source_First .. SFR.Source_Last); 572 null; 573 end if; 574 end if; 575 end Assertions; 576 577 -- Start of processing for Get_Source_File_Index 578 579 begin 580 if S > No_Location then 581 Result := Source_File_Index_Table (Int (S) / Source_Align); 582 else 583 Result := 1; 584 end if; 585 586 pragma Debug (Assertions); 587 588 return Result; 589 end Get_Source_File_Index; 590 591 ---------------- 592 -- Initialize -- 593 ---------------- 594 595 procedure Initialize is 596 begin 597 Source_gnat_adc := No_Source_File; 598 Source_File.Init; 599 Instances.Init; 600 Instances.Append (No_Location); 601 pragma Assert (Instances.Last = No_Instance_Id); 602 end Initialize; 603 604 ------------------- 605 -- Instantiation -- 606 ------------------- 607 608 function Instantiation (S : SFI) return Source_Ptr is 609 SIE : Source_File_Record renames Source_File.Table (S); 610 begin 611 if SIE.Inlined_Body or SIE.Inherited_Pragma then 612 return SIE.Inlined_Call; 613 else 614 return Instances.Table (SIE.Instance); 615 end if; 616 end Instantiation; 617 618 ------------------------- 619 -- Instantiation_Depth -- 620 ------------------------- 621 622 function Instantiation_Depth (S : Source_Ptr) return Nat is 623 Sind : Source_File_Index; 624 Sval : Source_Ptr; 625 Depth : Nat; 626 627 begin 628 Sval := S; 629 Depth := 0; 630 631 loop 632 Sind := Get_Source_File_Index (Sval); 633 Sval := Instantiation (Sind); 634 exit when Sval = No_Location; 635 Depth := Depth + 1; 636 end loop; 637 638 return Depth; 639 end Instantiation_Depth; 640 641 ---------------------------- 642 -- Instantiation_Location -- 643 ---------------------------- 644 645 function Instantiation_Location (S : Source_Ptr) return Source_Ptr is 646 begin 647 return Instantiation (Get_Source_File_Index (S)); 648 end Instantiation_Location; 649 650 -------------------------- 651 -- Iterate_On_Instances -- 652 -------------------------- 653 654 procedure Iterate_On_Instances is 655 begin 656 for J in 1 .. Instances.Last loop 657 Process (J, Instances.Table (J)); 658 end loop; 659 end Iterate_On_Instances; 660 661 ---------------------- 662 -- Last_Source_File -- 663 ---------------------- 664 665 function Last_Source_File return Source_File_Index is 666 begin 667 return Source_File.Last; 668 end Last_Source_File; 669 670 ---------------- 671 -- Line_Start -- 672 ---------------- 673 674 function Line_Start (P : Source_Ptr) return Source_Ptr is 675 Sindex : constant Source_File_Index := Get_Source_File_Index (P); 676 Src : constant Source_Buffer_Ptr := 677 Source_File.Table (Sindex).Source_Text; 678 Sfirst : constant Source_Ptr := 679 Source_File.Table (Sindex).Source_First; 680 S : Source_Ptr; 681 682 begin 683 S := P; 684 while S > Sfirst 685 and then Src (S - 1) /= CR 686 and then Src (S - 1) /= LF 687 loop 688 S := S - 1; 689 end loop; 690 691 return S; 692 end Line_Start; 693 694 function Line_Start 695 (L : Physical_Line_Number; 696 S : Source_File_Index) return Source_Ptr 697 is 698 begin 699 return Source_File.Table (S).Lines_Table (L); 700 end Line_Start; 701 702 ---------- 703 -- Lock -- 704 ---------- 705 706 procedure Lock is 707 begin 708 Source_File.Release; 709 Source_File.Locked := True; 710 end Lock; 711 712 ---------------------- 713 -- Num_Source_Files -- 714 ---------------------- 715 716 function Num_Source_Files return Nat is 717 begin 718 return Int (Source_File.Last) - Int (Source_File.First) + 1; 719 end Num_Source_Files; 720 721 ---------------------- 722 -- Num_Source_Lines -- 723 ---------------------- 724 725 function Num_Source_Lines (S : Source_File_Index) return Nat is 726 begin 727 return Nat (Source_File.Table (S).Last_Source_Line); 728 end Num_Source_Lines; 729 730 ----------------------- 731 -- Original_Location -- 732 ----------------------- 733 734 function Original_Location (S : Source_Ptr) return Source_Ptr is 735 Sindex : Source_File_Index; 736 Tindex : Source_File_Index; 737 738 begin 739 if S <= No_Location then 740 return S; 741 742 else 743 Sindex := Get_Source_File_Index (S); 744 745 if Instantiation (Sindex) = No_Location then 746 return S; 747 748 else 749 Tindex := Template (Sindex); 750 while Instantiation (Tindex) /= No_Location loop 751 Tindex := Template (Tindex); 752 end loop; 753 754 return S - Source_First (Sindex) + Source_First (Tindex); 755 end if; 756 end if; 757 end Original_Location; 758 759 ------------------------- 760 -- Physical_To_Logical -- 761 ------------------------- 762 763 function Physical_To_Logical 764 (Line : Physical_Line_Number; 765 S : Source_File_Index) return Logical_Line_Number 766 is 767 SFR : Source_File_Record renames Source_File.Table (S); 768 769 begin 770 if SFR.Num_SRef_Pragmas = 0 then 771 return Logical_Line_Number (Line); 772 else 773 return SFR.Logical_Lines_Table (Line); 774 end if; 775 end Physical_To_Logical; 776 777 -------------------------------- 778 -- Register_Source_Ref_Pragma -- 779 -------------------------------- 780 781 procedure Register_Source_Ref_Pragma 782 (File_Name : File_Name_Type; 783 Stripped_File_Name : File_Name_Type; 784 Mapped_Line : Nat; 785 Line_After_Pragma : Physical_Line_Number) 786 is 787 subtype size_t is Memory.size_t; 788 789 SFR : Source_File_Record renames Source_File.Table (Current_Source_File); 790 791 ML : Logical_Line_Number; 792 793 begin 794 if File_Name /= No_File then 795 SFR.Reference_Name := Stripped_File_Name; 796 SFR.Full_Ref_Name := File_Name; 797 798 if not Debug_Generated_Code then 799 SFR.Debug_Source_Name := Stripped_File_Name; 800 SFR.Full_Debug_Name := File_Name; 801 end if; 802 803 SFR.Num_SRef_Pragmas := SFR.Num_SRef_Pragmas + 1; 804 end if; 805 806 if SFR.Num_SRef_Pragmas = 1 then 807 SFR.First_Mapped_Line := Logical_Line_Number (Mapped_Line); 808 end if; 809 810 if SFR.Logical_Lines_Table = null then 811 SFR.Logical_Lines_Table := To_Pointer 812 (Memory.Alloc 813 (size_t (SFR.Lines_Table_Max * 814 Logical_Lines_Table_Type'Component_Size / 815 Storage_Unit))); 816 end if; 817 818 SFR.Logical_Lines_Table (Line_After_Pragma - 1) := No_Line_Number; 819 820 ML := Logical_Line_Number (Mapped_Line); 821 for J in Line_After_Pragma .. SFR.Last_Source_Line loop 822 SFR.Logical_Lines_Table (J) := ML; 823 ML := ML + 1; 824 end loop; 825 end Register_Source_Ref_Pragma; 826 827 --------------------------------- 828 -- Set_Source_File_Index_Table -- 829 --------------------------------- 830 831 procedure Set_Source_File_Index_Table (Xnew : Source_File_Index) is 832 Ind : Int; 833 SP : Source_Ptr; 834 SL : constant Source_Ptr := Source_File.Table (Xnew).Source_Last; 835 begin 836 SP := Source_File.Table (Xnew).Source_First; 837 pragma Assert (SP mod Source_Align = 0); 838 Ind := Int (SP) / Source_Align; 839 while SP <= SL loop 840 Source_File_Index_Table (Ind) := Xnew; 841 SP := SP + Source_Align; 842 Ind := Ind + 1; 843 end loop; 844 end Set_Source_File_Index_Table; 845 846 --------------------------- 847 -- Skip_Line_Terminators -- 848 --------------------------- 849 850 procedure Skip_Line_Terminators 851 (P : in out Source_Ptr; 852 Physical : out Boolean) 853 is 854 Chr : constant Character := Source (P); 855 856 begin 857 if Chr = CR then 858 if Source (P + 1) = LF then 859 P := P + 2; 860 else 861 P := P + 1; 862 end if; 863 864 elsif Chr = LF then 865 P := P + 1; 866 867 elsif Chr = FF or else Chr = VT then 868 P := P + 1; 869 Physical := False; 870 return; 871 872 -- Otherwise we have a wide character 873 874 else 875 Skip_Wide (Source, P); 876 end if; 877 878 -- Fall through in the physical line terminator case. First deal with 879 -- making a possible entry into the lines table if one is needed. 880 881 -- Note: we are dealing with a real source file here, this cannot be 882 -- the instantiation case, so we need not worry about Sloc adjustment. 883 884 declare 885 S : Source_File_Record 886 renames Source_File.Table (Current_Source_File); 887 888 begin 889 Physical := True; 890 891 -- Make entry in lines table if not already made (in some scan backup 892 -- cases, we will be rescanning previously scanned source, so the 893 -- entry may have already been made on the previous forward scan). 894 895 if Source (P) /= EOF 896 and then P > S.Lines_Table (S.Last_Source_Line) 897 then 898 Add_Line_Tables_Entry (S, P); 899 end if; 900 end; 901 end Skip_Line_Terminators; 902 903 -------------- 904 -- Set_Dope -- 905 -------------- 906 907 procedure Set_Dope 908 (Src : System.Address; New_Dope : Dope_Ptr) 909 is 910 -- A fat pointer is a pair consisting of data pointer and dope pointer, 911 -- in that order. So we want to overwrite the second word. 912 Dope : System.Address; 913 pragma Import (Ada, Dope); 914 use System.Storage_Elements; 915 for Dope'Address use Src + System.Address'Size / 8; 916 begin 917 Dope := New_Dope.all'Address; 918 end Set_Dope; 919 920 procedure Free_Dope (Src : System.Address) is 921 Dope : Dope_Ptr; 922 pragma Import (Ada, Dope); 923 use System.Storage_Elements; 924 for Dope'Address use Src + System.Address'Size / 8; 925 procedure Free is new Unchecked_Deallocation (Dope_Rec, Dope_Ptr); 926 begin 927 Free (Dope); 928 end Free_Dope; 929 930 ---------------- 931 -- Sloc_Range -- 932 ---------------- 933 934 procedure Sloc_Range (N : Node_Id; Min, Max : out Source_Ptr) is 935 936 Indx : constant Source_File_Index := Get_Source_File_Index (Sloc (N)); 937 938 function Process (N : Node_Id) return Traverse_Result; 939 -- Process function for traversing the node tree 940 941 procedure Traverse is new Traverse_Proc (Process); 942 943 ------------- 944 -- Process -- 945 ------------- 946 947 function Process (N : Node_Id) return Traverse_Result is 948 Loc : constant Source_Ptr := Sloc (Original_Node (N)); 949 950 begin 951 -- Skip nodes that may have been added during expansion and 952 -- that originate in other units, such as code for contracts 953 -- in subprogram bodies. 954 955 if Get_Source_File_Index (Loc) /= Indx then 956 return Skip; 957 end if; 958 959 if Loc > No_Location then 960 if Loc < Min then 961 Min := Loc; 962 elsif Loc > Max then 963 Max := Loc; 964 end if; 965 end if; 966 967 return OK_Orig; 968 end Process; 969 970 -- Start of processing for Sloc_Range 971 972 begin 973 Min := Sloc (N); 974 Max := Min; 975 Traverse (N); 976 end Sloc_Range; 977 978 ------------------- 979 -- Source_Offset -- 980 ------------------- 981 982 function Source_Offset (S : Source_Ptr) return Nat is 983 Sindex : constant Source_File_Index := Get_Source_File_Index (S); 984 Sfirst : constant Source_Ptr := 985 Source_File.Table (Sindex).Source_First; 986 begin 987 return Nat (S - Sfirst); 988 end Source_Offset; 989 990 ------------------------ 991 -- Top_Level_Location -- 992 ------------------------ 993 994 function Top_Level_Location (S : Source_Ptr) return Source_Ptr is 995 Oldloc : Source_Ptr; 996 Newloc : Source_Ptr; 997 998 begin 999 Newloc := S; 1000 loop 1001 Oldloc := Newloc; 1002 Newloc := Instantiation_Location (Oldloc); 1003 exit when Newloc = No_Location; 1004 end loop; 1005 1006 return Oldloc; 1007 end Top_Level_Location; 1008 1009 -------------------- 1010 -- Write_Location -- 1011 -------------------- 1012 1013 procedure Write_Location (P : Source_Ptr) is 1014 begin 1015 if P = No_Location then 1016 Write_Str ("<no location>"); 1017 1018 elsif P <= Standard_Location then 1019 Write_Str ("<standard location>"); 1020 1021 else 1022 declare 1023 SI : constant Source_File_Index := Get_Source_File_Index (P); 1024 1025 begin 1026 Write_Name (Debug_Source_Name (SI)); 1027 Write_Char (':'); 1028 Write_Int (Int (Get_Logical_Line_Number (P))); 1029 Write_Char (':'); 1030 Write_Int (Int (Get_Column_Number (P))); 1031 1032 if Instantiation (SI) /= No_Location then 1033 Write_Str (" ["); 1034 Write_Location (Instantiation (SI)); 1035 Write_Char (']'); 1036 end if; 1037 end; 1038 end if; 1039 end Write_Location; 1040 1041 ---------------------- 1042 -- Write_Time_Stamp -- 1043 ---------------------- 1044 1045 procedure Write_Time_Stamp (S : Source_File_Index) is 1046 T : constant Time_Stamp_Type := Time_Stamp (S); 1047 P : Natural; 1048 1049 begin 1050 if T (1) = '9' then 1051 Write_Str ("19"); 1052 P := 0; 1053 else 1054 Write_Char (T (1)); 1055 Write_Char (T (2)); 1056 P := 2; 1057 end if; 1058 1059 Write_Char (T (P + 1)); 1060 Write_Char (T (P + 2)); 1061 Write_Char ('-'); 1062 1063 Write_Char (T (P + 3)); 1064 Write_Char (T (P + 4)); 1065 Write_Char ('-'); 1066 1067 Write_Char (T (P + 5)); 1068 Write_Char (T (P + 6)); 1069 Write_Char (' '); 1070 1071 Write_Char (T (P + 7)); 1072 Write_Char (T (P + 8)); 1073 Write_Char (':'); 1074 1075 Write_Char (T (P + 9)); 1076 Write_Char (T (P + 10)); 1077 Write_Char (':'); 1078 1079 Write_Char (T (P + 11)); 1080 Write_Char (T (P + 12)); 1081 end Write_Time_Stamp; 1082 1083 ---------------------------------------------- 1084 -- Access Subprograms for Source File Table -- 1085 ---------------------------------------------- 1086 1087 function Debug_Source_Name (S : SFI) return File_Name_Type is 1088 begin 1089 return Source_File.Table (S).Debug_Source_Name; 1090 end Debug_Source_Name; 1091 1092 function Instance (S : SFI) return Instance_Id is 1093 begin 1094 return Source_File.Table (S).Instance; 1095 end Instance; 1096 1097 function File_Name (S : SFI) return File_Name_Type is 1098 begin 1099 return Source_File.Table (S).File_Name; 1100 end File_Name; 1101 1102 function File_Type (S : SFI) return Type_Of_File is 1103 begin 1104 return Source_File.Table (S).File_Type; 1105 end File_Type; 1106 1107 function First_Mapped_Line (S : SFI) return Logical_Line_Number is 1108 begin 1109 return Source_File.Table (S).First_Mapped_Line; 1110 end First_Mapped_Line; 1111 1112 function Full_Debug_Name (S : SFI) return File_Name_Type is 1113 begin 1114 return Source_File.Table (S).Full_Debug_Name; 1115 end Full_Debug_Name; 1116 1117 function Full_File_Name (S : SFI) return File_Name_Type is 1118 begin 1119 return Source_File.Table (S).Full_File_Name; 1120 end Full_File_Name; 1121 1122 function Full_Ref_Name (S : SFI) return File_Name_Type is 1123 begin 1124 return Source_File.Table (S).Full_Ref_Name; 1125 end Full_Ref_Name; 1126 1127 function Identifier_Casing (S : SFI) return Casing_Type is 1128 begin 1129 return Source_File.Table (S).Identifier_Casing; 1130 end Identifier_Casing; 1131 1132 function Inherited_Pragma (S : SFI) return Boolean is 1133 begin 1134 return Source_File.Table (S).Inherited_Pragma; 1135 end Inherited_Pragma; 1136 1137 function Inlined_Body (S : SFI) return Boolean is 1138 begin 1139 return Source_File.Table (S).Inlined_Body; 1140 end Inlined_Body; 1141 1142 function Inlined_Call (S : SFI) return Source_Ptr is 1143 begin 1144 return Source_File.Table (S).Inlined_Call; 1145 end Inlined_Call; 1146 1147 function Keyword_Casing (S : SFI) return Casing_Type is 1148 begin 1149 return Source_File.Table (S).Keyword_Casing; 1150 end Keyword_Casing; 1151 1152 function Last_Source_Line (S : SFI) return Physical_Line_Number is 1153 begin 1154 return Source_File.Table (S).Last_Source_Line; 1155 end Last_Source_Line; 1156 1157 function License (S : SFI) return License_Type is 1158 begin 1159 return Source_File.Table (S).License; 1160 end License; 1161 1162 function Num_SRef_Pragmas (S : SFI) return Nat is 1163 begin 1164 return Source_File.Table (S).Num_SRef_Pragmas; 1165 end Num_SRef_Pragmas; 1166 1167 function Reference_Name (S : SFI) return File_Name_Type is 1168 begin 1169 return Source_File.Table (S).Reference_Name; 1170 end Reference_Name; 1171 1172 function Source_Checksum (S : SFI) return Word is 1173 begin 1174 return Source_File.Table (S).Source_Checksum; 1175 end Source_Checksum; 1176 1177 function Source_First (S : SFI) return Source_Ptr is 1178 begin 1179 return Source_File.Table (S).Source_First; 1180 end Source_First; 1181 1182 function Source_Last (S : SFI) return Source_Ptr is 1183 begin 1184 return Source_File.Table (S).Source_Last; 1185 end Source_Last; 1186 1187 function Source_Text (S : SFI) return Source_Buffer_Ptr is 1188 begin 1189 return Source_File.Table (S).Source_Text; 1190 end Source_Text; 1191 1192 function Template (S : SFI) return SFI is 1193 begin 1194 return Source_File.Table (S).Template; 1195 end Template; 1196 1197 function Time_Stamp (S : SFI) return Time_Stamp_Type is 1198 begin 1199 return Source_File.Table (S).Time_Stamp; 1200 end Time_Stamp; 1201 1202 function Unit (S : SFI) return Unit_Number_Type is 1203 begin 1204 return Source_File.Table (S).Unit; 1205 end Unit; 1206 1207 ------------------------------------------ 1208 -- Set Procedures for Source File Table -- 1209 ------------------------------------------ 1210 1211 procedure Set_Identifier_Casing (S : SFI; C : Casing_Type) is 1212 begin 1213 Source_File.Table (S).Identifier_Casing := C; 1214 end Set_Identifier_Casing; 1215 1216 procedure Set_Keyword_Casing (S : SFI; C : Casing_Type) is 1217 begin 1218 Source_File.Table (S).Keyword_Casing := C; 1219 end Set_Keyword_Casing; 1220 1221 procedure Set_License (S : SFI; L : License_Type) is 1222 begin 1223 Source_File.Table (S).License := L; 1224 end Set_License; 1225 1226 procedure Set_Unit (S : SFI; U : Unit_Number_Type) is 1227 begin 1228 Source_File.Table (S).Unit := U; 1229 end Set_Unit; 1230 1231 ---------------------- 1232 -- Trim_Lines_Table -- 1233 ---------------------- 1234 1235 procedure Trim_Lines_Table (S : Source_File_Index) is 1236 Max : constant Nat := Nat (Source_File.Table (S).Last_Source_Line); 1237 1238 begin 1239 -- Release allocated storage that is no longer needed 1240 1241 Source_File.Table (S).Lines_Table := To_Pointer 1242 (Memory.Realloc 1243 (To_Address (Source_File.Table (S).Lines_Table), 1244 Memory.size_t 1245 (Max * (Lines_Table_Type'Component_Size / System.Storage_Unit)))); 1246 Source_File.Table (S).Lines_Table_Max := Physical_Line_Number (Max); 1247 end Trim_Lines_Table; 1248 1249 ------------ 1250 -- Unlock -- 1251 ------------ 1252 1253 procedure Unlock is 1254 begin 1255 Source_File.Locked := False; 1256 Source_File.Release; 1257 end Unlock; 1258 1259 -------- 1260 -- wl -- 1261 -------- 1262 1263 procedure wl (P : Source_Ptr) is 1264 begin 1265 Write_Location (P); 1266 Write_Eol; 1267 end wl; 1268 1269end Sinput; 1270