如果ANTLR中的/ else语句使用侦听器 [英] If/else statements in ANTLR using listeners

查看:130
本文介绍了如果ANTLR中的/ else语句使用侦听器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为学校项目创建一种简单的编程语言。我正在使用ANTLR 4从我的语法生成词法分析器和解析器。到目前为止,我一直在使用ANTLRs监听器模式来应用编程语言的实际功能。



现在我想实现if / else语句,但我不是确保在使用侦听器模式时实际可以实现这些,因为ANTLR决定在使用侦听器时遍历解析树的顺序,我想if / else语句的实现将需要在解析树中跳转,具体取决于语句是满意的。



有人能告诉我是否可以使用ANTLR实现if / else语句,或者我是否必须自己实现访问者模式?另外,任何人都可以给出一个非常简单的语句实现示例吗?

解决方案

默认情况下,ANTLR 4会生成监听器。但是如果你给 org.antlr.v4.Tool 命令行参数 -visitor ,ANTLR会为你生成访问者类。这些工作与听众非常相似,但可以让您更好地控制走路/访问哪些(子)树。如果要排除某些(子)树(如else / if块,如您的情况),这将特别有用。虽然这个可以使用听众完成,但与访问者一起做这件事要清楚得多。使用侦听器,您需要引入全局变量来跟踪是否需要评估(子)树,哪些不需要。



因为它恰好是,我正在研究一个小型的ANTLR 4教程。它尚未完成,但我将发布一个小的工作示例,演示如何使用这些访问者类和 if 语句构造。






1。语法



这是一个支持基本表达式的简单语法, if - , while - 和 log -statements:



Mu.g4



 语法Mu; 

解析
:阻止EOF
;

block
:stat *
;

stat
:赋值
| if_stat
| while_stat
| log
| OTHER {System.err.println(unknown char:+ $ OTHER.text);}
;

赋值
:ID ASSIGN expr SCOL
;

if_stat
:IF condition_block(ELSE IF condition_block)*(ELSE stat_block)?
;

condition_block
:expr stat_block
;

stat_block
:OBRACE块CBRACE
| stat
;

while_stat
:WHILE expr stat_block
;

log
:LOG expr SCOL
;

expr
:expr POW< assoc = right> expr #powExpr
| MINUS expr #unaryMinusExpr
| NOT expr #notExpr
| expr op =(MULT | DIV | MOD)expr #multiplicationExpr
| expr op =(PLUS | MINUS)expr #additiveExpr
| expr op =(LTEQ | GTEQ | LT | GT)expr #relationalExpr
| expr op =(EQ | NEQ)expr #equalityExpr
| expr AND expr #andExpr
| expr OR expr #orExpr
| atom #atomExpr
;

atom
:OPAR expr CPAR #parExpr
| (INT | FLOAT)#numberAtom
| (TRUE | FALSE)#booleanAtom
| ID #idAtom
| STRING #stringAtom
| NIL #nilAtom
;

OR:'||';
AND:'&&';
EQ:'==';
NEQ:'!=';
GT:'>';
LT:'<';
GTEQ:'> =';
LTEQ:'< =';
加:'+';
减:' - ';
MULT:'*';
DIV:'/';
MOD:'%';
POW:'^';
NOT:'!';

SCOL:';';
ASSIGN:'=';
OPAR:'(';
CPAR:')';
OBRACE:'{';
CBRACE:'}';

TRUE:'true';
FALSE:'false';
无:'无';
IF:'if';
ELSE:'else';
WHILE:'while';
日志:'log';

ID
:[a-zA-Z_] [a-zA-Z_0-9] *
;

INT
:[0-9] +
;

FLOAT
:[0-9] +'。'[0-9] *
| '。'[0-9] +
;

STRING
:'''(〜[\\ n] \\'')*''''
;

COMMENT
:'#'〜[\\\\ n] * - >跳过
;

SPACE
:[\\\ \ n] - >跳过
;

其他
:。
;

现在让我们说你要解析并评估输入如下:



