微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

带有小数的ANTLR4语法问题

如何解决带有小数的ANTLR4语法问题

我是ANTLR的新手,正在使用ANTLR4(4.7.2 Jar文件)。我目前正在研究Oracle Parser。 我在使用十进制数字时遇到问题。我只保留了相关部分。 我的语法文件如下。

现在,当我解析以下语句时就可以了。在我的情况下,“。1”是有效数字。 开始编号:=。1; END;

我没有显示语法,但是以下是在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 DATAFILE + DATA / BR / CONTROLFILE / Current.260.750;

在这里,数字260和750与DOT一起标记(根据NUMERIC_LIteraL的定义)。我希望这是由DOT分隔的2个独立数字(并分别分配给文件号和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 modes来隔离实例。例如,在给定的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);

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。