Categorías
Otros

Patrón de diseño Java-17, implementación de patrones de intérprete de lenguaje personalizado

Capítulo 17: Modo intérprete-Implementación del lenguaje personalizado

Definición:

Modo intérprete(Patrón de intérprete): defina la gramática de un idioma y cree un intérprete para interpretar las oraciones en el idioma. Aquí, «idioma» se refiere al código utilizando el formato y la gramática prescritos.

Explicar la expresión y, a continuación, calcular

Estructura:

imagen-2020111201641245

Código:

//Abstract expression
abstract class AbstractExpression {
    public abstract void interpret(Context ctx);
}
//Terminal expression
class TerminalExpression extends AbstractExpression {
    public void interpret(Context ctx) {
        //Explanation operation of terminal expression
    }
}
//Non-terminal expression: contains two operation elements
class NonterminalExpression extends AbstractExpression {
    private AbstractExpression left;
    private AbstractExpression right;

    public NonterminalExpression(AbstractExpression left, AbstractExpression right) {
        this.left = left;
        this.right = right;
    }

    public void interpret(Context ctx) {
        //Recursively call the interpret() method of each component
        //Specify the connection mode of the components during the recursive call, that is, the function of non-terminal symbols
    }
}
//Environment category, store global information
class Context {
    private HashMap map = new HashMap();

    public void assign(String key, String value) {
        //Set a value in the environment class
    }

    public String lookup(String key) {
        //Get the value stored in the environment class
        return null;
    }
}

Aplicaciones:

Programa de control de robots, muévete de acuerdo con el entorno de instrucción

Reglas gramaticales

expression ::= direction action distance | composite //expression
composite ::= expression 'and' expression //Compound expression
direction ::= 'up' | 'down' | 'left' | 'right' //Movement direction
action ::= 'move' | 'run' //Movement method
distance ::= an integer //Moving distance

1 + 2 + 3 – 4 + 1

expression ::= value | operation
operation ::= expression '+' expression | expression '-' expression
value ::= an integer //An integer value

Árbol de sintaxis

imagen-2020111201523048

Utilice el modo intérprete para lograr

imagen-20201112202433601

imagen-20201112202535199

Función de contexto

Entrar

LOOP 2 
	 PRINT Yang Guo SPACE SPACE PRINT Little Dragon Girl
BREAK END 
	 PRINT Guo Jing SPACE SPACE PRINT Huang Rong

Reglas gramaticales:

expression ::= command* //Expression, an expression contains multiple commands
command ::= loop | primitive //Statement command
loop ::= 'loopnumber' expression 'end' //Loop command, where number is a natural number
primitive ::= 'printstring' | 'space' | 'break' //Basic command, where string is a string

imagen-20201112205344914

//Environmental category: used to store and manipulate statements that need to be explained. In this example, each word that needs to be explained can be called an action mark (Action
class Context {
    private StringTokenizer tokenizer; //StringTokenizer class, used to decompose strings into smaller
    private String currentToken; //Current string mark

    public Context(String text) {
        tokenizer = new StringTokenizer(text); //Create StringTokenizer through the incoming command string
        nextToken();
    }

    //Return to the next mark
    public String nextToken() {
        if (tokenizer.hasMoreTokens()) {
            currentToken = tokenizer.nextToken();
        } else {
            currentToken = null;
        }
        return currentToken;
    }

    //Return the current mark
    public String currentToken() {
        return currentToken;
    }

    //Skip a mark
    public void skipToken(String token) {
        if (!token.equals(currentToken)) {
            System.err.println("Error message:" + currentToken + "The explanation is wrong!");
        }
        nextToken();
    }

    //If the current mark is a number, return the corresponding value
    public int currentNumber() {
        int number = 0;
        try {
            number = Integer.parseInt(currentToken); //Convert a string to an integer
        } catch (NumberFormatException e) {
            System.err.println("Error message:" + e);
        }
        return number;
    }
}
//Abstract node class: abstract expression
abstract class Node {
    public abstract void interpret(Context text); //Declare a method to explain the statement

    public abstract void execute(); //Declare a method to execute the command corresponding to the mark
}
//Expression node class: non-terminal expression
class ExpressionNode extends Node {
    private ArrayList<Node> list = new ArrayList<Node>(); //Define a set to store multiple tags

    public void interpret(Context context) {
        //Loop processing the tags in the Context
        while (true) {
            //If there is no mark, exit the explanation
            if (context.currentToken() == null) {
                break;
            }
            //If it is marked as END, then do not explain END and end this explanation process, you can continue the explanation after
            else if (context.currentToken().equals("END")) {
                context.skipToken("END");
                break;
            }
            //If it is another tag, explain the tag and add it to the command set
            else {
                Node commandNode = new CommandNode();
                commandNode.interpret(context);
                list.add(commandNode);
            }
        }
    }

