Voici un résumé du ** modèle d'interprétation ** du modèle de conception du GoF.
Un programme qui analyse la langue écrite dans un fichier texte. La notation BNF est utilisée dans la grammaire de la langue utilisée dans le texte à analyser.
<program> ::= program <command list>
<command list> ::= <command>* end
<command> ::= <repeat command> | <primitive command>
<repeat command> ::= repeat <number> <command list>
<primitive command> ::= go | right | left
--<programme>
・ ・ ・ Le programme de jetons est suivi de la colonne de commande <liste de commandes>
・ ・ ・ <commande>
・ ・ ・ Soit la commande de répétition <commande de répétition> soit la commande de base <commande de répétition>
・ ・ ・ La répétition du jeton est suivie du nombre de répétitions <commande primitive>
・ ・ ・ aller ou droite ou gauche.
Une classe qui représente le contexte de l'analyse syntaxique.
Context.java
import java.util.StringTokenizer;
public class Context {
private StringTokenizer tokenizer;
private String currentToken;
public Context(String text) {
tokenizer = new StringTokenizer(text);
nextToken();
}
public String nextToken() {
if (tokenizer.hasMoreTokens()) {
currentToken = tokenizer.nextToken();
} else {
currentToken = null;
}
return currentToken;
}
public String currentToken() {
return currentToken;
}
public void skipToken(String token) throws Exception {
if (!token.equals(currentToken)) {
throw new Exception("Warning: " + token + " is expected, but " + currentToken + " is found.");
}
nextToken();
}
public int currentNumber() throws Exception {
int number = 0;
try {
number = Integer.parseInt(currentToken);
} catch (NumberFormatException e) {
throw new Exception("Warning: " + e);
}
return number;
}
}
Cette classe est le "nœud" de l'arbre syntaxique.
Node.java
public abstract class Node {
public abstract void parse(Context context) throws Exception;
}
Cette classe correspond à
ProgramNode.java
// <program> ::= program <command list>
public class ProgramNode extends Node {
private Node commandListNode;
public void parse(Context context) throws Exception {
context.skipToken("program");
commandListNode = new CommandListNode();
commandListNode.parse(context);
}
public String toString() {
return "[program " + commandListNode + "]";
}
}
Cette classe correspond à
CommandNode.java
// <command> ::= <repeat command> | <primitive command>
public class CommandNode extends Node {
private Node node;
public void parse(Context context) throws Exception {
if (context.currentToken().equals("repeat")) {
node = new RepeatCommandNode();
node.parse(context);
} else {
node = new PrimitiveCommandNode();
node.parse(context);
}
}
public String toString() {
return node.toString();
}
}
Cette classe correspond à la <commande de répétition>.
RepeatCommandNode.java
// <repeat command> ::= repeat <number> <command list>
public class RepeatCommandNode extends Node {
private int number;
private Node commandListNode;
public void parse(Context context) throws Exception {
context.skipToken("repeat");
number = context.currentNumber();
context.nextToken();
commandListNode = new CommandListNode();
commandListNode.parse(context);
}
public String toString() {
return "[repeat " + number + " " + commandListNode + "]";
}
}
Cette classe correspond à
CommandListNode.java
import java.util.ArrayList;
// <command list> ::= <command>* end
public class CommandListNode extends Node {
private ArrayList list = new ArrayList();
public void parse(Context context) throws Exception {
while (true) {
if (context.currentToken() == null) {
throw new Exception("Missing 'end'");
} else if (context.currentToken().equals("end")) {
context.skipToken("end");
break;
} else {
Node commandNode = new CommandNode();
commandNode.parse(context);
list.add(commandNode);
}
}
}
public String toString() {
return list.toString();
}
}
Cette classe correspond à
PrimitiveCommandNode.java
// <primitive command> ::= go | right | left
public class PrimitiveCommandNode extends Node {
private String name;
public void parse(Context context) throws Exception {
name = context.currentToken();
context.skipToken(name);
if (!name.equals("go") && !name.equals("right") && !name.equals("left")) {
throw new Exception(name + " is undefined");
}
}
public String toString() {
return name;
}
}
Le texte à analyser syntaxiquement.
program.txt
program end
program go end
program go right go right go right go right end
program repeat 4 go right end end
program repeat 4 repeat 3 go right go left end right end end
Cette classe effectue le traitement principal.
Main.java
import java.io.BufferedReader;
import java.io.FileReader;
public class Main {
public static void main(String[] args) {
try {
BufferedReader reader = new BufferedReader(new FileReader("program.txt"));
String text;
while ((text = reader.readLine()) != null) {
System.out.println("text = \"" + text + "\"");
Node node = new ProgramNode();
node.parse(new Context(text));
System.out.println("node = " + node);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
text = "program end"
node = [program []]
text = "program go end"
node = [program [go]]
text = "program go right go right go right go right end"
node = [program [go, right, go, right, go, right, go, right]]
text = "program repeat 4 go right end end"
node = [program [[repeat 4 [go, right]]]]
text = "program repeat 4 repeat 3 go right go left end right end end"
node = [program [[repeat 4 [[repeat 3 [go, right, go, left]], right]]]]
Le modèle Interpreter facilite l'ajout ou la modification de règles. L'une des caractéristiques du modèle Interpreter est qu '"une règle est représentée par une classe". En d'autres termes, si vous souhaitez ajouter une nouvelle règle, tout ce que vous avez à faire est d'ajouter une sous-classe de la classe Node. De plus, si vous modifiez la règle, il vous suffit de modifier la sous-classe de la classe Node.
Cet article et exemple de programme ont été créés à partir des livres suivants.
C'était très facile à comprendre et j'ai beaucoup appris. Je vous remercie. Les explications détaillées des modèles de conception et des exemples de programmes sont écrites, veuillez donc également consulter les livres.
Recommended Posts