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