向Antlr3语法添加带引号的字符串支持

向Antlr3语法添加带引号的字符串支持,antlr,antlr3,Antlr,Antlr3,我正在尝试实现一种语法来解析查询。单个查询包含项,其中每个项可以是名称或名称引用 name要么是mystring(只有字母,没有空格),要么是“我的长字符串”(字母和空格,总是被引用)name-ref与name非常相似,唯一的区别是它应该以ref:开头(ref:mystring,ref:“我的长字符串”)。查询应至少包含1项(name或name ref) 以下是我所拥有的: NAME: ('a'..'z')+; REF_TAG: 'ref:'; SP: ' '+; name: NAME; na

我正在尝试实现一种语法来解析查询。单个查询包含
,其中每个项可以是
名称
名称引用

name
要么是
mystring
(只有字母,没有空格),要么是
“我的长字符串”
(字母和空格,总是被引用)
name-ref
name
非常相似,唯一的区别是它应该以
ref:
开头(
ref:mystring
ref:“我的长字符串”
)。查询应至少包含1项(
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)*;
这个语法演示了我基本上需要得到的东西,唯一的特点是它不支持长引号字符串(它适用于没有空格的名称)


但这不起作用。你知道有什么问题吗?可能这很重要:
我的第一个查询
应该被视为3个
s(3个
名称
s),
我的第一个查询是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();
           }
      }
  }
你应该看到lexer能很好地将所有东西分开(我希望;-))

应提供:

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]
得到一个令牌:[@-1,0:1='hi',1:0]
获得一个令牌:[@-1,2:2='',1:2]
得到一个令牌:[@-1,3:7='there',1:3]
获得一个令牌:[@-1,8:8='',1:8]
获得了一个令牌:[@-1,9:19='“long name”',1:9]
获得一个令牌:[@-1,20:20='',1:20]
获得一个令牌:[@-1,21:33='ref:shortname',1:21]
获得一个令牌:[@-1,34:34='',1:34]
得到一个令牌:[@-1,35:49='ref:“长名称”',1:35]

我不能百分之百确定你的语法有什么问题,但我怀疑这个问题与你对没有引号的
长名称的定义有关。也许您可以看到区别是什么?

这里有一个适合您需求的语法:

  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();
           }
      }
  }
你应该看到lexer能很好地将所有东西分开(我希望;-))

应提供:

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]
得到一个令牌:[@-1,0:1='hi',1:0]
获得一个令牌:[@-1,2:2='',1:2]
得到一个令牌:[@-1,3:7='there',1:3]
获得一个令牌:[@-1,8:8='',1:8]
获得了一个令牌:[@-1,9:19='“long name”',1:9]
获得一个令牌:[@-1,20:20='',1:20]
获得一个令牌:[@-1,21:33='ref:shortname',1:21]
获得一个令牌:[@-1,34:34='',1:34]
得到一个令牌:[@-1,35:49='ref:“长名称”',1:35]

我不能百分之百确定你的语法有什么问题,但我怀疑这个问题与你对没有引号的
长名称的定义有关。也许你可以看到区别是什么?

ANTLR的词法匹配得很好:这就是为什么像
my first query
这样的输入被标记为
LONG\u NAME
,而不是3个
SHORT\u NAME
之间有空格的原因

只需删除
LONG\u NAME
规则,并在解析器规则
LONG\u 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
详情如下:

但是,您也可以在lexer中标记一个带引号的名称,并使用一点自定义代码从中去掉引号。从lexer中删除空格也是一种选择。大概是这样的:

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;
它将解析相同的输入,如下所示:


请注意,实际的标记
LONG\u NAME
将从其起始和结束引号中删除。

ANTLR的词法匹配得非常好:这就是为什么像
my first query
这样的输入被标记为
LONG\u NAME
而不是3个
SHORT\u NAME
之间有空格的原因

只需删除
LONG\u NAME
规则,并在解析器规则
LONG\u 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
详情如下:

但是,您也可以在lexer中标记一个带引号的名称,并使用一点自定义代码从中去掉引号。从lexer中删除空格也是一种选择。大概是这样的:

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;
它将解析相同的输入,如下所示:


请注意,实际的令牌
LONG\u NAME
将从其起始和结束引号中删除。

谢谢您的回答,但它不会删除引号和
ref:
标记等辅助字符。谢谢您的回答,但它不会删除引号和
ref:
标记等辅助字符。有什么方法可以删除
long\u name
节点下?我需要语法,但在处理解析结果时不需要它们。非常感谢非内联Java解决方案。@loki2302,你是说从第一个树映像开始?等等,我看你接受了我的答案。这意味着你不再有问题了?在看到你更新答案之前,我已经回答了。嗯,是的。基本上,我这里的问题是——有没有一种方法可以在没有Java字符串过程的情况下实现第二种方法?有没有任何方法可以摆脱
long\u name
节点下?我需要语法,但在处理解析结果时不需要它们。非常感谢非内联Java解决方案。@loki2302,你是说从第一个树映像开始?等等,我看你接受了我的答案。这意味着你不再有问题了?在看到你更新答案之前,我已经回答了。嗯,是的。基本上,我这里的问题是——有没有一种方法可以在没有Java字符串过程的情况下实现第二种方法?