test.mu



  a = true; 
b = false;

如果a& & b {
log1 :: a =+ a +,b =+ b;
}
否则如果a || b {
log2 :: a =+ a +,b =+ b;
}
else {
log3 :: a =+ a +,b =+ b;
}

log完成!;






2.访客I



首先生成解析器和访问者类:



< pre class =lang-none prettyprint-override> java -cp antlr-4.0-complete.jar org.antlr.v4.Tool Mu.g4 -visitor

上面的命令会生成文件 MuBaseVisitor< T> 。这是我们将用自己的逻辑扩展的类:



EvalVisitor.java



 公共类EvalVisitor扩展MuBaseVisitor< Value> {
// ...
}

其中 Value 只是我们任何语言类型的包装器( String Boolean Double ):



Value.java



  public class Value {

public static Value VOID = new Value(new Object());

最终对象值;

public Value(Object value){
this.value = value;
}

public Boolean asBoolean(){
return(Boolean)value;
}

public Double asDouble(){
return(Double)value;
}

public String asString(){
return String.valueOf(value);
}

public boolean isDouble(){
返回值instanceof Double;
}

@Override
public int hashCode(){

if(value == null){
return 0;
}

返回this.value.hashCode();
}

@Override
public boolean equals(Object o){

if(value == o){
return true;
}

if(value == null || o == null || o.getClass()!= value.getClass()){
return false;
}

值=(值)o;

返回this.value.equals(that.value);
}

@Override
public String toString(){
return String.valueOf(value);
}
}






3。测试I



要测试类,请使用以下 Main 类:



Main.java



  import org.antlr.v4.runtime.ANTLRFileStream ; 
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;

公共类Main {
public static void main(String [] args)抛出异常{
MuLexer lexer = new MuLexer(new ANTLRFileStream(test.mu));
MuParser解析器=新的MuParser(新的CommonTokenStream(lexer));
ParseTree tree = parser.parse();
EvalVisitor visitor = new EvalVisitor();
visitor.visit(tree);
}
}

并编译并运行源文件:

  javac -cp antlr-4.0-complete.jar * .java 
java -cp。: antlr-4.0-complete.jar Main

