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

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

@=~
~p maximum_input_line_length = infinity

This file contains the specification of a processor
for a little programming language with variable declarations,
nested blocks, assignments, and some control-flow statements.

The following file contains correct input for the processor:
~O~<Statements.ok~>~{~-
{
  int i;
  i = 5;
  while (i) i = 0;
  { int x; x = 21; }
  int j;
  if (j) j = 1;
  { int k; k = i;
    { k = 42; }
  }
  { i = 42; }
}
~}

The following file contains erroneous input for the processor:
~O~<Statements.err~>~{
~}

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

Constructs:	Constructs Construct / Construct.
Construct:	Declaration.
Construct:	Statement.

Declaration:	'int' VarNameDef ';'.
VarNameDef:	Identifier.

Statement:	VarNameUse '=' Expression ';' /
		'while' '(' Expression ')' Statement /
		'if' '(' Expression ')' Statement /
		Block.

Expression:	VarNameUse / Number .
VarNameUse:	Identifier.
~}

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

The following file specifies the abstract sxntax.
It is recommended not to add computations to these
rule instances; rather copy rules to other lido fragments
and add computations there.
~O~<Abstract.lido~>~{
RULE: Program ::= Block COMPUTE END;
RULE: Block ::= '{' Constructs '}' COMPUTE END;

RULE: Constructs ::= Constructs Construct COMPUTE END;
RULE: Constructs ::= Construct COMPUTE END;
RULE: Construct ::= Declaration COMPUTE END;
RULE: Construct ::= Statement COMPUTE END;

RULE: Declaration ::= 'int' VarNameDef ';' COMPUTE END;
RULE: VarNameDef ::= Identifier COMPUTE END;

RULE: Statement ::= VarNameUse '=' Expression ';' COMPUTE END;
RULE: Statement ::= 'while' '(' Expression ')' Statement COMPUTE END;
RULE: Statement ::= 'if' '(' Expression ')' Statement COMPUTE END;
RULE: Statement ::= Block COMPUTE END;

RULE: Expression ::= VarNameUse COMPUTE END;
RULE: Expression ::= Number COMPUTE END;
RULE: VarNameUse ::= Identifier COMPUTE END;
~}

For name analysis we use the module for basic Algol-like scope rules:
~O~<NameAnalysis.specs~>~{
$/Name/AlgScope.gnrc:inst
~}

Subtask-1:
Use the basic name analysis module to bind all identifier occurrences 
to keys applying Algol-like scope rules.
Solution-1:
~O~<Test-1.ok~>~{~-
{ int a;
  {
    a = b;
    int a;
    c = a;
  }
  int b;
  a = b;
  int c;
  c = 42;
}
~}
~O~<Test-1.err~>~{~-
{ int a;
  {
    a = b;
    int a;
    c = a;
  }
}
~}
Roles of the name analysis module are associated to nonterminals of the 
abstract syntax, as descibed in Ch. 4 of the lecture material,
and in Eli's documentation on Name Analysis.
~O~<NameAnalysis.lido~>~{
CLASS SYMBOL IdentOcc: Sym: int;
CLASS SYMBOL IdentOcc COMPUTE SYNT.Sym = TERM; END;
SYMBOL VarNameDef INHERITS IdentOcc, IdDefScope END;
SYMBOL VarNameUse INHERITS IdentOcc, IdUseEnv, ChkIdUse END;
SYMBOL Block INHERITS RangeScope END;
~}

Subtask-2:
At each defining occurrence output its line number; 
at each using occurrence output its line number and the line number 
of the defining occurrence.
Solution-2:
We specify a property to represent line numbers:
~O~<LineInformation.pdl~>~{
Line: int;
~}

The line number of a definition is stored as
a property of the defined entity.
It is accessed and printed from uses of that entity. 
The dependence pattern "all D before
any U" guarantees that all stores into the definition module
have happened before any access is executed
~O~<LineInformation.lido~>~{
SYMBOL Program COMPUTE
  SYNT.GotLine = CONSTITUENTS VarNameDef.GotLine;
END;

SYMBOL VarNameDef COMPUTE
  printf ("%s defined in line %d\n", StringTable (THIS.Sym), LINE);
  SYNT.GotLine = ResetLine (THIS.Key, LINE);
END;

SYMBOL VarNameUse COMPUTE
  printf ("%s defined in line %d used in line %d\n", 
           StringTable (THIS.Sym), GetLine (THIS.Key, 0), LINE)
  <- INCLUDING Program.GotLine;
END;
~}

