JavaCC:如何指定在特定上下文中需要哪些令牌?

JavaCC:如何指定在特定上下文中需要哪些令牌?,java,parsing,token,javacc,Java,Parsing,Token,Javacc,我需要让JavaCC知道一个上下文(当前父令牌),并且根据该上下文,期望出现不同的令牌 考虑以下伪代码: TOKEN <abc> { "abc*" } // recognizes "abc", "abcd", "abcde", ... TOKEN <abcd> { "abcd*" } // recognizes "abcd", "abcde", "abcdef", ... TOKEN <element1> { "element1" "[" expectOnl

我需要让JavaCC知道一个上下文(当前父令牌),并且根据该上下文,期望出现不同的令牌

考虑以下伪代码:

TOKEN <abc> { "abc*" } // recognizes "abc", "abcd", "abcde", ...
TOKEN <abcd> { "abcd*" } // recognizes "abcd", "abcde", "abcdef", ...

TOKEN <element1> { "element1" "[" expectOnly(<abc>) "]" }
TOKEN <element2> { "element2" "[" expectOnly(<abcd>) "]" }
...
如果我没有错的话,它的行为将类似于XML文件的更复杂的DTD定义

那么,如何指定在哪个“上下文”中哪些令牌是有效的/预期的呢


注意:对于我的实际案例来说,定义一种令牌的“层次结构”是不够的,因此“abcdef”总是首先与
匹配,然后再与
匹配。我真的需要上下文感知令牌。

好的,这里似乎需要一种称为lookahead的技术。以下是一个非常好的教程:

当时我的第一次尝试是错误的,但由于它适用于定义上下文的不同标记,我将把它留在这里(可能对某人有用;o))


假设我们想要某种标记语言。我们希望“标记”的内容包括:

  • 由字母(abc…zABC…Z)和空格-->单词组成的表达式
  • 由数字(0-9)组成的表达式-->数字
我们想把单词放在标签里,把数字放在标签里。如果我没弄错,这就是你想要做的:如果你在单词上下文中(在单词标记之间),编译器应该期望字母和空格,在数字上下文中它期望数字

我创建了WordNumber.jj文件,该文件定义了要生成的语法和解析器:

options
{
    LOOKAHEAD= 1;

    CHOICE_AMBIGUITY_CHECK = 2;
    OTHER_AMBIGUITY_CHECK = 1;
    STATIC = true;
    DEBUG_PARSER = false;
    DEBUG_LOOKAHEAD = false;
    DEBUG_TOKEN_MANAGER = false;
    ERROR_REPORTING = true;
    JAVA_UNICODE_ESCAPE = false;
    UNICODE_INPUT = false;
    IGNORE_CASE = false;
    USER_TOKEN_MANAGER = false;
    USER_CHAR_STREAM = false;
    BUILD_PARSER = true;
    BUILD_TOKEN_MANAGER = true;
    SANITY_CHECK = true;
    FORCE_LA_CHECK = false;
}

PARSER_BEGIN(WordNumberParser)

/** Model-tree Parser */
public class WordNumberParser
{
    /** Main entry point. */
    public static void main(String args []) throws ParseException
    {
        WordNumberParser parser = new WordNumberParser(System.in);
        parser.Input();
    }
}

PARSER_END(WordNumberParser)

SKIP :
{
    " "
|   "\n"
|   "\r"
|   "\r\n"
|   "\t"
}

TOKEN :
{
    < WORD_TOKEN : (["a"-"z"] | ["A"-"Z"] | " " | "." | ",")+ > |
    < NUMBER_TOKEN : (["0"-"9"])+ >
}


/** Root production. */
void Input() :
{}
{
    ( WordContext() | NumberContext() )* < EOF >
}

/** WordContext production. */
void WordContext() :
{}
{
    "<WORDS>" (< WORD_TOKEN >)+ "</WORDS>"
}

/** NumberContext production. */
void NumberContext() :
{}
{
    "<NUMBER>" (< NUMBER_TOKEN >)+ "</NUMBER>"
}
选项
{
前瞻=1;
选择_歧义_检查=2;
其他检查=1;
静态=真;
DEBUG_PARSER=false;
DEBUG_LOOKAHEAD=false;
调试令牌管理器=false;
错误报告=真;
JAVA_UNICODE_ESCAPE=false;
UNICODE_输入=false;
忽略案例=错误;
用户\令牌\管理器=false;
USER\u CHAR\u STREAM=false;
BUILD_PARSER=true;
BUILD\u TOKEN\u MANAGER=true;
健全性检查=正确;
强制检查=错误;
}
解析器_BEGIN(WordNumberParser)
/**模型树解析器*/
公共类WordNumberParser
{
/**主要入口点*/
公共静态void main(字符串args[])引发异常
{
WordNumberParser解析器=新的WordNumberParser(System.in);
parser.Input();
}
}
解析器_END(WordNumberParser)
跳过:
{
" "
|“\n”
|“\r”
|“\r\n”
|“\t”
}
代币:
{
|

}
/**根系生产*/
无效输入():
{}
{
(WordContext()| NumberContext())*
}
/**WordContext生成*/
void WordContext():
{}
{
“”()+“”
}
/**数字上下文生成*/
void NumberContext():
{}
{
“”()+“”
}
您可以使用以下文件对其进行测试:

<WORDS>This is a sentence. As you can see the parser accepts it.</WORDS>
<WORDS>The answer to life, universe and everything is</WORDS><NUMBER>42</NUMBER>
<NUMBER>This sentence will make the parser sad. Do not make the parser sad.</NUMBER>
这是一个句子。如您所见,解析器接受它。
生命、宇宙和一切的答案是42
这句话会让解析器伤心。不要让解析器伤心。
最后一行将导致解析器引发如下异常:

线程“main”ParseException中的异常:遇到“”这句话会让解析器感到悲伤。不要让解析器伤心。“”在第3行第9列。
他期望:
…

这是因为解析器没有找到它所期望的

我希望这有帮助

干杯


注意:解析器不能“在”令牌中,因为令牌是一个终端符号(如果我错了,请纠正我),它不能再被产生式规则替换。因此,所有上下文方面都必须放在产生式规则(非终端)中,如我的示例中的“WordContext”。

您需要使用lexer状态。您的示例类似于:

标记:{:IN_ELEMENT1}
标记:{:IN_ELEMENT2}
令牌:{:DEFAULT}
令牌:{:DEFAULT}


请注意,
(…)*
不是正确的JavaCC语法,但您的示例也不是,因此我只能猜测。

非常感谢您提供的示例,但这不是我的问题所在。当使用的代币是可识别的时,就像您的情况一样(一个包含在
..
中,另一个包含在
..
中)。与此相反,在我的例子中,我有两个令牌都将匹配某些输入。@java.is.for.desktop:啊,好的,对不起。我想你可以用“向前看”。查看我编辑的文章中的链接;o) 我发现,
JavaCC
允许指定词汇上下文。可悲的是,这使得一切变得非常复杂,因为您有许多令牌,其中大多数都需要自己的状态。我已经开发了一个确定性状态机解析器,目前正在增强它以接受非确定性状态机。我必须承认,我的情况很特殊。
<WORDS>This is a sentence. As you can see the parser accepts it.</WORDS>
<WORDS>The answer to life, universe and everything is</WORDS><NUMBER>42</NUMBER>
<NUMBER>This sentence will make the parser sad. Do not make the parser sad.</NUMBER>