这是我的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
: [ rnt]+ -> channel(HIDDEN)
;
这是一个倾听者。我写得很随意,请忽略类名和其他琐碎的事情。
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"。我知道"输入"方法用于输入节点,并在遍历树时执行您想要的操作。但我尽量避免使用过多的if子句。你有其他方法来获取dataType吗?
sqlBaseListener类是由anltr4生成的,您应该了解anltr4
无论您有哪种类型,都会调用getText()
,因此实际上不需要检查类型。您可以随时拨打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;
...
}
}
这可能是最简单的解决方案,如果需要的话,以后很容易增强。
"ctx.dataType((.BOOLEAN((","ctx.data type((.FLOAT(!!