Subtask-3:
Report a message if an entity is defined more than once.
Give that message at all offending definitions.
Solution-3:
~O~<Test-3.err~>~{~-
{ int a;
  {
    a = b;
    int a;
    c = a;
  }
  int b;
  a = b;
  int c;
  c = 42;
  int b;
}
~}
The values of the property Defs indicate that an entity has
no (0), one (1), or several (2) definitions:
~O~<Unique.pdl~>~{
Defs: int;
~}

The property is set and read in the definition context.
The pattern "all set before any get" applies.
~O~<UniqueDefs.lido~>~{
SYMBOL Program COMPUTE
  SYNT.GotDefs = CONSTITUENTS VarNameDef.GotDefs;
END;

SYMBOL VarNameDef COMPUTE
  SYNT.GotDefs = SetDefs (THIS.Key, 1, 2);

  IF (GT (GetDefs (THIS.Key, 0), 1),
     message (ERROR, "multiple definitions", 0, COORDREF))
  <- INCLUDING Program.GotDefs;
END;
~}


Subtask-4:
Report a message if a use occurs before its definition.
Solution-4:
~O~<Test-4.err~>~{~-
{ int a;
  {
    a = b;
    int a;
    c = a;
  }
  int b;
  a = b;
  int c;
  c = 42;
}
~}
We can check whether a use occurs befor its definition
(in terms of line numbers), if we compare in the use
context its line number with that of the corresponding
definition. (This technique does not check the order within
the same line. If that is to be checked, too, the column has
to be stored and compared, too.)
~O~<DefBeforeUse.lido~>~{
SYMBOL VarNameUse COMPUTE
  IF (GT (GetLine (THIS.Key, 0), LINE),
  message (ERROR, "a use before its definition", 0, COORDREF))
  <- INCLUDING Program.GotLine;
END;
~}

Subtask-5:
At at every occurrence of an identifier, except the first one, output the 
line number of the previous occurrence. Definitions and uses are treated in 
the same way; it is irrelevant which entities are referenced.
Solution-5:
We use a CHAIN to output the line number of the previous
occurrence of an identifier. We associate the computations to a class symbol,
and reuse it twice:
~O~<Previous.lido~>~{~-
CHAIN prev: int;
SYMBOL Program COMPUTE
  CHAINSTART HEAD.prev = 0;
END;

CLASS SYMBOL Occurrence COMPUTE
  THIS.prev =
     ORDER (
        printf ("The previous construct was in line %d\n", THIS.prev),
        LINE);
END;

SYMBOL VarNameDef INHERITS Occurrence END;
SYMBOL VarNameUse INHERITS Occurrence END;
~}

Subtask-6:
Implement the "Do it once" pattern of slide GSS-4.5, and 
apply it to uses and definitions of variables, such that for each variable
at most one occurrence of either kind is printed.
Solution-6:
~O~<DoItOnce.pdl~>~{~-
Done: int;
~}
~O~<DoItOnce.lido~>~{~-
CLASS SYMBOL DoItOnce: DoIt: int;

CLASS SYMBOL DoItOnce INHERITS IdentOcc COMPUTE
  SYNT.DoIt =
    IF (GetDone (THIS.Key, 0),
       0,
       ORDER (ResetDone (THIS.Key, 1), 1));

  IF (THIS.DoIt, printf ("Definition in line %d once used in line %d\n", 
      GetLine (THIS.Key, 0), LINE));
END;

SYMBOL VarNameDef INHERITS DoItOnce END;
SYMBOL VarNameUse INHERITS DoItOnce END;
~}


The following three files implements some C functions which
may be used in the generated processor:
~O~<Statements.HEAD.phi~>==~{
#include "Statements.h"
~}
~O~<Statements.h~>==~{
~}
~O~<Statements.c~>==~{
#include <stdio.h>
#include <string.h>
#include "Statements.h"
~}

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