home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Geek Gadgets 1
/
ADE-1.bin
/
ade-dist
/
gnat-2.06-src.tgz
/
tar.out
/
fsf
/
gnat
/
ada
/
sem.ads
< prev
next >
Wrap
Text File
|
1996-09-28
|
15KB
|
303 lines
------------------------------------------------------------------------------
-- --
-- GNAT COMPILER COMPONENTS --
-- --
-- S E M --
-- --
-- S p e c --
-- --
-- $Revision: 1.77 $ --
-- --
-- Copyright (c) 1992,1993,1994,1995 NYU, All Rights Reserved --
-- --
-- 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- --
-- ware Foundation; either version 2, or (at your option) any later ver- --
-- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
-- for more details. You should have received a copy of the GNU General --
-- Public License distributed with GNAT; see file COPYING. If not, write --
-- to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. --
-- --
------------------------------------------------------------------------------
with Opt; use Opt;
with Snames; use Snames;
with Table;
with Types; use Types;
package Sem is
Subunit_Found : exception;
-- This exception is used when the main unit is a subunit, and the current
-- unit is one of its parents. In this case the parent is being analyzed
-- only to provide the necessary context for the subunit, so as soon as
-- the subunit has been analyzed, there is no need to continue with the
-- analysis of the parent, so this exception is raised to get out.
-------------------------------------
-- Handling of Default Expressions --
-------------------------------------
-- The default expressions in component declarations and in procedure
-- specifications (but not the ones in object declarations) are quite
-- tricky to handle. The problem is that some processing is required
-- at the point where the expression appears:
--
-- visibility analysis (including user defined operators)
-- freezing of static expressions
--
-- but other processing must be deferred until the enclosing entity
-- (record or procedure specification) is frozen:
--
-- freezing of any other types in the expression
-- generation of code
--
-- Code generation has to be deferred since you can't generate code for
-- expressions that refernce types that have not been frozen yet. Although
-- the generation of code at the machine level is deferred to Gigi and GCC
-- processing, our expander does a lot of code generation activity. As an
-- example, consider the following:
--
-- type x is delta 0.5 range -10.0 .. +10.0;
-- ...
-- type q is record
-- xx : x := y * z;
-- end record;
--
-- for x'small use 0.25
--
-- The expander is in charge of dealing with fixed-point, and of course
-- the small declaration, which is not too late, since the declaration of
-- type q does *not* freeze type x, definitely affects the expanded code.
--
-- Generally our model is to combine analysis and expansion, but this is
-- the one case where this model falls down. Here is how we patch it up
-- without causing too much distortion to our basic model.
--
-- A switch is set to indicate that we are in the initial occurence of
-- a default expression. The analyzer is then called on this expression
-- with the switch set true. Analysis and resolution proceed almost as
-- usual, except that Freeze_Expression will not freeze non-static
-- expressions if this switch is set, and the call to Expand at the end
-- of resolution is skipped. This also skips the code that normally sets
-- the Analyzed flag to True). The result is that when we are done the tree
-- is still marked as unanalyzed, but all types for static expressions are
-- frozen as required, and all entities of variables have been recorded.
-- We then turn off the switch, and later on reanalyze the expression with
-- the switch off. The effect is that this second analysis freezes the rest
-- of the types as required, and generates code but visibility analysis is
-- not repeated since all the entities are marked.
In_Default_Expression : Boolean := False;
-- Switch to indicate that we are in a default expression, as described
-- above. Note that this must be recursively saved on a Semantics call
-- since it is possible for the analysis of an expression to result in
-- a recursive call (e.g. to get the entity for System.Address as part
-- of the processing of an Address attribute reference).
-----------------
-- Scope Stack --
-----------------
Scope_Suppress : Suppress_Record := Suppress_Options;
-- This record contains the current scope based settings of the suppress
-- switches. It is initialized from the options as shown, and then modified
-- by pragma Suppress. On entry to each scope, the current setting is saved
-- the scope stack, and then restored on exit from the scope.
-- The scope stack holds all entries of the scope table. As in the parser,
-- we use Last as the stack pointer, so that we can always find the scope
-- that is currently open in Scope_Stack.Table (Scope_Stack.Last). The
-- oldest entry, at Scope_Stack (0) is Standard. The entries in the table
-- include the entity for the referenced scope, together with information
-- used to restore the proper setting of check suppressions on scope exit.
-- There are two kinds of suppress checks, scope based suppress checks
-- (from initial command line arguments, or from Suppress pragmas not
-- including an entity name). The scope based suppress checks are recorded
-- in the Sem.Supress variable, and all that is necessary is to save the
-- state of this variable on scope entry, and restore it on scope exit.
-- The other kind of suppress check is entity based suppress checks, from
-- Suppress pragmas giving an Entity_Id. These checks are reflected by the
-- appropriate bit being set in the corresponding entity, and restoring the
-- setting of these bits is a little trickier. In particular a given pragma
-- Suppress may or may not affect the current state. If it sets a check for
-- an entity that is already checked, then it is important that this check
-- not be restored on scope exit. The situation is made more complicated
-- by the fact that a given suppress pragma can specify multiple entities
-- (in the overloaded case), and multiple checks (by using All_Checks), so
-- that it may be partially effective. On exit only checks that were in
-- fact effective must be removed. Logically we could do this by saving
-- the entire state of the entity flags on scope entry and restoring them
-- on scope exit, but that would be ludicrous, so what we do instead is to
-- maintain the following differential structure that shows what checks
-- were installed for the current scope.
-- Note: Suppress pragmas that specify entities defined in a package
-- spec do not make entries in this table, since such checks suppress
-- requests are valid for the entire life of the entity.
type Entity_Check_Suppress_Record is record
Entity : Entity_Id;
-- Entity to which the check applies
Check : Check_Id;
-- Check which is set (note this cannot be All_Checks, if the All_Checks
-- case, a sequence of eentries appears for the individual checks.
end record;
-- Entity_Suppress is a stack, to which new entries are added as they
-- are processed (see pragma Suppress circuit in Sem_Prag). The scope
-- stack entry simply saves the stack pointer on entry, and restores
-- it on exit by reversing the checks one by one.
package Entity_Suppress is new Table (
Table_Component_Type => Entity_Check_Suppress_Record,
Table_Index_Type => Int,
Table_Low_Bound => 0,
Table_Initial => 1000,
Table_Increment => 100,
Table_Name => "Sem.Entity_Suppress");
-- Here is the scope stack itself
type Scope_Stack_Entry is record
Entity : Entity_Id;
-- Entity representing the scope
Save_Scope_Suppress : Suppress_Record;
-- Save contents of Scope_Suppress on entry
Save_Entity_Suppress : Int;
-- Save contents of Entity_Suppress.Last on entry
Is_Transient : Boolean;
-- Marks Transient Scopes (See Exp_Ch7 body for details)
Node_To_Be_Wrapped : Node_Id;
-- Only used in transient scopes. Records the node which will
-- be wrapped by the transient block.
Actions_To_Be_Wrapped : List_Id;
-- Actions that have to be inserted at the start of a transient
-- block. Used to temporarily hold these actions until the block
-- is created, at which time the actions are moved to the block.
Pending_Freeze_Nodes : List_Id;
-- Used to collect freeze entity nodes that are generated in a inner
-- context but need to be analyzed outside, such as records and
-- initialization procedures. On exit from the scope, this list of
-- freeze entity nodes is inserted before the scope construct and
-- analyzed to generate the corresponding freeze actions.
First_Use_Clause : Node_Id;
-- Head of list of Use_Clauses in current scope. The list is built
-- when the declarations in the scope are processed. The list is
-- traversed on scope exit to undo the effect of the use clauses.
end record;
package Scope_Stack is new Table (
Table_Component_Type => Scope_Stack_Entry,
Table_Index_Type => Int,
Table_Low_Bound => 0,
Table_Initial => 50,
Table_Increment => 100,
Table_Name => "Sem.Scope_Stack");
function Get_Scope_Suppress (C : Check_Id) return Boolean;
-- Get suppress status of check C for the current scope
procedure Set_Scope_Suppress (C : Check_Id; B : Boolean);
-- Set suppress status of check C for the current scope
-----------------
-- Subprograms --
-----------------
procedure Semantics (Comp_Unit : Node_Id);
-- This procedure is called to perform semantic analysis on the specified
-- node which is the N_Compilation_Unit node for the unit.
procedure Analyze (N : Node_Id);
procedure Analyze (N : Node_Id; Suppress : Check_Id);
-- This is the recursive procedure which is applied to individual nodes
-- of the tree, starting at the top level node (compilation unit node)
-- and then moving down the tree in a top down traversal. It calls
-- individual routines with names Analyze_xxx to analyze node xxx. Each
-- of these routines is responsible for calling Analyze on the components
-- of the subtree.
--
-- Note: In the case of expression components (nodes whose Nkind is in
-- N_Subexpr), the call to Analyze does not complete the semantic analysis
-- of the node, since the type resolution cannot be completed until the
-- complete context is analyzed. The completion of the type analysis occurs
-- in the corresponding Resolve routine (see Sem_Res).
--
-- Note: for integer and real literals, the analyzer sets the flag to
-- indicate that the result is a static expression. If the expander
-- generates a literal that does NOT correspond to a static expression,
-- e.g. by folding an expression whose value is known at compile-time,
-- but is not technically static, then the caller should reset the
-- Is_Static_Expression flag after analyzing but before resolving.
--
-- If the Suppress argument is present, then the analysis is done
-- with the specified check suppressed (can be All_Checks to suppress
-- all checks).
procedure Analyze_List (L : List_Id);
procedure Analyze_List (L : List_Id; Suppress : Check_Id);
-- Analyzes each element of a list. If the Suppress argument is present,
-- then the analysis is done with the specified check suppressed (can
-- be All_Checks to suppress all checks).
procedure Insert_List_After_And_Analyze
(N : Node_Id; L : List_Id);
procedure Insert_List_After_And_Analyze
(N : Node_Id; L : List_Id; Suppress : Check_Id);
-- Inserts list L after node N using Nlists.Insert_List_After, and then,
-- after this insertion is complete, analyzes all the nodes in the list,
-- including any additional nodes generated by this analysis. If the list
-- is empty or be No_List, the call has no effect. If the Suppress
-- argument is present, then the analysis is done with the specified
-- check suppressed (can be All_Checks to suppress all checks).
-- Same as Insert_List_After_And_Analyze, with specified check
-- suppressed (can be All_Checks).
procedure Insert_List_Before_And_Analyze
(N : Node_Id; L : List_Id);
procedure Insert_List_Before_And_Analyze
(N : Node_Id; L : List_Id; Suppress : Check_Id);
-- Inserts list L before node N using Nlists.Insert_List_Before, and then,
-- after this insertion is complete, analyzes all the nodes in the list,
-- including any additional nodes generated by this analysis. If the list
-- is empty or be No_List, the call has no effect. If the Suppress
-- argument is present, then the analysis is done with the specified
-- check suppressed (can be All_Checks to suppress all checks).
procedure Insert_After_And_Analyze
(N : Node_Id; M : Node_Id);
procedure Insert_After_And_Analyze
(N : Node_Id; M : Node_Id; Suppress : Check_Id);
-- Inserts node M after node N and then after the insertion is complete,
-- analyzes the inserted node and all nodes that are generated by
-- this analysis. If the node is empty, the call has no effect. If the
-- Suppress argument is present, then the analysis is done with the
-- specified check suppressed (can be All_Checks to suppress all checks).
procedure Insert_Before_And_Analyze
(N : Node_Id; M : Node_Id);
procedure Insert_Before_And_Analyze
(N : Node_Id; M : Node_Id; Suppress : Check_Id);
-- Inserts node M before node N and then after the insertion is complete,
-- analyzes the inserted node and all nodes that could be generated by
-- this analysis. If the node is empty, the call has no effect. If the
-- Suppress argument is present, then the analysis is done with the
-- specified check suppressed (can be All_Checks to suppress all checks).
end Sem;