Je voudrais prendre en charge un tableau de structures de données de base. Cet article est une suite de "Correspondant aux appels de méthode".
Confirmez ce que vous voulez faire avec la prise en charge de la baie.
Par exemple, il existe le programme suivant.
Créez un tableau sur la première ligne et affectez-le à la variable ʻar. La deuxième ligne affiche la longueur du tableau «3». La troisième ligne vise à afficher le troisième élément du tableau,
" c "`.
var ar = ["a", "b", "c"]
println(ar.size())
println(ar[2])
Nous examinerons comment l'implémenter dans l'ordre de l'analyse des phrases (Lexer), de l'analyse syntaxique (Parser) et de l'interpréteur (Interpreter).
Puisqu'il n'y a pas de fonction pour analyser [
et ]
, ajoutez-la.
L'implémentation de l'analyse syntaxique correspond à deux syntaxes: l'une qui crée un tableau et l'autre qui accède aux éléments du tableau.
La syntaxe de génération d'un tableau commence par un jeton [
.
Implémentez-le dans la méthode lead ()
, tout comme les autres premières constructions de jetons.
La syntaxe pour accéder aux éléments d'un tableau est équivalente à la syntaxe d'un appel de fonction qui prend un argument.
Le remplacement de «[]» de «ar [2]» par «()» dans l'exemple de programme entraîne «ar (2)».
Vous pouvez voir qu'ils sont équivalents car ils ressemblent à des appels de fonction.
Implémentez-le dans la méthode bind ()
de la même manière que l'analyse syntaxique des appels de fonction.
Puisque l'entité du tableau peut ajouter des éléments et obtenir la longueur par la méthode d'instance, J'ai décidé d'utiliser ʻArrayList
Le traitement de la syntaxe implémente la génération du tableau et l'accès aux éléments du tableau. Lors de la génération de tableaux, ʻArrayList
Passez à la mise en œuvre. À propos de l'analyse de phrases (Lexer), de l'analyse syntaxique (Parser), de l'interpréteur (Interpreter) Jetons un coup d'œil aux modifications et aux ajouts dans l'ordre.
Lexer.java
Une implémentation de Lexer.java.
Ajoutez la fonction d'analyse de phrase de [
et ]
.
Ajoutez la méthode ʻisBracketStart () `. Détecte «[» et «]».
Lexer.java
private boolean isBracketStart(char c) {
return c == '[' || c == ']';
}
Ajoutez la méthode bracket ()
.
Analyser [
et ]
en jetons.
kind
, qui signifie [
et]
, devrait être bracket
.
Lexer.java
private Token bracket() throws Exception {
Token t = new Token();
t.kind = "bracket";
t.value = Character.toString(next());
return t;
}
Modifiez la méthode nextToken ()
.
Ajoutez l'appel à la méthode ajoutée à // Add
.
Vous pouvez maintenant décomposer [
et ]
en jetons.
Lexer.java
public Token nextToken() throws Exception {
skipSpace();
if (isEOT()) {
return null;
} else if (isSignStart(c())) {
return sign();
} else if (isDotStart(c())) {
return dot();
} else if (isDigitStart(c())) {
return digit();
} else if (isStringStart(c())) {
return string();
} else if (isIdentStart(c())) {
return ident();
} else if (isParenStart(c())) {
return paren();
} else if (isCurlyStart(c())) {
return curly();
// Add
} else if (isBracketStart(c())) {
return bracket();
} else if (isSymbolStart(c())) {
return symbol();
} else {
throw new Exception("Not a character for tokens");
}
}
C'est tout pour changer Lexer.java.
Parser.java
Une implémentation de Parser.java.
Ajoutez une définition de la façon dont cela fonctionne pour la signification du jeton.
Ajout du degré de classement de [
to // Add
.
[
Est meilleur que les opérateurs arithmétiques comme +
et *
Parce qu'il relie fortement les jetons gauche et droit,
Il est de 80, ce qui est plus grand que le degré de «+» et «*».
Parser.java
public Parser() {
degrees = new HashMap<>();
degrees.put(".", 80);
degrees.put("(", 80);
degrees.put("[", 80); // Add
degrees.put("*", 60);
degrees.put("/", 60);
degrees.put("+", 50);
degrees.put("-", 50);
degrees.put("==", 40);
degrees.put("!=", 40);
degrees.put("<", 40);
degrees.put("<=", 40);
degrees.put(">", 40);
degrees.put(">=", 40);
degrees.put("&&", 30);
degrees.put("||", 30);
degrees.put("=", 10);
factorKinds = Arrays.asList(new String[] { "digit", "ident", "string" });
binaryKinds = Arrays.asList(new String[] { "sign", "dot" });
rightAssocs = Arrays.asList(new String[] { "=" });
unaryOperators = Arrays.asList(new String[] { "+", "-", "!" });
reserved = Arrays.asList(new String[] { "function", "return", "if", "else", "while", "break", "var" });
}
Implémente l'analyse syntaxique de génération de séquence.
De la méthode lead ()
qui implémente la syntaxe déterminée par le premier jeton
Ajout d'un appel à la méthode newArray ()
qui effectue une analyse de syntaxe de génération de tableau à // Add
.
Parser.java
private Token lead(Token token) throws Exception {
if (token.kind.equals("ident") && token.value.equals("function")) {
return func(token);
} else if (token.kind.equals("ident") && token.value.equals("return")) {
token.kind = "ret";
if (!token().kind.equals("eob")) {
token.left = expression(0);
}
return token;
} else if (token.kind.equals("ident") && token.value.equals("if")) {
return if_(token);
} else if (token.kind.equals("ident") && token.value.equals("while")) {
return while_(token);
} else if (token.kind.equals("ident") && token.value.equals("break")) {
token.kind = "brk";
return token;
} else if (token.kind.equals("ident") && token.value.equals("var")) {
return var(token);
} else if (factorKinds.contains(token.kind)) {
return token;
} else if (unaryOperators.contains(token.value)) {
token.kind = "unary";
token.left = expression(70);
return token;
} else if (token.kind.equals("paren") && token.value.equals("(")) {
Token expr = expression(0);
consume(")");
return expr;
// Add
} else if (token.kind.equals("bracket") && token.value.equals("[")) {
return newArray(token);
} else {
throw new Exception("The token cannot place there.");
}
}
Ajout de la méthode newArray ()
pour effectuer une analyse de la syntaxe de génération de tableaux.
Rassemblez les éléments séparés par ,
dans les params
du [
token" jusqu'à ce que le token ]
soit atteint.
Le type de jeton «kind» est défini sur «newArray».
Si le dernier élément du tableau est vide, comme [1,2,]
, il sera ignoré en tant qu'élément.
Si un élément vide est spécifié au milieu de la séquence, comme «[1 ,, 3]» dans le tableau,
Le jeton «vierge» préparé à l'avance est attribué.
Parser.java
private Token newArray(Token token) throws Exception {
token.kind = "newArray";
token.params = new ArrayList<Token>();
while(true) {
if (token().value.equals("]")) {
consume("]");
break;
}
if (token().value.equals(",")) {
token.params.add(blank);
consume(",");
continue;
}
token.params.add(expression(0));
if (token().value.equals(",")) {
consume(",");
continue;
} else {
consume("]");
break;
}
}
return token;
}
J'ai ajouté le jeton «vide» qui représente l'élément vide sorti plus tôt à la variable de champ statique.
Parser.java
public static Token blank;
static {
blank = new Token();
blank.kind = "blank";
blank.value = "";
}
Implémente la syntaxe d'accès au tableau.
De la méthode bind ()
qui analyse la syntaxe d'appel de fonction, etc.
Ajout de l'analyse de la syntaxe d'accès au tableau à // Add
.
Attribuez le tableau lui-même, par exemple, le jeton correspondant à ʻar de
ʻar [2] à
gauche de ʻopérateur
correspondant au jeton [
.
Pour «droit» de «opérateur», attribuez l'index auquel accéder, par exemple le jeton correspondant à «2» de «ar [2]».
Parser.java
private Token bind(Token left, Token operator) throws Exception {
if (binaryKinds.contains(operator.kind)) {
operator.left = left;
int leftDegree = degree(operator);
if (rightAssocs.contains(operator.value)) {
leftDegree -= 1;
}
operator.right = expression(leftDegree);
return operator;
} else if (operator.kind.equals("paren") && operator.value.equals("(")) {
operator.left = left;
operator.params = new ArrayList<Token>();
if (!token().value.equals(")")) {
operator.params.add(expression(0));
while (!token().value.equals(")")) {
consume(",");
operator.params.add(expression(0));
}
}
consume(")");
return operator;
// Add
} else if (operator.kind.equals("bracket") && operator.value.equals("[")) {
operator.left = left;
operator.right = expression(0);
consume("]");
return operator;
} else {
throw new Exception("The token cannot place there.");
}
}
C'est tout pour changer Parser.java.
Interpreter.java
Une implémentation d'Interpreter.java.
Modification de la méthode ʻExpression () . C'est un processus qui se ramifie en fonction de la signification (sorte) du jeton qui représente l'expression. Sous «// Ajouter», Appelez la méthode
blank ()pour les éléments vides, Appelez la méthode
newArray ()pour la génération de tableaux, Ajout de l'appel de la méthode ʻaccessArray ()
pour l'accès au tableau.
Interpreter.java
public Object expression(Token expr) throws Exception {
if (expr.kind.equals("digit")) {
return digit(expr);
} else if (expr.kind.equals("string")) {
return string(expr);
} else if (expr.kind.equals("ident")) {
return ident(expr);
// Add
} else if (expr.kind.equals("blank")) {
return blank(expr);
// Add
} else if (expr.kind.equals("newArray")) {
return newArray(expr);
// Add
} else if (expr.kind.equals("bracket")) {
return accessArray(expr);
} else if (expr.kind.equals("func")) {
return func(expr);
} else if (expr.kind.equals("fexpr")) {
return fexpr(expr);
} else if (expr.kind.equals("paren")) {
return invoke(expr);
} else if (expr.kind.equals("sign") && expr.value.equals("=")) {
return assign(expr);
} else if (expr.kind.equals("unary")) {
return unaryCalc(expr);
} else if (expr.kind.equals("sign")) {
return calc(expr);
} else if (expr.kind.equals("dot")) {
return dot(expr);
} else {
throw new Exception("Expression error");
}
}
Ajout d'une méthode blank ()
pour les éléments vides.
Il renvoie simplement «null».
Interpreter.java
public Object blank(Token token) {
return null;
}
Ajout de la méthode newArray ()
pour la génération de tableaux.
Après avoir généré ʻArrayList
Interpreter.java
public Object newArray(Token expr) throws Exception {
List<Object> a = new ArrayList<>();
for (Token item : expr.params) {
a.add(value(expression(item)));
}
return a;
}
Changement de la méthode value ()
de la méthode qui garantit que l'argument est une valeur.
Le premier // Add
autorise maintenant ʻArrayList
Interpreter.java
public Object value(Object value) throws Exception {
if (value instanceof Integer) {
return value;
} else if (value instanceof String) {
return value;
// Add
} else if (value instanceof List<?>) {
return value;
// Add
} else if (value == null) {
return value;
} else if (value instanceof Func) {
return value;
} else if (value instanceof Variable) {
Variable v = (Variable) value;
return value(v.value);
}
throw new Exception("right value error");
}
Ajout de la méthode ʻaccessArray () pour l'accès aux tableaux. L'argument ʻexpr
reçoit un jeton [
.
Le [
token left
résout le tableau lui-même.
Le [
token right
résout l'index d'accès.
En les utilisant, utilisez la méthode ʻArrayList
Interpreter.java
public Object accessArray(Token expr) throws Exception {
List<Object> ar = array(expression(expr.left));
Integer index = integer(expression(expr.right));
return ar.get(index);
}
Ajout de la méthode ʻarray () , une méthode qui garantit que l'argument est un tableau (
List
Interpreter.java
@SuppressWarnings("unchecked")
public List<Object> array(Object value) throws Exception {
if (value instanceof List<?>) {
return (List<Object>) value;
} else if (value instanceof Variable) {
Variable v = (Variable) value;
return array(v.value);
}
throw new Exception("right value error");
}
Le programme ci-dessous utilisant l'implémentation ci-dessus
var ar = ["a", "b", "c"]
println(ar.size())
println(ar[2])
Pour afficher la longueur du tableau "3" et le troisième élément du tableau "" c "".
Interpreter.java
public static void main(String[] args) throws Exception {
String text = "";
text += "var ar = [\"a\", \"b\", \"c\"]";
text += "println(ar.size())";
text += "println(ar[2])";
List<Token> tokens = new Lexer().init(text).tokenize();
List<Token> blk = new Parser().init(tokens).block();
new Interpreter().init(blk).run();
// --> 3
// --> c
}
C'est tout pour la mise en œuvre. Merci beaucoup.
La source complète est disponible ici.
Calc https://github.com/quwahara/Calc/tree/article-17-array/Calc/src/main/java
Il y a un article de suite.
** Correspond à la définition d'objet de type JSON ** http://qiita.com/quwahara/items/5e6cee17b7b03bd994ee
Recommended Posts