(在Windows上,最后一个命令是: java -cp .; antlr-4.0-complete.jar Main



运行 Main ,没有任何反应(当然?)。这是因为我们没有在 EvalVisitor 类中实现任何规则。为了能够正确评估文件 test.mu ,我们需要为以下规则提供正确的实现:




  • if_stat

  • andExpr

  • orExpr

  • plusExpr

  • 作业

  • idAtom

  • booleanAtom

  • stringAtom

  • log






4。访客II&测试II



以下是这些规则的实现:

  import org.antlr.v4.runtime.misc.NotNull; 

import java.util.HashMap;
import java.util.List;
import java.util.Map;

公共类EvalVisitor扩展MuBaseVisitor< Value> {

//用于比较浮点数
public static final double SMALL_VALUE = 0.00000000001;

//存储变量(只有一个全局范围!)
private Map< String,Value> memory = new HashMap< String,Value>();

//赋值/ id覆盖
@Override
public值visitAssignment(MuParser.AssignmentContext ctx){
String id = ctx.ID()。getText() ;
值value = this.visit(ctx.expr());
返回memory.put(id,value);
}

@Override
public值visitIdAtom(MuParser.IdAtomContext ctx){
String id = ctx.getText();
值value = memory.get(id);
if(value == null){
抛出新的RuntimeException(没有这样的变量:+ id);
}
返回值;
}

//原子覆盖
@Override
public值visitStringAtom(MuParser.StringAtomContext ctx){
String str = ctx.getText();
//条带引号
str = str.substring(1,str.length() - 1).replace(\\,\);
返回新值(str);
}

@Override
公共值visitNumberAtom(MuParser.NumberAtomContext ctx){
返回新值(Double.valueOf(ctx) .getText()));
}

@Override
public值visitBooleanAtom(MuParser.BooleanAtomContext ctx){
返回新值(Boolean.valueOf(ctx。 getText()));
}

@Override
public值visitNilAtom(MuParser.NilAtomContext ctx){
返回新值(null);
}

// expr覆盖
@Override
public值visitParExpr(MuParser.ParExprContext ctx){
return this.visit(ctx.expr());
}

@Override
public值visitPowExpr(MuParser.PowExprContext ctx){
Value left = this.visit(ctx.expr(0));
价值权利= this.vis它(ctx.expr(1));
返回新值(Math.pow(left.asDouble(),right.asDouble()));
}

@Override
public值visitUnaryMinusExpr(MuParser.UnaryMinusExprContext ctx){
Value value = this.visit(ctx.expr());
返回新值(-value.asDouble());
}

@Override
public值visitNotExpr(MuParser.NotExprContext ctx){
Value value = this.visit(ctx.expr());
返回新值(!value.asBoolean());
}

@Override
public值visitMultiplicationExpr(@NotNull MuParser.MultiplicationExprContext ctx){

Value left = this.visit(ctx.expr( 0));
Value right = this.visit(ctx.expr(1));

switch(ctx.op.getType()){
case MuParser.MULT:
返回新值(left.asDouble()* right.asDouble());
case MuParser.DIV:
返回新值(left.asDouble()/ right.asDouble());
case MuParser.MOD:
返回新值(left.asDouble()%right.asDouble());
默认值:
抛出新的RuntimeException(未知运算符:+ MuParser.tokenNames [ctx.op.getType()]);
}
}

@Override
public值visitAdditiveExpr(@NotNull MuParser.AdditiveExprContext ctx){

Value left = this.visit (ctx.expr(0));
Value right = this.visit(ctx.expr(1));

switch(ctx.op.getType()){
case MuParser.PLUS:
return left.isDouble()&& right.isDouble()?
new Value(left.asDouble()+ right.asDouble()):
new Value(left.asString()+ right.asString());
case MuParser.MINUS:
返回新值(left.asDouble() - right.asDouble());
默认值:
抛出新的RuntimeException(未知运算符:+ MuParser.tokenNames [ctx.op.getType()]);
}
}

@Override
public值visitRelationalExpr(@NotNull MuParser.RelationalExprContext ctx){

Value left = this.visit (ctx.expr(0));
Value right = this.visit(ctx.expr(1));

switch(ctx.op.getType()){
case MuParser.LT:
返回新值(left.asDouble()< right.asDouble());
case MuParser.LTEQ:
返回新值(left.asDouble()< = right.asDouble());
case MuParser.GT:
返回新值(left.asDouble()> right.asDouble());
case MuParser.GTEQ:
返回新值(left.asDouble()> = right.asDouble());
默认值:
抛出新的RuntimeException(未知运算符:+ MuParser.tokenNames [ctx.op.getType()]);
}
}

@Override
public值visitEqualityExpr(@NotNull MuParser.EqualityExprContext ctx){

Value left = this.visit (ctx.expr(0));
Value right = this.visit(ctx.expr(1));

switch(ctx.op.getType()){
case MuParser.EQ:
return left.isDouble()&& right.isDouble()?
new Value(Math.abs(left.asDouble() - right.asDouble())< SMALL_VALUE):
new Value(left.equals(right));
case MuParser.NEQ:
return left.isDouble()&& right.isDouble()?
new Value(Math.abs(left.asDouble() - right.asDouble())> = SMALL_VALUE):
new Value(!left.equals(right));
默认值:
抛出新的RuntimeException(未知运算符:+ MuParser.tokenNames [ctx.op.getType()]);
}
}

@Override
public值visitAndExpr(MuParser.AndExprContext ctx){
Value left = this.visit(ctx.expr(0 ));
Value right = this.visit(ctx.expr(1));
返回新值(left.asBoolean()&& right.asBoolean());
}

@Override
public值visitOrExpr(MuParser.OrExprContext ctx){
Value left = this.visit(ctx.expr(0));
Value right = this.visit(ctx.expr(1));
返回新值(left.asBoolean()|| right.asBoolean());
}

//日志覆盖
@Override
公共值visitLog(MuParser.LogContext ctx){
值value = this.visit(ctx。 EXPR());
System.out.println(value);
返回值;
}

//如果覆盖
@Override
public值visitIf_stat(MuParser.If_statContext ctx){

List< MuParser.Condition_blockContext> ; conditions = ctx.condition_block();

boolean evaluatedBlock = false;

for(MuParser.Condition_blockContext condition:conditions){

Value evaluatedal = this.visit(condition.expr());

if(assess.asBoolean()){
evaluateBlock = true;
//评估这个块的expr == true
this.visit(condition.stat_block());
休息;
}
}

if(!evaluateBlock&& ctx.stat_block()!= null){
//评估else-stat_block(如果存在) == not null)
this.visit(ctx.stat_block());
}

返回Value.VOID;
}

//覆盖
@Override
public值visitWhile_stat(MuParser.While_statContext ctx){

值value = this。访问(ctx.expr());

while(value.asBoolean()){

//评估代码块
this.visit(ctx.stat_block());

//计算表达式
value = this.visit(ctx.expr());
}

返回Value.VOID;
}
}

