Dans un article précédent, j'ai implémenté une analyse de syntaxe (http://qiita.com/quwahara/items/9bf468ff4286b28d2a24). En passant, je voudrais l'utiliser pour implémenter un interpréteur simple.
Confirmez ce que vous souhaitez faire lors de la mise en œuvre. Ce que je veux faire avec l'interpréteur est de calculer la chaîne de programmation. En prenant la formule suivante à titre d'exemple, nous visons à avoir finalement «23» assigné à «a».
a = 3 + 4 * 5
Réfléchissons à la façon de calculer. J'ai analysé l'expression dans l'article précédent (http://qiita.com/quwahara/items/9bf468ff4286b28d2a24). L'expression syntaxiquement analysée a été analysée afin que les jetons d'opérateur «gauche» et «droite» aient les valeurs calculées par cet opérateur. Par exemple, dans l'expression «6-7», le jeton d'opérateur est «-», «gauche» a «6», «droite» a «7», et ainsi de suite. De plus, «gauche» et «droite» peuvent avoir non seulement des valeurs mais aussi des formules qui viennent en premier dans l'ordre de calcul. Par exemple, l'expression «3 + 4 * 5» a le jeton d'opérateur «+», «gauche» a «3» et «droite» a «4 * 5». Puisqu'il a une telle structure de données, afin de calculer, descendez les jetons d'opérateur «gauche» et «droite» dans l'ordre. Lorsque vous atteignez l'opérateur du terminal, calculez-le. Sur la base du résultat du calcul, l'opérateur immédiatement supérieur est calculé. Vous pouvez calculer en répétant cette opération jusqu'en haut. Dans la formule "3 + 4 * 5" de l'exemple précédent, l'opérateur du terminal est "*" de "4 * 5", donc il est calculé comme étant "20". Le résultat du calcul est utilisé pour calculer l'opérateur supérieur suivant «+». Puisque «gauche» est «3» et «droite» est le résultat du calcul «20», il est ajouté à «23» et le calcul est terminé.
Passez à la mise en œuvre. Jetons un coup d'œil partiel à l'implémentation de l'interpréteur.
La première est la partie d'initialisation. Reçoit la liste de jetons analysée par l'analyse syntaxique. Calculez cette liste de jetons. De plus, puisque l'interpréteur correspond à une variable, préparez une carte contenant le nom de la variable et sa valeur.
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;
}
Ceci est une description de la partie qui démarre le calcul.
run ()
calcule le corps de la liste de jetons `passé plus tôt et renvoie une variable Map qui contient le résultat du calcul.
Interpreter.java
public Map<String, Integer> run() throws Exception {
body(body);
return variables;
}
C'est l'explication de la pièce à calculer.
body ()
prend le jeton pour une expression de la liste de jetons passée précédemment body
et le passe à ʻexpression () `qui traite l'expression.
Interpreter.java
public void body(List<Token> body) throws Exception {
for (Token exprs : body) {
expression(exprs);
}
}
Selon la signification du jeton, ʻexpression () `appelle la méthode qui traite chacun et renvoie le résultat tel quel.
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 ()
prend un jeton numérique et le rend ʻInteger`.
Interpreter.java
public Integer digit(Token token) {
return Integer.decode(token.value);
}
var ()
reçoit le jeton de la variable et en fait le nom de la variable.
Si le nom de la variable n'est pas enregistré dans la variable Map, enregistrez la valeur avec «0».
Interpreter.java
public Object var(Token token) {
String name = token.value;
if (!variables.containsKey(name)) {
variables.put(name, 0);
}
return name;
}
ʻAssign () `attribue une valeur à une variable.
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 ()
est le processus de ʻassign () et confirme que le résultat de ʻexpr.left
est le nom de la variable.
Interpreter.java
public String variable(Object value) throws Exception {
if (value instanceof String) {
return (String) value;
} else {
throw new Exception("left value error");
}
}
value ()
est adapté à une valeur qui peut être calculée par ʻexpr.rightdans le traitement de ʻassign ()
et le traitement des quatre opérations de règles décrites plus loin.
Si l'argument valeur
est ʻInteger`, il est renvoyé tel quel. S'il s'agit de «String», la valeur est extraite de la variable Map et renvoyée.
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 ()
exécute quatre règles.
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");
}
}
En utilisant l'implémentation ci-dessus, la chaîne de caractères qui est l'exemple de programme
a = 3 + 4 * 5
Et imprimez les variables et leurs valeurs sur la sortie standard.
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
}
}
C'est tout pour la mise en œuvre. Merci beaucoup.
La source est disponible ici.
Calc https://github.com/quwahara/Calc/tree/article-3-interpreter/Calc/src/main/java
Il y a un article de suite.
** Ajouter println à l'interpréteur ** http://qiita.com/quwahara/items/82067b00cbe1cb974e4a
Enfin, je vais vous donner un résumé des cours d'interprète.
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