为Antlr3语法添加引用字符串支持

时间:2012-01-22 07:24:43

标签: antlr antlr3

我正在尝试实现解析查询的语法。单个查询包含items,其中每个项目可以是namename-ref

namemystring(仅限字母,无空格)或"my long string"(字母和空格,始终引用)。 name-refname非常相似,唯一的区别是它应该以{{1​​}}(ref:ref:mystring)开头。查询应包含至少1个项目(ref:"my long string"name)。

这就是我所拥有的:

name-ref

这个语法演示了我基本上需要获得的内容,唯一的特性是它不支持长引号字符串(对于没有空格的名称,它可以正常工作)。

NAME: ('a'..'z')+;
REF_TAG: 'ref:';
SP: ' '+;

name: NAME;
name_ref: REF_TAG name;
item: name | name_ref;
query: item (SP item)*;

但这不起作用。有什么想法是什么问题?可能,这很重要:SHORT_NAME: ('a'..'z')+; LONG_NAME: SHORT_NAME (SP SHORT_NAME)*; REF_TAG: 'ref:'; SP: ' '+; Q: '"'; short_name: SHORT_NAME; long_name: LONG_NAME; name_ref: REF_TAG (short_name | (Q long_name Q)); item: (short_name | (Q long_name Q)) | name_ref; query: item (SP item)*; 应被视为3 my first query s(3 item s),name为1 "my first query"(1 item )。

2 个答案:

答案 0 :(得分:3)

ANTLR的词法分析器贪婪地匹配:这就是为什么像my first query这样的输入被标记为LONG_NAME而不是3 SHORT_NAME s,其间有空格。

只需删除LONG_NAME规则,然后在解析器规则long_name中对其进行定义。

以下语法:

SHORT_NAME : ('a'..'z')+;
REF_TAG    : 'ref:';
SP         : ' '+;
Q          : '"';

short_name : SHORT_NAME;
long_name  : Q SHORT_NAME (SP SHORT_NAME)* Q;
name_ref   : REF_TAG (short_name | (Q long_name Q));
item       : short_name | long_name | name_ref;
query      : item (SP item)*;

将解析输入:

my first query "my first query" ref:mystring

如下:

enter image description here

但是,你还可以对词法分析器中的引用名称进行标记,并使用一些自定义代码从中删除引号。从词法分析器中删除空格也是一种选择。像这样:

SHORT_NAME : ('a'..'z')+;
LONG_NAME  : '"' ~'"'* '"' {setText(getText().substring(1, getText().length()-1));};
REF_TAG    : 'ref:';
SP         : ' '+ {skip();};

name_ref   : REF_TAG (SHORT_NAME | LONG_NAME);
item       : SHORT_NAME | LONG_NAME | name_ref;
query      : item+ EOF;

将解析相同的输入,如下所示:

enter image description here

请注意,实际令牌LONG_NAME将被删除其开始和结束引用。

答案 1 :(得分:1)

这是一个符合您要求的语法:

  SP: ' '+;
  SHORT_NAME: ('a'..'z')+;
  LONG_NAME: '"' SHORT_NAME (SP SHORT_NAME)* '"';
  REF: 'ref:' (SHORT_NAME | LONG_NAME);

  item: SHORT_NAME | LONG_NAME  | REF;
  query: item (SP item)*;

如果你把它放在最上面:

  grammar Query;

  @members {
      public static void main(String[] args) throws Exception {
          QueryLexer lex = new QueryLexer(new ANTLRFileStream(args[0]));
           CommonTokenStream tokens = new CommonTokenStream(lex);

          QueryParser parser = new QueryParser(tokens);

          try {
              TokenSource ts = parser.getTokenStream().getTokenSource();
              Token tok = ts.nextToken();
              while (EOF != (tok.getType())) {
                 System.out.println("Got a token: " + tok);
                 tok = ts.nextToken();
              }
          } catch (Exception e) {
              e.printStackTrace();
           }
      }
  }

你应该看到词法分析器很好地区分了一切(我希望;-))

hi there "long name" ref:shortname ref:"long name"

应该给:

Got a token: [@-1,0:1='hi',<6>,1:0]
Got a token: [@-1,2:2=' ',<7>,1:2]
Got a token: [@-1,3:7='there',<6>,1:3]
Got a token: [@-1,8:8=' ',<7>,1:8]
Got a token: [@-1,9:19='"long name"',<4>,1:9]
Got a token: [@-1,20:20=' ',<7>,1:20]
Got a token: [@-1,21:33='ref:shortname',<5>,1:21]
Got a token: [@-1,34:34=' ',<7>,1:34]
Got a token: [@-1,35:49='ref:"long name"',<5>,1:35]

我不是100%确定你的语法有什么问题,但我怀疑这个问题与你没有引号的LONG_NAME的定义有关。也许你可以看出它的区别是什么?