In einem früheren Artikel habe ich eine Syntaxanalyse implementiert (http://qiita.com/quwahara/items/9bf468ff4286b28d2a24). Übrigens möchte ich damit einen einfachen Interpreter implementieren.
Bestätigen Sie, was Sie in der Implementierung tun möchten. Was ich mit dem Interpreter machen möchte, ist die Berechnung der programmatischen Zeichenfolge. Am Beispiel der folgenden Formel wollen wir schließlich "23" "a" zuweisen.
a = 3 + 4 * 5
Lassen Sie uns überlegen, wie man berechnet. Ich habe den Ausdruck im vorherigen Artikel analysiert (http://qiita.com/quwahara/items/9bf468ff4286b28d2a24). Der syntaktisch analysierte Ausdruck wurde analysiert, so dass die Operator-Token "links" und "rechts" Werte hatten, die von diesem Operator berechnet wurden. Zum Beispiel ist im Ausdruck "6-7" das Operator-Token "-", "links" hat "6", "rechts" hat "7" und so weiter. Außerdem können "links" und "rechts" nicht nur Werte haben, sondern auch Formeln, die in der Berechnungsreihenfolge an erster Stelle stehen. Zum Beispiel hat der Ausdruck "3 + 4 * 5" das Operator-Token "+", "links" hat "3" und "rechts" hat "4 * 5". Da es eine solche Datenstruktur hat, gehen Sie zur Berechnung die Operator-Token "links" und "rechts" nach unten. Wenn Sie den Terminalbetreiber erreichen, berechnen Sie ihn. Basierend auf dem Berechnungsergebnis wird der nächsthöhere Operator berechnet. Sie können berechnen, indem Sie diesen Vorgang bis zum Anfang wiederholen. In der Formel "3 + 4 * 5" im vorherigen Beispiel ist der Terminaloperator "*" von "4 * 5", daher wird er mit "20" berechnet. Das Berechnungsergebnis wird verwendet, um den nächsthöheren Operator "+" zu berechnen. Da "links" "3" und "rechts" das Berechnungsergebnis "20" ist, wird es zu "23" addiert und die Berechnung ist abgeschlossen.
Fahren Sie mit der Implementierung fort. Lassen Sie uns einen Teil der Implementierung des Interpreters betrachten.
Erstens ist der Initialisierungsteil. Empfängt die durch Syntaxanalyse analysierte Token-Liste. Berechnen Sie diese Token-Liste. Da der Interpreter einer Variablen entspricht, bereiten Sie eine Map vor, die den Variablennamen und seinen Wert enthält.
Interpreter.java
public class Interpreter {
public Map<String, Integer> variables;
List<Token> body;
public Interpreter init(List<Token> body) {
variables = new HashMap<>();
this.body = body;
return this;
}
Dies ist eine Beschreibung des Teils, mit dem die Berechnung gestartet wird.
run ()
berechnet den zuvor übergebenen Token-Liste body
und gibt eine variable Map zurück, die das Berechnungsergebnis enthält.
Interpreter.java
public Map<String, Integer> run() throws Exception {
body(body);
return variables;
}
Dies ist die Erklärung des zu berechnenden Teils.
body ()
nimmt das Token für einen Ausdruck aus der zuvor übergebenen Token-Liste body
und übergibt es an expression ()
, der den Ausdruck verarbeitet.
Interpreter.java
public void body(List<Token> body) throws Exception {
for (Token exprs : body) {
expression(exprs);
}
}
expression ()
ruft die Methoden auf, die je nach Bedeutung des Tokens jeweils verarbeitet werden, und gibt das Ergebnis unverändert zurück.
Interpreter.java
public Object expression(Token expr) throws Exception {
if (expr.kind.equals("digit")) {
return digit(expr);
} else if (expr.kind.equals("variable")) {
return var(expr);
} else if (expr.kind.equals("sign") && expr.value.equals("=")) {
return assign(expr);
} else if (expr.kind.equals("sign")) {
return calc(expr);
} else {
throw new Exception("Expression error");
}
}
digit ()
nimmt ein numerisches Token und macht es zu 'Integer`.
Interpreter.java
public Integer digit(Token token) {
return Integer.decode(token.value);
}
var () empfängt das Token der Variablen und macht es zum Variablennamen. Wenn der Variablenname nicht in der Variablenzuordnung registriert ist, registrieren Sie den Wert mit "0".
Interpreter.java
public Object var(Token token) {
String name = token.value;
if (!variables.containsKey(name)) {
variables.put(name, 0);
}
return name;
}
assign ()
weist einer Variablen einen Wert zu.
Interpreter.java
public String assign(Token expr) throws Exception {
String name = variable(expression(expr.left));
Integer value = value(expression(expr.right));
variables.put(name, value);
return name;
}
variable ()
ist der Prozess vonassign ()
und stellt sicher, dass das Ergebnis von expr.left
der Variablenname ist.
Interpreter.java
public String variable(Object value) throws Exception {
if (value instanceof String) {
return (String) value;
} else {
throw new Exception("left value error");
}
}
value ()
wird zu einem numerischen Wert gemacht, der durch expr.right
der Verarbeitung von assign ()
und der Verarbeitung der vier später beschriebenen Regeloperationen berechnet werden kann.
Wenn das Argument "Wert" "Ganzzahl" ist, wird es unverändert zurückgegeben. Wenn es sich um "String" handelt, wird der Wert aus der Variablen "Map" abgerufen und zurückgegeben.
Interpreter.java
public Integer value(Object value) throws Exception {
if (value instanceof Integer) {
return (Integer) value;
} else if (value instanceof String) {
return variables.get((String) value);
} else {
throw new Exception("right value error");
}
}
calc ()
führt vier Regeln aus.
Interpreter.java
public Object calc(Token expr) throws Exception {
Integer left = value(expression(expr.left));
Integer right = value(expression(expr.right));
if (expr.value.equals("+")) {
return left + right;
} else if (expr.value.equals("-")) {
return left - right;
} else if (expr.value.equals("*")) {
return left * right;
} else if (expr.value.equals("/")) {
return left / right;
} else {
throw new Exception("Unknown sign for Calc");
}
}
Unter Verwendung der obigen Implementierung die Zeichenfolge, die das Beispielprogramm ist
a = 3 + 4 * 5
Drucken Sie die Variablen und ihre Werte in die Standardausgabe.
Interpreter.java
public static void main(String[] args) throws Exception {
String text = "a = 3 + 4 * 5";
List<Token> tokens = new Lexer().init(text).tokenize();
List<Token> blk = new Parser().init(tokens).block();
Map<String, Integer> variables = new Interpreter().init(blk).run();
for (Map.Entry<String, Integer> variable : variables.entrySet()) {
System.out.println(variable.getKey() + " " + variable.getValue());
}
// --> a 23
}
}
Das ist alles für die Implementierung. Vielen Dank.
Die Quelle finden Sie hier.
Calc https://github.com/quwahara/Calc/tree/article-3-interpreter/Calc/src/main/java
Es gibt einen Folgeartikel.
** Println zum Interpreter hinzufügen ** http://qiita.com/quwahara/items/82067b00cbe1cb974e4a
Abschließend werde ich Ihnen eine Zusammenfassung der Dolmetscherklassen geben.
Interpreter.java
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Interpreter {
public Map<String, Integer> variables;
List<Token> body;
public Interpreter init(List<Token> body) {
variables = new HashMap<>();
this.body = body;
return this;
}
public Map<String, Integer> run() throws Exception {
body(body);
return variables;
}
public void body(List<Token> body) throws Exception {
for (Token exprs : body) {
expression(exprs);
}
}
public Object expression(Token expr) throws Exception {
if (expr.kind.equals("digit")) {
return digit(expr);
} else if (expr.kind.equals("variable")) {
return var(expr);
} else if (expr.kind.equals("sign") && expr.value.equals("=")) {
return assign(expr);
} else if (expr.kind.equals("sign")) {
return calc(expr);
} else {
throw new Exception("Expression error");
}
}
public Integer digit(Token token) {
return Integer.decode(token.value);
}
public Object var(Token token) {
String name = token.value;
if (!variables.containsKey(name)) {
variables.put(name, 0);
}
return name;
}
public String assign(Token expr) throws Exception {
String name = variable(expression(expr.left));
Integer value = value(expression(expr.right));
variables.put(name, value);
return name;
}
public String variable(Object value) throws Exception {
if (value instanceof String) {
return (String) value;
} else {
throw new Exception("left value error");
}
}
public Integer value(Object value) throws Exception {
if (value instanceof Integer) {
return (Integer) value;
} else if (value instanceof String) {
return variables.get((String) value);
} else {
throw new Exception("right value error");
}
}
public Object calc(Token expr) throws Exception {
Integer left = value(expression(expr.left));
Integer right = value(expression(expr.right));
if (expr.value.equals("+")) {
return left + right;
} else if (expr.value.equals("-")) {
return left - right;
} else if (expr.value.equals("*")) {
return left * right;
} else if (expr.value.equals("/")) {
return left / right;
} else {
throw new Exception("Unknown sign for Calc");
}
}
public static void main(String[] args) throws Exception {
String text = "a = 3 + 4 * 5";
List<Token> tokens = new Lexer().init(text).tokenize();
List<Token> blk = new Parser().init(tokens).block();
Map<String, Integer> variables = new Interpreter().init(blk).run();
for (Map.Entry<String, Integer> variable : variables.entrySet()) {
System.out.println(variable.getKey() + " " + variable.getValue());
}
// --> a 23
}
}
Recommended Posts