Universität Paderborn - Home Universität Paderborn
Die Universität der Informationsgesellschaft

Generating Software from Specifications WS 2013/14 - File QualNamesSol.fw

@=~
~p maximum_input_line_length = infinity

This file contains the specification of a processor
for structured types and qualified names.

The following tasks are to be solved:
1. Read and understand name analysis and type analysis as
specified below. The specification is NOT explained.
Insert explanations according to your understanding.

2. A processor can be generated from this specification.
However, it does not work as expected. Compare its results
at least for the given examples to the expected results.
The author of this specification has failed to specify 
necessary preconditions explicily for several computations.
Add those necessary dependences, and test the corrected analysis.

The following file contains correct input for the processor.
Under Algol-like scope rules the order of declarations and uses
of identifiers is irrelevant:
~O~<QualNames.ok~>~{~-
{
  l.a = 42; l.next = l;
  b.a = l.next.next.a;
  b.left = nil; b.right = nil;
  list l;
  btree b;
  type list = (int a; list next;)
  type btree = (int a; btree left; btree right;)
}
~}

The following file contains erroneous input for the processor:
~O~<QualNames.err~>~{~-
{
  type list = (int a; list next;)
  list l;
  l.a = nil;
  l.next = 42;
  v.a = 42;
  l.next = b;
  type btree = (int a; btree left; btree right;)
  btree b;
  int b;
  type xlist = (int a; list next; list a;)
}
~}

The following file contains the messages expected for the above example
~O~<QualNames.msg~>~{~-
"QualNames.err", line 9:9 ERROR: multiply defined: b
"QualNames.err", line 10:7 ERROR: multiply defined: b
"QualNames.err", line 11:21 ERROR: multiply defined: a
"QualNames.err", line 11:40 ERROR: multiply defined: a
"QualNames.err", line 4:3 ERROR: wrong type in assignment
"QualNames.err", line 5:3 ERROR: wrong type in assignment
"QualNames.err", line 6:3 ERROR: identifier is not defined: v
"QualNames.err", line 6:5 ERROR: identifier is not defined: a
"QualNames.err", line 7:3 ERROR: wrong type in assignment
~}

The following file specifies the concrete syntax:
~O~<QualNames.con~>~{
Program:	'{' Constructs '}'.

Constructs:	Constructs Construct / Construct.
Construct:	TypeDecl.
Construct:	VariableDecl.
Construct:	Assignment.

TypeDecl:	'type' TypeDefName '=' Record.
TypeDefName:	Identifier.
Record:		'(' Fields ')'.
Fields:		Fields Field / Field.
Field:		Type FieldDefName ';'.
FieldDefName:	Identifier.
Type:		'int' / TypeUseName.
TypeUseName:	Identifier.
VariableDecl:	Type VarDefName ';'.
VarDefName:	Identifier.

QualifiedName:	VarUseName / QualifiedName '.' FieldUseName.
VarUseName:	Identifier.
FieldUseName:	Identifier.

Assignment:	 QualifiedName '=' Expression ';'.
Expression:	 QualifiedName / Number / 'nil'.
~}

The following file specifies the non-literal tokens:
~O~<QualNames.gla~>~{
Identifier: C_IDENTIFIER
Number:     C_INTEGER
            C_COMMENT
~}

Basic Name Analysis
-------------------

The following file instantiates the basic name analysis module
from Eli's specification modules which establishes
bindings according to Algol-like scope rules:
~O~<Name.specs~>~{
$/Name/AlgScope.gnrc:inst
$/Tech/Strings.specs
~}

EXPLAIN:
The class symbol IdentOcc provides the computation of the
Sym attribute for occurrences of names.
The module roles for the root, the range, the defining and the
applied occurrences are associated:
~O~<IdentOcc.lido~>~{
CLASS SYMBOL IdentOcc: Sym: int;
CLASS SYMBOL IdentOcc COMPUTE
  SYNT.Sym = TERM; 
END;

SYMBOL Program INHERITS RootScope END;
SYMBOL Record INHERITS RangeScope END;

SYMBOL TypeDefName INHERITS IdentOcc, IdDefScope END;
SYMBOL VarDefName INHERITS IdentOcc, IdDefScope END;
SYMBOL FieldDefName INHERITS IdentOcc, IdDefScope END;

SYMBOL TypeUseName INHERITS IdentOcc, IdUseEnv, ChkIdUse END;
SYMBOL VarUseName INHERITS IdentOcc, IdUseEnv, ChkIdUse END;
~}

EXPLAIN:
An identifier must not be definied more than once in any range:

MISSING DEPENDENCE:
A processor generated from the specification given in the task
does not give error messages on multiple definitions of the
same identifier.

The GetDefs operation must not be called before all calls of
the SetDefs operation are executed. That dependence is
established by the well-known dependence pattern on the
attributes Program.GotDefs and UniqueDefName.GotDefs.
~O~<UniqueDefs.pdl~>~{~-
Defs: int;
~}
~O~<UniqueDefs.lido~>~{~-
SYMBOL Program COMPUTE
  SYNT.GotDefs = CONSTITUENTS UniqueDefName.GotDefs;
END;
CLASS SYMBOL UniqueDefName COMPUTE
  SYNT.GotDefs = SetDefs (THIS.Key, 1, 2);

  IF (GT (GetDefs (THIS.Key, 0), 1),
     message (ERROR, CatStrStr ("multiply defined: ", StringTable (THIS.Sym)), 
              0, COORDREF))
  <- INCLUDING Program.GotDefs;
END;
SYMBOL TypeDefName INHERITS UniqueDefName END;
SYMBOL VarDefName INHERITS UniqueDefName END;
SYMBOL FieldDefName INHERITS UniqueDefName END;
~}