当你重新编译并运行 Main ,以下内容将打印到您的控制台:

  2 :: a = true,b = false 
完成!






有关所有其他规则的实施,请参阅: https://github.com/bkiers/Mu



编辑



来自@pwwpche,在评论中:


for那些使用jdk1.8并遇到 IndexOutOfBoundsException ,antlr 4.0
在某种程度上与jdk1.8不兼容。下载antlr-4.6-complete.jar,
替换 expr POW< assoc = right> expr with < assoc = right> expr POW expr
消除错误和警告。



I'm creating a simple programming language for a school project. I'm using ANTLR 4 to generate a lexer and a parser from my grammar. Until now, I have been using ANTLRs listener pattern to apply the actual functionality of the programming language.

Now I would like to implement if/else statements but I'm not sure that these can actually be implemented when using the listener pattern as ANTLR decides in which order to traverse the parse tree when using listeners and I imagine that the implementation of if/else statements will require jumping around the parse tree depending on which condition in the statement is satisfied.

Can anyone tell me if it will be possible to implement if/else statements using ANTLR or if I will have to implement the visitor pattern myself? Also, can anyone give an extremely simple example of the implementation the statements?

解决方案

By default, ANTLR 4 generates listeners. But if you give org.antlr.v4.Tool the command line parameter -visitor, ANTLR generates visitor classes for you. These work much like listeners, but give you more control over which (sub) trees are walked/visited. This is particularly useful if you want to exclude certain (sub) trees (like else/if blocks, as in your case). While this can be done using listeners, it's much cleaner to do this with a visitor. Using listeners, you'll need to introduce global variables that keep track if a (sub) tree needs to be evaluated, and which do not.

As it happens to be, I'm working on a small ANTLR 4 tutorial. It's not done yet, but I'll post a small working example that demonstrates the use of these visitor classes and an if statement construct.


1. Grammar

Here's a simple grammar supporting basic expressions, if-, while- and log-statements:

Mu.g4

grammar Mu;

parse
 : block EOF
 ;

block
 : stat*
 ;

stat
 : assignment
 | if_stat
 | while_stat
 | log
 | OTHER {System.err.println("unknown char: " + $OTHER.text);}
 ;

assignment
 : ID ASSIGN expr SCOL
 ;

if_stat
 : IF condition_block (ELSE IF condition_block)* (ELSE stat_block)?
 ;

condition_block
 : expr stat_block
 ;

stat_block
 : OBRACE block CBRACE
 | stat
 ;

while_stat
 : WHILE expr stat_block
 ;

log
 : LOG expr SCOL
 ;

