Übungsblatt 5: Übersetzer und sprachverarbeitende Werkzeuge (SS

Werbung
Prof. Dr. A. Poetzsch-Heffter
Dipl.-Inform. M. Gawkowski
Technische Universität Kaiserslautern
Fachbereich Informatik
AG Softwaretechnik
Übungsblatt 5: Übersetzer und sprachverarbeitende Werkzeuge
(SS 2007)
Ausgabe:
Abgabe:
18. Mai 2007
25. Mai 2007
Zum Zwecke der nachfolgenden Übungen definieren wir eine Minisprache Let1 :
1. Schritt: Die abstrakte Syntax: Wir spezifizieren die abstrakte Syntax für unsere Sprache und speichern diese in
der Datei spec.katja:
1
specification AbstractSyntax
2
3
4
5
6
7
backend java {
package Expr.Example
import java.lang.String
import java.lang.Integer
}
8
9
10
external String
external Integer
11
12
13
// ein Beispiel fuer ein Kommentar
/* ein Beispiel fuer ein Kommentar */
14
15
Exp = Let | Var | Const | Plus | Mult
16
17
18
19
Let (VarDefs vardefs, Exp exp)
VarDefs * VarDef
VarDef (Var var, Exp exp)
20
21
22
Var (String name)
Const (Integer value)
23
24
25
Plus (Exp left, Exp right)
Mult (Exp left, Exp right)
26
27
28
29
Vars * Var
Binding (Var var, Const constant)
Env * Binding
Anschließend geben wir spec.katja als Eingabe für das katja-System2 :
gawkowsk@tux1 [LetDemo] java15 -jar katja.jar -b java -o spec.katja -j
katja erzeugt eine jar-Datei AbstractSyntax.jar. Die Datei enthält zu jeder in spec.katja definierten Sorte S jeweils eine java- und eine class-Dateien: S.java und S.class. Die Verwendung des Interfaces
der Klassen wird im Folgenden anhand eines kleinen Beispiels demonstriert.
2. Schritt: Die Parser-Spezifikation: Wir spezifizieren die konkrete Syntax für unsere Sprache und speichern die
Spezifikation in der Datei spec.cup:
1 Alle nachfolgenden Spezifikations- und java-Dateien sowie alle anderen Dateien, die Sie zum Lösen der Aufgaben auf diesem Übungsblatt
benötigen, finden Sie auf der Vorlesungsseite “Materialien” in der Datei LetDemo.tar.
2 Die Implementierung des Java Programms LetDemo wurde auf dem Rechner tux1.informatik.uni-kl.de durchgeführt.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java_cup.runtime.*;
import Expr.Example.*;
import katja.common.*;
terminal LET, IN, END, VAL, PLUS, MULT, EQ;
terminal java.lang.Integer CONST;
terminal java.lang.String VAR;
non
non
non
non
terminal
terminal
terminal
terminal
Exp mytree;
Exp expr;
VarDefs vardefs;
VarDef vardef;
precedence left PLUS;
precedence left MULT;
mytree ::= expr: e
expr
{: RESULT = e; :};
::= LET vardefs:l IN expr:e END
{: RESULT = AbstractSyntax.Let(l,e);
|
:}
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
VAR:v
{: RESULT = AbstractSyntax.Var(v); :}
|
CONST:i
{: RESULT = AbstractSyntax.Const(i); :}
|
expr:e1 PLUS expr:e2
{: RESULT = AbstractSyntax.Plus(e1,e2); :}
|
expr:e1 MULT expr:e2
{: RESULT = AbstractSyntax.Mult(e1,e2); :}
;
vardefs ::= vardefs:vdl
{: RESULT
|
{: RESULT
;
vardef
::= VAL VAR:v
{: RESULT
;
vardef:vd
= vdl.appBack(vd); :}
= AbstractSyntax.VarDefs(); :}
EQ expr:e
= AbstractSyntax.VarDef(AbstractSyntax.Var(v),e); :}
Anschließend geben wir spec.cup als Eingabe für den Parser-Generator CUP:
gawkowsk@tux1 [LetBsp] java15 -cp java_cup.jar java_cup.Main spec.cup
CUP generiert zwei java-Dateien: parser.java (hier nicht gezeigt, siehe das tar-Archiv LetDemo.tar)
und sym.java
1
2
3
4
5
6
7
8
9
10
11
//---------------------------------------------------// The following code was generated by CUP v0.10k
// Wed May 16 22:00:37 CEST 2007
//---------------------------------------------------/** CUP generated class containing symbol constants. */
public class sym {
/* terminals */
public static final int IN = 3;
public static final int MULT = 7;
12
13
14
15
16
17
18
19
20
21
22
public
public
public
public
public
public
public
public
public
static
static
static
static
static
static
static
static
static
final
final
final
final
final
final
final
final
final
int
int
int
int
int
int
int
int
int
EQ = 8;
EOF = 0;
PLUS = 6;
VAR = 10;
error = 1;
VAL = 5;
LET = 2;
END = 4;
CONST = 9;
}
3. Schritt: Die Scanner-Spezifikation: Wir spezifizieren die lexikalische Syntax für unsere Sprache und speichern
die Spezifikation in der Datei Yylex:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import java_cup.runtime.Symbol;
%%
%cup
%eofval{
return new Symbol(sym.EOF);
%eofval}
WHITESPACE=[\ \t\n\r]|\r\f
ALPHA=[A-Za-z]
DIGIT=[0-9]
%%
{WHITESPACE}+
{ System.out.println("WHITESPACES"); }
"let"
{ System.out.println(yytext().toUpperCase()); return new Symbol(sym.LET); }
"in"
{ System.out.println(yytext().toUpperCase()); return new Symbol(sym.IN); }
"val"
{ System.out.println(yytext().toUpperCase()); return new Symbol(sym.VAL); }
"end"
{ System.out.println(yytext().toUpperCase()); return new Symbol(sym.END); }
"*"
{ System.out.println(yytext().toUpperCase()); return new Symbol(sym.MULT); }
"+"
{ System.out.println(yytext().toUpperCase()); return new Symbol(sym.PLUS); }
\=
{ System.out.println(yytext().toUpperCase()); return new Symbol(sym.EQ); }
{ALPHA}({ALPHA}|{DIGIT})*
{ System.out.println("IDENTIFIER: " + yytext()); return new Symbol(sym.VAR, yytext());}
{DIGIT}+
{return new Symbol(sym.CONST, Integer.decode(yytext()));}
.
{ System.out.println("unrecognized input" + "("+yytext()+")"); return new Symbol(sym.EOF); }
4. Schritt: “Glue-Code”: Wir implementieren ein Java-Programm, die Klasse LetDemo, welche die Verwendung
des Interfaces der von Katja-System generierten Klassen demonstriert:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import static Expr.Example.AbstractSyntax.*;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.Reader;
import
import
import
import
import
import
import
import
import
import
import
katja.common.NE;
Expr.Example.Binding;
Expr.Example.Const;
Expr.Example.Env;
Expr.Example.Exp;
Expr.Example.Let;
Expr.Example.Mult;
Expr.Example.Plus;
Expr.Example.Var;
Expr.Example.VarDef;
Expr.Example.Vars;
class LetDemo {
public static void main(String args[]) throws Exception {
if(args.length < 1) {
System.out.println("usage: java LetDemo <infile>");
System.exit(0);
}
Reader input = new BufferedReader(new FileReader(args[0]));
Yylex MinilangScanner = new Yylex(input);
parser parser_obj = new parser(MinilangScanner);
Exp prog = (Exp)parser_obj.parse().value;
System.out.println(prog.toString());
System.out.println("Test: "+test(prog));
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
Exp t = test2();
System.out.println("Test2: "+test(t));
}
private static String test (Exp expr) throws Exception {
if (expr instanceof Const) {
return "(Const("+(Integer.toString(((Const)expr).value()))+"))";
}
if (expr instanceof Var) {
return "(Var("+((Var)expr).name()+"))";
}
if (expr instanceof Mult) {
String a = test(((Mult)expr).left());
String b = test(((Mult)expr).right());
return "(MULT("+a+","+b+"))";
}
if (expr instanceof Plus) {
String a = test(((Plus)expr).left());
String b = test(((Plus)expr).right());
return "(PLUS("+a+","+b+"))";
}
if (expr instanceof Let){
String cur = "";
for(VarDef vd : ((Let)expr).vardefs()) {
String a = "(VarDef("+vd.var().name()+test(vd.exp())+"))";
cur = cur+a;
}
return "(LET("+cur+")IN("+ (test(((Let)expr).exp())) +")END)";
}
throw new Exception ("error in test");
}
private static Exp test2(){
int x = 4;
int y = 5;
String v1 = "var1";
Const const_a = Const(x);
Const const_b = Const(y);
Var
var_1 = Var(v1);
Exp e1 = Mult((Exp)const_a, Mult((Exp)var_1,(Exp)const_b));
return e1;
}
}
Aufgabe 1
MIMA Parser
Schreiben Sie eine Klasse MIMAParser, die in der Methode main ein Parser-Objekt parser_obj initialisiert, die
Methode parser_obj.parse() aufruft und das Ergebnis des Aufrufs, ein abstrakter Syntaxbaum eines MIMAProgramms, ein einer Variable speichert.
Aufgabe 2
Erweiterung des Let-Beispiels
Schreiben Sie eine Klasse LetInterpreter mit Methoden zu Namensanalyse und Interpretationen der LetAusdrücke, d.h.:
a) Schreiben Sie eine Java-Methode, die (1) den generierten Parser für unsere Minisprache initialisiert, (2) die entsprechende Prozedur zum Parsen aufruft, (3) das Result des Parsens als eine Datenstruktur vom Typ Exp in einer
temporären Variable e speichert und (4) die Namensanalyse von e durchführt.
Hinweis: Die Methode soll die folgende Signatur haben:
public bool namensanalyse(Exp e, Vars vs).
Dabei soll beim Aufruf der Methode eine leere Bezeichnerliste als Wert des Parameters vs übergeben werden,
siehe die Vorlesungsfolien und die Datei spec.katja.
b) Schreiben Sie eine Methode, die einen Ausdruck evom Typ Exp und eine leere Umgebung env vom Typ Env als
Parameter entgegennimmnt und e in env zu einem Wert vom Typ int auswertet.
Hinweis: Die Methode soll die folgende Signatur haben:
public int eval(Exp e, Env env)
Siehe die Vorlesungsfolien und die Datei spec.katja.
Aufgabe 3
Zusatzaufgabe: Fehlerbehandlung
a) Erweitern Sie Ihr Programm aus Aufgabe 2 um die Fehlerbehandlung: Beim Auftreten eines Syntaxfehlers soll Ihr
Programm die Zeilen- und Spaltennummer der Stelle, an der der Fehler aufgetreten ist, ausgeben.
Herunterladen