General Information
Tutorials
Reference Manuals
Libraries
Translation Tasks
Tools
Administration
|
Name analysis according to scope rulesInheritance of ScopesThe basic scope rule concepts are described by hierarchically nested environments which reflect the structure of nested ranges in a program. Using scopes as properties of objects, as described in See Scopes Being Properties of Objects, allows to export a scope with bindings from a range, propagate them by a property, and bind single identifiers that occur outside of the range where the binding is established, e.g. a component identifier that is qualified by a module name.
In this section we further extend that concept such that scope rules
for language constructs like module m { int i; float f() {...} } { float g; with m { int i; g = f();} }
The new concept is described by an inheritance relation between scopes
that is used when applied identifier occurrences in a range are bound
to definitions. In the above example the range of the Name analysis computations for such constructs rely on several different operations: scopes being created, bindings in a scope being established, scope properties being set, inheritance relations between scopes being established. The propagation of scope properties is not limited to strictly nested structures. Hence, the dependencies between the computations are rather sophisticated. That is why the combination of modules is restricted. There are three modules that provide computations for the consistent renaming task based on inheritance. They rely on the use of the corresponding modules for basic scope rules and for scope properties:
Using one of these modules requires that the corresponding
basic scope rule module and a suitable scope property module is instantiated
with the same generic parameters
Each of the three modules implements consistent renaming of identifiers.
Identifier occurrences are bound to object keys of type
An inheritance relation between scopes is introduced:
A scope Together with the nesting of ranges the following general scope rule is applied:
An applied occurrence of an identifier Definitions contained in a range hide definitions inherited (directly or indirectly) by that range. Definitions inherited by a range hide definitions of enclosing ranges.
Using multiple inheritance a scope
If several definitions of an identifier
If the computations of this module are used to establish inheritance
relations, then the computations of identifier roles, like
The modules provide
SYNT.SrcMsg= IF(THIS.SrcErr, message (ERROR, "Source of inheritance is missing", 0, COORDREF));
If the stated inheritance is invalid, then the attribute
SYNT.InhMsg= IF(THIS.InhErr, message (ERROR, "Wrong scope inherited", 0, COORDREF));
SYNT.MulMsg= IF(THIS.MulErr, message (ERROR, CatStrInd( "Several definitions are inherited for: ", IdnOf(THIS.|KEY|Bind)), 0, COORDREF));
We demonstrate the use of inheritance by extending our
running example by a
Statement: 'with' WithClause 'do' WithBody. WithClause: ModUseIdent. WithBody: Statement.
The identifier should be bound to a module. The
SYMBOL WithBody INHERITS InhRange END; SYMBOL WithClause INHERITS InheritScope, ChkInherit END; RULE: Statement ::= 'with' WithClause 'do' WithBody COMPUTE WithClause.InnerScope = WithBody.Env; WithBody.GotInh = WithClause.InheritOk; END; RULE: WithClause ::= ModUseIdent COMPUTE WithClause.ScopeKey = ModUseIdent.Key; END;
Note: In this example the Similarly we can extend the language of our running example by classes with multiple inheritance:
Declaration: 'class' DefIdent Inheritances ClassBlock ';'. ClassBlock: Compound. Inheritances: Inheritance*. Inheritance: ':' InheritIdent. InheritIdent: Ident.
A declaration of a class exports the bindings of the class body,
like the declaration of a module (see Scopes Being Properties of Objects).
Additionally other classes may be inherited by a class, i.e.
their definitions are valid within the class body, if not
hidden by inner definitions. The inherited definitions may hide
definitions in ranges the class declaration is contained in.
Hence, the scope of the class body is the target of
all
SYMBOL ClassBlock INHERITS ExportRange, InhRange END; RULE: Declaration ::= 'class' DefIdent Inheritances ClassBlock ';' COMPUTE ClassBlock.ScopeKey = DefIdent.Key; ClassBlock.GotInh = Inheritances CONSTITUENTS InheritIdent.InheritOk; Inheritances.InnerScope = ClassBlock.Env; END; SYMBOL Inheritances: InnerScope: Environment; SYMBOL InheritIdent INHERITS InheritScope, ChkInherit, IdUseEnv, ChkIdUse, IdentOcc COMPUTE SYNT.InnerScope = INCLUDING Inheritances.InnerScope; SYNT.Scopekey = THIS.KeyK; END;
Note: In this example the inherited classes are determined by an unqualified
identifier each,
Languages (like C++) allow that different definitions of an
identifier may be inherited on different inheritance paths
to a range. But in that case such an identifier may not be applied
in that range.
This restriction is checked by the roles SYMBOL UseIdent INHERITS ChkInhIdUse END; SYMBOL QualIdent INHERITS ChkInhIdUseScopeProp END;
The error messages can be changed globally by symbol computations
overriding the computations of the SYMBOL UseIdent COMPUTE SYNT.MulMsg=IF(THIS.MulErr,message (ERROR, CatStrInd("Ambiguous symbol: ", IdnOf(THIS.|KEY|Bind)), 0, COORDREF)); END;
The above specification also fits to the specification
for identifiers that are qualified by a module name given in
(see Scopes Being Properties of Objects).
If in a construct
These examples are applied in the same way for Algol-like and for
C-like scope rules. The differences for bottom-up computation
are explained in the description of the Inheritance with Algol-like Scope RulesThis module implements consistent renaming of identifiers according to inheritance relations. It assumes that the scope rules do not restrict defining and applied occurrences of identifiers by a certain order in the program text, as the C-like scope rules do. The module computation in particular fit to Algol-like scope rules as described in See Inheritance of Scopes. The module is instantiated by $/Name/AlgInh.gnrc+instance=NAME +referto=KEY :inst
Using this module requires that the modules
The module provides
The dependence pattern used in the computations of this module, as
described below, imposes a restriction on the use of the role
Computations of the module provide attributes Inheritance with C-like Scope Rules
This module implements consistent renaming of identifiers
according to inheritance relations
as described in See Inheritance of Scopes.
However, the module computations establish bindings, lookup names,
associate scope properties, establish inheritance relations, and
lookup qualified names in left-to-right depth-first order.
It imposes the strong requirement that a
qualified name, for example the The module is instantiated by $/Name/CInh.gnrc+instance=NAME +referto=KEY :inst
Using this module requires that the modules The use of this module enforces the requirement that for any kind of identifier occurrence strictly hold that the definition precedes its uses.
The module provides
This module uses a strict left-to-right depth-first dependence
pattern for all its attribute computations.
The attribute C-like Inheritance Bottom-UpThis module implements consistent renaming of identifiers according to inheritance relations based on C-like scope rules. The computations can be executed while input is read. The module is instantiated by $/Name/BuInh.gnrc+instance=NAME +referto=KEY :inst
Using this module requires that the modules The use of this module enforces the requirement that for any kind of identifier occurrence strictly hold that the definition precedes its uses.
The module provides
The role
The target scope for the inheritance relation is assumed to be
computed by the role
A lower computation of The examples given in See Inheritance of Scopes are modified here to allow for bottom-up computation using this module.
We demonstrate the use of single inheritance by extending our
running example by a
Statement: 'with' WithUseIdent 'do' WithBody. WithBody: Statement.
The identifier should be bound to a module. The
RULE: Statement ::= 'with' WithUseIdent 'do' WithBody END; SYMBOL WithBody INHERITS RangeScope END; SYMBOL WithUseIdent INHERITS GetScopeProp, CreateNewScope, InheritScope, OpenNewScope, IdUseEnv, ChkIdUse, IdentOcc COMPUTE SYNT.ScopeKey = SYNT.Key; SYNT.OuterScope = SYNT.ScopeProp; SYNT.OpenPrecond = SYNT.Key; END; Similarly we can extend the language of our running example by classes with multiple inheritance:
The scope of the class body is created in the context
RULE: Declaration ::= 'class' ClassDefIdent Inheritances BuClass ClassBlock ';' END; SYMBOL ClassDefIdent INHERITS CreateNewScope, IdSetScopeProp, IdDefScope, IdentOcc END; SYMBOL BuClass INHERITS RecentNewScope, OpenNewScope END;
In the
SYMBOL InheritIdent INHERITS GetScopeProp, InheritScope, IdUseEnv, ChkIdUse, IdentOcc COMPUTE SYNT.ScopeKey = SYNT.Key; SYNT.OuterScope = SYNT.ScopeProp; IF (AND (NOT (THIS.InheritOk), NE (THIS.Key, NoKey)), message (FATAL, CatStrInd ("cyclic inheritance: ", THIS.Sym), 0, COORDREF)) BOTTOMUP; END;
The above specification also fits to the specification
for identifiers that are qualified by a module name given in
(see Scopes Being Properties of Objects).
If in a construct |