[dir] Zum Verzeichnisinhalt     [exercise] Zur Musterlösung     [download] (SHIFT + Linke Maustaste)
@=~
~p maximum_input_line_length = infinity
~p typesetter = none

~t title titlefont left "Eine Loesung der Projektaufgabe"

~A~<Funktionsweise des Prozessors~>

Ziel des zu entwickelnden Prozessors ist es, aus Verbundspezifikationen
C-Datenstrukturen, Zugriffsmakros und Allokationsfunktionen zu erzeugen.
Hier ist eine Beispieleingabe fuer unseren Prozessor:

~O~<simple~>~{
import "String.h"
Adresse
  (name:  String;
   plz:   int;
   stadt: String;
  )
~}

Daraus erzeugt der generierte Textprozessor eine .h-Datei und eine
.c-Datei. Die .h-Datei hat folgendes Aussehen:

~O~<simple.hout~>~{
#include "String.h"

typedef struct __Adresse *Adresse;
typedef struct __Adresse {
  String name_fld;
  int plz_fld;
  String stadt_fld;
} _Adresse;

#define nameOfAdresse(x) ((x)->name_fld)
#define plzOfAdresse(x) ((x)->plz_fld)
#define stadtOfAdresse(x) ((x)->stadt_fld)

extern Adresse newAdresse ();
~}

Die .c-Datei sieht wie folgt aus:

~O~<simple.cout~>~{
#include <stdlib.h>
#include "Adresse.h"

Adresse newAdresse ()
{ return (Adresse)malloc(sizeof(_Adresse));
}
~}

~A~<Die syntaktische und lexikalische Struktur der Eingabesprache~>

~O~<Struct.con~>~{
Program:          Import* StructDef*.
Import:           'import' FileName.
StructDef:        StructName '(' Fields ')'.
Fields:           Field+.
Field:            FieldName ':' TypeName ';'.
StructName:       Ident.
FieldName:        Ident.
TypeName:         Ident.
~}

Die verschiedenen fuer die Semantikanalyse und Transformation wichtigen 
Rollen von Bezeichnern werden hier bereits in der konkreten Syntax
unterschieden.

Die nichtliteralen Terminalsymbole dieser Grammatik sind Bezeichner
(~{Ident~}) und Dateiname (~{FileName~}):

~O~<Struct.gla~>~{
Ident:           PASCAL_IDENTIFIER
FileName:        C_STRING_LIT
                 C_COMMENT
~}

~A~<Namensanalyse~>

Fuer die Namensanalyse benoetigen wir die Bibliotheksmodule
~{AlgScope~} und ~{Unique~}.

~O~<StructName.specs~>~{
$/Name/AlgScope.gnrc:inst
$/Prop/Unique.gnrc:inst
~}

~B~<Die Gueltigkeit der Namen~>

Die Symbolrollen aus diesen Bibliotheksmodulen ordnen wir wie folgt
den konkreten Symbolen unserer Grammatik zu:

~O~<StructName.lido~>~{
ATTR Sym: int;
CLASS SYMBOL IdentOcc COMPUTE SYNT.Sym = TERM; END;

SYMBOL Program INHERITS RootScope END;
SYMBOL Fields  INHERITS RangeScope END;

SYMBOL StructName INHERITS IdentOcc, IdDefScope END;
SYMBOL FieldName  INHERITS IdentOcc, IdDefScope END;
SYMBOL TypeName   INHERITS IdentOcc, IdUseEnv END;

SYMBOL Program  INHERITS RangeUnique END;

SYMBOL StructName INHERITS Unique COMPUTE
  IF (NOT (THIS.Unique),
  message (ERROR, CatStrInd("Structure name is multiply defined: ",
                            THIS.Sym),
  0, COORDREF));
END;

SYMBOL FieldName INHERITS Unique COMPUTE
  IF (NOT (THIS.Unique),
  message (ERROR, CatStrInd("Field name is multiply defined: ",
                            THIS.Sym),
  0, COORDREF));
END;
~}

~B~<Die Eigenschaften der Namen~>

Die Eigenschaft von Bezeichnern, die fuer die Ueberpruefung des 
Eingabetextes wichtig ist, ist die Unterscheidung, ob sie als Feldnamen
(~{FieldName~}) oder Strukturname (~{StructName~}) definiert wurden:

~O~<NameKind.h~>~{
typedef enum {isFieldName, isStructName} NameProp;
~}

Definition der Eigenschaft ~{NameKind~}:

~O~<NameKind.pdl~>~{
NameKind: NameProp; "NameKind.h"
~}

Die folgenden Berechnungen stellen sicher, dass Bezeichner, die als Feldnamen
definiert sind, nicht als Typnamen verwendet werden. Wir haben diese 
Berechnungen als Beispiel fuer semantische Ueberpruefungen eingefuegt. Sie 
waeren fuer die vorliegende
Aufgabenstellung wegen der Art der Ausgabeerzeugung
(Feldnamen bekommen den Suffix ~{_fld~}) ansonsten nicht unbedingt noetig.

~O~<NameKind.lido~>~{
SYMBOL Program COMPUTE
   SYNT.GotNameKind = 
    CONSTITUENTS (StructName.GotNameKind, FieldName.GotNameKind);
END;

SYMBOL StructName COMPUTE
  SYNT.GotNameKind = ResetNameKind (THIS.Key, isStructName);
END;

SYMBOL FieldName COMPUTE
  SYNT.GotNameKind = ResetNameKind (THIS.Key, isFieldName);
END;

SYMBOL TypeName COMPUTE
  IF (EQ (GetNameKind (THIS.Key, isStructName), isFieldName),
  message (ERROR,
           CatStrInd
             ("Field identifier used as type name: ",
              THIS.Sym),
           0, COORDREF))
  <- INCLUDING Program.GotNameKind;
END;
~}