expr
 : expr POW<assoc=right> expr           #powExpr
 | MINUS expr                           #unaryMinusExpr
 | NOT expr                             #notExpr
 | expr op=(MULT | DIV | MOD) expr      #multiplicationExpr
 | expr op=(PLUS | MINUS) expr          #additiveExpr
 | expr op=(LTEQ | GTEQ | LT | GT) expr #relationalExpr
 | expr op=(EQ | NEQ) expr              #equalityExpr
 | expr AND expr                        #andExpr
 | expr OR expr                         #orExpr
 | atom                                 #atomExpr
 ;

atom
 : OPAR expr CPAR #parExpr
 | (INT | FLOAT)  #numberAtom
 | (TRUE | FALSE) #booleanAtom
 | ID             #idAtom
 | STRING         #stringAtom
 | NIL            #nilAtom
 ;

OR : '||';
AND : '&&';
EQ : '==';
NEQ : '!=';
GT : '>';
LT : '<';
GTEQ : '>=';
LTEQ : '<=';
PLUS : '+';
MINUS : '-';
MULT : '*';
DIV : '/';
MOD : '%';
POW : '^';
NOT : '!';

SCOL : ';';
ASSIGN : '=';
OPAR : '(';
CPAR : ')';
OBRACE : '{';
CBRACE : '}';

TRUE : 'true';
FALSE : 'false';
NIL : 'nil';
IF : 'if';
ELSE : 'else';
WHILE : 'while';
LOG : 'log';

ID
 : [a-zA-Z_] [a-zA-Z_0-9]*
 ;

INT
 : [0-9]+
 ;

FLOAT
 : [0-9]+ '.' [0-9]* 
 | '.' [0-9]+
 ;

STRING
 : '"' (~["\r\n] | '""')* '"'
 ;

COMMENT
 : '#' ~[\r\n]* -> skip
 ;

SPACE
 : [ \t\r\n] -> skip
 ;

OTHER
 : . 
 ;

Now let's say you would like to parse, and evaluate, input like this:

test.mu

a = true;
b = false;

if a && b {
  log "1 :: a=" + a +", b=" + b;
}
else if a || b {
  log "2 :: a=" + a +", b=" + b;
}
else {
  log "3 :: a=" + a +", b=" + b;
}

log "Done!";


2. Visitor I

Start by generating the parser and visitor classes:

java -cp antlr-4.0-complete.jar org.antlr.v4.Tool Mu.g4 -visitor

The command above would have generated, among others the file MuBaseVisitor<T>. This is the class we're going to extend with out own logic:

EvalVisitor.java

public class EvalVisitor extends MuBaseVisitor<Value> {
    // ...
}

where Value is just a wrapper for any of our language's types (String, Boolean, Double):

Value.java

public class Value {

    public static Value VOID = new Value(new Object());

    final Object value;

    public Value(Object value) {
        this.value = value;
    }

    public Boolean asBoolean() {
        return (Boolean)value;
    }

    public Double asDouble() {
        return (Double)value;
    }

    public String asString() {
        return String.valueOf(value);
    }

    public boolean isDouble() {
        return value instanceof Double;
    }

    @Override
    public int hashCode() {

        if(value == null) {
            return 0;
        }

        return this.value.hashCode();
    }

    @Override
    public boolean equals(Object o) {

        if(value == o) {
            return true;
        }

        if(value == null || o == null || o.getClass() != value.getClass()) {
            return false;
        }

        Value that = (Value)o;

        return this.value.equals(that.value);
    }

    @Override
    public String toString() {
        return String.valueOf(value);
    }
}


3. Test I

To test the classes, use the following Main class:

Main.java

import org.antlr.v4.runtime.ANTLRFileStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;

public class Main {
    public static void main(String[] args) throws Exception {
        MuLexer lexer = new MuLexer(new ANTLRFileStream("test.mu"));
        MuParser parser = new MuParser(new CommonTokenStream(lexer));
        ParseTree tree = parser.parse();
        EvalVisitor visitor = new EvalVisitor();
        visitor.visit(tree);
    }
}

and compile and run the source files:

javac -cp antlr-4.0-complete.jar *.java
java -cp .:antlr-4.0-complete.jar Main

(on Windows, the last command would be: java -cp .;antlr-4.0-complete.jar Main)

After running Main, nothing happens (of course?). This is because we didn't implement any of the rules in our EvalVisitor class. To be able to evaluate the file test.mu properly, we need to provide a proper implementation for the following rules:

  • if_stat
  • andExpr
  • orExpr
  • plusExpr
  • assignment
  • idAtom
  • booleanAtom
  • stringAtom
  • log

4. Visitor II & Test II

Here's a implementation of these rules:

import org.antlr.v4.runtime.misc.NotNull;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class EvalVisitor extends MuBaseVisitor<Value> {

    // used to compare floating point numbers
    public static final double SMALL_VALUE = 0.00000000001;

    // store variables (there's only one global scope!)
    private Map<String, Value> memory = new HashMap<String, Value>();

    // assignment/id overrides
    @Override
    public Value visitAssignment(MuParser.AssignmentContext ctx) {
        String id = ctx.ID().getText();
        Value value = this.visit(ctx.expr());
        return memory.put(id, value);
    }

    @Override
    public Value visitIdAtom(MuParser.IdAtomContext ctx) {
        String id = ctx.getText();
        Value value = memory.get(id);
        if(value == null) {
            throw new RuntimeException("no such variable: " + id);
        }
        return value;
    }

    // atom overrides
    @Override
    public Value visitStringAtom(MuParser.StringAtomContext ctx) {
        String str = ctx.getText();
        // strip quotes
        str = str.substring(1, str.length() - 1).replace("\"\"", "\"");
        return new Value(str);
    }

    @Override
    public Value visitNumberAtom(MuParser.NumberAtomContext ctx) {
        return new Value(Double.valueOf(ctx.getText()));
    }

    @Override
    public Value visitBooleanAtom(MuParser.BooleanAtomContext ctx) {
        return new Value(Boolean.valueOf(ctx.getText()));
    }

    @Override
    public Value visitNilAtom(MuParser.NilAtomContext ctx) {
        return new Value(null);
    }

    // expr overrides
    @Override
    public Value visitParExpr(MuParser.ParExprContext ctx) {
        return this.visit(ctx.expr());
    }

    @Override
    public Value visitPowExpr(MuParser.PowExprContext ctx) {
        Value left = this.visit(ctx.expr(0));
        Value right = this.visit(ctx.expr(1));
        return new Value(Math.pow(left.asDouble(), right.asDouble()));
    }

    @Override
    public Value visitUnaryMinusExpr(MuParser.UnaryMinusExprContext ctx) {
        Value value = this.visit(ctx.expr());
        return new Value(-value.asDouble());
    }

    @Override
    public Value visitNotExpr(MuParser.NotExprContext ctx) {
        Value value = this.visit(ctx.expr());
        return new Value(!value.asBoolean());
    }

    @Override
    public Value visitMultiplicationExpr(@NotNull MuParser.MultiplicationExprContext ctx) {

        Value left = this.visit(ctx.expr(0));
        Value right = this.visit(ctx.expr(1));

        switch (ctx.op.getType()) {
            case MuParser.MULT:
                return new Value(left.asDouble() * right.asDouble());
            case MuParser.DIV:
                return new Value(left.asDouble() / right.asDouble());
            case MuParser.MOD:
                return new Value(left.asDouble() % right.asDouble());
            default:
                throw new RuntimeException("unknown operator: " + MuParser.tokenNames[ctx.op.getType()]);
        }
    }

    @Override
    public Value visitAdditiveExpr(@NotNull MuParser.AdditiveExprContext ctx) {

        Value left = this.visit(ctx.expr(0));
        Value right = this.visit(ctx.expr(1));

        switch (ctx.op.getType()) {
            case MuParser.PLUS:
                return left.isDouble() && right.isDouble() ?
                        new Value(left.asDouble() + right.asDouble()) :
                        new Value(left.asString() + right.asString());
            case MuParser.MINUS:
                return new Value(left.asDouble() - right.asDouble());
            default:
                throw new RuntimeException("unknown operator: " + MuParser.tokenNames[ctx.op.getType()]);
        }
    }

    @Override
    public Value visitRelationalExpr(@NotNull MuParser.RelationalExprContext ctx) {

        Value left = this.visit(ctx.expr(0));
        Value right = this.visit(ctx.expr(1));

        switch (ctx.op.getType()) {
            case MuParser.LT:
                return new Value(left.asDouble() < right.asDouble());
            case MuParser.LTEQ:
                return new Value(left.asDouble() <= right.asDouble());
            case MuParser.GT:
                return new Value(left.asDouble() > right.asDouble());
            case MuParser.GTEQ:
                return new Value(left.asDouble() >= right.asDouble());
            default:
                throw new RuntimeException("unknown operator: " + MuParser.tokenNames[ctx.op.getType()]);
        }
    }

    @Override
    public Value visitEqualityExpr(@NotNull MuParser.EqualityExprContext ctx) {

        Value left = this.visit(ctx.expr(0));
        Value right = this.visit(ctx.expr(1));

        switch (ctx.op.getType()) {
            case MuParser.EQ:
                return left.isDouble() && right.isDouble() ?
                        new Value(Math.abs(left.asDouble() - right.asDouble()) < SMALL_VALUE) :
                        new Value(left.equals(right));
            case MuParser.NEQ:
                return left.isDouble() && right.isDouble() ?
                        new Value(Math.abs(left.asDouble() - right.asDouble()) >= SMALL_VALUE) :
                        new Value(!left.equals(right));
            default:
                throw new RuntimeException("unknown operator: " + MuParser.tokenNames[ctx.op.getType()]);
        }
    }

    @Override
    public Value visitAndExpr(MuParser.AndExprContext ctx) {
        Value left = this.visit(ctx.expr(0));
        Value right = this.visit(ctx.expr(1));
        return new Value(left.asBoolean() && right.asBoolean());
    }

    @Override
    public Value visitOrExpr(MuParser.OrExprContext ctx) {
        Value left = this.visit(ctx.expr(0));
        Value right = this.visit(ctx.expr(1));
        return new Value(left.asBoolean() || right.asBoolean());
    }

    // log override
    @Override
    public Value visitLog(MuParser.LogContext ctx) {
        Value value = this.visit(ctx.expr());
        System.out.println(value);
        return value;
    }

    // if override
    @Override
    public Value visitIf_stat(MuParser.If_statContext ctx) {

        List<MuParser.Condition_blockContext> conditions =  ctx.condition_block();

        boolean evaluatedBlock = false;

        for(MuParser.Condition_blockContext condition : conditions) {

            Value evaluated = this.visit(condition.expr());

            if(evaluated.asBoolean()) {
                evaluatedBlock = true;
                // evaluate this block whose expr==true
                this.visit(condition.stat_block());
                break;
            }
        }

        if(!evaluatedBlock && ctx.stat_block() != null) {
            // evaluate the else-stat_block (if present == not null)
            this.visit(ctx.stat_block());
        }

        return Value.VOID;
    }

    // while override
    @Override
    public Value visitWhile_stat(MuParser.While_statContext ctx) {

        Value value = this.visit(ctx.expr());

        while(value.asBoolean()) {

            // evaluate the code block
            this.visit(ctx.stat_block());

            // evaluate the expression
            value = this.visit(ctx.expr());
        }

        return Value.VOID;
    }
}

When you re-compile and run Main, the following would be printed to your console:

2 :: a=true, b=false
Done!


For an implementation of all other rules, see: https://github.com/bkiers/Mu

EDIT

From @pwwpche, in the comments:

for those using jdk1.8 and encounter IndexOutOfBoundsException, antlr 4.0 is somehow not compatible with jdk1.8. Download antlr-4.6-complete.jar, and replace expr POW<assoc=right> expr with <assoc=right>expr POW expr will eliminate the error and warnings.

这篇关于如果ANTLR中的/ else语句使用侦听器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