支持ANTLR语法中的二进制运算符和引号

支持ANTLR语法中的二进制运算符和引号,antlr,antlr4,Antlr,Antlr4,我们正在尝试以以下形式解析查询: Taiwan OR China Taiwan OR "Republic of China" 基本上,像或/和/不这样的二进制运算符将用于构造此类查询,引号用于标记包含多个单词的术语。然后,我们的目标是在此处提取各个名称: 台湾和中国在第一种情况下 台湾和中华民国在第二种情况下 (问题更复杂,但这是第一个里程碑) 从基础开始,我们将在第一个用例中使用以下内容 grammar Query; parse : expr EOF ; expr : name bino

我们正在尝试以以下形式解析查询:

Taiwan OR China
Taiwan OR "Republic of China"
基本上,像或/和/不这样的二进制运算符将用于构造此类查询,引号用于标记包含多个单词的术语。然后,我们的目标是在此处提取各个名称:

  • 台湾中国在第一种情况下
  • 台湾中华民国在第二种情况下
(问题更复杂,但这是第一个里程碑)

从基础开始,我们将在第一个用例中使用以下内容

grammar Query;
parse : expr EOF ;
expr : name binop name ;
binop : 'AND' | 'OR' | 'NOT' ;
name
  :  WORD
  ;
WORD              : ('a' .. 'z' | 'A' .. 'Z')+ ;
WS : [ \t\r\n]+ -> skip ;
当试图扩展它以捕获引号并处理引号中的术语的空格时,我们有点挣扎

我们试过这样的方法:

grammar Query;
parse : expr EOF ;
expr : name binop name ;
binop : 'AND' | 'OR' | 'NOT' ;
name
  :  WORD
  | '"' NAME_WITH_SPACES '"'
  ;
WORD              : ('a' .. 'z' | 'A' .. 'Z')+ ;
NAME_WITH_SPACES  : ('a' .. 'z' | 'A' .. 'Z' | ' ')+ ;
WS : [ \t\r\n]+ -> skip ;
WORD              : [a-zA-Z]+ ;
NAME_WITH_SPACES  : '"' [a-zA-Z ]+ '"' ;
更具体地说,输出是:

line 1:0 mismatched input 'TAIWAN OR CHINA' expecting {'"', WORD}
分别为:

line 1:0 extraneous input 'TAIWAN OR ' expecting {'"', WORD}
line 1:29 mismatched input '<EOF>' expecting {'AND', 'OR', 'NOT'}
行1:0无关输入'TAIWAN或'expecting{'',WORD}
第1行:29不匹配的输入“”应为{'AND','OR','NOT'}
我们理解,在引号内包含空格的同时,在引号外跳过空格可能会产生摩擦


任何想法都是受欢迎的-作为两个新的想法,很难说如何适应这些围绕空白的冲突要求。

进一步,我们尝试了以下方法:

grammar Query;
parse : expr EOF ;
expr : name binop name ;
binop : 'AND' | 'OR' | 'NOT' ;
name
  : WORD
  | NAME_WITH_SPACES
  ;
WORD              : ('a' .. 'z' | 'A' .. 'Z')+ ;
NAME_WITH_SPACES  : '"' ('a' .. 'z' | 'A' .. 'Z' | ' ')+ '"' ;
WS : [ \t\r\n]+ -> skip ;
这似乎工作得相当好,尽管在我看来,它在语义上与我们的第一次尝试相同,但没有成功:

grammar Query;
parse : expr EOF ;
expr : name binop name ;
binop : 'AND' | 'OR' | 'NOT' ;
name
  :  WORD
  | '"' NAME_WITH_SPACES '"'
  ;
WORD              : ('a' .. 'z' | 'A' .. 'Z')+ ;
NAME_WITH_SPACES  : ('a' .. 'z' | 'A' .. 'Z' | ' ')+ ;
WS : [ \t\r\n]+ -> skip ;
不,这是:

name
  :  WORD
  | '"' NAME_WITH_SPACES '"'
  ;

...

NAME_WITH_SPACES  : ('a' .. 'z' | 'A' .. 'Z' | ' ')+ ;
不同于:

name
  : WORD
  | NAME_WITH_SPACES
  ;

...

NAME_WITH_SPACES  : '"' ('a' .. 'z' | 'A' .. 'Z' | ' ')+ '"' ;
在第一种情况下,
台湾或“中华民国”
等输入标记如下:

  • 台湾或
    (类型:名称加空格)
  • 中华民国
    (类型:名称加空格)
因为ANTLR的lexer规则试图匹配尽可能多的字符。因此,如果您让引号包含在
NAME\u中,并带有空格
lexer规则:

NAME_WITH_SPACES  : '"' ('a' .. 'z' | 'A' .. 'Z' | ' ')+ '"' ;
然后输入
台湾或“中华民国”
标记如下:

  • 台湾(类型:WORD)
  • (类型:或)
  • “中华民国”
    (类型:名称加空格)
并正确跳过引用标记之外的空格

请注意,您可以这样写:

grammar Query;
parse : expr EOF ;
expr : name binop name ;
binop : 'AND' | 'OR' | 'NOT' ;
name
  :  WORD
  | '"' NAME_WITH_SPACES '"'
  ;
WORD              : ('a' .. 'z' | 'A' .. 'Z')+ ;
NAME_WITH_SPACES  : ('a' .. 'z' | 'A' .. 'Z' | ' ')+ ;
WS : [ \t\r\n]+ -> skip ;
WORD              : [a-zA-Z]+ ;
NAME_WITH_SPACES  : '"' [a-zA-Z ]+ '"' ;

另请参阅此相关问答:

太好了,这是一件非常有用的事情,需要了解并明确这种行为的原因!谢谢你,巴特!(谢谢你的文档参考,我将对此进行更深入的讨论)