OSDN Git Service

2007-08-14 Vincent Celier <celier@adacore.com>
[pf3gnuchains/gcc-fork.git] / gcc / ada / prj-strt.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                         GNAT COMPILER COMPONENTS                         --
4 --                                                                          --
5 --                             P R J . S T R T                              --
6 --                                                                          --
7 --                                 B o d y                                  --
8 --                                                                          --
9 --          Copyright (C) 2001-2007, 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 2,  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 COPYING.  If not, write --
19 -- to  the  Free Software Foundation,  51  Franklin  Street,  Fifth  Floor, --
20 -- Boston, MA 02110-1301, USA.                                              --
21 --                                                                          --
22 -- GNAT was originally developed  by the GNAT team at  New York University. --
23 -- Extensive contributions were provided by Ada Core Technologies Inc.      --
24 --                                                                          --
25 ------------------------------------------------------------------------------
26
27 with Err_Vars; use Err_Vars;
28 with Prj.Attr; use Prj.Attr;
29 with Prj.Err;  use Prj.Err;
30 with Snames;
31 with Table;
32 with Uintp;    use Uintp;
33
34 package body Prj.Strt is
35
36    Buffer      : String_Access;
37    Buffer_Last : Natural := 0;
38
39    type Choice_String is record
40       The_String   : Name_Id;
41       Already_Used : Boolean := False;
42    end record;
43    --  The string of a case label, and an indication that it has already
44    --  been used (to avoid duplicate case labels).
45
46    Choices_Initial   : constant := 10;
47    Choices_Increment : constant := 100;
48    --  These should be in alloc.ads
49
50    Choice_Node_Low_Bound  : constant := 0;
51    Choice_Node_High_Bound : constant := 099_999_999;
52    --  In practice, infinite
53
54    type Choice_Node_Id is
55      range Choice_Node_Low_Bound .. Choice_Node_High_Bound;
56
57    First_Choice_Node_Id : constant Choice_Node_Id :=
58      Choice_Node_Low_Bound;
59
60    package Choices is
61      new Table.Table
62        (Table_Component_Type => Choice_String,
63         Table_Index_Type     => Choice_Node_Id'Base,
64         Table_Low_Bound      => First_Choice_Node_Id,
65         Table_Initial        => Choices_Initial,
66         Table_Increment      => Choices_Increment,
67         Table_Name           => "Prj.Strt.Choices");
68    --  Used to store the case labels and check that there is no duplicate
69
70    package Choice_Lasts is
71      new Table.Table
72        (Table_Component_Type => Choice_Node_Id,
73         Table_Index_Type     => Nat,
74         Table_Low_Bound      => 1,
75         Table_Initial        => 10,
76         Table_Increment      => 100,
77         Table_Name           => "Prj.Strt.Choice_Lasts");
78    --  Used to store the indices of the choices in table Choices,
79    --  to distinguish nested case constructions.
80
81    Choice_First : Choice_Node_Id := 0;
82    --  Index in table Choices of the first case label of the current
83    --  case construction. Zero means no current case construction.
84
85    type Name_Location is record
86       Name     : Name_Id := No_Name;
87       Location : Source_Ptr := No_Location;
88    end record;
89    --  Store the identifier and the location of a simple name
90
91    package Names is
92      new Table.Table
93        (Table_Component_Type => Name_Location,
94         Table_Index_Type     => Nat,
95         Table_Low_Bound      => 1,
96         Table_Initial        => 10,
97         Table_Increment      => 100,
98         Table_Name           => "Prj.Strt.Names");
99    --  Used to accumulate the single names of a name
100
101    procedure Add (This_String : Name_Id);
102    --  Add a string to the case label list, indicating that it has not
103    --  yet been used.
104
105    procedure Add_To_Names (NL : Name_Location);
106    --  Add one single names to table Names
107
108    procedure External_Reference
109      (In_Tree         : Project_Node_Tree_Ref;
110       Current_Project : Project_Node_Id;
111       Current_Package : Project_Node_Id;
112       External_Value  : out Project_Node_Id);
113    --  Parse an external reference. Current token is "external"
114
115    procedure Attribute_Reference
116      (In_Tree         : Project_Node_Tree_Ref;
117       Reference       : out Project_Node_Id;
118       First_Attribute : Attribute_Node_Id;
119       Current_Project : Project_Node_Id;
120       Current_Package : Project_Node_Id);
121    --  Parse an attribute reference. Current token is an apostrophe
122
123    procedure Terms
124      (In_Tree         : Project_Node_Tree_Ref;
125       Term            : out Project_Node_Id;
126       Expr_Kind       : in out Variable_Kind;
127       Current_Project : Project_Node_Id;
128       Current_Package : Project_Node_Id;
129       Optional_Index  : Boolean);
130    --  Recursive procedure to parse one term or several terms concatenated
131    --  using "&".
132
133    ---------
134    -- Add --
135    ---------
136
137    procedure Add (This_String : Name_Id) is
138    begin
139       Choices.Increment_Last;
140       Choices.Table (Choices.Last) :=
141         (The_String   => This_String,
142          Already_Used => False);
143    end Add;
144
145    ------------------
146    -- Add_To_Names --
147    ------------------
148
149    procedure Add_To_Names (NL : Name_Location) is
150    begin
151       Names.Increment_Last;
152       Names.Table (Names.Last) := NL;
153    end Add_To_Names;
154
155    -------------------------
156    -- Attribute_Reference --
157    -------------------------
158
159    procedure Attribute_Reference
160      (In_Tree         : Project_Node_Tree_Ref;
161       Reference       : out Project_Node_Id;
162       First_Attribute : Attribute_Node_Id;
163       Current_Project : Project_Node_Id;
164       Current_Package : Project_Node_Id)
165    is
166       Current_Attribute : Attribute_Node_Id := First_Attribute;
167
168    begin
169       --  Declare the node of the attribute reference
170
171       Reference :=
172         Default_Project_Node
173           (Of_Kind => N_Attribute_Reference, In_Tree => In_Tree);
174       Set_Location_Of (Reference, In_Tree, To => Token_Ptr);
175       Scan (In_Tree); --  past apostrophe
176
177       --  Body may be an attribute name
178
179       if Token = Tok_Body then
180          Token      := Tok_Identifier;
181          Token_Name := Snames.Name_Body;
182       end if;
183
184       Expect (Tok_Identifier, "identifier");
185
186       if Token = Tok_Identifier then
187          Set_Name_Of (Reference, In_Tree, To => Token_Name);
188
189          --  Check if the identifier is one of the attribute identifiers in the
190          --  context (package or project level attributes).
191
192          Current_Attribute :=
193            Attribute_Node_Id_Of (Token_Name, Starting_At => First_Attribute);
194
195          --  If the identifier is not allowed, report an error
196
197          if Current_Attribute = Empty_Attribute then
198             Error_Msg_Name_1 := Token_Name;
199             Error_Msg ("unknown attribute %%", Token_Ptr);
200             Reference := Empty_Node;
201
202             --  Scan past the attribute name
203
204             Scan (In_Tree);
205
206          else
207             --  Give its characteristics to this attribute reference
208
209             Set_Project_Node_Of (Reference, In_Tree, To => Current_Project);
210             Set_Package_Node_Of (Reference, In_Tree, To => Current_Package);
211             Set_Expression_Kind_Of
212               (Reference, In_Tree, To => Variable_Kind_Of (Current_Attribute));
213             Set_Case_Insensitive
214               (Reference, In_Tree,
215                To => Attribute_Kind_Of (Current_Attribute) in
216                       Case_Insensitive_Associative_Array ..
217                         Optional_Index_Case_Insensitive_Associative_Array);
218
219             --  Scan past the attribute name
220
221             Scan (In_Tree);
222
223             --  If the attribute is an associative array, get the index
224
225             if Attribute_Kind_Of (Current_Attribute) /= Single then
226                Expect (Tok_Left_Paren, "`(`");
227
228                if Token = Tok_Left_Paren then
229                   Scan (In_Tree);
230                   Expect (Tok_String_Literal, "literal string");
231
232                   if Token = Tok_String_Literal then
233                      Set_Associative_Array_Index_Of
234                        (Reference, In_Tree, To => Token_Name);
235                      Scan (In_Tree);
236                      Expect (Tok_Right_Paren, "`)`");
237
238                      if Token = Tok_Right_Paren then
239                         Scan (In_Tree);
240                      end if;
241                   end if;
242                end if;
243             end if;
244          end if;
245
246          --  Change name of obsolete attributes
247
248          if Reference /= Empty_Node then
249             case Name_Of (Reference, In_Tree) is
250                when Snames.Name_Specification =>
251                   Set_Name_Of (Reference, In_Tree, To => Snames.Name_Spec);
252
253                when Snames.Name_Specification_Suffix =>
254                   Set_Name_Of
255                     (Reference, In_Tree, To => Snames.Name_Spec_Suffix);
256
257                when Snames.Name_Implementation =>
258                   Set_Name_Of (Reference, In_Tree, To => Snames.Name_Body);
259
260                when Snames.Name_Implementation_Suffix =>
261                   Set_Name_Of
262                     (Reference, In_Tree, To => Snames.Name_Body_Suffix);
263
264                when others =>
265                   null;
266             end case;
267          end if;
268       end if;
269    end Attribute_Reference;
270
271    ---------------------------
272    -- End_Case_Construction --
273    ---------------------------
274
275    procedure End_Case_Construction
276      (Check_All_Labels   : Boolean;
277       Case_Location      : Source_Ptr)
278    is
279       Non_Used : Natural := 0;
280       First_Non_Used : Choice_Node_Id := First_Choice_Node_Id;
281    begin
282       --  First, if Check_All_Labels is True, check if all values
283       --  of the string type have been used.
284
285       if Check_All_Labels then
286          for Choice in Choice_First .. Choices.Last loop
287                if not Choices.Table (Choice).Already_Used then
288                   Non_Used := Non_Used + 1;
289
290                   if Non_Used = 1 then
291                      First_Non_Used := Choice;
292                   end if;
293                end if;
294          end loop;
295
296          --  If only one is not used, report a single warning for this value
297
298          if Non_Used = 1 then
299             Error_Msg_Name_1 := Choices.Table (First_Non_Used).The_String;
300             Error_Msg ("?value %% is not used as label", Case_Location);
301
302          --  If several are not used, report a warning for each one of them
303
304          elsif Non_Used > 1 then
305             Error_Msg
306               ("?the following values are not used as labels:",
307                Case_Location);
308
309             for Choice in First_Non_Used .. Choices.Last loop
310                if not Choices.Table (Choice).Already_Used then
311                   Error_Msg_Name_1 := Choices.Table (Choice).The_String;
312                   Error_Msg ("\?%%", Case_Location);
313                end if;
314             end loop;
315          end if;
316       end if;
317
318       --  If this is the only case construction, empty the tables
319
320       if Choice_Lasts.Last = 1 then
321          Choice_Lasts.Set_Last (0);
322          Choices.Set_Last (First_Choice_Node_Id);
323          Choice_First := 0;
324
325       elsif Choice_Lasts.Last = 2 then
326
327          --  This is the second case construction, set the tables to the first
328
329          Choice_Lasts.Set_Last (1);
330          Choices.Set_Last (Choice_Lasts.Table (1));
331          Choice_First := 1;
332
333       else
334          --  This is the 3rd or more case construction, set the tables to the
335          --  previous one.
336
337          Choice_Lasts.Decrement_Last;
338          Choices.Set_Last (Choice_Lasts.Table (Choice_Lasts.Last));
339          Choice_First := Choice_Lasts.Table (Choice_Lasts.Last - 1) + 1;
340       end if;
341    end End_Case_Construction;
342
343    ------------------------
344    -- External_Reference --
345    ------------------------
346
347    procedure External_Reference
348      (In_Tree         : Project_Node_Tree_Ref;
349       Current_Project : Project_Node_Id;
350       Current_Package : Project_Node_Id;
351       External_Value  : out Project_Node_Id)
352    is
353       Field_Id : Project_Node_Id := Empty_Node;
354
355    begin
356       External_Value :=
357         Default_Project_Node
358           (Of_Kind       => N_External_Value,
359            In_Tree       => In_Tree,
360            And_Expr_Kind => Single);
361       Set_Location_Of (External_Value, In_Tree, To => Token_Ptr);
362
363       --  The current token is External
364
365       --  Get the left parenthesis
366
367       Scan (In_Tree);
368       Expect (Tok_Left_Paren, "`(`");
369
370       --  Scan past the left parenthesis
371
372       if Token = Tok_Left_Paren then
373          Scan (In_Tree);
374       end if;
375
376       --  Get the name of the external reference
377
378       Expect (Tok_String_Literal, "literal string");
379
380       if Token = Tok_String_Literal then
381          Field_Id :=
382            Default_Project_Node
383              (Of_Kind       => N_Literal_String,
384               In_Tree       => In_Tree,
385               And_Expr_Kind => Single);
386          Set_String_Value_Of (Field_Id, In_Tree, To => Token_Name);
387          Set_External_Reference_Of (External_Value, In_Tree, To => Field_Id);
388
389          --  Scan past the first argument
390
391          Scan (In_Tree);
392
393          case Token is
394
395             when Tok_Right_Paren =>
396                Scan (In_Tree); -- scan past right paren
397
398             when Tok_Comma =>
399                Scan (In_Tree); -- scan past comma
400
401                --  Get the string expression for the default
402
403                declare
404                   Loc : constant Source_Ptr := Token_Ptr;
405
406                begin
407                   Parse_Expression
408                     (In_Tree         => In_Tree,
409                      Expression      => Field_Id,
410                      Current_Project => Current_Project,
411                      Current_Package => Current_Package,
412                      Optional_Index  => False);
413
414                   if Expression_Kind_Of (Field_Id, In_Tree) = List then
415                      Error_Msg ("expression must be a single string", Loc);
416                   else
417                      Set_External_Default_Of
418                        (External_Value, In_Tree, To => Field_Id);
419                   end if;
420                end;
421
422                Expect (Tok_Right_Paren, "`)`");
423
424                if Token = Tok_Right_Paren then
425                   Scan (In_Tree); -- scan past right paren
426                end if;
427
428             when others =>
429                Error_Msg ("`,` or `)` expected", Token_Ptr);
430          end case;
431       end if;
432    end External_Reference;
433
434    -----------------------
435    -- Parse_Choice_List --
436    -----------------------
437
438    procedure Parse_Choice_List
439      (In_Tree      : Project_Node_Tree_Ref;
440       First_Choice : out Project_Node_Id)
441    is
442       Current_Choice : Project_Node_Id := Empty_Node;
443       Next_Choice    : Project_Node_Id := Empty_Node;
444       Choice_String  : Name_Id         := No_Name;
445       Found          : Boolean         := False;
446
447    begin
448       --  Declare the node of the first choice
449
450       First_Choice :=
451         Default_Project_Node
452           (Of_Kind       => N_Literal_String,
453            In_Tree       => In_Tree,
454            And_Expr_Kind => Single);
455
456       --  Initially Current_Choice is the same as First_Choice
457
458       Current_Choice := First_Choice;
459
460       loop
461          Expect (Tok_String_Literal, "literal string");
462          exit when Token /= Tok_String_Literal;
463          Set_Location_Of (Current_Choice, In_Tree, To => Token_Ptr);
464          Choice_String := Token_Name;
465
466          --  Give the string value to the current choice
467
468          Set_String_Value_Of (Current_Choice, In_Tree, To => Choice_String);
469
470          --  Check if the label is part of the string type and if it has not
471          --  been already used.
472
473          Found := False;
474          for Choice in Choice_First .. Choices.Last loop
475             if Choices.Table (Choice).The_String = Choice_String then
476
477                --  This label is part of the string type
478
479                Found := True;
480
481                if Choices.Table (Choice).Already_Used then
482
483                   --  But it has already appeared in a choice list for this
484                   --  case construction so report an error.
485
486                   Error_Msg_Name_1 := Choice_String;
487                   Error_Msg ("duplicate case label %%", Token_Ptr);
488
489                else
490                   Choices.Table (Choice).Already_Used := True;
491                end if;
492
493                exit;
494             end if;
495          end loop;
496
497          --  If the label is not part of the string list, report an error
498
499          if not Found then
500             Error_Msg_Name_1 := Choice_String;
501             Error_Msg ("illegal case label %%", Token_Ptr);
502          end if;
503
504          --  Scan past the label
505
506          Scan (In_Tree);
507
508          --  If there is no '|', we are done
509
510          if Token = Tok_Vertical_Bar then
511
512             --  Otherwise, declare the node of the next choice, link it to
513             --  Current_Choice and set Current_Choice to this new node.
514
515             Next_Choice :=
516               Default_Project_Node
517                 (Of_Kind       => N_Literal_String,
518                  In_Tree       => In_Tree,
519                  And_Expr_Kind => Single);
520             Set_Next_Literal_String
521               (Current_Choice, In_Tree, To => Next_Choice);
522             Current_Choice := Next_Choice;
523             Scan (In_Tree);
524          else
525             exit;
526          end if;
527       end loop;
528    end Parse_Choice_List;
529
530    ----------------------
531    -- Parse_Expression --
532    ----------------------
533
534    procedure Parse_Expression
535      (In_Tree         : Project_Node_Tree_Ref;
536       Expression      : out Project_Node_Id;
537       Current_Project : Project_Node_Id;
538       Current_Package : Project_Node_Id;
539       Optional_Index  : Boolean)
540    is
541       First_Term      : Project_Node_Id := Empty_Node;
542       Expression_Kind : Variable_Kind := Undefined;
543
544    begin
545       --  Declare the node of the expression
546
547       Expression :=
548         Default_Project_Node (Of_Kind => N_Expression, In_Tree => In_Tree);
549       Set_Location_Of (Expression, In_Tree, To => Token_Ptr);
550
551       --  Parse the term or terms of the expression
552
553       Terms (In_Tree         => In_Tree,
554              Term            => First_Term,
555              Expr_Kind       => Expression_Kind,
556              Current_Project => Current_Project,
557              Current_Package => Current_Package,
558              Optional_Index  => Optional_Index);
559
560       --  Set the first term and the expression kind
561
562       Set_First_Term (Expression, In_Tree, To => First_Term);
563       Set_Expression_Kind_Of (Expression, In_Tree, To => Expression_Kind);
564    end Parse_Expression;
565
566    ----------------------------
567    -- Parse_String_Type_List --
568    ----------------------------
569
570    procedure Parse_String_Type_List
571      (In_Tree      : Project_Node_Tree_Ref;
572       First_String : out Project_Node_Id)
573    is
574       Last_String  : Project_Node_Id := Empty_Node;
575       Next_String  : Project_Node_Id := Empty_Node;
576       String_Value : Name_Id         := No_Name;
577
578    begin
579       --  Declare the node of the first string
580
581       First_String :=
582         Default_Project_Node
583           (Of_Kind       => N_Literal_String,
584            In_Tree       => In_Tree,
585            And_Expr_Kind => Single);
586
587       --  Initially, Last_String is the same as First_String
588
589       Last_String := First_String;
590
591       loop
592          Expect (Tok_String_Literal, "literal string");
593          exit when Token /= Tok_String_Literal;
594          String_Value := Token_Name;
595
596          --  Give its string value to Last_String
597
598          Set_String_Value_Of (Last_String, In_Tree, To => String_Value);
599          Set_Location_Of (Last_String, In_Tree, To => Token_Ptr);
600
601          --  Now, check if the string is already part of the string type
602
603          declare
604             Current : Project_Node_Id := First_String;
605
606          begin
607             while Current /= Last_String loop
608                if String_Value_Of (Current, In_Tree) = String_Value then
609
610                   --  This is a repetition, report an error
611
612                   Error_Msg_Name_1 := String_Value;
613                   Error_Msg ("duplicate value %% in type", Token_Ptr);
614                   exit;
615                end if;
616
617                Current := Next_Literal_String (Current, In_Tree);
618             end loop;
619          end;
620
621          --  Scan past the literal string
622
623          Scan (In_Tree);
624
625          --  If there is no comma following the literal string, we are done
626
627          if Token /= Tok_Comma then
628             exit;
629
630          else
631             --  Declare the next string, link it to Last_String and set
632             --  Last_String to its node.
633
634             Next_String :=
635               Default_Project_Node
636                 (Of_Kind       => N_Literal_String,
637                  In_Tree       => In_Tree,
638                  And_Expr_Kind => Single);
639             Set_Next_Literal_String (Last_String, In_Tree, To => Next_String);
640             Last_String := Next_String;
641             Scan (In_Tree);
642          end if;
643       end loop;
644    end Parse_String_Type_List;
645
646    ------------------------------
647    -- Parse_Variable_Reference --
648    ------------------------------
649
650    procedure Parse_Variable_Reference
651      (In_Tree         : Project_Node_Tree_Ref;
652       Variable        : out Project_Node_Id;
653       Current_Project : Project_Node_Id;
654       Current_Package : Project_Node_Id)
655    is
656       Current_Variable : Project_Node_Id := Empty_Node;
657
658       The_Package : Project_Node_Id := Current_Package;
659       The_Project : Project_Node_Id := Current_Project;
660
661       Specified_Project : Project_Node_Id   := Empty_Node;
662       Specified_Package : Project_Node_Id   := Empty_Node;
663       Look_For_Variable : Boolean           := True;
664       First_Attribute   : Attribute_Node_Id := Empty_Attribute;
665       Variable_Name     : Name_Id;
666
667    begin
668       Names.Init;
669
670       loop
671          Expect (Tok_Identifier, "identifier");
672
673          if Token /= Tok_Identifier then
674             Look_For_Variable := False;
675             exit;
676          end if;
677
678          Add_To_Names (NL => (Name => Token_Name, Location => Token_Ptr));
679          Scan (In_Tree);
680          exit when Token /= Tok_Dot;
681          Scan (In_Tree);
682       end loop;
683
684       if Look_For_Variable then
685
686          if Token = Tok_Apostrophe then
687
688             --  Attribute reference
689
690             case Names.Last is
691                when 0 =>
692
693                   --  Cannot happen
694
695                   null;
696
697                when 1 =>
698                   --  This may be a project name or a package name.
699                   --  Project name have precedence.
700
701                   --  First, look if it can be a package name
702
703                   First_Attribute :=
704                     First_Attribute_Of
705                       (Package_Node_Id_Of (Names.Table (1).Name));
706
707                   --  Now, look if it can be a project name
708
709                   if Names.Table (1).Name =
710                        Name_Of (Current_Project, In_Tree)
711                   then
712                      The_Project := Current_Project;
713
714                   else
715                      The_Project :=
716                        Imported_Or_Extended_Project_Of
717                          (Current_Project, In_Tree, Names.Table (1).Name);
718                   end if;
719
720                   if The_Project = Empty_Node then
721
722                      --  If it is neither a project name nor a package name,
723                      --  report an error.
724
725                      if First_Attribute = Empty_Attribute then
726                         Error_Msg_Name_1 := Names.Table (1).Name;
727                         Error_Msg ("unknown project %",
728                                    Names.Table (1).Location);
729                         First_Attribute := Attribute_First;
730
731                      else
732                         --  If it is a package name, check if the package has
733                         --  already been declared in the current project.
734
735                         The_Package :=
736                           First_Package_Of (Current_Project, In_Tree);
737
738                         while The_Package /= Empty_Node
739                           and then Name_Of (The_Package, In_Tree) /=
740                                                       Names.Table (1).Name
741                         loop
742                            The_Package :=
743                              Next_Package_In_Project (The_Package, In_Tree);
744                         end loop;
745
746                         --  If it has not been already declared, report an
747                         --  error.
748
749                         if The_Package = Empty_Node then
750                            Error_Msg_Name_1 := Names.Table (1).Name;
751                            Error_Msg ("package % not yet defined",
752                                       Names.Table (1).Location);
753                         end if;
754                      end if;
755
756                   else
757                      --  It is a project name
758
759                      First_Attribute := Attribute_First;
760                      The_Package     := Empty_Node;
761                   end if;
762
763                when others =>
764
765                   --  We have either a project name made of several simple
766                   --  names (long project), or a project name (short project)
767                   --  followed by a package name. The long project name has
768                   --  precedence.
769
770                   declare
771                      Short_Project : Name_Id;
772                      Long_Project  : Name_Id;
773
774                   begin
775                      --  Clear the Buffer
776
777                      Buffer_Last := 0;
778
779                      --  Get the name of the short project
780
781                      for Index in 1 .. Names.Last - 1 loop
782                         Add_To_Buffer
783                           (Get_Name_String (Names.Table (Index).Name),
784                            Buffer, Buffer_Last);
785
786                         if Index /= Names.Last - 1 then
787                            Add_To_Buffer (".", Buffer, Buffer_Last);
788                         end if;
789                      end loop;
790
791                      Name_Len := Buffer_Last;
792                      Name_Buffer (1 .. Buffer_Last) :=
793                        Buffer (1 .. Buffer_Last);
794                      Short_Project := Name_Find;
795
796                      --  Now, add the last simple name to get the name of the
797                      --  long project.
798
799                      Add_To_Buffer (".", Buffer, Buffer_Last);
800                      Add_To_Buffer
801                        (Get_Name_String (Names.Table (Names.Last).Name),
802                         Buffer, Buffer_Last);
803                      Name_Len := Buffer_Last;
804                      Name_Buffer (1 .. Buffer_Last) :=
805                        Buffer (1 .. Buffer_Last);
806                      Long_Project := Name_Find;
807
808                      --  Check if the long project is imported or extended
809
810                      if Long_Project = Name_Of (Current_Project, In_Tree) then
811                         The_Project := Current_Project;
812
813                      else
814                         The_Project :=
815                           Imported_Or_Extended_Project_Of
816                             (Current_Project,
817                              In_Tree,
818                              Long_Project);
819                      end if;
820
821                      --  If the long project exists, then this is the prefix
822                      --  of the attribute.
823
824                      if The_Project /= Empty_Node then
825                         First_Attribute := Attribute_First;
826                         The_Package     := Empty_Node;
827
828                      else
829                         --  Otherwise, check if the short project is imported
830                         --  or extended.
831
832                         if Short_Project =
833                              Name_Of (Current_Project, In_Tree)
834                         then
835                            The_Project := Current_Project;
836
837                         else
838                            The_Project := Imported_Or_Extended_Project_Of
839                                             (Current_Project, In_Tree,
840                                              Short_Project);
841                         end if;
842
843                         --  If short project does not exist, report an error
844
845                         if The_Project = Empty_Node then
846                            Error_Msg_Name_1 := Long_Project;
847                            Error_Msg_Name_2 := Short_Project;
848                            Error_Msg ("unknown projects % or %",
849                                       Names.Table (1).Location);
850                            The_Package := Empty_Node;
851                            First_Attribute := Attribute_First;
852
853                         else
854                            --  Now, we check if the package has been declared
855                            --  in this project.
856
857                            The_Package :=
858                              First_Package_Of (The_Project, In_Tree);
859                            while The_Package /= Empty_Node
860                              and then Name_Of (The_Package, In_Tree) /=
861                              Names.Table (Names.Last).Name
862                            loop
863                               The_Package :=
864                                 Next_Package_In_Project (The_Package, In_Tree);
865                            end loop;
866
867                            --  If it has not, then we report an error
868
869                            if The_Package = Empty_Node then
870                               Error_Msg_Name_1 :=
871                                 Names.Table (Names.Last).Name;
872                               Error_Msg_Name_2 := Short_Project;
873                               Error_Msg ("package % not declared in project %",
874                                          Names.Table (Names.Last).Location);
875                               First_Attribute := Attribute_First;
876
877                            else
878                               --  Otherwise, we have the correct project and
879                               --  package.
880
881                               First_Attribute :=
882                                 First_Attribute_Of
883                                   (Package_Id_Of (The_Package, In_Tree));
884                            end if;
885                         end if;
886                      end if;
887                   end;
888             end case;
889
890             Attribute_Reference
891               (In_Tree,
892                Variable,
893                Current_Project => The_Project,
894                Current_Package => The_Package,
895                First_Attribute => First_Attribute);
896             return;
897          end if;
898       end if;
899
900       Variable :=
901         Default_Project_Node
902           (Of_Kind => N_Variable_Reference, In_Tree => In_Tree);
903
904       if Look_For_Variable then
905          case Names.Last is
906             when 0 =>
907
908                --  Cannot happen (so why null instead of raise PE???)
909
910                null;
911
912             when 1 =>
913
914                --  Simple variable name
915
916                Set_Name_Of (Variable, In_Tree, To => Names.Table (1).Name);
917
918             when 2 =>
919
920                --  Variable name with a simple name prefix that can be
921                --  a project name or a package name. Project names have
922                --  priority over package names.
923
924                Set_Name_Of (Variable, In_Tree, To => Names.Table (2).Name);
925
926                --  Check if it can be a package name
927
928                The_Package := First_Package_Of (Current_Project, In_Tree);
929
930                while The_Package /= Empty_Node
931                  and then Name_Of (The_Package, In_Tree) /=
932                             Names.Table (1).Name
933                loop
934                   The_Package :=
935                     Next_Package_In_Project (The_Package, In_Tree);
936                end loop;
937
938                --  Now look for a possible project name
939
940                The_Project := Imported_Or_Extended_Project_Of
941                               (Current_Project, In_Tree, Names.Table (1).Name);
942
943                if The_Project /= Empty_Node then
944                   Specified_Project := The_Project;
945
946                elsif The_Package = Empty_Node then
947                   Error_Msg_Name_1 := Names.Table (1).Name;
948                   Error_Msg ("unknown package or project %",
949                              Names.Table (1).Location);
950                   Look_For_Variable := False;
951
952                else
953                   Specified_Package := The_Package;
954                end if;
955
956             when others =>
957
958                --  Variable name with a prefix that is either a project name
959                --  made of several simple names, or a project name followed
960                --  by a package name.
961
962                Set_Name_Of
963                  (Variable, In_Tree, To => Names.Table (Names.Last).Name);
964
965                declare
966                   Short_Project : Name_Id;
967                   Long_Project  : Name_Id;
968
969                begin
970                   --  First, we get the two possible project names
971
972                   --  Clear the buffer
973
974                   Buffer_Last := 0;
975
976                   --  Add all the simple names, except the last two
977
978                   for Index in 1 .. Names.Last - 2 loop
979                      Add_To_Buffer
980                        (Get_Name_String (Names.Table (Index).Name),
981                         Buffer, Buffer_Last);
982
983                      if Index /= Names.Last - 2 then
984                         Add_To_Buffer (".", Buffer, Buffer_Last);
985                      end if;
986                   end loop;
987
988                   Name_Len := Buffer_Last;
989                   Name_Buffer (1 .. Name_Len) := Buffer (1 .. Buffer_Last);
990                   Short_Project := Name_Find;
991
992                   --  Add the simple name before the name of the variable
993
994                   Add_To_Buffer (".", Buffer, Buffer_Last);
995                   Add_To_Buffer
996                     (Get_Name_String (Names.Table (Names.Last - 1).Name),
997                      Buffer, Buffer_Last);
998                   Name_Len := Buffer_Last;
999                   Name_Buffer (1 .. Name_Len) := Buffer (1 .. Buffer_Last);
1000                   Long_Project := Name_Find;
1001
1002                   --  Check if the prefix is the name of an imported or
1003                   --  extended project.
1004
1005                   The_Project := Imported_Or_Extended_Project_Of
1006                                    (Current_Project, In_Tree, Long_Project);
1007
1008                   if The_Project /= Empty_Node then
1009                      Specified_Project := The_Project;
1010
1011                   else
1012                      --  Now check if the prefix may be a project name followed
1013                      --  by a package name.
1014
1015                      --  First check for a possible project name
1016
1017                      The_Project :=
1018                        Imported_Or_Extended_Project_Of
1019                          (Current_Project, In_Tree, Short_Project);
1020
1021                      if The_Project = Empty_Node then
1022                         --  Unknown prefix, report an error
1023
1024                         Error_Msg_Name_1 := Long_Project;
1025                         Error_Msg_Name_2 := Short_Project;
1026                         Error_Msg
1027                           ("unknown projects % or %",
1028                            Names.Table (1).Location);
1029                         Look_For_Variable := False;
1030
1031                      else
1032                         Specified_Project := The_Project;
1033
1034                         --  Now look for the package in this project
1035
1036                         The_Package := First_Package_Of (The_Project, In_Tree);
1037
1038                         while The_Package /= Empty_Node
1039                           and then Name_Of (The_Package, In_Tree) /=
1040                                               Names.Table (Names.Last - 1).Name
1041                         loop
1042                            The_Package :=
1043                              Next_Package_In_Project (The_Package, In_Tree);
1044                         end loop;
1045
1046                         if The_Package = Empty_Node then
1047
1048                            --  The package does not exist, report an error
1049
1050                            Error_Msg_Name_1 := Names.Table (2).Name;
1051                            Error_Msg ("unknown package %",
1052                                    Names.Table (Names.Last - 1).Location);
1053                            Look_For_Variable := False;
1054
1055                         else
1056                            Specified_Package := The_Package;
1057                         end if;
1058                      end if;
1059                   end if;
1060                end;
1061          end case;
1062       end if;
1063
1064       if Look_For_Variable then
1065          Variable_Name := Name_Of (Variable, In_Tree);
1066          Set_Project_Node_Of (Variable, In_Tree, To => Specified_Project);
1067          Set_Package_Node_Of (Variable, In_Tree, To => Specified_Package);
1068
1069          if Specified_Project /= Empty_Node then
1070             The_Project := Specified_Project;
1071          else
1072             The_Project := Current_Project;
1073          end if;
1074
1075          Current_Variable := Empty_Node;
1076
1077          --  Look for this variable
1078
1079          --  If a package was specified, check if the variable has been
1080          --  declared in this package.
1081
1082          if Specified_Package /= Empty_Node then
1083             Current_Variable :=
1084               First_Variable_Of (Specified_Package, In_Tree);
1085             while Current_Variable /= Empty_Node
1086               and then
1087               Name_Of (Current_Variable, In_Tree) /= Variable_Name
1088             loop
1089                Current_Variable := Next_Variable (Current_Variable, In_Tree);
1090             end loop;
1091
1092          else
1093             --  Otherwise, if no project has been specified and we are in
1094             --  a package, first check if the variable has been declared in
1095             --  the package.
1096
1097             if Specified_Project = Empty_Node
1098               and then Current_Package /= Empty_Node
1099             then
1100                Current_Variable :=
1101                  First_Variable_Of (Current_Package, In_Tree);
1102                while Current_Variable /= Empty_Node
1103                  and then Name_Of (Current_Variable, In_Tree) /= Variable_Name
1104                loop
1105                   Current_Variable :=
1106                     Next_Variable (Current_Variable, In_Tree);
1107                end loop;
1108             end if;
1109
1110             --  If we have not found the variable in the package, check if the
1111             --  variable has been declared in the project.
1112
1113             if Current_Variable = Empty_Node then
1114                Current_Variable := First_Variable_Of (The_Project, In_Tree);
1115                while Current_Variable /= Empty_Node
1116                  and then Name_Of (Current_Variable, In_Tree) /= Variable_Name
1117                loop
1118                   Current_Variable :=
1119                     Next_Variable (Current_Variable, In_Tree);
1120                end loop;
1121             end if;
1122          end if;
1123
1124          --  If the variable was not found, report an error
1125
1126          if Current_Variable = Empty_Node then
1127             Error_Msg_Name_1 := Variable_Name;
1128             Error_Msg
1129               ("unknown variable %", Names.Table (Names.Last).Location);
1130          end if;
1131       end if;
1132
1133       if Current_Variable /= Empty_Node then
1134          Set_Expression_Kind_Of
1135            (Variable, In_Tree,
1136             To => Expression_Kind_Of (Current_Variable, In_Tree));
1137
1138          if Kind_Of (Current_Variable, In_Tree) =
1139                                       N_Typed_Variable_Declaration
1140          then
1141             Set_String_Type_Of
1142               (Variable, In_Tree,
1143                To => String_Type_Of (Current_Variable, In_Tree));
1144          end if;
1145       end if;
1146
1147       --  If the variable is followed by a left parenthesis, report an error
1148       --  but attempt to scan the index.
1149
1150       if Token = Tok_Left_Paren then
1151          Error_Msg ("\variables cannot be associative arrays", Token_Ptr);
1152          Scan (In_Tree);
1153          Expect (Tok_String_Literal, "literal string");
1154
1155          if Token = Tok_String_Literal then
1156             Scan (In_Tree);
1157             Expect (Tok_Right_Paren, "`)`");
1158
1159             if Token = Tok_Right_Paren then
1160                Scan (In_Tree);
1161             end if;
1162          end if;
1163       end if;
1164    end Parse_Variable_Reference;
1165
1166    ---------------------------------
1167    -- Start_New_Case_Construction --
1168    ---------------------------------
1169
1170    procedure Start_New_Case_Construction
1171      (In_Tree      : Project_Node_Tree_Ref;
1172       String_Type  : Project_Node_Id)
1173    is
1174       Current_String : Project_Node_Id;
1175
1176    begin
1177       --  Set Choice_First, depending on whether this is the first case
1178       --  construction or not.
1179
1180       if Choice_First = 0 then
1181          Choice_First := 1;
1182          Choices.Set_Last (First_Choice_Node_Id);
1183       else
1184          Choice_First := Choices.Last + 1;
1185       end if;
1186
1187       --  Add the literal of the string type to the Choices table
1188
1189       if String_Type /= Empty_Node then
1190          Current_String := First_Literal_String (String_Type, In_Tree);
1191          while Current_String /= Empty_Node loop
1192             Add (This_String => String_Value_Of (Current_String, In_Tree));
1193             Current_String := Next_Literal_String (Current_String, In_Tree);
1194          end loop;
1195       end if;
1196
1197       --  Set the value of the last choice in table Choice_Lasts
1198
1199       Choice_Lasts.Increment_Last;
1200       Choice_Lasts.Table (Choice_Lasts.Last) := Choices.Last;
1201    end Start_New_Case_Construction;
1202
1203    -----------
1204    -- Terms --
1205    -----------
1206
1207    procedure Terms
1208      (In_Tree         : Project_Node_Tree_Ref;
1209       Term            : out Project_Node_Id;
1210       Expr_Kind       : in out Variable_Kind;
1211       Current_Project : Project_Node_Id;
1212       Current_Package : Project_Node_Id;
1213       Optional_Index  : Boolean)
1214    is
1215       Next_Term          : Project_Node_Id := Empty_Node;
1216       Term_Id            : Project_Node_Id := Empty_Node;
1217       Current_Expression : Project_Node_Id := Empty_Node;
1218       Next_Expression    : Project_Node_Id := Empty_Node;
1219       Current_Location   : Source_Ptr      := No_Location;
1220       Reference          : Project_Node_Id := Empty_Node;
1221
1222    begin
1223       --  Declare a new node for the term
1224
1225       Term := Default_Project_Node (Of_Kind => N_Term, In_Tree => In_Tree);
1226       Set_Location_Of (Term, In_Tree, To => Token_Ptr);
1227
1228       case Token is
1229          when Tok_Left_Paren =>
1230
1231             --  If we have a left parenthesis and we don't know the expression
1232             --  kind, then this is a string list.
1233
1234             case Expr_Kind is
1235                when Undefined =>
1236                   Expr_Kind := List;
1237
1238                when List =>
1239                   null;
1240
1241                when Single =>
1242
1243                   --  If we already know that this is a single string, report
1244                   --  an error, but set the expression kind to string list to
1245                   --  avoid several errors.
1246
1247                   Expr_Kind := List;
1248                   Error_Msg
1249                     ("literal string list cannot appear in a string",
1250                      Token_Ptr);
1251             end case;
1252
1253             --  Declare a new node for this literal string list
1254
1255             Term_Id := Default_Project_Node
1256               (Of_Kind       => N_Literal_String_List,
1257                In_Tree       => In_Tree,
1258                And_Expr_Kind => List);
1259             Set_Current_Term (Term, In_Tree, To => Term_Id);
1260             Set_Location_Of  (Term, In_Tree, To => Token_Ptr);
1261
1262             --  Scan past the left parenthesis
1263
1264             Scan (In_Tree);
1265
1266             --  If the left parenthesis is immediately followed by a right
1267             --  parenthesis, the literal string list is empty.
1268
1269             if Token = Tok_Right_Paren then
1270                Scan (In_Tree);
1271
1272             else
1273                --  Otherwise parse the expression(s) in the literal string list
1274
1275                loop
1276                   Current_Location := Token_Ptr;
1277                   Parse_Expression
1278                     (In_Tree         => In_Tree,
1279                      Expression      => Next_Expression,
1280                      Current_Project => Current_Project,
1281                      Current_Package => Current_Package,
1282                      Optional_Index  => Optional_Index);
1283
1284                   --  The expression kind is String list, report an error
1285
1286                   if Expression_Kind_Of (Next_Expression, In_Tree) = List then
1287                      Error_Msg ("single expression expected",
1288                                 Current_Location);
1289                   end if;
1290
1291                   --  If Current_Expression is empty, it means that the
1292                   --  expression is the first in the string list.
1293
1294                   if Current_Expression = Empty_Node then
1295                      Set_First_Expression_In_List
1296                        (Term_Id, In_Tree, To => Next_Expression);
1297                   else
1298                      Set_Next_Expression_In_List
1299                        (Current_Expression, In_Tree, To => Next_Expression);
1300                   end if;
1301
1302                   Current_Expression := Next_Expression;
1303
1304                   --  If there is a comma, continue with the next expression
1305
1306                   exit when Token /= Tok_Comma;
1307                   Scan (In_Tree); -- past the comma
1308                end loop;
1309
1310                --  We expect a closing right parenthesis
1311
1312                Expect (Tok_Right_Paren, "`)`");
1313
1314                if Token = Tok_Right_Paren then
1315                   Scan (In_Tree);
1316                end if;
1317             end if;
1318
1319          when Tok_String_Literal =>
1320
1321             --  If we don't know the expression kind (first term), then it is
1322             --  a simple string.
1323
1324             if Expr_Kind = Undefined then
1325                Expr_Kind := Single;
1326             end if;
1327
1328             --  Declare a new node for the string literal
1329
1330             Term_Id :=
1331               Default_Project_Node
1332                 (Of_Kind => N_Literal_String, In_Tree => In_Tree);
1333             Set_Current_Term (Term, In_Tree, To => Term_Id);
1334             Set_String_Value_Of (Term_Id, In_Tree, To => Token_Name);
1335
1336             --  Scan past the string literal
1337
1338             Scan (In_Tree);
1339
1340             --  Check for possible index expression
1341
1342             if Token = Tok_At then
1343                if not Optional_Index then
1344                   Error_Msg ("index not allowed here", Token_Ptr);
1345                   Scan (In_Tree);
1346
1347                   if Token = Tok_Integer_Literal then
1348                      Scan (In_Tree);
1349                   end if;
1350
1351                --  Set the index value
1352
1353                else
1354                   Scan (In_Tree);
1355                   Expect (Tok_Integer_Literal, "integer literal");
1356
1357                   if Token = Tok_Integer_Literal then
1358                      declare
1359                         Index : constant Int := UI_To_Int (Int_Literal_Value);
1360                      begin
1361                         if Index = 0 then
1362                            Error_Msg ("index cannot be zero", Token_Ptr);
1363                         else
1364                            Set_Source_Index_Of
1365                              (Term_Id, In_Tree, To => Index);
1366                         end if;
1367                      end;
1368
1369                      Scan (In_Tree);
1370                   end if;
1371                end if;
1372             end if;
1373
1374          when Tok_Identifier =>
1375             Current_Location := Token_Ptr;
1376
1377             --  Get the variable or attribute reference
1378
1379             Parse_Variable_Reference
1380               (In_Tree         => In_Tree,
1381                Variable        => Reference,
1382                Current_Project => Current_Project,
1383                Current_Package => Current_Package);
1384             Set_Current_Term (Term, In_Tree, To => Reference);
1385
1386             if Reference /= Empty_Node then
1387
1388                --  If we don't know the expression kind (first term), then it
1389                --  has the kind of the variable or attribute reference.
1390
1391                if Expr_Kind = Undefined then
1392                   Expr_Kind := Expression_Kind_Of (Reference, In_Tree);
1393
1394                elsif Expr_Kind = Single
1395                  and then Expression_Kind_Of (Reference, In_Tree) = List
1396                then
1397                   --  If the expression is a single list, and the reference is
1398                   --  a string list, report an error, and set the expression
1399                   --  kind to string list to avoid multiple errors.
1400
1401                   Expr_Kind := List;
1402                   Error_Msg
1403                     ("list variable cannot appear in single string expression",
1404                      Current_Location);
1405                end if;
1406             end if;
1407
1408          when Tok_Project =>
1409
1410             --  Project can appear in an expression as the prefix of an
1411             --  attribute reference of the current project.
1412
1413             Current_Location := Token_Ptr;
1414             Scan (In_Tree);
1415             Expect (Tok_Apostrophe, "`'`");
1416
1417             if Token = Tok_Apostrophe then
1418                Attribute_Reference
1419                  (In_Tree         => In_Tree,
1420                   Reference       => Reference,
1421                   First_Attribute => Prj.Attr.Attribute_First,
1422                   Current_Project => Current_Project,
1423                   Current_Package => Empty_Node);
1424                Set_Current_Term (Term, In_Tree, To => Reference);
1425             end if;
1426
1427             --  Same checks as above for the expression kind
1428
1429             if Reference /= Empty_Node then
1430                if Expr_Kind = Undefined then
1431                   Expr_Kind := Expression_Kind_Of (Reference, In_Tree);
1432
1433                elsif Expr_Kind = Single
1434                  and then Expression_Kind_Of (Reference, In_Tree) = List
1435                then
1436                   Error_Msg
1437                     ("lists cannot appear in single string expression",
1438                      Current_Location);
1439                end if;
1440             end if;
1441
1442          when Tok_External =>
1443
1444             --  An external reference is always a single string
1445
1446             if Expr_Kind = Undefined then
1447                Expr_Kind := Single;
1448             end if;
1449
1450             External_Reference
1451               (In_Tree         => In_Tree,
1452                Current_Project => Current_Project,
1453                Current_Package => Current_Package,
1454                External_Value  => Reference);
1455             Set_Current_Term (Term, In_Tree, To => Reference);
1456
1457          when others =>
1458             Error_Msg ("cannot be part of an expression", Token_Ptr);
1459             Term := Empty_Node;
1460             return;
1461       end case;
1462
1463       --  If there is an '&', call Terms recursively
1464
1465       if Token = Tok_Ampersand then
1466          Scan (In_Tree); -- scan past ampersand
1467
1468          Terms
1469            (In_Tree         => In_Tree,
1470             Term            => Next_Term,
1471             Expr_Kind       => Expr_Kind,
1472             Current_Project => Current_Project,
1473             Current_Package => Current_Package,
1474             Optional_Index  => Optional_Index);
1475
1476          --  And link the next term to this term
1477
1478          Set_Next_Term (Term, In_Tree, To => Next_Term);
1479       end if;
1480    end Terms;
1481
1482 end Prj.Strt;