summaryrefslogtreecommitdiff
path: root/gcc/ada/prj-strt.adb
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/ada/prj-strt.adb')
-rw-r--r--gcc/ada/prj-strt.adb778
1 files changed, 550 insertions, 228 deletions
diff --git a/gcc/ada/prj-strt.adb b/gcc/ada/prj-strt.adb
index 0fda16feceb..1d1d1a8cb5d 100644
--- a/gcc/ada/prj-strt.adb
+++ b/gcc/ada/prj-strt.adb
@@ -6,7 +6,7 @@
-- --
-- B o d y --
-- --
--- Copyright (C) 2001-2002 Free Software Foundation, Inc. --
+-- Copyright (C) 2001-2003 Free Software Foundation, Inc. --
-- --
-- GNAT is free software; you can redistribute it and/or modify it under --
-- terms of the GNU General Public License as published by the Free Soft- --
@@ -24,45 +24,31 @@
-- --
------------------------------------------------------------------------------
-with Errout; use Errout;
+with Err_Vars; use Err_Vars;
with Namet; use Namet;
with Prj.Attr; use Prj.Attr;
+with Prj.Err; use Prj.Err;
with Prj.Tree; use Prj.Tree;
with Scans; use Scans;
-with Sinfo; use Sinfo;
-with Stringt; use Stringt;
+with Snames;
with Table;
with Types; use Types;
package body Prj.Strt is
- type Name_Location is record
- Name : Name_Id := No_Name;
- Location : Source_Ptr := No_Location;
- end record;
- -- Store the identifier and the location of a simple name
-
- type Name_Range is range 0 .. 3;
- subtype Name_Index is Name_Range range 1 .. Name_Range'Last;
- -- A Name may contain up to 3 simple names
-
- type Names is array (Name_Index) of Name_Location;
- -- Used to store 1 to 3 simple_names. 2 simple names are for
- -- <project>.<package>, <project>.<variable> or <package>.<variable>.
- -- 3 simple names are for <project>.<package>.<variable>.
-
type Choice_String is record
- The_String : String_Id;
+ The_String : Name_Id;
Already_Used : Boolean := False;
end record;
-- The string of a case label, and an indication that it has already
-- been used (to avoid duplicate case labels).
Choices_Initial : constant := 10;
- Choices_Increment : constant := 10;
+ Choices_Increment : constant := 50;
Choice_Node_Low_Bound : constant := 0;
- Choice_Node_High_Bound : constant := 099_999_999; -- In practice, infinite
+ Choice_Node_High_Bound : constant := 099_999_999;
+ -- In practice, infinite
type Choice_Node_Id is
range Choice_Node_Low_Bound .. Choice_Node_High_Bound;
@@ -83,21 +69,38 @@ package body Prj.Strt is
new Table.Table (Table_Component_Type => Choice_Node_Id,
Table_Index_Type => Nat,
Table_Low_Bound => 1,
- Table_Initial => 3,
- Table_Increment => 3,
+ Table_Initial => 10,
+ Table_Increment => 100,
Table_Name => "Prj.Strt.Choice_Lasts");
-- Used to store the indices of the choices in table Choices,
-- to distinguish nested case constructions.
Choice_First : Choice_Node_Id := 0;
-- Index in table Choices of the first case label of the current
- -- case construction.
- -- 0 means no current case construction.
+ -- case construction. Zero means no current case construction.
+
+ type Name_Location is record
+ Name : Name_Id := No_Name;
+ Location : Source_Ptr := No_Location;
+ end record;
+ -- Store the identifier and the location of a simple name
+
+ package Names is
+ new Table.Table (Table_Component_Type => Name_Location,
+ Table_Index_Type => Nat,
+ Table_Low_Bound => 1,
+ Table_Initial => 10,
+ Table_Increment => 100,
+ Table_Name => "Prj.Strt.Names");
+ -- Used to accumulate the single names of a name
- procedure Add (This_String : String_Id);
+ procedure Add (This_String : Name_Id);
-- Add a string to the case label list, indicating that it has not
-- yet been used.
+ procedure Add_To_Names (NL : Name_Location);
+ -- Add one single names to table Names
+
procedure External_Reference (External_Value : out Project_Node_Id);
-- Parse an external reference. Current token is "external".
@@ -120,7 +123,7 @@ package body Prj.Strt is
-- Add --
---------
- procedure Add (This_String : String_Id) is
+ procedure Add (This_String : Name_Id) is
begin
Choices.Increment_Last;
Choices.Table (Choices.Last) :=
@@ -128,6 +131,16 @@ package body Prj.Strt is
Already_Used => False);
end Add;
+ ------------------
+ -- Add_To_Names --
+ ------------------
+
+ procedure Add_To_Names (NL : Name_Location) is
+ begin
+ Names.Increment_Last;
+ Names.Table (Names.Last) := NL;
+ end Add_To_Names;
+
-------------------------
-- Attribute_Reference --
-------------------------
@@ -141,14 +154,27 @@ package body Prj.Strt is
Current_Attribute : Attribute_Node_Id := First_Attribute;
begin
+ -- Declare the node of the attribute reference
+
Reference := Default_Project_Node (Of_Kind => N_Attribute_Reference);
Set_Location_Of (Reference, To => Token_Ptr);
Scan; -- past apostrophe
- Expect (Tok_Identifier, "Identifier");
+
+ -- Body may be an attribute name
+
+ if Token = Tok_Body then
+ Token := Tok_Identifier;
+ Token_Name := Snames.Name_Body;
+ end if;
+
+ Expect (Tok_Identifier, "identifier");
if Token = Tok_Identifier then
Set_Name_Of (Reference, To => Token_Name);
+ -- Check if the identifier is one of the attribute identifiers in the
+ -- context (package or project level attributes).
+
while Current_Attribute /= Empty_Attribute
and then
Attributes.Table (Current_Attribute).Name /= Token_Name
@@ -156,12 +182,20 @@ package body Prj.Strt is
Current_Attribute := Attributes.Table (Current_Attribute).Next;
end loop;
+ -- If the identifier is not allowed, report an error
+
if Current_Attribute = Empty_Attribute then
Error_Msg_Name_1 := Token_Name;
Error_Msg ("unknown attribute %", Token_Ptr);
Reference := Empty_Node;
+ -- Scan past the attribute name
+
+ Scan;
+
else
+ -- Give its characteristics to this attribute reference
+
Set_Project_Node_Of (Reference, To => Current_Project);
Set_Package_Node_Of (Reference, To => Current_Package);
Set_Expression_Kind_Of
@@ -169,10 +203,15 @@ package body Prj.Strt is
Set_Case_Insensitive
(Reference, To => Attributes.Table (Current_Attribute).Kind_2 =
Case_Insensitive_Associative_Array);
+
+ -- Scan past the attribute name
+
Scan;
+ -- If the attribute is an associative array, get the index
+
if Attributes.Table (Current_Attribute).Kind_2 /= Single then
- Expect (Tok_Left_Paren, "(");
+ Expect (Tok_Left_Paren, "`(`");
if Token = Tok_Left_Paren then
Scan;
@@ -180,9 +219,9 @@ package body Prj.Strt is
if Token = Tok_String_Literal then
Set_Associative_Array_Index_Of
- (Reference, To => Strval (Token_Node));
+ (Reference, To => Token_Name);
Scan;
- Expect (Tok_Right_Paren, ")");
+ Expect (Tok_Right_Paren, "`)`");
if Token = Tok_Right_Paren then
Scan;
@@ -191,6 +230,27 @@ package body Prj.Strt is
end if;
end if;
end if;
+
+ -- Change name of obsolete attributes
+
+ if Reference /= Empty_Node then
+ case Name_Of (Reference) is
+ when Snames.Name_Specification =>
+ Set_Name_Of (Reference, To => Snames.Name_Spec);
+
+ when Snames.Name_Specification_Suffix =>
+ Set_Name_Of (Reference, To => Snames.Name_Spec_Suffix);
+
+ when Snames.Name_Implementation =>
+ Set_Name_Of (Reference, To => Snames.Name_Body);
+
+ when Snames.Name_Implementation_Suffix =>
+ Set_Name_Of (Reference, To => Snames.Name_Body_Suffix);
+
+ when others =>
+ null;
+ end case;
+ end if;
end if;
end Attribute_Reference;
@@ -200,17 +260,24 @@ package body Prj.Strt is
procedure End_Case_Construction is
begin
+ -- If this is the only case construction, empty the tables
+
if Choice_Lasts.Last = 1 then
Choice_Lasts.Set_Last (0);
Choices.Set_Last (First_Choice_Node_Id);
Choice_First := 0;
elsif Choice_Lasts.Last = 2 then
+ -- This is the second case onstruction, set the tables to the first
+
Choice_Lasts.Set_Last (1);
Choices.Set_Last (Choice_Lasts.Table (1));
Choice_First := 1;
else
+ -- This is the 3rd or more case construction, set the tables to the
+ -- previous one.
+
Choice_Lasts.Decrement_Last;
Choices.Set_Last (Choice_Lasts.Table (Choice_Lasts.Last));
Choice_First := Choice_Lasts.Table (Choice_Lasts.Last - 1) + 1;
@@ -235,7 +302,7 @@ package body Prj.Strt is
-- Get the left parenthesis
Scan;
- Expect (Tok_Left_Paren, "(");
+ Expect (Tok_Left_Paren, "`(`");
-- Scan past the left parenthesis
@@ -251,7 +318,7 @@ package body Prj.Strt is
Field_Id :=
Default_Project_Node (Of_Kind => N_Literal_String,
And_Expr_Kind => Single);
- Set_String_Value_Of (Field_Id, To => Strval (Token_Node));
+ Set_String_Value_Of (Field_Id, To => Token_Name);
Set_External_Reference_Of (External_Value, To => Field_Id);
-- Scan past the first argument
@@ -279,10 +346,10 @@ package body Prj.Strt is
Field_Id :=
Default_Project_Node (Of_Kind => N_Literal_String,
And_Expr_Kind => Single);
- Set_String_Value_Of (Field_Id, To => Strval (Token_Node));
+ Set_String_Value_Of (Field_Id, To => Token_Name);
Set_External_Default_Of (External_Value, To => Field_Id);
Scan;
- Expect (Tok_Right_Paren, ")");
+ Expect (Tok_Right_Paren, "`)`");
end if;
-- Scan past the right parenthesis
@@ -291,7 +358,7 @@ package body Prj.Strt is
end if;
when others =>
- Error_Msg ("',' or ')' expected", Token_Ptr);
+ Error_Msg ("`,` or `)` expected", Token_Ptr);
end case;
end if;
end External_Reference;
@@ -303,32 +370,45 @@ package body Prj.Strt is
procedure Parse_Choice_List (First_Choice : out Project_Node_Id) is
Current_Choice : Project_Node_Id := Empty_Node;
Next_Choice : Project_Node_Id := Empty_Node;
- Choice_String : String_Id := No_String;
+ Choice_String : Name_Id := No_Name;
Found : Boolean := False;
begin
+ -- Declare the node of the first choice
+
First_Choice :=
Default_Project_Node (Of_Kind => N_Literal_String,
And_Expr_Kind => Single);
+
+ -- Initially Current_Choice is the same as First_Choice
+
Current_Choice := First_Choice;
loop
Expect (Tok_String_Literal, "literal string");
exit when Token /= Tok_String_Literal;
Set_Location_Of (Current_Choice, To => Token_Ptr);
- Choice_String := Strval (Token_Node);
+ Choice_String := Token_Name;
+
+ -- Give the string value to the current choice
+
Set_String_Value_Of (Current_Choice, To => Choice_String);
+ -- Check if the label is part of the string type and if it has not
+ -- been already used.
+
Found := False;
for Choice in Choice_First .. Choices.Last loop
- if String_Equal (Choices.Table (Choice).The_String,
- Choice_String)
- then
+ if Choices.Table (Choice).The_String = Choice_String then
+ -- This label is part of the string type
+
Found := True;
if Choices.Table (Choice).Already_Used then
- String_To_Name_Buffer (Choice_String);
- Error_Msg_Name_1 := Name_Find;
+ -- But it has already appeared in a choice list for this
+ -- case construction; report an error.
+
+ Error_Msg_Name_1 := Choice_String;
Error_Msg ("duplicate case label {", Token_Ptr);
else
Choices.Table (Choice).Already_Used := True;
@@ -338,15 +418,23 @@ package body Prj.Strt is
end if;
end loop;
+ -- If the label is not part of the string list, report an error
+
if not Found then
- String_To_Name_Buffer (Choice_String);
- Error_Msg_Name_1 := Name_Find;
+ Error_Msg_Name_1 := Choice_String;
Error_Msg ("illegal case label {", Token_Ptr);
end if;
+ -- Scan past the label
+
Scan;
+ -- If there is no '|', we are done
+
if Token = Tok_Vertical_Bar then
+ -- Otherwise, declare the node of the next choice, link it to
+ -- Current_Choice and set Current_Choice to this new node.
+
Next_Choice :=
Default_Project_Node (Of_Kind => N_Literal_String,
And_Expr_Kind => Single);
@@ -372,12 +460,20 @@ package body Prj.Strt is
Expression_Kind : Variable_Kind := Undefined;
begin
+ -- Declare the node of the expression
+
Expression := Default_Project_Node (Of_Kind => N_Expression);
Set_Location_Of (Expression, To => Token_Ptr);
+
+ -- Parse the term or terms of the expression
+
Terms (Term => First_Term,
Expr_Kind => Expression_Kind,
Current_Project => Current_Project,
Current_Package => Current_Package);
+
+ -- Set the first term and the expression kind
+
Set_First_Term (Expression, To => First_Term);
Set_Expression_Kind_Of (Expression, To => Expression_Kind);
end Parse_Expression;
@@ -389,29 +485,40 @@ package body Prj.Strt is
procedure Parse_String_Type_List (First_String : out Project_Node_Id) is
Last_String : Project_Node_Id := Empty_Node;
Next_String : Project_Node_Id := Empty_Node;
- String_Value : String_Id := No_String;
+ String_Value : Name_Id := No_Name;
begin
+ -- Declare the node of the first string
+
First_String :=
Default_Project_Node (Of_Kind => N_Literal_String,
And_Expr_Kind => Single);
+
+ -- Initially, Last_String is the same as First_String
+
Last_String := First_String;
loop
Expect (Tok_String_Literal, "literal string");
exit when Token /= Tok_String_Literal;
- String_Value := Strval (Token_Node);
+ String_Value := Token_Name;
+
+ -- Give its string value to Last_String
+
Set_String_Value_Of (Last_String, To => String_Value);
Set_Location_Of (Last_String, To => Token_Ptr);
+ -- Now, check if the string is already part of the string type
+
declare
Current : Project_Node_Id := First_String;
begin
while Current /= Last_String loop
- if String_Equal (String_Value_Of (Current), String_Value) then
- String_To_Name_Buffer (String_Value);
- Error_Msg_Name_1 := Name_Find;
+ if String_Value_Of (Current) = String_Value then
+ -- This is a repetition, report an error
+
+ Error_Msg_Name_1 := String_Value;
Error_Msg ("duplicate value { in type", Token_Ptr);
exit;
end if;
@@ -420,12 +527,19 @@ package body Prj.Strt is
end loop;
end;
+ -- Scan past the literal string
+
Scan;
+ -- If there is no comma following the literal string, we are done
+
if Token /= Tok_Comma then
exit;
else
+ -- Declare the next string, link it to Last_String and set
+ -- Last_String to its node.
+
Next_String :=
Default_Project_Node (Of_Kind => N_Literal_String,
And_Expr_Kind => Single);
@@ -445,8 +559,6 @@ package body Prj.Strt is
Current_Project : Project_Node_Id;
Current_Package : Project_Node_Id)
is
- The_Names : Names;
- Last_Name : Name_Range := 0;
Current_Variable : Project_Node_Id := Empty_Node;
The_Package : Project_Node_Id := Current_Package;
@@ -459,7 +571,9 @@ package body Prj.Strt is
Variable_Name : Name_Id;
begin
- for Index in The_Names'Range loop
+ Names.Init;
+
+ loop
Expect (Tok_Identifier, "identifier");
if Token /= Tok_Identifier then
@@ -467,21 +581,19 @@ package body Prj.Strt is
exit;
end if;
- Last_Name := Last_Name + 1;
- The_Names (Last_Name) :=
- (Name => Token_Name,
- Location => Token_Ptr);
+ Add_To_Names (NL => (Name => Token_Name, Location => Token_Ptr));
Scan;
exit when Token /= Tok_Dot;
Scan;
end loop;
if Look_For_Variable then
+
if Token = Tok_Apostrophe then
-- Attribute reference
- case Last_Name is
+ case Names.Last is
when 0 =>
-- Cannot happen
@@ -489,9 +601,14 @@ package body Prj.Strt is
null;
when 1 =>
+ -- This may be a project name or a package name.
+ -- Project name have precedence.
+
+ -- First, look if it can be a package name
+
for Index in Package_First .. Package_Attributes.Last loop
if Package_Attributes.Table (Index).Name =
- The_Names (1).Name
+ Names.Table (1).Name
then
First_Attribute :=
Package_Attributes.Table (Index).First_Attribute;
@@ -499,96 +616,159 @@ package body Prj.Strt is
end if;
end loop;
- if First_Attribute /= Empty_Attribute then
- The_Package := First_Package_Of (Current_Project);
- while The_Package /= Empty_Node
- and then Name_Of (The_Package) /= The_Names (1).Name
- loop
- The_Package := Next_Package_In_Project (The_Package);
- end loop;
+ -- Now, look if it can be a project name
- if The_Package = Empty_Node then
- Error_Msg_Name_1 := The_Names (1).Name;
- Error_Msg ("package % not yet defined",
- The_Names (1).Location);
+ The_Project := Imported_Or_Extended_Project_Of
+ (Current_Project, Names.Table (1).Name);
+
+ if The_Project = Empty_Node then
+ -- If it is neither a project name nor a package name,
+ -- report an error
+
+ if First_Attribute = Empty_Attribute then
+ Error_Msg_Name_1 := Names.Table (1).Name;
+ Error_Msg ("unknown project %",
+ Names.Table (1).Location);
+ First_Attribute := Attribute_First;
+
+ else
+ -- If it is a package name, check if the package
+ -- has already been declared in the current project.
+
+ The_Package := First_Package_Of (Current_Project);
+
+ while The_Package /= Empty_Node
+ and then Name_Of (The_Package) /=
+ Names.Table (1).Name
+ loop
+ The_Package :=
+ Next_Package_In_Project (The_Package);
+ end loop;
+
+ -- If it has not been already declared, report an
+ -- error.
+
+ if The_Package = Empty_Node then
+ Error_Msg_Name_1 := Names.Table (1).Name;
+ Error_Msg ("package % not yet defined",
+ Names.Table (1).Location);
+ end if;
end if;
else
+ -- It is a project name
+
First_Attribute := Attribute_First;
The_Package := Empty_Node;
-
- declare
- The_Project_Name_And_Node :
- constant Tree_Private_Part.Project_Name_And_Node :=
- Tree_Private_Part.Projects_Htable.Get
- (The_Names (1).Name);
-
- use Tree_Private_Part;
-
- begin
- if The_Project_Name_And_Node =
- Tree_Private_Part.No_Project_Name_And_Node
- then
- Error_Msg_Name_1 := The_Names (1).Name;
- Error_Msg ("unknown project %",
- The_Names (1).Location);
- else
- The_Project := The_Project_Name_And_Node.Node;
- end if;
- end;
end if;
- when 2 =>
+ when others =>
+
+ -- We have either a project name made of several simple
+ -- names (long project), or a project name (short project)
+ -- followed by a package name. The long project name has
+ -- precedence.
+
declare
- With_Clause : Project_Node_Id :=
- First_With_Clause_Of (Current_Project);
+ Short_Project : Name_Id;
+ Long_Project : Name_Id;
begin
- while With_Clause /= Empty_Node loop
- The_Project := Project_Node_Of (With_Clause);
- exit when Name_Of (The_Project) = The_Names (1).Name;
- With_Clause := Next_With_Clause_Of (With_Clause);
+ -- Clear the Buffer
+
+ Buffer_Last := 0;
+
+ -- Get the name of the short project
+
+ for Index in 1 .. Names.Last - 1 loop
+ Add_To_Buffer
+ (Get_Name_String (Names.Table (Index).Name));
+
+ if Index /= Names.Last - 1 then
+ Add_To_Buffer (".");
+ end if;
end loop;
- if With_Clause = Empty_Node then
- Error_Msg_Name_1 := The_Names (1).Name;
- Error_Msg ("unknown project %",
- The_Names (1).Location);
- The_Project := Empty_Node;
- The_Package := Empty_Node;
+ Name_Len := Buffer_Last;
+ Name_Buffer (1 .. Buffer_Last) :=
+ Buffer (1 .. Buffer_Last);
+ Short_Project := Name_Find;
+
+ -- Now, add the last simple name to get the name of the
+ -- long project.
+
+ Add_To_Buffer (".");
+ Add_To_Buffer
+ (Get_Name_String (Names.Table (Names.Last).Name));
+ Name_Len := Buffer_Last;
+ Name_Buffer (1 .. Buffer_Last) :=
+ Buffer (1 .. Buffer_Last);
+ Long_Project := Name_Find;
+
+ -- Check if the long project is imported or extended
+
+ The_Project := Imported_Or_Extended_Project_Of
+ (Current_Project, Long_Project);
+
+ -- If the long project exists, then this is the prefix
+ -- of the attribute.
+
+ if The_Project /= Empty_Node then
First_Attribute := Attribute_First;
+ The_Package := Empty_Node;
else
- The_Package := First_Package_Of (The_Project);
- while The_Package /= Empty_Node
- and then Name_Of (The_Package) /= The_Names (2).Name
- loop
- The_Package :=
- Next_Package_In_Project (The_Package);
- end loop;
+ -- Otherwise, check if the short project is imported
+ -- or extended.
- if The_Package = Empty_Node then
- Error_Msg_Name_1 := The_Names (2).Name;
- Error_Msg_Name_2 := The_Names (1).Name;
- Error_Msg ("package % not declared in project %",
- The_Names (2).Location);
+ The_Project := Imported_Or_Extended_Project_Of
+ (Current_Project, Short_Project);
+
+ -- If the short project does not exist, we report an
+ -- error.
+
+ if The_Project = Empty_Node then
+ Error_Msg_Name_1 := Long_Project;
+ Error_Msg_Name_2 := Short_Project;
+ Error_Msg ("unknown projects % or %",
+ Names.Table (1).Location);
+ The_Package := Empty_Node;
First_Attribute := Attribute_First;
else
- First_Attribute :=
- Package_Attributes.Table
- (Package_Id_Of (The_Package)).First_Attribute;
+ -- Now, we check if the package has been declared
+ -- in this project.
+
+ The_Package := First_Package_Of (The_Project);
+ while The_Package /= Empty_Node
+ and then Name_Of (The_Package) /=
+ Names.Table (Names.Last).Name
+ loop
+ The_Package :=
+ Next_Package_In_Project (The_Package);
+ end loop;
+
+ -- If it has not, then we report an error
+
+ if The_Package = Empty_Node then
+ Error_Msg_Name_1 :=
+ Names.Table (Names.Last).Name;
+ Error_Msg_Name_2 := Short_Project;
+ Error_Msg ("package % not declared in project %",
+ Names.Table (Names.Last).Location);
+ First_Attribute := Attribute_First;
+
+ else
+ -- Otherwise, we have the correct project and
+ -- package.
+
+ First_Attribute :=
+ Package_Attributes.Table
+ (Package_Id_Of (The_Package)).First_Attribute;
+ end if;
end if;
end if;
end;
-
- when 3 =>
- Error_Msg
- ("too many single names for an attribute reference",
- The_Names (1).Location);
- Scan;
- Variable := Empty_Node;
- return;
end case;
Attribute_Reference
@@ -604,7 +784,7 @@ package body Prj.Strt is
Default_Project_Node (Of_Kind => N_Variable_Reference);
if Look_For_Variable then
- case Last_Name is
+ case Names.Last is
when 0 =>
-- Cannot happen
@@ -612,117 +792,146 @@ package body Prj.Strt is
null;
when 1 =>
- Set_Name_Of (Variable, To => The_Names (1).Name);
- -- Header comment needed ???
+ -- Simple variable name
+
+ Set_Name_Of (Variable, To => Names.Table (1).Name);
when 2 =>
- Set_Name_Of (Variable, To => The_Names (2).Name);
+
+ -- Variable name with a simple name prefix that can be
+ -- a project name or a package name. Project names have
+ -- priority over package names.
+
+ Set_Name_Of (Variable, To => Names.Table (2).Name);
+
+ -- Check if it can be a package name
+
The_Package := First_Package_Of (Current_Project);
while The_Package /= Empty_Node
- and then Name_Of (The_Package) /= The_Names (1).Name
+ and then Name_Of (The_Package) /= Names.Table (1).Name
loop
The_Package := Next_Package_In_Project (The_Package);
end loop;
- if The_Package /= Empty_Node then
- Specified_Package := The_Package;
- The_Project := Empty_Node;
+ -- Now look for a possible project name
- else
- declare
- With_Clause : Project_Node_Id :=
- First_With_Clause_Of (Current_Project);
+ The_Project := Imported_Or_Extended_Project_Of
+ (Current_Project, Names.Table (1).Name);
- begin
- while With_Clause /= Empty_Node loop
- The_Project := Project_Node_Of (With_Clause);
- exit when Name_Of (The_Project) = The_Names (1).Name;
- With_Clause := Next_With_Clause_Of (With_Clause);
- end loop;
+ if The_Project /= Empty_Node then
+ Specified_Project := The_Project;
- if With_Clause = Empty_Node then
- The_Project :=
- Modified_Project_Of
- (Project_Declaration_Of (Current_Project));
+ elsif The_Package = Empty_Node then
+ Error_Msg_Name_1 := Names.Table (1).Name;
+ Error_Msg ("unknown package or project %",
+ Names.Table (1).Location);
+ Look_For_Variable := False;
- if The_Project /= Empty_Node
- and then
- Name_Of (The_Project) /= The_Names (1).Name
- then
- The_Project := Empty_Node;
- end if;
- end if;
-
- if The_Project = Empty_Node then
- Error_Msg_Name_1 := The_Names (1).Name;
- Error_Msg ("unknown package or project %",
- The_Names (1).Location);
- Look_For_Variable := False;
- else
- Specified_Project := The_Project;
- end if;
- end;
+ else
+ Specified_Package := The_Package;
end if;
- -- Header comment needed ???
+ when others =>
+
+ -- Variable name with a prefix that is either a project name
+ -- made of several simple names, or a project name followed
+ -- by a package name.
- when 3 =>
- Set_Name_Of (Variable, To => The_Names (3).Name);
+ Set_Name_Of (Variable, To => Names.Table (Names.Last).Name);
declare
- With_Clause : Project_Node_Id :=
- First_With_Clause_Of (Current_Project);
+ Short_Project : Name_Id;
+ Long_Project : Name_Id;
begin
- while With_Clause /= Empty_Node loop
- The_Project := Project_Node_Of (With_Clause);
- exit when Name_Of (The_Project) = The_Names (1).Name;
- With_Clause := Next_With_Clause_Of (With_Clause);
- end loop;
+ -- First, we get the two possible project names
- if With_Clause = Empty_Node then
- The_Project :=
- Modified_Project_Of
- (Project_Declaration_Of (Current_Project));
+ -- Clear the buffer
- if The_Project /= Empty_Node
- and then Name_Of (The_Project) /= The_Names (1).Name
- then
- The_Project := Empty_Node;
+ Buffer_Last := 0;
+
+ -- Add all the simple names, except the last two
+
+ for Index in 1 .. Names.Last - 2 loop
+ Add_To_Buffer
+ (Get_Name_String (Names.Table (Index).Name));
+
+ if Index /= Names.Last - 2 then
+ Add_To_Buffer (".");
end if;
- end if;
+ end loop;
- if The_Project = Empty_Node then
- Error_Msg_Name_1 := The_Names (1).Name;
- Error_Msg ("unknown package or project %",
- The_Names (1).Location);
- Look_For_Variable := False;
+ Name_Len := Buffer_Last;
+ Name_Buffer (1 .. Name_Len) := Buffer (1 .. Buffer_Last);
+ Short_Project := Name_Find;
- else
+ -- Add the simple name before the name of the variable
+
+ Add_To_Buffer (".");
+ Add_To_Buffer
+ (Get_Name_String (Names.Table (Names.Last - 1).Name));
+ Name_Len := Buffer_Last;
+ Name_Buffer (1 .. Name_Len) := Buffer (1 .. Buffer_Last);
+ Long_Project := Name_Find;
+
+ -- Check if the prefix is the name of an imported or
+ -- extended project.
+
+ The_Project := Imported_Or_Extended_Project_Of
+ (Current_Project, Long_Project);
+
+ if The_Project /= Empty_Node then
Specified_Project := The_Project;
- The_Package := First_Package_Of (The_Project);
- while The_Package /= Empty_Node
- and then Name_Of (The_Package) /= The_Names (2).Name
- loop
- The_Package := Next_Package_In_Project (The_Package);
- end loop;
+ else
+ -- Now check if the prefix may be a project name followed
+ -- by a package name.
+
+ -- First check for a possible project name
- if The_Package = Empty_Node then
- Error_Msg_Name_1 := The_Names (2).Name;
- Error_Msg ("unknown package %",
- The_Names (2).Location);
+ The_Project := Imported_Or_Extended_Project_Of
+ (Current_Project, Short_Project);
+
+ if The_Project = Empty_Node then
+ -- Unknown prefix, report an error
+
+ Error_Msg_Name_1 := Long_Project;
+ Error_Msg_Name_2 := Short_Project;
+ Error_Msg ("unknown projects % or %",
+ Names.Table (1).Location);
Look_For_Variable := False;
else
- Specified_Package := The_Package;
- The_Project := Empty_Node;
+ Specified_Project := The_Project;
+
+ -- Now look for the package in this project
+
+ The_Package := First_Package_Of (The_Project);
+
+ while The_Package /= Empty_Node
+ and then Name_Of (The_Package) /=
+ Names.Table (Names.Last - 1).Name
+ loop
+ The_Package :=
+ Next_Package_In_Project (The_Package);
+ end loop;
+
+ if The_Package = Empty_Node then
+ -- The package does not vexist, report an error
+
+ Error_Msg_Name_1 := Names.Table (2).Name;
+ Error_Msg ("unknown package %",
+ Names.Table (Names.Last - 1).Location);
+ Look_For_Variable := False;
+
+ else
+ Specified_Package := The_Package;
+ end if;
end if;
end if;
end;
-
end case;
end if;
@@ -731,8 +940,22 @@ package body Prj.Strt is
Set_Project_Node_Of (Variable, To => Specified_Project);
Set_Package_Node_Of (Variable, To => Specified_Package);
- if The_Package /= Empty_Node then
- Current_Variable := First_Variable_Of (The_Package);
+ if Specified_Project /= Empty_Node then
+ The_Project := Specified_Project;
+
+ else
+ The_Project := Current_Project;
+ end if;
+
+ Current_Variable := Empty_Node;
+
+ -- Look for this variable
+
+ -- If a package was specified, check if the variable has been
+ -- declared in this package.
+
+ if Specified_Package /= Empty_Node then
+ Current_Variable := First_Variable_Of (Specified_Package);
while Current_Variable /= Empty_Node
and then
@@ -740,22 +963,44 @@ package body Prj.Strt is
loop
Current_Variable := Next_Variable (Current_Variable);
end loop;
- end if;
- if Current_Variable = Empty_Node
- and then The_Project /= Empty_Node
- then
- Current_Variable := First_Variable_Of (The_Project);
- while Current_Variable /= Empty_Node
- and then Name_Of (Current_Variable) /= Variable_Name
- loop
- Current_Variable := Next_Variable (Current_Variable);
- end loop;
+ else
+ -- Otherwise, if no project has been specified and we are in
+ -- a package, first check if the variable has been declared in
+ -- the package.
+
+ if Specified_Project = Empty_Node
+ and then Current_Package /= Empty_Node
+ then
+ Current_Variable := First_Variable_Of (Current_Package);
+
+ while Current_Variable /= Empty_Node
+ and then Name_Of (Current_Variable) /= Variable_Name
+ loop
+ Current_Variable := Next_Variable (Current_Variable);
+ end loop;
+ end if;
+
+ -- If we have not found the variable in the package, check if the
+ -- variable has been declared in the project.
+
+ if Current_Variable = Empty_Node then
+ Current_Variable := First_Variable_Of (The_Project);
+
+ while Current_Variable /= Empty_Node
+ and then Name_Of (Current_Variable) /= Variable_Name
+ loop
+ Current_Variable := Next_Variable (Current_Variable);
+ end loop;
+ end if;
end if;
+ -- If the variable was not found, report an error
+
if Current_Variable = Empty_Node then
Error_Msg_Name_1 := Variable_Name;
- Error_Msg ("unknown variable %", The_Names (Last_Name).Location);
+ Error_Msg
+ ("unknown variable %", Names.Table (Names.Last).Location);
end if;
end if;
@@ -769,6 +1014,9 @@ package body Prj.Strt is
end if;
end if;
+ -- If the variable is followed by a left parenthesis, report an error
+ -- but attempt to scan the index.
+
if Token = Tok_Left_Paren then
Error_Msg ("\variables cannot be associative arrays", Token_Ptr);
Scan;
@@ -776,7 +1024,7 @@ package body Prj.Strt is
if Token = Tok_String_Literal then
Scan;
- Expect (Tok_Right_Paren, ")");
+ Expect (Tok_Right_Paren, "`)`");
if Token = Tok_Right_Paren then
Scan;
@@ -793,6 +1041,9 @@ package body Prj.Strt is
Current_String : Project_Node_Id;
begin
+ -- Set Choice_First, depending on whether is the first case
+ -- construction or not.
+
if Choice_First = 0 then
Choice_First := 1;
Choices.Set_Last (First_Choice_Node_Id);
@@ -800,6 +1051,8 @@ package body Prj.Strt is
Choice_First := Choices.Last + 1;
end if;
+ -- Add to table Choices the literal of the string type
+
if String_Type /= Empty_Node then
Current_String := First_Literal_String (String_Type);
@@ -809,6 +1062,8 @@ package body Prj.Strt is
end loop;
end if;
+ -- Set the value of the last choice in table Choice_Lasts
+
Choice_Lasts.Increment_Last;
Choice_Lasts.Table (Choice_Lasts.Last) := Choices.Last;
@@ -818,10 +1073,11 @@ package body Prj.Strt is
-- Terms --
-----------
- procedure Terms (Term : out Project_Node_Id;
- Expr_Kind : in out Variable_Kind;
- Current_Project : Project_Node_Id;
- Current_Package : Project_Node_Id)
+ procedure Terms
+ (Term : out Project_Node_Id;
+ Expr_Kind : in out Variable_Kind;
+ Current_Project : Project_Node_Id;
+ Current_Package : Project_Node_Id)
is
Next_Term : Project_Node_Id := Empty_Node;
Term_Id : Project_Node_Id := Empty_Node;
@@ -831,46 +1087,74 @@ package body Prj.Strt is
Reference : Project_Node_Id := Empty_Node;
begin
+ -- Declare a new node for the term
+
Term := Default_Project_Node (Of_Kind => N_Term);
Set_Location_Of (Term, To => Token_Ptr);
case Token is
-
when Tok_Left_Paren =>
+
+ -- If we have a left parenthesis and we don't know the expression
+ -- kind, then this is a string list.
+
case Expr_Kind is
when Undefined =>
Expr_Kind := List;
+
when List =>
null;
+
when Single =>
+
+ -- If we already know that this is a single string, report
+ -- an error, but set the expression kind to string list to
+ -- avoid several errors.
+
Expr_Kind := List;
Error_Msg
("literal string list cannot appear in a string",
Token_Ptr);
end case;
+ -- Declare a new node for this literal string list
+
Term_Id := Default_Project_Node
(Of_Kind => N_Literal_String_List,
And_Expr_Kind => List);
Set_Current_Term (Term, To => Term_Id);
Set_Location_Of (Term, To => Token_Ptr);
+ -- Scan past the left parenthesis
+
Scan;
+
+ -- If the left parenthesis is immediately followed by a right
+ -- parenthesis, the literal string list is empty.
+
if Token = Tok_Right_Paren then
Scan;
else
+ -- Otherwise, we parse the expression(s) in the literal string
+ -- list.
+
loop
Current_Location := Token_Ptr;
Parse_Expression (Expression => Next_Expression,
Current_Project => Current_Project,
Current_Package => Current_Package);
+ -- The expression kind is String list, report an error
+
if Expression_Kind_Of (Next_Expression) = List then
Error_Msg ("single expression expected",
Current_Location);
end if;
+ -- If Current_Expression is empty, it means that the
+ -- expression is the first in the string list.
+
if Current_Expression = Empty_Node then
Set_First_Expression_In_List
(Term_Id, To => Next_Expression);
@@ -880,11 +1164,16 @@ package body Prj.Strt is
end if;
Current_Expression := Next_Expression;
+
+ -- If there is a comma, continue with the next expression
+
exit when Token /= Tok_Comma;
Scan; -- past the comma
end loop;
- Expect (Tok_Right_Paren, "(");
+ -- We expect a closing right parenthesis
+
+ Expect (Tok_Right_Paren, "`)`");
if Token = Tok_Right_Paren then
Scan;
@@ -892,18 +1181,29 @@ package body Prj.Strt is
end if;
when Tok_String_Literal =>
+
+ -- If we don't know the expression kind (first term), then it is
+ -- a simple string.
+
if Expr_Kind = Undefined then
Expr_Kind := Single;
end if;
+ -- Declare a new node for the string literal
+
Term_Id := Default_Project_Node (Of_Kind => N_Literal_String);
Set_Current_Term (Term, To => Term_Id);
- Set_String_Value_Of (Term_Id, To => Strval (Token_Node));
+ Set_String_Value_Of (Term_Id, To => Token_Name);
+
+ -- Scan past the string literal
Scan;
when Tok_Identifier =>
Current_Location := Token_Ptr;
+
+ -- Get the variable or attribute reference
+
Parse_Variable_Reference
(Variable => Reference,
Current_Project => Current_Project,
@@ -911,12 +1211,20 @@ package body Prj.Strt is
Set_Current_Term (Term, To => Reference);
if Reference /= Empty_Node then
+
+ -- If we don't know the expression kind (first term), then it
+ -- has the kind of the variable or attribute reference.
+
if Expr_Kind = Undefined then
Expr_Kind := Expression_Kind_Of (Reference);
elsif Expr_Kind = Single
and then Expression_Kind_Of (Reference) = List
then
+ -- If the expression is a single list, and the reference is
+ -- a string list, report an error, and set the expression
+ -- kind to string list to avoid multiple errors.
+
Expr_Kind := List;
Error_Msg
("list variable cannot appear in single string expression",
@@ -925,9 +1233,13 @@ package body Prj.Strt is
end if;
when Tok_Project =>
+
+ -- project can appear in an expression as the prefix of an
+ -- attribute reference of the current project.
+
Current_Location := Token_Ptr;
Scan;
- Expect (Tok_Apostrophe, "'");
+ Expect (Tok_Apostrophe, "`'`");
if Token = Tok_Apostrophe then
Attribute_Reference
@@ -938,6 +1250,8 @@ package body Prj.Strt is
Set_Current_Term (Term, To => Reference);
end if;
+ -- Same checks as above for the expression kind
+
if Reference /= Empty_Node then
if Expr_Kind = Undefined then
Expr_Kind := Expression_Kind_Of (Reference);
@@ -952,6 +1266,8 @@ package body Prj.Strt is
end if;
when Tok_External =>
+ -- An external reference is always a single string
+
if Expr_Kind = Undefined then
Expr_Kind := Single;
end if;
@@ -965,17 +1281,23 @@ package body Prj.Strt is
return;
end case;
+ -- If there is an '&', call Terms recursively
+
if Token = Tok_Ampersand then
+
+ -- Scan past the '&'
+
Scan;
Terms (Term => Next_Term,
Expr_Kind => Expr_Kind,
Current_Project => Current_Project,
Current_Package => Current_Package);
- Set_Next_Term (Term, To => Next_Term);
- end if;
+ -- And link the next term to this term
+ Set_Next_Term (Term, To => Next_Term);
+ end if;
end Terms;
end Prj.Strt;