1------------------------------------------------------------------------------ 2-- -- 3-- GNAT SYSTEM UTILITIES -- 4-- -- 5-- C S I N F O -- 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-- Check consistency of sinfo.ads and sinfo.adb. Checks that field name usage 27-- is consistent and that assertion cross-reference lists are correct, as well 28-- as making sure that all the comments on field name usage are consistent. 29 30-- Note that this is used both as a standalone program, and as a procedure 31-- called by XSinfo. This raises an unhandled exception if it finds any 32-- errors; we don't attempt any sophisticated error recovery. 33 34with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; 35with Ada.Strings.Unbounded.Text_IO; use Ada.Strings.Unbounded.Text_IO; 36with Ada.Strings.Maps; use Ada.Strings.Maps; 37with Ada.Strings.Maps.Constants; use Ada.Strings.Maps.Constants; 38with Ada.Text_IO; use Ada.Text_IO; 39 40with GNAT.Spitbol; use GNAT.Spitbol; 41with GNAT.Spitbol.Patterns; use GNAT.Spitbol.Patterns; 42with GNAT.Spitbol.Table_Boolean; 43with GNAT.Spitbol.Table_VString; 44 45procedure CSinfo is 46 47 package TB renames GNAT.Spitbol.Table_Boolean; 48 package TV renames GNAT.Spitbol.Table_VString; 49 use TB, TV; 50 51 Infil : File_Type; 52 Lineno : Natural := 0; 53 54 Err : exception; 55 -- Raised on fatal error 56 57 Done : exception; 58 -- Raised after error is found to terminate run 59 60 WSP : constant Pattern := Span (' ' & ASCII.HT); 61 62 Fields : TV.Table (300); 63 Fields1 : TV.Table (300); 64 Refs : TV.Table (300); 65 Refscopy : TV.Table (300); 66 Special : TB.Table (50); 67 Inlines : TV.Table (100); 68 69 -- The following define the standard fields used for binary operator, 70 -- unary operator, and other expression nodes. Numbers in the range 1-5 71 -- refer to the Fieldn fields. Letters D-R refer to flags: 72 73 -- D = Flag4 74 -- E = Flag5 75 -- F = Flag6 76 -- G = Flag7 77 -- H = Flag8 78 -- I = Flag9 79 -- J = Flag10 80 -- K = Flag11 81 -- L = Flag12 82 -- M = Flag13 83 -- N = Flag14 84 -- O = Flag15 85 -- P = Flag16 86 -- Q = Flag17 87 -- R = Flag18 88 89 Flags : TV.Table (20); 90 -- Maps flag numbers to letters 91 92 N_Fields : constant Pattern := BreakX ("JL"); 93 E_Fields : constant Pattern := BreakX ("5EFGHIJLOP"); 94 U_Fields : constant Pattern := BreakX ("1345EFGHIJKLOPQ"); 95 B_Fields : constant Pattern := BreakX ("12345EFGHIJKLOPQ"); 96 97 Line : VString; 98 Bad : Boolean; 99 100 Field : constant VString := Nul; 101 Fields_Used : VString := Nul; 102 Name : constant VString := Nul; 103 Next : constant VString := Nul; 104 Node : VString := Nul; 105 Ref : VString := Nul; 106 Synonym : constant VString := Nul; 107 Nxtref : constant VString := Nul; 108 109 Which_Field : aliased VString := Nul; 110 111 Node_Search : constant Pattern := WSP & "-- N_" & Rest * Node; 112 Break_Punc : constant Pattern := Break (" .,"); 113 Plus_Binary : constant Pattern := WSP 114 & "-- plus fields for binary operator"; 115 Plus_Unary : constant Pattern := WSP 116 & "-- plus fields for unary operator"; 117 Plus_Expr : constant Pattern := WSP 118 & "-- plus fields for expression"; 119 Break_Syn : constant Pattern := WSP & "-- " 120 & Break (' ') * Synonym 121 & " (" & Break (')') * Field; 122 Break_Field : constant Pattern := BreakX ('-') * Field; 123 Get_Field : constant Pattern := BreakX (Decimal_Digit_Set) 124 & Span (Decimal_Digit_Set) * Which_Field; 125 Break_WFld : constant Pattern := Break (Which_Field'Access); 126 Get_Funcsyn : constant Pattern := WSP & "function " & Rest * Synonym; 127 Extr_Field : constant Pattern := BreakX ('-') & "-- " & Rest * Field; 128 Get_Procsyn : constant Pattern := WSP & "procedure Set_" & Rest * Synonym; 129 Get_Inline : constant Pattern := WSP & "pragma Inline (" 130 & Break (')') * Name; 131 Set_Name : constant Pattern := "Set_" & Rest * Name; 132 Func_Rest : constant Pattern := " function " & Rest * Synonym; 133 Get_Nxtref : constant Pattern := Break (',') * Nxtref & ','; 134 Test_Syn : constant Pattern := Break ('=') & "= N_" 135 & (Break (" ,)") or Rest) * Next; 136 Chop_Comma : constant Pattern := BreakX (',') * Next; 137 Return_Fld : constant Pattern := WSP & "return " & Break (' ') * Field; 138 Set_Syn : constant Pattern := " procedure Set_" & Rest * Synonym; 139 Set_Fld : constant Pattern := WSP & "Set_" & Break (' ') * Field 140 & " (N, Val)"; 141 Break_With : constant Pattern := Break ('_') ** Field & "_With_Parent"; 142 143 type VStringA is array (Natural range <>) of VString; 144 145 procedure Next_Line; 146 -- Read next line trimmed from Infil into Line and bump Lineno 147 148 procedure Sort (A : in out VStringA); 149 -- Sort a (small) array of VString's 150 151 procedure Next_Line is 152 begin 153 Line := Get_Line (Infil); 154 Trim (Line); 155 Lineno := Lineno + 1; 156 end Next_Line; 157 158 procedure Sort (A : in out VStringA) is 159 Temp : VString; 160 begin 161 <<Sort>> 162 for J in 1 .. A'Length - 1 loop 163 if A (J) > A (J + 1) then 164 Temp := A (J); 165 A (J) := A (J + 1); 166 A (J + 1) := Temp; 167 goto Sort; 168 end if; 169 end loop; 170 end Sort; 171 172-- Start of processing for CSinfo 173 174begin 175 Anchored_Mode := True; 176 New_Line; 177 Open (Infil, In_File, "sinfo.ads"); 178 Put_Line ("Check for field name consistency"); 179 180 -- Setup table for mapping flag numbers to letters 181 182 Set (Flags, "4", V ("D")); 183 Set (Flags, "5", V ("E")); 184 Set (Flags, "6", V ("F")); 185 Set (Flags, "7", V ("G")); 186 Set (Flags, "8", V ("H")); 187 Set (Flags, "9", V ("I")); 188 Set (Flags, "10", V ("J")); 189 Set (Flags, "11", V ("K")); 190 Set (Flags, "12", V ("L")); 191 Set (Flags, "13", V ("M")); 192 Set (Flags, "14", V ("N")); 193 Set (Flags, "15", V ("O")); 194 Set (Flags, "16", V ("P")); 195 Set (Flags, "17", V ("Q")); 196 Set (Flags, "18", V ("R")); 197 198 -- Special fields table. The following names are not recorded or checked 199 -- by Csinfo, since they are specially handled. This means that any field 200 -- definition or subprogram with a matching name is ignored. 201 202 Set (Special, "Analyzed", True); 203 Set (Special, "Assignment_OK", True); 204 Set (Special, "Associated_Node", True); 205 Set (Special, "Cannot_Be_Constant", True); 206 Set (Special, "Chars", True); 207 Set (Special, "Comes_From_Source", True); 208 Set (Special, "Do_Overflow_Check", True); 209 Set (Special, "Do_Range_Check", True); 210 Set (Special, "Entity", True); 211 Set (Special, "Entity_Or_Associated_Node", True); 212 Set (Special, "Error_Posted", True); 213 Set (Special, "Etype", True); 214 Set (Special, "Evaluate_Once", True); 215 Set (Special, "First_Itype", True); 216 Set (Special, "Has_Aspect_Specifications", True); 217 Set (Special, "Has_Dynamic_Itype", True); 218 Set (Special, "Has_Dynamic_Range_Check", True); 219 Set (Special, "Has_Dynamic_Length_Check", True); 220 Set (Special, "Has_Private_View", True); 221 Set (Special, "Is_Controlling_Actual", True); 222 Set (Special, "Is_Overloaded", True); 223 Set (Special, "Is_Static_Expression", True); 224 Set (Special, "Left_Opnd", True); 225 Set (Special, "Must_Not_Freeze", True); 226 Set (Special, "Nkind_In", True); 227 Set (Special, "Parens", True); 228 Set (Special, "Pragma_Name", True); 229 Set (Special, "Raises_Constraint_Error", True); 230 Set (Special, "Right_Opnd", True); 231 232 -- Loop to acquire information from node definitions in sinfo.ads, 233 -- checking for consistency in Op/Flag assignments to each synonym 234 235 loop 236 Bad := False; 237 Next_Line; 238 exit when Match (Line, " -- Node Access Functions"); 239 240 if Match (Line, Node_Search) 241 and then not Match (Node, Break_Punc) 242 then 243 Fields_Used := Nul; 244 245 elsif Node = "" then 246 null; 247 248 elsif Line = "" then 249 Node := Nul; 250 251 elsif Match (Line, Plus_Binary) then 252 Bad := Match (Fields_Used, B_Fields); 253 254 elsif Match (Line, Plus_Unary) then 255 Bad := Match (Fields_Used, U_Fields); 256 257 elsif Match (Line, Plus_Expr) then 258 Bad := Match (Fields_Used, E_Fields); 259 260 elsif not Match (Line, Break_Syn) then 261 null; 262 263 elsif Match (Synonym, "plus") then 264 null; 265 266 else 267 Match (Field, Break_Field); 268 269 if not Present (Special, Synonym) then 270 if Present (Fields, Synonym) then 271 if Field /= Get (Fields, Synonym) then 272 Put_Line 273 ("Inconsistent field reference at line" & 274 Lineno'Img & " for " & Synonym); 275 raise Done; 276 end if; 277 278 else 279 Set (Fields, Synonym, Field); 280 end if; 281 282 Set (Refs, Synonym, Node & ',' & Get (Refs, Synonym)); 283 Match (Field, Get_Field); 284 285 if Match (Field, "Flag") then 286 Which_Field := Get (Flags, Which_Field); 287 end if; 288 289 if Match (Fields_Used, Break_WFld) then 290 Put_Line 291 ("Overlapping field at line " & Lineno'Img & 292 " for " & Synonym); 293 raise Done; 294 end if; 295 296 Append (Fields_Used, Which_Field); 297 Bad := Bad or Match (Fields_Used, N_Fields); 298 end if; 299 end if; 300 301 if Bad then 302 Put_Line ("fields conflict with standard fields for node " & Node); 303 raise Done; 304 end if; 305 end loop; 306 307 Put_Line (" OK"); 308 New_Line; 309 Put_Line ("Check for function consistency"); 310 311 -- Loop through field function definitions to make sure they are OK 312 313 Fields1 := Fields; 314 loop 315 Next_Line; 316 exit when Match (Line, " -- Node Update"); 317 318 if Match (Line, Get_Funcsyn) 319 and then not Present (Special, Synonym) 320 then 321 if not Present (Fields1, Synonym) then 322 Put_Line 323 ("function on line " & Lineno & 324 " is for unused synonym"); 325 raise Done; 326 end if; 327 328 Next_Line; 329 330 if not Match (Line, Extr_Field) then 331 raise Err; 332 end if; 333 334 if Field /= Get (Fields1, Synonym) then 335 Put_Line ("Wrong field in function " & Synonym); 336 raise Done; 337 338 else 339 Delete (Fields1, Synonym); 340 end if; 341 end if; 342 end loop; 343 344 Put_Line (" OK"); 345 New_Line; 346 Put_Line ("Check for missing functions"); 347 348 declare 349 List : constant TV.Table_Array := Convert_To_Array (Fields1); 350 351 begin 352 if List'Length > 0 then 353 Put_Line ("No function for field synonym " & List (1).Name); 354 raise Done; 355 end if; 356 end; 357 358 -- Check field set procedures 359 360 Put_Line (" OK"); 361 New_Line; 362 Put_Line ("Check for set procedure consistency"); 363 364 Fields1 := Fields; 365 loop 366 Next_Line; 367 exit when Match (Line, " -- Inline Pragmas"); 368 exit when Match (Line, " -- Iterator Procedures"); 369 370 if Match (Line, Get_Procsyn) 371 and then not Present (Special, Synonym) 372 then 373 if not Present (Fields1, Synonym) then 374 Put_Line 375 ("procedure on line " & Lineno & " is for unused synonym"); 376 raise Done; 377 end if; 378 379 Next_Line; 380 381 if not Match (Line, Extr_Field) then 382 raise Err; 383 end if; 384 385 if Field /= Get (Fields1, Synonym) then 386 Put_Line ("Wrong field in procedure Set_" & Synonym); 387 raise Done; 388 389 else 390 Delete (Fields1, Synonym); 391 end if; 392 end if; 393 end loop; 394 395 Put_Line (" OK"); 396 New_Line; 397 Put_Line ("Check for missing set procedures"); 398 399 declare 400 List : constant TV.Table_Array := Convert_To_Array (Fields1); 401 402 begin 403 if List'Length > 0 then 404 Put_Line ("No procedure for field synonym Set_" & List (1).Name); 405 raise Done; 406 end if; 407 end; 408 409 Put_Line (" OK"); 410 New_Line; 411 Put_Line ("Check pragma Inlines are all for existing subprograms"); 412 413 Clear (Fields1); 414 while not End_Of_File (Infil) loop 415 Next_Line; 416 417 if Match (Line, Get_Inline) 418 and then not Present (Special, Name) 419 then 420 exit when Match (Name, Set_Name); 421 422 if not Present (Fields, Name) then 423 Put_Line 424 ("Pragma Inline on line " & Lineno & 425 " does not correspond to synonym"); 426 raise Done; 427 428 else 429 Set (Inlines, Name, Get (Inlines, Name) & 'r'); 430 end if; 431 end if; 432 end loop; 433 434 Put_Line (" OK"); 435 New_Line; 436 Put_Line ("Check no pragma Inlines were omitted"); 437 438 declare 439 List : constant TV.Table_Array := Convert_To_Array (Fields); 440 Nxt : VString := Nul; 441 442 begin 443 for M in List'Range loop 444 Nxt := List (M).Name; 445 446 if Get (Inlines, Nxt) /= "r" then 447 Put_Line ("Incorrect pragma Inlines for " & Nxt); 448 raise Done; 449 end if; 450 end loop; 451 end; 452 453 Put_Line (" OK"); 454 New_Line; 455 Clear (Inlines); 456 457 Close (Infil); 458 Open (Infil, In_File, "sinfo.adb"); 459 Lineno := 0; 460 Put_Line ("Check references in functions in body"); 461 462 Refscopy := Refs; 463 loop 464 Next_Line; 465 exit when Match (Line, " -- Field Access Functions --"); 466 end loop; 467 468 loop 469 Next_Line; 470 exit when Match (Line, " -- Field Set Procedures --"); 471 472 if Match (Line, Func_Rest) 473 and then not Present (Special, Synonym) 474 then 475 Ref := Get (Refs, Synonym); 476 Delete (Refs, Synonym); 477 478 if Ref = "" then 479 Put_Line 480 ("Function on line " & Lineno & " is for unknown synonym"); 481 raise Err; 482 end if; 483 484 -- Alpha sort of references for this entry 485 486 declare 487 Refa : VStringA (1 .. 100); 488 N : Natural := 0; 489 490 begin 491 loop 492 exit when not Match (Ref, Get_Nxtref, Nul); 493 N := N + 1; 494 Refa (N) := Nxtref; 495 end loop; 496 497 Sort (Refa (1 .. N)); 498 Next_Line; 499 Next_Line; 500 Next_Line; 501 502 -- Checking references for one entry 503 504 for M in 1 .. N loop 505 Next_Line; 506 507 if not Match (Line, Test_Syn) then 508 Put_Line ("Expecting N_" & Refa (M) & " at line " & Lineno); 509 raise Done; 510 end if; 511 512 Match (Next, Chop_Comma); 513 514 if Next /= Refa (M) then 515 Put_Line ("Expecting N_" & Refa (M) & " at line " & Lineno); 516 raise Done; 517 end if; 518 end loop; 519 520 Next_Line; 521 Match (Line, Return_Fld); 522 523 if Field /= Get (Fields, Synonym) then 524 Put_Line 525 ("Wrong field for function " & Synonym & " at line " & 526 Lineno & " should be " & Get (Fields, Synonym)); 527 raise Done; 528 end if; 529 end; 530 end if; 531 end loop; 532 533 Put_Line (" OK"); 534 New_Line; 535 Put_Line ("Check for missing functions in body"); 536 537 declare 538 List : constant TV.Table_Array := Convert_To_Array (Refs); 539 540 begin 541 if List'Length /= 0 then 542 Put_Line ("Missing function " & List (1).Name & " in body"); 543 raise Done; 544 end if; 545 end; 546 547 Put_Line (" OK"); 548 New_Line; 549 Put_Line ("Check Set procedures in body"); 550 Refs := Refscopy; 551 552 loop 553 Next_Line; 554 exit when Match (Line, "end"); 555 exit when Match (Line, " -- Iterator Procedures"); 556 557 if Match (Line, Set_Syn) 558 and then not Present (Special, Synonym) 559 then 560 Ref := Get (Refs, Synonym); 561 Delete (Refs, Synonym); 562 563 if Ref = "" then 564 Put_Line 565 ("Function on line " & Lineno & " is for unknown synonym"); 566 raise Err; 567 end if; 568 569 -- Alpha sort of references for this entry 570 571 declare 572 Refa : VStringA (1 .. 100); 573 N : Natural; 574 575 begin 576 N := 0; 577 578 loop 579 exit when not Match (Ref, Get_Nxtref, Nul); 580 N := N + 1; 581 Refa (N) := Nxtref; 582 end loop; 583 584 Sort (Refa (1 .. N)); 585 586 Next_Line; 587 Next_Line; 588 Next_Line; 589 590 -- Checking references for one entry 591 592 for M in 1 .. N loop 593 Next_Line; 594 595 if not Match (Line, Test_Syn) 596 or else Next /= Refa (M) 597 then 598 Put_Line ("Expecting N_" & Refa (M) & " at line " & Lineno); 599 raise Err; 600 end if; 601 end loop; 602 603 loop 604 Next_Line; 605 exit when Match (Line, Set_Fld); 606 end loop; 607 608 Match (Field, Break_With); 609 610 if Field /= Get (Fields, Synonym) then 611 Put_Line 612 ("Wrong field for procedure Set_" & Synonym & 613 " at line " & Lineno & " should be " & 614 Get (Fields, Synonym)); 615 raise Done; 616 end if; 617 618 Delete (Fields1, Synonym); 619 end; 620 end if; 621 end loop; 622 623 Put_Line (" OK"); 624 New_Line; 625 Put_Line ("Check for missing set procedures in body"); 626 627 declare 628 List : constant TV.Table_Array := Convert_To_Array (Fields1); 629 begin 630 if List'Length /= 0 then 631 Put_Line ("Missing procedure Set_" & List (1).Name & " in body"); 632 raise Done; 633 end if; 634 end; 635 636 Put_Line (" OK"); 637 New_Line; 638 Put_Line ("All tests completed successfully, no errors detected"); 639 640end CSinfo; 641