![]() |
![]() |
![]() |
General Information
Tutorials
Reference Manuals
Libraries
Translation Tasks
Tools
Administration
![]() |
![]() |
Name analysis according to scope rulesScopes Being Properties of Objects
Language constructs like modules, classes, or record types have a body
that is a range. The set of bindings for the components defined
in that range constitutes its scope.
In an applied context of a module, class, or record identifier
its components may be selected, e.g. in
This specific task of consistent renaming for component identifiers is often
closely related to type analysis. If The following four modules extend the basic scope rule modules (see Basic Scope Rules) by facilities that support scope properties. How to select one of the modules is explained below.
The design of scope rules and their description needs careful consideration if the concept of scopes being properties is involved. We have to answer some questions on the described language before we can decide which of the library modules is to be used: It is easily decided that we need the facility of scope properties: Assume the language has named program objects, say modules, which consists of a range with definitions of components or members. Those members are accressible outside their defining range wherever the name of the module is accessible: module m { int i; float f (); {...} } m:f();In this example the module body is a range where the members i and
f are defined. The scope of the range contains bindings for
i and f . It is a property of the module m which is
set in the module definition. The construct m:f is a qualified name:
A binding for f is to be found in the scope property of the
qualifying module name m . The definitions valid in the context of
the qualified name are irrelevant for the binding of f .
The same application pattern occurs for example with types that have components, like record types, structure types, and union types. There component selections are usually qualified with variables having such a type rather than with the type identifier itself.
It is recommended to use the module m; m:f(); module m { int i; float f (); {...} }Even if it should be considered erroneous to use the qualified name f before its definition, it is recommended to specify
the binding in the described way, and to enforce that restriction by
a check of the related positions.
The same holds for bottom-up basic scope rules. One only has to be aware
that the binding of qualified names is determined after the
bottom-up computations.
There are a few specific reasons where the modules
If the basic scope rules are specified C-like using
If the basic scope rules are specified C-like using The general description of this set of module is given in the section see Scope Properties without Ordering Restrictions, the deviations of its variants are described in see Scope Properties Algol-like, see Scope Properties C-like, and see Scope Properties C-like Bottom-Up.
Scope Properties without Ordering Restrictions
This module The module is instantiated by $/Name/ScopeProp.gnrc+instance=NAME +referto=KEY :inst
It is required that a
basic scope rule module is instantiated with the same generic parameters
Each of the modules introduces a
The module provide
The attribute We demonstrate the use of these facilities by extending the language of our running example by module declarations and access of module components. The notation is specified by the following two concrete productions:
Declaration: 'module' DefIdent ModBlock ';'. ModBlock: Compound. Operand: ModUseIdent '::' QualIdent. ModUseIdent: Ident. QualIdent: Ident. The symbols inherit the roles provided by the scope property module as described above:
RULE: Declaration ::= 'module' DefIdent ModBlock ';' COMPUTE ModBlock.ScopeKey = DefIdent.Key; END; SYMBOL ModBlock INHERITS RangeScopeProp END; In the context of the module declaration it is specified that the scope of the module body is associated to the key of the module identifer. In the context of the selection the scope is specified in which the selected component is to be bound. It is accessed from the key of the module identifer. The dependency ensures that all scope properties are associated before accessed here:
RULE: Expression ::= ModUseIdent '::' QualIdent COMPUTE QualIdent.ScopeKey = ModUseIdent.Key; END; SYMBOL ModUseIdent INHERITS IdUseEnv, ChkIdUse, IdentOcc END; SYMBOL QualIdent INHERITS IdUseScopeProp, ChkIdUse, IdentOcc END; In order to make sure that the it is really a module identifier to which the selection is applied we specify the following check
RULE: Expression ::= ModUseIdent '::' QualIdent COMPUTE IF (AND (NE (ModUseIdent.Key, NoKey), EQ (QualIdent.Scope, NoEnv)), message (FATAL, CatStrInd ("module identifier required: ", ModUseIdent.Sym), 0, COORDREF)); END; The message is only issued if the identifier is defined but does not have a scope property.
(The
Scope Properties Algol-like
This module
Scope Properties C-like
This module implements consistent renaming of identifiers
using scopes which are properties associated to object keys.
The module computations ensure that scope properties are associated
and accessed in left-to-right depth-first order.
It imposes the strong requirement that a
qualified name, for example the
It is recommended to use this module only if it is needed as
a companion of the module The module is instantiated by $/Name/CScopeProp.gnrc+instance=NAME +referto=KEY :inst
Using this module requires that the module
The module provides a
In case of All computations of this module follow strictly C-like scope rules, i.e. binding of identifier occurrences, association of scope properties, and access of scope properties are done in left-to-right depth-first order.
Calls of
Scope Properties C-like Bottom-Up
This module implements consistent renaming of identifiers
using scopes which are properties associated to object keys.
The module computations ensure that scope properties are associated
and accessed in left-to-right depth-first order.
It imposes the strong requirement that a
qualified name, for example the
It is recommended to use this module only if qualified identifiers
have to be bound in the bottom-up phase, or if the module is needed as
a companion of the module The computations provided by this module are executed while reading the input. The module is instantiated by $/Name/BuScopeProp.gnrc+instance=NAME +referto=KEY :inst
Using this module requires that the module
The module provides a All computations of this module follow strictly C-like scope rules, i.e. binding of identifier occurrences, association of scope properties, and access of scope properties are done in left-to-right depth-first order.
As a consequence of bottom-up computation the value of a key can
not be propagated by an upper computation to the range symbol.
Hence, if the defining identifier occurrence precedes the range,
the scope has to be created by the role
The role that opens the range scope (
The range symbol has the role The module declaration of our example then reads: RULE: Declaration ::= 'module' ModDefIdent Block ';' END; SYMBOL ModDefIdent INHERITS CreateNewScope, OpenNewScope, IdSetScopeProp, IdDefScope, IdentOcc COMPUTE SYNT.OpenPrecond = SYNT.Key; END;
In component selections the scope property needs to be propagated
from the context that provides it to the selector context.
The module role Hence, in our running example the selection is specified as follows:
RULE: Expression ::= ModUseIdent '::' QualIdent END; SYMBOL ModUseIdent INHERITS GetScopeProp, IdUseEnv, ChkIdUse, IdentOcc COMPUTE SYNT.ScopeKey = THIS.Key; END; SYMBOL QualIdent INHERITS IdUseScopeProp, ChkIdUse, IdentOcc END;
If we had a typed record expression instead of the module identifier
to select from,
|