General Information
Tutorials
Reference Manuals
Libraries
Translation Tasks
Tools
Administration
|
Tutorial for Name Analysis Using ScopeGraphsInteraction with Type Analysis
Classes provide the structure for objects.
An object can be created by applying the Here is an example whose classes implement a very simple NameLan expression tree: expr.nl[75]== class Expr { int eval() { } } class Dyadic extends Expr { Oper op; Expr left; Expr right; int eval() { return op.eval(left.eval(), right.eval()); } } class IntDenot extends Expr { int v; /* v is set when the object is created */ int eval() { return v; } } class Oper { int eval(int l, int r) { } } class Plus extends Oper { int eval(int l, int r) { return l + r; } } class Minus extends Oper { int eval(int l, int r) { return l - r; } } { IntDenot l = new IntDenot; l.v = 3; Expr e = l; int v = e.eval(); /* v now holds the integer value 3 */ } This macro is attached to a non-product file.
The block here creates an object representing an integer expression
"
The only obvious extensions necessary to accommodate this example are to
accept a Phrase structure[76]== Type: Name. Expr: 'new' Name. This macro is defined in definitions 2, 25, 30, 32, 41, 50, 55, 67, 76, 97, 118, and 124. This macro is invoked in definition 3.
In these contexts, the Make contexts of complete names explicit[77]== RULE: Type ::= ClassName END; RULE: Expr ::= 'new' ClassName END; RULE: ClassName ::= Name END; This macro is defined in definitions 37, 44, 56, 57, 68, 77, and 98. This macro is invoked in definition 38. Although these syntactic extensions allow us to accept programs like `expr.nl', they are not sufficient to support name analysis.
Consider the three occurrences of
Notice that a type-qualified You can see the effect of type-qualified names by generating a processor that is missing computations to derive members from types, and applying that processor to `expr.nl' (see Execute a command in a specified directory of Products and Parameters Reference Manual).
-> $elipkg/Name/LearnSG%Type > . -> . +cmd=(NameLan.specs :exe) (expr.nl) :run
Connect to the Typing moduleIn order to analyze a type-qualified name, we need to know the qualifier's type. The task of type analysis is to determine a type for every construct that has a type, and therefore name analysis of type-qualified names needs support from type analysis.
The basic type analysis computations are provided by the Eli Specification files[78]== $/Type/Typing.gnrc :inst This macro is defined in definitions 12, 16, 23, 27, 74, 78, 81, 91, 117, 121, 139, 142, 146, and 152. This macro is invoked in definition 13.
NameLan uses name equivalence for types, so
We need to initialize definition table keys for the
three language-defined types
(see How to specify the initial state of The Property Definition Language).
Each of these definition table keys should have a property Properties and property computations[79]== intType -> IsType={1}; floatType -> IsType={1}; voidType -> IsType={1}; This macro is defined in definitions 79, 94, 126, 132, 143, and 148. This macro is invoked in definition 80. Property definitions and computations are specified in a file of type `.pdl', which must be added to the set of specifications: NameLan.pdl[80]== Properties and property computations[79] This macro is attached to a product file. Specification files[81]== NameLan.pdl This macro is defined in definitions 12, 16, 23, 27, 74, 78, 81, 91, 117, 121, 139, 142, 146, and 152. This macro is invoked in definition 13.
Definition table keys for user-defined types are created by the
Construct that represents a subtree denoting a type[82]== SYMBOL ClassBody INHERITS TypeDenotation END; This macro is invoked in definition 88.
This guarantees that each
Type keys are made available to a variable declaration via the
Establish the Type attribute of Type[83]== ATTR Type: DefTableKey; RULE: Type ::= 'int' COMPUTE Type.Type = intType; END; RULE: Type ::= 'float' COMPUTE Type.Type = floatType; END; RULE: Type ::= 'void' COMPUTE Type.Type = voidType; END; RULE: Type ::= ClassName COMPUTE Type.Type = ClassName.Type; END; This macro is invoked in definition 88.
Note that in order to establish the
An identifier that is a Construct defining one or more entities of the same type[84]== SYMBOL VarDecl INHERITS TypedDefinition END; RULE: VarDecl ::= Type VarDefs ';' COMPUTE VarDecl.Type = Type.Type; END; SYMBOL Parameter INHERITS TypedDefinition END; RULE: Parameter ::= Type ParamDefName COMPUTE Parameter.Type = Type.Type; END; This macro is invoked in definition 88. Defining occurrence of an identifier for a typed entity[85]== SYMBOL VarDefName INHERITS TypedDefId END; SYMBOL ParamDefName INHERITS TypedDefId END; This macro is invoked in definition 88. Defining occurrence of a type identifier[86]== SYMBOL ClassDefName INHERITS TypeDefDefId END; RULE: ClassDecl ::= 'class' ClassDefName Inheritance ClassBody COMPUTE ClassDefName.Type = ClassBody.Type; END; This macro is invoked in definition 88. Applied occurrence of a type identifier[87]== SYMBOL ClassName INHERITS TypeDefUseId END; RULE: ClassName ::= Name COMPUTE ClassName.Key = Name.Key; END; This macro is invoked in definition 88.
In summary, the computations to connect the Abstract syntax tree[88]== Establish the Type attribute of Type[83] Construct defining one or more entities of the same type[84] Defining occurrence of an identifier for a typed entity[85] Construct that represents a subtree denoting a type[82] Defining occurrence of a type identifier[86] Applied occurrence of a type identifier[87] This macro is defined in definitions 10, 18, 22, 38, 47, 52, 53, 65, 69, 71, 88, 89, 92, 93, 95, 96, 101, 105, 108, 110, 111, 112, 113, 122, 133, 134, 135, 136, 137, 144, and 153. This macro is invoked in definition 11.
Type-qualified entity names
Consider the declaration of
class Dyadic extends Expr { Oper op; Expr left; Expr right; int eval() { return op.eval(left.eval(), right.eval()); } }The variable op is a qualifier in the return expression, so
the processor must determine its type in order to find the member set
containing the binding for eval .
But before the type property of the variable op
can be determined, name analysis must find the meaning of Oper .
(We mentioned this constraint in the last section.)
We must make certain that the type of Abstract syntax tree[89]== RULE: MethName ::= Name COMPUTE Name.ContextIsReady += INCLUDING RootType.TypeIsSet; END; RULE: ExprName ::= Name COMPUTE Name.ContextIsReady += INCLUDING RootType.TypeIsSet; END; RULE: Name ::= Name '.' QualifiedId COMPUTE Name[2].ContextIsReady += Name[1].ContextIsReady; END; This macro is defined in definitions 10, 18, 22, 38, 47, 52, 53, 65, 69, 71, 88, 89, 92, 93, 95, 96, 101, 105, 108, 110, 111, 112, 113, 122, 133, 134, 135, 136, 137, 144, and 153. This macro is invoked in definition 11.
We cannot make
The generic lookup invokes AccessNodesFromQualifier.c[90]== #include "AccessNodesFromQualifier.h" #include "pdl_gen.h" NodeTuplePtr AccessNodesFromQualifier(DefTableKey qualifier, DefTableKey appselector) { NodeTuplePtr res = GetOwnedNodeTuple(qualifier, NoNodeTuple); if (res == NoNodeTuple) res = GetOwnedNodeTuple(GetTypeOf(qualifier, NoKey), NoNodeTuple); return res; } This macro is attached to a product file.
Note that this implementation of `AccessNodesFromQualifier.c' is one of the specification files: Specification files[91]== AccessNodesFromQualifier.c This macro is defined in definitions 12, 16, 23, 27, 74, 78, 81, 91, 117, 121, 139, 142, 146, and 152. This macro is invoked in definition 13.
The only remaining issue is how to report a violation of the rule that a
variable name is not allowed in a Abstract syntax tree[92]== SYMBOL SimpleName INHERITS ChkLegalClassName END; SYMBOL QualifiedId INHERITS ChkLegalClassName END; This macro is defined in definitions 10, 18, 22, 38, 47, 52, 53, 65, 69, 71, 88, 89, 92, 93, 95, 96, 101, 105, 108, 110, 111, 112, 113, 122, 133, 134, 135, 136, 137, 144, and 153. This macro is invoked in definition 11.
Abstract syntax tree[93]== SYMBOL ChkLegalClassName COMPUTE IF(AND(AND( NOT(EQ(THIS.Key, NoKey)), GetIsVariable(THIS.Key, 0)), INCLUDING (ClassName.InClassName, RootScope.InClassName)), message( ERROR, CatStrInd ("Must not occur in a class name: ", THIS.Sym), 0, COORDREF)); END; This macro is defined in definitions 10, 18, 22, 38, 47, 52, 53, 65, 69, 71, 88, 89, 92, 93, 95, 96, 101, 105, 108, 110, 111, 112, 113, 122, 133, 134, 135, 136, 137, 144, and 153. This macro is invoked in definition 11.
The Properties and property computations[94]== IsVariable: int; /* 1 if the entity is a variable */ This macro is defined in definitions 79, 94, 126, 132, 143, and 148. This macro is invoked in definition 80. Abstract syntax tree[95]== SYMBOL VarDefName COMPUTE SYNT.GotDefKeyProp += ResetIsVariable(THIS.Key,1); END; This macro is defined in definitions 10, 18, 22, 38, 47, 52, 53, 65, 69, 71, 88, 89, 92, 93, 95, 96, 101, 105, 108, 110, 111, 112, 113, 122, 133, 134, 135, 136, 137, 144, and 153. This macro is invoked in definition 11.
Making
Finally, we need to set the Abstract syntax tree[96]== SYMBOL ClassName, RootScope: InClassName: int; SYMBOL ClassName COMPUTE SYNT.InClassName = 1; END; SYMBOL RootScope COMPUTE SYNT.InClassName = 0; END; This macro is defined in definitions 10, 18, 22, 38, 47, 52, 53, 65, 69, 71, 88, 89, 92, 93, 95, 96, 101, 105, 108, 110, 111, 112, 113, 122, 133, 134, 135, 136, 137, 144, and 153. This macro is invoked in definition 11.
ExercisesThese exercises are based on files defined in the Tutorial. To obtain copies of those files in your current directory, enter Eli and give the following command:
-> $elipkg/Name/LearnSG%TQ > .None of these files will have write permission in your current directory.
Type-qualified edge names
We have seen that type-qualified names require cooperation between
name and type analysis modules, and how they introduce dependence among
computations.
The type-qualified names in `expr.nl' describe
components of an expression in a value context.
Suppose that, for some reason, there is a section of code containing a
number of references to the members of some computed object.
The NameLan Phrase structure[97]== Statement: 'with' Name 'do' WithBody. WithBody: Statement. This macro is defined in definitions 2, 25, 30, 32, 41, 50, 55, 67, 76, 97, 118, and 124. This macro is invoked in definition 3.
The attributes needed for a Make contexts of complete names explicit[98]== RULE: Statement ::= 'with' WithName 'do' WithBody END; RULE: WithName ::= Name END; This macro is defined in definitions 37, 44, 56, 57, 68, 77, and 98. This macro is invoked in definition 38.
Because the Ensure that types are defined[99]== RULE: WithName ::= Name COMPUTE Name.ContextIsReady += INCLUDING RootType.TypeIsSet; END; This macro is invoked in definition 105.
Here is an example in which the with.nl[100]== class T { int a, b, c; } { float a, c = 1.2; T p = new T; p.c = 3; T r = new T; r.b = 4; a = r.b + c; with p do a = r.b + c; } This macro is attached to a non-product file.
Our scope rule for a NameLan
WithBody must be a range:
Abstract syntax tree[101]== SYMBOL WithBody INHERITS RangeScope END; This macro is defined in definitions 10, 18, 22, 38, 47, 52, 53, 65, 69, 71, 88, 89, 92, 93, 95, 96, 101, 105, 108, 110, 111, 112, 113, 122, 133, 134, 135, 136, 137, 144, and 153. This macro is invoked in definition 11. Recall that inheritance is modeled by a path edge in the scope graph (see Inheritance). We need to add that edge to the graph, but the edge tip is defined by a name that may be type-qualified. Therefore the inheritance edge cannot be constructed until all edges have been added to the graph and the types of all typed identifiers have been determined. This is clearly impossible: "all edges have been added" cannot be a precondition for "add an edge".
The paradox can be avoided by using the Partition the program analysis[102]== SYMBOL WithBody INHERITS OutSideInDeps END; This macro is defined in definitions 102 and 104. This macro is invoked in definition 105.
This statement implies that there is a subgraph `W' of the
scope graph `G', such that no edge may have its tail in
`G-W' and its tip in `W'.
Subgraph `W' corresponds to the abstract syntax subtree rooted in the
The Add the path edge to the graph[103]== SYMBOL WithBody INHERITS OutSideInEdge END; RULE: Statement ::= 'with' WithName 'do' WithBody COMPUTE WithBody.tipEnv = AccessNodesFromQualifier(WithName.Key, NoKey); END; RULE: WithName ::= Name COMPUTE WithName.Key = Name.Key; END; This macro is invoked in definition 105. We need to partition the type analysis as well (see Interaction with type analysis of Name Analysis Reference Manual). Partition the program analysis[104]== SYMBOL TypedDefId INHERITS SetTypeOfEntity END; SYMBOL TypedUseId COMPUTE SYNT.TypeIsSet=INCLUDING OutSideInDeps.GotEntityTypes; END; This macro is defined in definitions 102 and 104. This macro is invoked in definition 105. Combining the attribute computations and adding them to the other specifications gives us a complete specification from which we can generate a processor that handles programs like `with.nl': Abstract syntax tree[105]== Ensure that types are defined[99] Partition the program analysis[102] Add the path edge to the graph[103] This macro is defined in definitions 10, 18, 22, 38, 47, 52, 53, 65, 69, 71, 88, 89, 92, 93, 95, 96, 101, 105, 108, 110, 111, 112, 113, 122, 133, 134, 135, 136, 137, 144, and 153. This macro is invoked in definition 11.
ExercisesThese exercises are based on files defined in the Tutorial. To obtain copies of those files in your current directory, enter Eli and give the following command:
-> $elipkg/Name/LearnSG%With > . None of these files will have write permission in your current directory. You will need to add write permission in order to do the exercises.
|