JavaCC-lexer不';无法按预期工作(不忽略空白)

JavaCC-lexer不';无法按预期工作(不忽略空白),java,parsing,javacc,Java,Parsing,Javacc,我正在尝试为下面列出的示例文件实现一个解析器。我想将它们之间带有“+”的带引号的字符串识别为单个标记。所以我创建了一个jj文件,但它与这样的字符串不匹配。我的印象是JavaCC应该为每个令牌规范匹配尽可能长的匹配项,但对我来说似乎不是这样 我做错了什么?为什么我的标记与'+'不匹配,即使在那里指定了它?为什么空白不能被忽略 options { TOKEN_FACTORY = "Token"; } PARSER_BEGIN(Parser) package com.example.parse

我正在尝试为下面列出的示例文件实现一个解析器。我想将它们之间带有
“+”
的带引号的字符串识别为单个标记。所以我创建了一个jj文件,但它与这样的字符串不匹配。我的印象是JavaCC应该为每个令牌规范匹配尽可能长的匹配项,但对我来说似乎不是这样

我做错了什么?为什么我的
标记与
'+'
不匹配,即使在那里指定了它?为什么空白不能被忽略

options {
  TOKEN_FACTORY = "Token";
}

PARSER_BEGIN(Parser)

package com.example.parser;

public class Parser {

  public static void main(String args[]) throws ParseException {

      ParserTokenManager manager = new ParserTokenManager(new SimpleCharStream(Parser.class.getResourceAsStream("example")));
      Token token = manager.getNextToken();
      while (token != null && token.kind != ParserConstants.EOF) {
          System.out.println(token.toString() + "[" + token.kind + "]");
          token = manager.getNextToken();
      }

      Parser parser = new Parser(Parser.class.getResourceAsStream("example"));
      parser.start();
  }

}

PARSER_END(Parser)

// WHITE SPACE
<DEFAULT, IN_STRING_KEYWORD>
SKIP :
{
  " " // <-- skipping spaces
| "\t"
| "\n"
| "\r"
| "\f"
}

// TOKENS
TOKEN :
{
< KEYWORD1 : "keyword1" > : IN_STRING_KEYWORD
}

<IN_STRING_KEYWORD>
TOKEN : {<STRING : <CONCAT_STRING> | <UNQUOTED_STRING> > : DEFAULT 
| <#CONCAT_STRING : <QUOTED_STRING> ("+" <QUOTED_STRING>)+ >
// <-- CONCAT_STRING never matches   "+" part when input is "'smth' +", because whitespace is not ignored!?
| <#QUOTED_STRING : <SINGLEQUOTED_STRING> | <DOUBLEQUOTED_STRING> >
| <#SINGLEQUOTED_STRING : "'" (~["'"])* "'" >
| <#DOUBLEQUOTED_STRING : 
    "\""
      (
        (~["\"", "\\"]) |
        ("\\" ["n", "t", "\"", "\\"])
      )* 
    "\""
  >
| <#UNQUOTED_STRING : (~[" ","\t", ";", "{", "}", "/", "*", "'", "\"", "\n", "\r"] | "/" ~["/", "*"] | "*" ~["/"])+ >
}

void start() :
{}
{
  (<KEYWORD1><STRING>";")+ <EOF>
}
我想将第一个
关键字1
的参数作为单个
标记进行匹配

电流输出:

keyword1[6]
Exception in thread "main" com.example.parser.TokenMgrError: Lexical error at line 1, column 15.  Encountered: " " (32), after : "\"foo\""
    at com.example.parser.ParserTokenManager.getNextToken(ParserTokenManager.java:616)
    at com.example.parser.Parser.main(Parser.java:12)

我正在使用JavaCC 5.0。

STRING
正在扩展到可以匹配的最长序列,如错误所示,即
“foo”
。结束双引号后的空格不属于专用令牌定义的一部分。跳过标记不适用于其他标记的定义,因此必须在
+
的任一侧将空格直接合并到定义中

顺便说一句,我建议有这样一个最终的令牌定义:

<each-state-in-which-the-empty-string-cannot-be-recognized>
TOKEN : {
    < ILLEGAL : ~[] >
}

代币:{
<非法:~[]>
}

这可以防止抛出
TokenMgrError
s,并使调试更容易。

这似乎是一个重复的。我仍然希望得到一个答复。如果这是一个bug,或者是一个解决方法。你是说无论何时定义一个新的令牌,我都不应该期望通过SKIP自动处理其中的空白?如果我不能在我的作品中利用它,那么跳过的目的是什么。。。您能让我参考一下JavaCC文档中说明您的声明的部分吗?@predi:没错,跳过标记不适用于其他标记的定义。跳过标记的目的是定义在匹配BNF规则时应忽略的标记(在其他标记之间,但不在其他标记内)。但是,您可以将跳过令牌合并到其他令牌的定义中,就像您可以合并任何其他令牌一样。例如,为跳过标记指定一个名称,如
WS
。然后将
CONCAT\u字符串重新定义为
。。。()? (“+”(…)+
.Oops,那应该是
.(“+”()?…)+
。忘记了一些元字符。嗯..现在我想起来了。只有“顶级”标记周围的空格才会被跳过,这有点道理。毕竟,在我的情况下,当内部引用时,所有其他空格可能都很重要(我甚至发布了一个这样的示例).JavaCC FAQ 3.10意味着SKIP可能被应用,也可能不被应用。但是没有提到何时何地。我接受这个答案。Predi:最好不要用“顶级”标记来思考。所有标记都在同一级别。“私有正则表达式”(带#s的那些)的名称它们实际上只是宏。选择是否应用跳过的令牌定义的规则与常规令牌的规则相同,并在前面的FAQ中介绍。
<each-state-in-which-the-empty-string-cannot-be-recognized>
TOKEN : {
    < ILLEGAL : ~[] >
}