如何在不使用太多 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;
...
}
}
这可能是最简单的解决方案,如果需要,以后很容易增强。
这是我的 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;
...
}
}
这可能是最简单的解决方案,如果需要,以后很容易增强。