CC S01E03

Oct. 24, 2013, 8:48 p.m.

Простейший транслятор

Зададимся целью транслировать арифметические выражения в их аналоги, например, на языке lisp (scheme). Рассмотрим упрощенный случай, когда грамматикой допускаются только суммы чисел.

Решение с использованием visitor'а

Calc.g4

grammar Calc;

input
        : expr EOF               
        ;

expr 
        : l3=expr PLUS r3=expr    # plus
        | INT                     # int
        ;

INT     : [0-9]+;
WS      : [ \t\r\n]+ -> skip;
ID      : [a-zA-Z_][a-zA-Z_0-9]*;

PLUS    : '+';
MINUS   : '-';
MULT    : '*';
DIV     : '/';
LPAR    : '(';
RPAR    : ')';

Чтобы сгенерировать код для visitor'а, запускаем antlr4 со следующими параметрами:

$ antlr4 -no-listener -visitor Calc.g4

CalculationVisitor.java

public class CalculationVisitor extends CalcBaseVisitor<Integer> {
    @Override
    public Integer visitPlus(CalcParser.PlusContext ctx) {
        System.out.print("(+ ");
        visit(ctx.expr(0));
        visit(ctx.expr(1));
        System.out.print(") ");
        return 0;
    }

    @Override
    public Integer visitInt(CalcParser.IntContext ctx) {
        System.out.print(ctx.INT().getText() + " ");
        return 0;
    }
}

main.java

import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.tree.*;
import java.io.FileInputStream;
import java.io.InputStream;

public class main {
    public static void main(String[] args) throws Exception {
        ANTLRInputStream input = new ANTLRInputStream(System.in); 
        CalcLexer lexer = new CalcLexer(input); 
        CommonTokenStream tokens = new CommonTokenStream(lexer); 
        CalcParser parser = new CalcParser(tokens); 
        ParseTree tree = parser.input();
        System.out.println(tree.toStringTree(parser));
        CalculationVisitor eval = new CalculationVisitor();
        eval.visit(tree);
    }
}

Решение с использованием listener'а

Calc.g4

grammar Calc;

input
        : expr EOF               
        ;

expr 
        : l3=expr PLUS r3=expr 
        | INT
        ;

INT     : [0-9]+;
WS      : [ \t\r\n]+ -> skip;
ID      : [a-zA-Z_][a-zA-Z_0-9]*;

PLUS    : '+';
MINUS   : '-';
MULT    : '*';
DIV     : '/';
LPAR    : '(';
RPAR    : ')';

Запускаем antlr4:

$ antlr4 -listener Calc.g4

CalculationListener.java

import org.antlr.v4.runtime.TokenStream;
import org.antlr.v4.runtime.TokenStreamRewriter;

public class CalculationListener extends CalcBaseListener {
    @Override 
    public void enterExpr(CalcParser.ExprContext ctx) { 
        if (ctx.INT() != null) {
            System.out.print(ctx.INT() + " ");
        }
        else if (ctx.PLUS() != null) {
            System.out.print("(+ ");
        }
    }

    @Override 
    public void exitExpr(CalcParser.ExprContext ctx) { 
        if (ctx.PLUS() != null)
            System.out.print(") ");
    }
}

main.java

import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.tree.*;
import java.io.FileInputStream;
import java.io.InputStream;

public class main {
    public static void main(String[] args) throws Exception {
        ANTLRInputStream input = new ANTLRInputStream(System.in); 
        CalcLexer lexer = new CalcLexer(input); 
        CommonTokenStream tokens = new CommonTokenStream(lexer); 
        CalcParser parser = new CalcParser(tokens); 
        ParseTree tree = parser.input();
        System.out.println(tree.toStringTree(parser));
        ParseTreeWalker walker = new ParseTreeWalker();
        CalculationListener listener = new CalculationListener();
        walker.walk(listener, tree);
    }
}

Домашнее задание

Создать при помощи listener'а транслятор микроязыка с переменными, арифметическими выражениями и вводом-выводом в scheme.

Пример

Вход

read a
b = a - 1
display a ** b * (-a + 2 * b + b / 2 - 1)
read c
display a + c

Выход

(define a (read))
(define b (- a 1))
(display (* (expt a b) (- (+ (- a) (* 2 b) (/ b 2)) 1)))
(define c (read))
(display (+ a c))
comments powered by Disqus