    //Circularly execute each command in the command set
    public void execute() {
        Iterator iterator = list.iterator();
        while (iterator.hasNext()) {
            ((Node) iterator.next()).execute();
        }
    }
}
//Statement command node class: non-terminal expression
class CommandNode extends Node {
    private Node node;

    public void interpret(Context context) {
        //Processing LOOP loop commands
        if (context.currentToken().equals("LOOP")) {
            node = new LoopCommandNode();
            node.interpret(context);
        }
        //Process other basic commands
        else {
            node = new PrimitiveCommandNode();
            node.interpret(context);
        }
    }

    public void execute() {
        node.execute();
    }
}
//Cyclic command node class: non-terminal expression
class LoopCommandNode extends Node {
    private int number; //Cycles
    private Node commandNode; //Expression in loop statement

    //Explain the loop command
    public void interpret(Context context) {
        context.skipToken("LOOP");
        number = context.currentNumber();
        context.nextToken();
        commandNode = new ExpressionNode(); //Expression in loop statement
        commandNode.interpret(context);
    }

    public void execute() {
        for (int i = 0; i < number; i++)
            commandNode.execute();
    }
}
//Basic command node class: terminator expression
class PrimitiveCommandNode extends Node {
    private String name;
    private String text;

    //Explain the basic commands
    public void interpret(Context context) {
        name = context.currentToken();
        context.skipToken(name);
        if (!name.equals("PRINT") && !name.equals("BREAK") && !name.equals("SPACE")) {
            System.err.println("Illegal order!");
        }
        if (name.equals("PRINT")) {
            text = context.currentToken();
            context.nextToken();
        }
    }

    public void execute() {
        if (name.equals("PRINT"))
            System.out.print(text);
        else if (name.equals("SPACE"))
            System.out.print(" ");
        else if (name.equals("BREAK"))
            System.out.println();
    }
}
class Client {
    public static void main(String[] args) {
        String text = "LOOP 2 PRINT Yang Guo SPACE SPACE PRINT Little Dragon Girl BREAK END PRINT Guo Jing SPACE SPACE PRINT Huang Rong";
        Context context = new Context(text);
        Node node = new ExpressionNode();
        node.interpret(context);
        node.execute();
    }
}

imagen-20201112211825221

Ventaja:

  1. Fácil de cambiar y ampliar la gramática. Puesto que las clases se utilizan para representar las reglas gramaticales del lenguaje en el modo de intérprete, la gramática se puede cambiar o ampliar a través de mecanismos como la herencia.
  2. Cada regla gramatical se puede expresar como una clase, por lo que un lenguaje simple se puede implementar fácilmente.
  3. Es más fácil implementar la gramática. La implementación de cada clase de nodo de expresión en el árbol de sintaxis abstracta es similar, el código de estas clases no es especialmente complicado y el código de clase de nodo puede ser generado automáticamente por algunas herramientas.
  4. Es más conveniente agregar nuevas expresiones de explicación. Si el usuario necesita agregar una nueva expresión de interpretación, solo necesita agregar una nueva expresión de terminal o una clase de expresión no terminal. El código de clase de expresión original no necesita ser modificado y se ajusta al «principio de apertura y cierre».
  C++ aprendiendo cuatro

Desventajas:

  1. Es difícil mantener una gramática compleja. En el modo de intérprete, cada regla debe definir al menos una clase. Por lo tanto, si un idioma contiene demasiadas reglas gramaticales, el número de clases aumentará bruscamente, lo que dificultará la gestión y el mantenimiento del sistema. En este momento, puede considerar el uso de un programa de análisis de sintaxis, etc. Forma de reemplazar el modo de intérprete.
  2. La eficiencia de ejecución es baja. Dado que un gran número de bucles y llamadas recursivas se usan en el modo de intérprete, es muy lento al interpretar oraciones más complejas y el proceso de depuración del código también es más problemático.

Escena aplicable:

  1. Una oración de un lenguaje que necesita ser interpretada y ejecutada se puede representar como un árbol de sintaxis abstracto.
  2. Algunos problemas recurrentes se pueden expresar en un lenguaje sencillo.
  3. La gramática de un lenguaje es relativamente simple.
  4. La eficiencia de ejecución no es un problema clave.

.

Por Programación.Click

Más de 20 años programando en diferentes lenguajes de programación. Apasionado del code clean y el terminar lo que se empieza. ¿Programamos de verdad?

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *