如何在不使用太多 if 子句的情况下获取类型?

How to get a type without using too many if clause?

这是我的 g4 文件

grammar sql;

singleStatement
    : CREATE TIMESERIES dataType
    ;


CREATE: 'CREATE';

TIMESERIES: 'TIMESERIES';

dataType
    : INT32 | INT64 | FLOAT | DOUBLE | BOOLEAN | TEXT
    ;

INT32: 'INT32';

INT64: 'INT64';

FLOAT: 'FLOAT';

DOUBLE: 'DOUBLE';

BOOLEAN: 'BOOLEAN';

TEXT: 'TEXT';

WS
    : [ \r\n\t]+ -> channel(HIDDEN)
    ;

这是一个监听器。随便写的,请忽略class名字等琐事

package com.boris.sql;

import com.boris.sql.sqlParser.SingleStatementContext;

public class Hello extends sqlBaseListener {

  @Override
  public void enterSingleStatement(SingleStatementContext ctx) {
    super.enterSingleStatement(ctx);
    if (ctx.dataType().BOOLEAN() != null) {
      System.out.println(ctx.dataType().BOOLEAN().getText());
    }

    if (ctx.dataType().FLOAT() != null) {
      System.out.println(ctx.dataType().FLOAT().getText());
    }

    if(ctx.dataType().DOUBLE() != null) {
      System.out.println(ctx.dataType().DOUBLE().getText());
    }

    if(ctx.dataType().INT32() != null) {
      System.out.println(ctx.dataType().INT32().getText());
    }

    if(ctx.dataType().INT64() != null) {
      System.out.println(ctx.dataType().INT64().getText());
    }

    if(ctx.dataType().TEXT() != null) {
      System.out.println(ctx.dataType().TEXT().getText());
    }

  }
}

一个驱动程序运行一个简单的例子,

package com.boris.sql;

import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.ParseTreeWalker;

public class Driver {

  public static void main(String[] args) {
    String query = "CREATE TIMESERIES INT32";
    sqlLexer lexer = new sqlLexer(new ANTLRInputStream(query));
    CommonTokenStream tokns = new CommonTokenStream(lexer);
    sqlParser parser = new sqlParser(tokns);
    ParseTree tree = parser.singleStatement();
    ParseTreeWalker walker = new ParseTreeWalker();
    walker.walk(new Hello(), tree);
  }
}

是的,如您所见,我得到了正确的结果,"INT32"。我知道 "enter" 方法用于输入节点并在遍历树时执行您想要的操作。但我尽量避免使用过多的 if 子句。您还有其他获取数据类型的方法吗?


sqlBaseListener class是anltr4生成的,要懂anltr4才能看懂。

"ctx.dataType().BOOLEAN()","ctx.dataType().FLOAT()"...returns 不同类型的 class ,你应该创建一个父 class A ,使用 "ctx.dataType.A().getTxt()",多态性。然后将不同类型的class实例分配给父class A,避免使用过多的if子句!!

无论您使用哪种类型,您都在调用 getText(),因此您不需要实际检查类型。你可以只调用 always call getText。由于 dataType 完全由单个标记组成,您只需调用 ctx.dataType().getText() 即可获得与当前代码相同的结果。

如果您想在不使用 if 的情况下区别对待不同的备选方案,您可以命名备选方案,然后为每种类型定义不同的 enter 方法:

dataType
    : INT32 #TypeInt32
    | INT64 #TypeInt64
    | FloatType #Float
    ...
    ;

然后在监听器中:

@Override
public void enterTypeInt32(TypeInt32Context ctx) {
    System.out.println("It's a 32-bit integer!");
}

@Override
public void enterTypeInt64(TypeInt64Context ctx) {
    System.out.println("It's a 64-bit integer!");
}

@Override
public void enterTypeFloat(TypeFloatContext ctx) {
    System.out.println("It's a single-precision float!");
}

这是另一种选择。更改您的规则以将匹配的标记分配给上下文成员变量:

dataType
    : type = INT32
    | type = INT64
    | type = FLOAT
    | type = DOUBLE
    | type = BOOLEAN
    | type = TEXT
;

然后在switch语句中使用这个成员进行不同的处理:

  @Override
  public void enterDataType(DataTypeContext ctx) {
    switch (ctx.type.getType()) {
      case INT32:
        System.out.println("It's a 32-bit integer!");
        break;
      case INT64:
        System.out.println("It's a 64-bit integer!");
        break;
      ...
    }
  }

这可能是最简单的解决方案,如果需要,以后很容易增强。