Код посетителя / слушателя для цикла while в ANTLR 4
до сих пор я искал всю "окончательную справочную книгу ANTLR 4", а также многие сайты для ответа на мой вопрос, и я до сих пор не могу найти ничего по этой теме.
Я использую ANTLR 4 для создания подмножества языка C, который выполняет некоторые основные функции. Я понятия не имею, как реализовать простой цикл while в моем классе посетителей. До сих пор я получил это в своей грамматике:
grammar Expr;
prog: stat+ ;
stat: expr NEWLINE # printExpr
| ID '=' expr NEWLINE # assign
| loop NEWLINE # whileLoop
| relational NEWLINE # relat
| NEWLINE # blank
;
expr: expr op=('*'|'/') expr # MulDiv
| expr op=('+'|'-') expr # AddSub
| INT # int
| ID # id
| '(' expr ')' # parens
;
relational: expr op=(GREATER|LESS) expr # GreaterEqual
;
loop: 'while' '('relational')' NEWLINE? '{'stat*'}' #while
;
GREATER : '>' ;
LESS : '<' ;
MUL : '*' ; // assigns token name to '*' used above in grammar
DIV : '/' ;
ADD : '+' ;
SUB : '-' ;
ID : [a-zA-Z]+ ; // match identifiers
INT : [0-9]+ ; // match integers
NEWLINE:'r'? 'n' ; // return newlines to parser (is end-statement signal)
WS : [ t]+ -> skip ; // toss out whitespace
таким образом я могу иметь несколько операторов внутри некоторое время петля. Мой класс посетителей выглядит так:
public class EvalVisitor extends ExprBaseVisitor<Integer> {
/** "memory" for our calculator; variable/value pairs go here */
Map<String, Integer> memory;
public EvalVisitor() {
memory = new HashMap<String, Integer>();
}
/** ID '=' expr NEWLINE */
@Override
public Integer visitAssign(ExprParser.AssignContext ctx) {
String id = ctx.ID().getText(); // id is left-hand side of '='
int value = super.visit(ctx.expr()); // compute value of expression on right
memory.put(id, value); // store it in our memory
return value;
}
/** expr NEWLINE */
@Override
public Integer visitPrintExpr(ExprParser.PrintExprContext ctx) {
Integer value = super.visit(ctx.expr()); // evaluate the expr child
System.out.println(value); // print the result
return 0; // return dummy value
}
/** INT */
@Override
public Integer visitInt(ExprParser.IntContext ctx) {
return Integer.valueOf(ctx.INT().getText());
}
/** ID */
@Override
public Integer visitId(ExprParser.IdContext ctx) {
String id = ctx.ID().getText();
if ( memory.containsKey(id) ) return memory.get(id);
return 0;
}
/** expr op=('*'|'/') expr */
@Override
public Integer visitMulDiv(ExprParser.MulDivContext ctx) {
int left = super.visit(ctx.expr(0)); // get value of left subexpression
int right = super.visit(ctx.expr(1)); // get value of right subexpression
if ( ctx.op.getType() == ExprParser.MUL ) return left * right;
return left / right; // must be DIV
}
/** expr op=('+'|'-') expr */
@Override
public Integer visitAddSub(ExprParser.AddSubContext ctx) {
int left = super.visit(ctx.expr(0)); // get value of left subexpression
int right = super.visit(ctx.expr(1)); // get value of right subexpression
if ( ctx.op.getType() == ExprParser.ADD ) return left + right;
return left - right; // must be SUB
}
/** '(' expr ')' */
@Override
public Integer visitParens(ExprParser.ParensContext ctx) {
return super.visit(ctx.expr()); // return child expr's value
}
@Override
public boolean visitGreaterEqual(GreaterEqualContext ctx) {
int left = super.visit(ctx.expr(0));
int right = super.visit(ctx.expr(1));
if(ctx.op.getType() == ExprParser.GREATER) {
return left > right;
}
else {
return left < right;
}
}
@Override
public Integer visitWhileLoop(WhileLoopContext ctx) {
if(visit(ctx.getRuleContext())) {
}
return super.visitWhileLoop(ctx);
}
}
большая часть кода в классе посетителей я взял из книги, потому что я только начинаю использовать ANTLR 4. Мне трудно поверить, что, кроме грамматики цикла while, нет упоминания о том, как реализовать каких-либо посетителей/слушателей или действий для простого цикла While в книге, написанной Теренсом Парром. Может ли кто-нибудь помочь мне написать Java-код посетителя/слушателя на некоторое время?
1 ответов
мне трудно поверить, что, кроме грамматики для цикла while, нет упоминания о том, как реализовать каких-либо посетителей/слушателей или действий для простого цикла While в книге, написанной Теренсом Парром.
это потому, что ссылка ANTLR касается ANTLR, которая касается синтаксического анализа, а не стадии после парсинг.
вы не можете сделать это:
@Override public boolean visitGreaterEqual(GreaterEqualContext ctx) { ...
вы уже объявлено, что ваш посетитель возвращается Integer
s, так что каждое правило должно возвращаться. Либо сделайте пользовательскую обертку Value
, который инкапсулирует значения вашего языка (числа, строки, логические значения), или просто вернуть 0
когда выражение отношения ложно:
@Override
public Integer visitGreaterEqual(ExprParser.GreaterEqualContext ctx) {
int left = this.visit(ctx.expr(0));
int right = this.visit(ctx.expr(1));
if (ctx.op.getType() == ExprParser.GREATER) {
return left > right ? 1 : 0; // 0 is false (all other values are true)
}
else {
return left < right ? 1 : 0;
}
}
затем вы можете написать свой while
следующим образом:
@Override
public Integer visitWhile(ExprParser.WhileContext ctx) {
// Evaluate the relational expression and continue the while
// loop as long as it is true (does not equal zero).
while (this.visit(ctx.relational()) != 0) {
// Evaluate all statements inside the while loop.
for (ExprParser.StatContext stat : ctx.stat()) {
this.visit(stat);
}
}
// 0 now also is false, so maybe return null instead which would be
// some sort of VOID value (or make a proper Value class).
return 0;
}
обратите внимание, что приведенный выше код завершится ошибкой при вложении while
заявления, потому что внутреннее время вернется 0
причинять наружное пока к хватит петлять. В таких случаях вам лучше создать пользовательский Value
класс и ввести какой-то Value.VOID
экземпляр, который не приведет к остановке цикла.
запуск следующего основного метода:
public static void main(String[] args) throws Exception {
String expression = "n = 1\n" +
"while (n < 10) {\n" +
" n\n" +
" n = n + 1\n" +
"}\n";
ExprLexer lexer = new ExprLexer(new ANTLRInputStream(expression));
ExprParser parser = new ExprParser(new CommonTokenStream(lexer));
new EvalVisitor().visit(parser.prog());
}
выведет:
1 2 3 4 5 6 7 8 9
Также посмотрите на этот демо-язык, который использует ANTLR4 и if
и while
заявления, а также пользовательским Value
объект:https://github.com/bkiers/Mu