~A~<Die Erzeugung der Ausgabe-Dateien~>

~B~<Die Erzeugung der .c-Datei~>

Die .c-Datei besteht aus einem Kopf, der die .h-Datei und
~{stdlib.h~} inkludiert und der Defintion der new-Funktionen 
fuer die einzelnen Verbundtypen:

~O~<StructC.ptg~>~{
CStructFile:
        "#include \"" $1 string "\"\n"
        "#include <stdlib.h>\n\n"
        $2
NewFct:
        $1 string 
        " new" $1 string " ()\n"
        "{ return (" 
            $1 string ")malloc(sizeof(_" $1 string "));\n"
        "}\n\n"
~}

Die Ausgabeerzeugung benoetigt die Deklarationen des Source-Moduls
(~{source.h~}) zum Zugriff auf den Eingabedateinamen (~{SRCFILE~})
und die Deklarationen aus ~{csm.h~} zur Stringmanipulation.

~O~<TransC.head~>~{
#include "source.h"
#include "csm.h"
~}

Die Erzeugung der .c-Datei wird an der Wurzel des Strukturbaumes initiiert.
Auf die Programmtexte fuer die new-Funktionen wird dabei durch 
Fern-Zugriff (~{CONSTITUENTS~}) zugegriffen.

~O~<TransC.lido~>~{
ATTR CPtg: PTGNode;

SYMBOL Program COMPUTE
  PTGOutFile 
    (CatStrStr (SRCFILE, ".c"), 
     PTGCStructFile 
       (CatStrStr (SRCFILE, ".h"),
        CONSTITUENTS StructDef.CPtg
          WITH (PTGNode, PTGSeq, IDENTICAL, PTGNull)));
END;

RULE: StructDef ::= StructName '(' Fields ')' COMPUTE
  StructDef.CPtg = PTGNewFct (StringTable (StructName.Sym));
END;
~}

~B~<Die Erzeugung der .h-Datei~>

Die erzeugte .h-Datei besteht aus 3 Abschnitten: Import-Vereinbarungen,
Pointer-Typ-Definitionen und der Uebersetzung der 
Verbundstrukur mit Vereinbarung der new-Funktionen und
Zugriffsmakros fuer die Verbund-Komponenten:

~O~<TransH.ptg~>~{
HStructFile:
        $1 /*imports*/
        "\n"
        $2 /*ptr types*/
        "\n"
        $3 /*access*/

Import:
        "#include " $ string "\n"

PtrType:
        "typedef struct __" $1 string " *" $1 string ";\n"

StructTrans:
        $1 /*struct type*/
        "\n"
        $2 /*field macros*/
        "\n"
        $3 /*extern new*/
        "\n"

ExternNew:
        "extern " $1 string " new" $1 string " ();\n"

StructType:
        "typedef struct __" $1 string " {\n"
        $2 /*fields*/
        "} _" $1 string ";\n"

Field:        "  " $1 string " " $2 string "_fld;\n"

FieldMacro:
        "#define " $1 string "Of" $2 string 
                "(x) ((x)->" $1 string "_fld)\n"

Seq: $ $
~}

Die Erzeugung der .h-Datei wird an der Wurzel des Strukturbaumes initiiert.
Auf die Programmtexte fuer die import-Klauseln, die
Pointer-Typ-Definitionen und die Struktur-Information wird durch 3
Fern-Zugriffe (~{CONSTITUENTS~}) zugegriffen.

~O~<TransH.lido~>~{
ATTR HPtg, PtrPtg, MacroPtg: PTGNode;

SYMBOL Program COMPUTE
  PTGOutFile
    (CatStrStr (SRCFILE, ".h"),
     PTGHStructFile 
       (CONSTITUENTS Import.HPtg
          WITH (PTGNode, PTGSeq, IDENTICAL, PTGNull),
        CONSTITUENTS StructDef.PtrPtg
          WITH (PTGNode, PTGSeq, IDENTICAL, PTGNull),
        CONSTITUENTS StructDef.HPtg
          WITH (PTGNode, PTGSeq, IDENTICAL, PTGNull)));
END;

RULE: Import ::= 'import' FileName COMPUTE
  Import.HPtg = PTGImport (StringTable (FileName));
END;

RULE: StructDef ::= StructName '(' Fields ')' COMPUTE
  StructDef.PtrPtg =
    PTGPtrType (StringTable (StructName.Sym));

  StructDef.HPtg =
    PTGStructTrans
      (PTGStructType
         (StringTable (StructName.Sym),
          CONSTITUENTS Field.HPtg
            WITH (PTGNode, PTGSeq, IDENTICAL, PTGNull)),
       CONSTITUENTS Field.MacroPtg
          WITH (PTGNode, PTGSeq, IDENTICAL, PTGNull),
       PTGExternNew (StringTable (StructName.Sym)));

  StructDef.Sym = StructName.Sym;
END;

RULE: Field ::= FieldName ':' TypeName ';' COMPUTE
  Field.HPtg =
    PTGField
      (StringTable (TypeName.Sym),
       StringTable (FieldName.Sym));

  Field.MacroPtg =
    PTGFieldMacro
      (StringTable (FieldName.Sym),
       StringTable (INCLUDING StructDef.Sym));
END;
~}