Der
Setty-Interpreter
wertet ein gegebenes
Setty-Programm
aus und gibt das Ergebnis auf der Konsole aus.
Folgendes Programm, welches den
Setty-Interpreter
in Java implementiert,
ist bemerkenswert kurz und übersichtlich.
Der Grund dafür ist, dass ein Interpreter im Wesentlichen alle notwendigen Aufgaben an seine Komponenten delegiert:
- Präprozessor,
- Scanner,
- Parser
und
- Syntaxbaum.
Lassen wir doch einfach mal dieses Programm für sich alleine sprechen!
:-)
/**
* Die Klasse Setty interpretiert die gleichnamige Quellsprache auf viererlei
* unterschiedliche Arten:
* 1. Auswertung des Quellprogramms (eval)
* 2. Ausgabe eines gleichwertigen C-Programms (c)
* 3. Ausgabe eines gleichwertigen Pascal-Programms (pascal)
* 4. Ausgabe eines gleichwertigen SML-Programms (sml)
*/
public class Setty {
/**
* Der Setty-Interpreter, das Hauptprogramm.
* @param arguments Die Aufrufparameter.
* Der erste Parameter gibt den Typ der Ausgabe und
* der zweite Parameter das Setty-Programm als String an.
*/
public static void main(String[] arguments) {
if (arguments.length == 2) {
/* Präprozessor:
* Der Präprozessor bereitet das gegebene Setty-Programm "arguments[1]"
* zur weiteren Analyse vor.
*/
Preprocessor preprocessor = new Preprocessor(arguments[1]);
/* Scanner:
* Der Scanner erhält das vom Präprozessor bearbeitete Setty-Programm
* zur lexikalischen Analyse.
*/
Scanner scanner = new Scanner(preprocessor.program());
/* Parser:
* Der Parser erhält diesen Scanner zur syntaktischen Analyse.
*/
Parser parser = new Parser(scanner);
try {
// Der Parse-Vorgang erzeugt den Syntaxbaum (parseTree)
// Während dem Parse-Vorgang können ParseExceptions auftreten
ProgramNode parseTree = parser.parse();
// Ausgabe gemäß Aufruf (eval|c|pascal|sml) "arguments[0]"
if (arguments[0].toLowerCase().equals("eval")) {
// Auswertung des Quellprogramms ("yes" oder "no")
System.out.println(arguments[1] + " -> " + parseTree.getResult());
} else if (arguments[0].toLowerCase().equals("c")) {
// Ausgabe eines gleichwertigen C-Programms
System.out.println(parseTree.generateCCode());
} else if (arguments[0].toLowerCase().equals("pascal")) {
// Ausgabe eines gleichwertigen Pascal-Programms
System.out.println(parseTree.generatePascalCode());
} else if (arguments[0].toLowerCase().equals("sml")) {
// Ausgabe eines gleichwertigen SML-Programms
System.out.println(parseTree.generateSmlCode());
} else {
// Ausgabe der Kurzhilfe, da unbekannter Parameter verwendet wird
System.err.println(usage());
}
} catch (ParseException pe) {
// Quellprogramm (Setty-Programm) ist fehlerhaft, da ParseException
System.err.println(pe.getMessage());
}
} else {
// Ausgabe der Kurzhilfe
System.out.println(usage());
}
}
/**
* Erläuterung zum korrekten Aufruf des SettyInterpreters (Kurzhilfe).
* @return Die Kurzhilfe als Zeichenkette.
*/
public static String usage() {
String result = "java Setty (eval|c|pascal|sml) <SettyProgramm>\r\n";
result += "\r\nBeispiele zur Auswertung:\r\n";
result += " java Setty eval \"Is 1 in {}?\"\r\n";
result += " java Setty eval \"Is 2.0 not in C([0;+inf[)?\"\r\n";
result += " java Setty eval \"Is 0.5 in ]-1;4.0[ n ]-inf;+3.0]?\"\r\n";
result += "\r\nBeispiele zur Ausgabe eines C-Programms:\r\n";
result += " java Setty c \"Is 1 in {-1;0;+1}?\"\r\n";
result += " java Setty c \"Is 1 in [-1;+1]?\"\r\n";
result += " java Setty c \"Is 1 in ]-1;+1[ \\ {0}?\"\r\n";
result += "\r\nBeispiele zur Ausgabe eines Pascal-Programms:\r\n";
result += " java Setty pascal \"Is 7 not in ({} v {1}) n {1;2}?\"\r\n";
result += " java Setty pascal \"Is 11 in ]-inf;-1[ v ]1;+inf[?\"\r\n";
result += " java Setty pascal \"Is 2 in E \\ E v R \\ R?\"\r\n";
result += "\r\nBeispiele zur Ausgabe eines SML-Programms:\r\n";
result += " java Setty sml \"Is 2 in C(]-inf;5[) \\ {2.0}?\"\r\n";
result += " java Setty sml \"Is 0.5 in {0.5} n ]-3.0;inf[?\"";
return result;
}
}
Wenn der
Setty-Interpreter
ohne Parameter gestartet wird,
erhält der Benutzer folgende Kurzhilfe zum Aufruf des
Setty-Interpreters.
java Setty (eval|c|pascal|sml) <SettyProgramm>
Beispiele zur Auswertung:
java Setty eval "Is 1 in {}?"
java Setty eval "Is 2.0 not in C([0;+inf[)?"
java Setty eval "Is 0.5 in ]-1;4.0[ n ]-inf;+3.0]?"
Beispiele zur Ausgabe eines C-Programms:
java Setty c "Is 1 in {-1;0;+1}?"
java Setty c "Is 1 in [-1;+1]?"
java Setty c "Is 1 in ]-1;+1[ \ {0}?"
Beispiele zur Ausgabe eines Pascal-Programms:
java Setty pascal "Is 7 not in ({} v {1}) n {1;2}?"
java Setty pascal "Is 11 in ]-inf;-1[ v ]1;+inf[?"
java Setty pascal "Is 2 in E \ E v R \ R?"
Beispiele zur Ausgabe eines SML-Programms:
java Setty sml "Is 2 in C(]-inf;5[) \ {2.0}?"
java Setty sml "Is 0.5 in {0.5} n ]-3.0;inf[?"
Auch wenn der
Setty-Interpreter
in andere Sprachen übersetzen kann,
wäre die Bezeichnung eines Compilers zu hoch gegriffen,
da strenggenommen wichtige Phasen des Compilers fehlen, die da wären:
- Semantische Analyse
- Zwischencodeerzeugung
und
- Optimierung.
Hierzu mehr unter
Compiler.
Im Folgenden werden alle Beispiele der Kurzhilfe mit dem
Setty-Interpreter
ausgeführt.
Der
Setty-Interpreter
versteht hier das
Setty-Programm
als Satzfrage und beantwortet diese Frage mit
„yes”
bzw. mit
„no”.
Is 2.0 not in C([0;+inf[)? -> yes
Is 0.5 in ]-1;4.0[ n ]-inf;+3.0]? -> yes
Die Übersetzung eines
Setty-Programms
in ein
C-Programm.
Die Hauptarbeit besteht darin, das
Setty-Programm
in eine
If-Anweisung
umzuformulieren.
#include <stdio.h>
int main(void) {
double element = 1.0;
if ((element == -1.0) || (element == 0.0) || (element == 1.0)) {
printf("yes\n");
} else {
printf("no\n");
}
return 0;
}
#include <stdio.h>
int main(void) {
double element = 1.0;
if ((element >= -1.0) && (element <= 1.0)) {
printf("yes\n");
} else {
printf("no\n");
}
return 0;
}
#include <stdio.h>
int main(void) {
double element = 1.0;
if ((!(element == 0.0)) && ((element > -1.0) && (element < 1.0))) {
printf("yes\n");
} else {
printf("no\n");
}
return 0;
}
Die Übersetzung eines
Setty-Programms
in ein
Pascal-Programm.
Auch hier besteht die Hauptarbeit darin, das
Setty-Programm
in eine
If-Anweisung
umzuformulieren.
program a_setty;
var Element: Extended;
begin
Element := 7.0;
if not(((false) or (Element = 1.0)) and ((Element = 1.0) or (Element = 2.0)))
then writeln('yes')
else writeln('no');
end.
program a_setty;
var Element: Extended;
begin
Element := 11.0;
if (Element < -1.0) or (Element > 1.0)
then writeln('yes')
else writeln('no');
end.
program a_setty;
var Element: Extended;
begin
Element := 2.0;
if ((not(false)) and (false)) or ((not(not(false))) and (not(false)))
then writeln('yes')
else writeln('no');
end.
Die Übersetzung eines
Setty-Programms
in ein
SML-Programm.
SML können Sie unter
www.smlnj.org
herunterladen.
Auch hier wäre es leicht möglich, das
Setty-Programm
als kurze
If-Anweisung
auszudrücken.
Doch aufgrund der besonderen Ausdruckstärke von SML, kann eine Menge extrem prägnant als
charakteristische Funktion
dargestellt werden.
Vergleichbares bräuchte unter C und Pascal ein aufwendigeres Konzept.
abstype 'a SET = Set of 'a -> bool
with
fun set b = Set b
val EmptySet = Set (fn x => false)
val RealSet = Set (fn x => true)
fun union (Set s) (Set t) = Set (fn x => s x orelse t x)
fun unionN [] = EmptySet
| unionN (s::sl) = union s (unionN sl)
fun inter (Set s) (Set t) = Set (fn x => s x andalso t x)
fun interN [] = RealSet
| interN (s::sl) = inter s (interN sl)
fun elem e = Set (fn x => Real.==(x, e))
fun elemN [] = EmptySet
| elemN (e::el) = union (elem e) (elemN el)
fun compl (Set s) = Set (not o s)
fun minus S T = inter (compl T) S
fun isin e (Set s) = s e
fun isnotin e (Set s) = (not o s) e
end;
fun yesorno true = print("yes\n")
| yesorno false = print("no\n");
yesorno (isin 6.0 (minus (compl (set (fn x => x < 5.0))) (elemN [7.5])));
abstype 'a SET = Set of 'a -> bool
with
fun set b = Set b
val EmptySet = Set (fn x => false)
val RealSet = Set (fn x => true)
fun union (Set s) (Set t) = Set (fn x => s x orelse t x)
fun unionN [] = EmptySet
| unionN (s::sl) = union s (unionN sl)
fun inter (Set s) (Set t) = Set (fn x => s x andalso t x)
fun interN [] = RealSet
| interN (s::sl) = inter s (interN sl)
fun elem e = Set (fn x => Real.==(x, e))
fun elemN [] = EmptySet
| elemN (e::el) = union (elem e) (elemN el)
fun compl (Set s) = Set (not o s)
fun minus S T = inter (compl T) S
fun isin e (Set s) = s e
fun isnotin e (Set s) = (not o s) e
end;
fun yesorno true = print("yes\n")
| yesorno false = print("no\n");
yesorno (isin 1.5 (interN [(elemN [0.5]), (set (fn x => x > ~3.0))]));