Name Analysis for Qualified Names
---------------------------------
EXPLAIN:
Record types have an environment as their property,
where the field names are bound in.
~O~<ScopeProperty.pdl~>~{~-
Scope: Environment; "envmod.h"
~}

That property is set in the defining context of a type name.
The scope property is accessed from the type of a QualifiedName.
Program.GotScope guarantees that the property is not used before
it is set for all type definitons.
The function KeyInScope is used to lookup a field name.
The dependence on Program.GotDefs guarantees that a lookup
is not tried before all definitions are processed.

MISSING DEPENDENCE:
A processor generated from the specification given in the task
does not find a binding for any used occurrence of a field name,
and indicates it by a message.

The GetScope operation must not be called before all calls of
the ResetScope operation are executed. That dependence is
established by the well-known dependence pattern on the
attributes Program.GotScope and TypeDefName.GotScope.
~O~<ScopeProperty.lido~>~{~-
SYMBOL Program COMPUTE
  THIS.GotScope = CONSTITUENTS TypeDefName.GotScope;
END;
ATTR Env: Environment;
RULE: TypeDecl ::= 'type' TypeDefName '=' Record COMPUTE
  TypeDefName.Env = Record.Env;
END;
SYMBOL TypeDefName COMPUTE
  SYNT.GotScope = ResetScope (THIS.Key, THIS.Env);
END;

RULE: QualifiedName ::= QualifiedName '.' FieldUseName COMPUTE
  FieldUseName.Env = GetScope (QualifiedName[2].Type, NoEnv)
    <- INCLUDING Program.GotScope;
  IF (EQ (QualifiedName[2].Type, intType),
    message (ERROR, "wrong type of qualifier", 0, COORDREF));
END;
SYMBOL FieldUseName INHERITS IdentOcc, ChkIdUse COMPUTE
  THIS.Key = KeyInScope (THIS.Env, THIS.Sym)
    <- INCLUDING Program.GotDefs;
END;
~}

Type Analysis
-------------
EXPLAIN:
A type property and two types for int and for nil are 
introduced.
~O~<TypeProperty.pdl~>~{~-
Type: DefTableKey;
intType;
nilType;
~}

The Type property of fields and of variables are set in their
definition contexts. It is accessed in applied occurrences
of fields or variables. The dependence on Program.GotType
guarantees that all types are set before any is accessed.

In qualified names the Type attribute is propagated upward from
VarUseName or the FieldUseName.

In the assignment context it is checked that the types 
of both sides are the same, that nil is not used with int.
No message is given if one of the two types is NoKey, which 
represents an unknown type due to an error which is reported
elsewhere.

MISSING DEPENDENCE:
The processor generated from the specification given in the task
does complain on "wrong type in assignment" if the definitions
of the involved variables precede the assignment in the program.
However, if the assignment precedes one of the definitions,
the message is not given. In the latter case the call of the
GetType operation has yielded NoKey instead of the defined 
type key, and a message is suppressed.

The GetType operation in the FieldUseName must not be called 
before all calls of the ResetType operation in the contexts
of VarDefName and FieldDefName are executed. That dependence is
established by the well-known dependence pattern on the
attributes Program.GotType, VarDefName.GotType and, FieldDefName.Type.

~O~<TypeProperty.lido~>~{~-
SYMBOL Program COMPUTE
  SYNT.GotType = 
     CONSTITUENTS (VarDefName.GotType, FieldDefName.GotType);
END;
ATTR Type: DefTableKey;
RULE: Field ::= Type FieldDefName ';' COMPUTE
  FieldDefName.Type = Type.Type;
END;
RULE: VariableDecl ::= Type VarDefName ';' COMPUTE
  VarDefName.Type = Type.Type;
END;
RULE: Type ::= 'int' COMPUTE
  Type.Type = intType;
END;
RULE: Type ::= TypeUseName COMPUTE
  Type.Type = TypeUseName.Key;
END;

SYMBOL VarDefName COMPUTE
  SYNT.GotType = ResetType (THIS.Key, THIS.Type);
END;

SYMBOL FieldDefName COMPUTE
  SYNT.GotType = ResetType (THIS.Key, THIS.Type);
END;

SYMBOL VarUseName COMPUTE
  SYNT.Type = GetType (THIS.Key, NoKey)
    <- INCLUDING Program.GotType;
END;

SYMBOL FieldUseName COMPUTE
  SYNT.Type = GetType (THIS.Key, NoKey)
    <- INCLUDING Program.GotType;
END;

RULE: QualifiedName ::= VarUseName COMPUTE
  QualifiedName.Type = VarUseName.Type;
END;
RULE: QualifiedName ::= QualifiedName '.' FieldUseName COMPUTE
  QualifiedName[1].Type = FieldUseName.Type;
END;
RULE: Assignment ::= QualifiedName '=' Expression ';' COMPUTE
  IF (
     NOT (OR (OR (OR (EQ (QualifiedName.Type, NoKey),
          EQ (Expression.Type, NoKey)),
          EQ (QualifiedName.Type, Expression.Type)), 
              AND (EQ (Expression.Type, nilType),
                   NE (QualifiedName.Type, intType)))),
     message (ERROR, "wrong type in assignment", 0, COORDREF));
END;
RULE: Expression ::= QualifiedName COMPUTE
  Expression.Type = QualifiedName.Type;
END;
RULE: Expression ::= Number COMPUTE
  Expression.Type = intType;
END;
RULE: Expression ::= 'nil' COMPUTE
  Expression.Type = nilType;
END;
~}

Generiert mit Camelot | Probleme mit Camelot? | Geändert am: 08.01.2014