antlr4 - 十进制数的 ANTLR4 语法问题
问题描述
我是 ANTLR 新手并使用 ANTLR4(4.7.2 Jar 文件)。我目前正在研究 Oracle Parser。我遇到了十进制数的问题。我只保留了相关部分。我的语法文件如下。
现在,当我解析以下语句时,它很好。在我的情况下,“.1”是一个有效数字。开始一个数字:=.1;结尾;
我没有展示语法,但以下是我在 Oracle 中的有效案例。
a NUMBER:= .1; // with Space after operator
a NUMBER:=1.1; // without Space after operator
a NUMBER:=1; // without Space after operator
a NUMER:= 3; // with Space after operator
现在我需要创建一个表空间,如下所示。创建表空间 tbs_01 数据文件 +DATA/BR/CONTROLFILE/Current.260.750;
在这里,数字 260 和 750 与 DOT 一起被标记化(根据 NUMERIC_LITERAL 的定义)。我希望这是由 DOT 分隔的 2 个单独的数字(并分别分配给 filenumber 和 incarnation_number,如语法所示)。
我该怎么做呢?我试过使用 _input.LA(-1)!='.'}?等,但对我来说不能正常工作。我尝试了提到的许多其他步骤(大多数解决方案适用于 ANTLR3,不适用于 ANTLR4)。在 LEXER 中是否有一种简单的方法可以做到这一点?我不想编写解析器规则来拆分十进制数字。
grammar Oracle;
parse
: ( sql_statements | error )* EOF
;
error
: UNEXPECTED_CHAR
{
throw new RuntimeException("UNEXPECTED_CHAR=" + $UNEXPECTED_CHAR.text);
}
;
sql_statements
: 'CREATE' 'TABLESPACE' tablespace_name 'DATAFILE' fully_qualified_file_name ';'
| 'BEGIN' var1 'NUMBER' ':=' num1 ';' 'END' ';'
;
tablespace_name : IDENTIFIER;
fully_qualified_file_name : K_PLUS_SIGN diskgroup_name K_SOLIDUS db_name K_SOLIDUS file_type K_SOLIDUS file_type_tag '.' filenumber '.' incarnation_number;
diskgroup_name : IDENTIFIER;
db_name : IDENTIFIER;
file_type : IDENTIFIER;
file_type_tag : IDENTIFIER;
filenumber : NUMERIC_LITERAL;
incarnation_number : NUMERIC_LITERAL;
var1 : IDENTIFIER;
num1 : NUMERIC_LITERAL;
IDENTIFIER : [a-zA-Z_] ([a-zA-Z] | '$' | '_' | '#' | DIGIT)* ;
K_PLUS_SIGN : '+';
K_SOLIDUS : '/';
NUMERIC_LITERAL
: DIGIT+ ( '.' DIGIT+ )? ( E ('+'|'-')? DIGIT+ )? ('D' | 'F')?
| '.' DIGIT+ ( E ('+'|'-')? DIGIT+ )? ('D' | 'F')?
;
SPACES : [ \u000B\t\r\n] -> skip;
WS : [ \t\r\n]+ -> skip;
UNEXPECTED_CHAR : . ;
fragment DIGIT : [0-9];
fragment A : [aA];
fragment B : [bB];
fragment C : [cC];
fragment D : [dD];
fragment E : [eE];
fragment F : [fF];
fragment G : [gG];
fragment H : [hH];
fragment I : [iI];
fragment J : [jJ];
fragment K : [kK];
fragment L : [lL];
fragment M : [mM];
fragment N : [nN];
fragment O : [oO];
fragment P : [pP];
fragment Q : [qQ];
fragment R : [rR];
fragment S : [sS];
fragment T : [tT];
fragment U : [uU];
fragment V : [vV];
fragment W : [wW];
fragment X : [xX];
fragment Y : [yY];
fragment Z : [zZ];
解决方案
您的 Dsl 有一个自然的歧义:在某些情况下,数字是整数,而在其他情况下,是小数。
如果Dsl 提供了足够的保护条件,则可以使用Antlr模式来隔离实例。例如,在给定的 Dsl 中,十进制数字似乎总是出现在:=
和;
守卫之间。
...
K_ASSIGN : ':=' -> pushMode(Decimals);
K_SEMI : ';' ;
NUMERIC_LITERAL : DIGIT+ ;
...
mode Decimals;
D_SEMI : ';' -> type(K_SEMI), popMode ;
NUMERIC:
DIGIT+ ( '.' DIGIT+ )? ( E ('+'|'-')? DIGIT+ )? 'D'
| 'F')?
| '.' DIGIT+ ( E ('+'|'-')? DIGIT+ )? ('D' | 'F')?
-> type(NUMERIC_LITERAL);
推荐阅读
- console - tmux/.tmux.conf:从左边截取的字符串
- c# - 如何根据列值对列表进行排序
- javascript - iOS Safari:对于像弹出菜单这样的覆盖,100vh 无法正常工作,并隐藏在 44px 像素高的 safari 菜单栏下
- php - 如何修复“Illuminate/Database/QueryException with message 'SQLSTATE[42S22]: Column not found: 1054 Unknown column”?
- c++ - std::map 插入的可疑结果
- hyperledger-fabric-ca - 是否有用于注册的 Fabric-CA API(不使用用户实例)
- html - 有没有机会使用 CSS/HTML 技巧来创建图像,比如 CD Trey 和 CD Rings
- marklogic - 如何提交升级?什么时候发生?
- mpi - 如何调试:如果 mpi 不能跨机器运行
- rdlc - 如何在每页中重复行组标题?