2017-09-26 73 views
0

具有相同的规则,但不同的位置匹配的令牌,我有以下声明我要解析:ANTLR4:在语法

in(name,(Silver,Gold)) 
  • 在:是一个函数。
  • name:是一个ID。
  • (Silver,Gold):是元素为'Silver'和'Gold'的字符串数组。

解析器总是混淆不清,因为ID和字符串数组元素具有相同的规则。对于字符串使用引号或双引号将有所帮助,但这不是这种情况。

另外,谓词没有多大帮助。

语法:

grammar Rql; 

statement 
: EOF 
| query EOF 
; 

query 
: function 
; 

function 
: FUNCTION_IN OPAR id COMMA OPAR array CPAR CPAR 
; 

array 
: VALUE (COMMA VALUE)* 
; 

FUNCTION_IN: 'in'; 

id 
: {in(}? ID 
; 

ID 
: [a-zA-Z_] [a-zA-Z_0-9]* 
; 

VALUE 
: STRING 
| INT 
| FLOAT 
; 

OPAR : '('; 
CPAR : ')'; 
COMMA : ','; 

INT 
: [0-9]+ 
; 

FLOAT 
: [0-9]+ '.' [0-9]* 
| '.' [0-9]+ 
; 

SPACE 
: [ \t\r\n] -> skip 
; 

STRING 
: [a-zA-Z_] [a-zA-Z_0-9]* 
; 

OTHER 
: . 
; 
+0

这不是解析器混淆,相信我。它总是知道要解析什么:-)那么,真正的问题是什么?你能指望什么? –

+0

您的输入'Silver,Gold'是否正确?是不是'银','金'?没有撇号,他们没有机会与'STRING'规则匹配。 – BernardK

+0

@BernardK:是的。该语法与引用“Silver”和“Gold”的字符串一起使用。如果我删除了引号,解析器会认为它是一个ID。 –

回答

1

的想法是改变一些条件下的标记的类型。这里首次在一行中看到一个ID会将开关设置为真。下次匹配ID时,词法分析器将执行if并将类型设置为ID_VALUE。我想在进入规则function重置开关,但它不工作:

function 
@init {QuestionLexer.id_seen = false; System.out.println("id_seen has been reset" + QuestionLexer.id_seen);} 
: FUNCTION_IN OPAR ID COMMA OPAR array CPAR CPAR 

ID=name1 seen ? false 
ID=Silver seen ? true 
... 
ID=Platinum seen ? true 
[@0,0:1='in',<'in'>,1:0] 
[@1,2:2='(',<'('>,1:2] 
[@2,3:7='name1',<ID>,1:3] 
[@3,8:8=',',<','>,1:8] 
[@4,9:9='(',<'('>,1:9] 
[@5,10:15='Silver',<10>,1:10] 
... 
[@12,27:31='name2',<10>,2:3] 
... 
[@20,52:51='<EOF>',<EOF>,3:0] 
Question last update 1336 
id_seen has been reset false 
id_seen has been reset false 
line 2:3 mismatched input 'name2' expecting ID 

这就是为什么我重置它在FUNCTION_IN规则。

语法Question.g4:

grammar Question; 

@lexer::members { 
    static boolean id_seen = false; 
} 

tokens { ID_VALUE } 

question 
@init {System.out.println("Question last update 1352");} 
: function+ EOF 
; 

function 
: FUNCTION_IN OPAR ID COMMA OPAR array CPAR CPAR 
; 

array 
: value (COMMA value)* 
; 

value 
: ID_VALUE 
| INT 
| FLOAT 
; 

FUNCTION_IN: 'in' {id_seen = false;} ; 

ID : [a-zA-Z_] [a-zA-Z_0-9]* 
    {System.out.println("ID=" + getText() + " seen ? " + id_seen); 
     if (id_seen) setType(QuestionParser.ID_VALUE); id_seen = true; } ; 

OPAR : '('; 
CPAR : ')'; 
COMMA : ','; 

INT 
: [0-9]+ 
; 

FLOAT 
: [0-9]+ '.' [0-9]* 
| '.' [0-9]+ 
; 

SPACE 
: [ \t\r\n] -> skip 
; 

OTHER 
: . 
; 

文件t.text:

in(name1,(Silver,Gold)) 
in(name2,(Copper,Platinum)) 

执行与ANTLR 4.6:

$ grun Question question -tokens -diagnostics t.text 
ID=name1 seen ? false 
ID=Silver seen ? true 
ID=Gold seen ? true 
ID=name2 seen ? false 
ID=Copper seen ? true 
ID=Platinum seen ? true 
[@0,0:1='in',<'in'>,1:0] 
[@1,2:2='(',<'('>,1:2] 
[@2,3:7='name1',<ID>,1:3] 
[@3,8:8=',',<','>,1:8] 
[@4,9:9='(',<'('>,1:9] 
[@5,10:15='Silver',<10>,1:10] 
[@6,16:16=',',<','>,1:16] 
[@7,17:20='Gold',<10>,1:17] 
[@8,21:21=')',<')'>,1:21] 
[@9,22:22=')',<')'>,1:22] 
[@10,24:25='in',<'in'>,2:0] 
[@11,26:26='(',<'('>,2:2] 
[@12,27:31='name2',<ID>,2:3] 
[@13,32:32=',',<','>,2:8] 
[@14,33:33='(',<'('>,2:9] 
[@15,34:39='Copper',<10>,2:10] 
[@16,40:40=',',<','>,2:16] 
[@17,41:48='Platinum',<10>,2:17] 
[@18,49:49=')',<')'>,2:25] 
[@19,50:50=')',<')'>,2:26] 
[@20,52:51='<EOF>',<EOF>,3:0] 
Question last update 1352 

类型< 10>是ID_VALUE如可以看到的在.tokens文件中

$ cat Question.tokens 
FUNCTION_IN=1 
... 
OTHER=9 
ID_VALUE=10 
'in'=1 
+0

感谢您的努力!这个语法是否会生成一个C#访问者/侦听器? –

+0

@AmrEllafy ANTLR4比以前版本/其他解析器生成器的优势在于代码已被移入侦听器/访问者。然而,在很多情况下,语法中需要代码,例如语义谓词。在语法中编写代码的缺点是它必须用目标语言编写,并且必须改变为另一个目标。请参阅[The Mega Tutorial](https://tomassetti.me/antlr-mega-tutorial)中的示例。 – BernardK