【问题标题】:Handling Token Ambiguity in JavaCC在 JavaCC 中处理令牌歧义
【发布时间】:2009-06-06 05:24:57
【问题描述】:

我正在尝试在 JavaCC 中编写一个解析器,该解析器可以识别在令牌级别有一些歧义的语言。在这种特殊情况下,该语言本身支持“/”标记作为除法运算符,同时它还支持正则表达式文字。

考虑以下 JavaCC 语法:

TOKEN : 
{
    ...
    < VAR : "var" > |
    < DIV : "/" > |
    < EQUALS : "=" > |
    < SEMICOLON : ";" > |
    ...
}

TOKEN :
{
    < IDENTIFIER : <IDENTIFIER_START> (<IDENTIFIER_START> | <IDENTIFIER_CHAR>)* > |
    < #IDENTIFIER_START : ( [ "$","_","A"-"Z","a"-"z" ] )> |
    < #IDENTIFIER_CHAR : ( [ "$","_","A"-"Z","a"-"z","0"-"9" ] ) >  |

    < REGEX_LITERAL : ("/" <REGEX_BODY> "/" ( <REGEX_FLAGS> )? ) > |
    < #REGEX_BODY : ( <REGEX_FIRST_CHAR> <REGEX_CHARS> ) > |
    < #REGEX_CHARS : ( <REGEX_CHAR> )* > |
    < #REGEX_FIRST_CHAR : ( ~["\r", "\n", "*", "/", "\\"] | <BACKSLASH_SEQUENCE> ) > |
    < #REGEX_CHAR : ( ~[ "\r", "\n", "/", "\\" ] | <BACKSLASH_SEQUENCE> ) > |
    < #BACKSLASH_SEQUENCE : ("\\" ~[ "\r", "\n"] ) > |
    < #REGEX_FLAGS : ( <IDENTIFIER_CHAR> )* >

}

给定以下代码:

var y = a/b/c;

可以生成两组不同的令牌。令牌流应该是:

<VAR> <IDENTIFIER> <EQUALS> <IDENTIFIER> <DIV> <IDENTIFIER> <DIV> <SEMICOLON>

<VAR> <IDENTIFIER> <EQUALS> <IDENTIFIER> <REGEX_LITERAL> <SEMICOLON>

我如何确保 TokenManager 生成我期望在这种情况下的令牌流?

【问题讨论】:

    标签: parsing javacc


    【解决方案1】:

    JavaCC 将始终使用最大的可用令牌,否则无法配置它。实现这一点的唯一方法是添加一个词法状态,例如IGNORE_REGEX,它不包括标记,在这种情况下为&lt;REGEX_LITERAL&gt;。然后,当识别出不能跟在&lt;REGEX_LITERAL&gt; 之后的标记时,词法状态必须切换到IGNORE_REGEX

    输入:

    var y = a/b/c
    

    会发生以下情况:

    1. &lt;VAR&gt; 被消费,词法状态设置为 DEFAULT
    2. &lt;IDENTIFIER&gt; 被消费,词法状态设置为 IGNORE_REGEX
    3. &lt;EQUALS&gt; 被消费,词法状态设置为 DEFAULT
    4. &lt;IDENTIFIER&gt; 被消费,词法状态设置为IGNORE_REGEX

      此时,语法存在歧义,&lt;DIV&gt;&lt;REGEX_LITERAL&gt; 将被消耗。由于词法状态是 IGNORE_REGEX 并且该状态与 &lt;REGEX_LITERAL&gt; 不匹配,因此将使用 &lt;DIV&gt;

    5. &lt;DIV&gt; 被消费,词法状态设置为DEFAULT

    6. &lt;IDENTIFIER&gt; 被消费,词法状态设置为 IGNORE_REGEX
    7. &lt;DIV&gt; 被消费,词法状态设置为 DEFAULT
    8. &lt;IDENTIFIER&gt; 被消费,词法状态设置为 IGNORE_REGEX

    【讨论】:

      【解决方案2】:

      据我所知(我曾与 JavaCC 合作过)

      您编写每个规则的顺序就是它被解析的顺序,因此请按照始终生成您想要的表达式的顺序编写您的规则。

      【讨论】:

        【解决方案3】:

        由于 JavaScript/EcmaScript 做同样的事情(也就是说,它包含正则表达式文字和一个除法运算符,看起来就像您的示例中的那些),您可能想要寻找现有的 JavaCC 语法来学习。我从this blog entry找到了一个链接,可能还有其他的。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-02-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-04-05
          • 1970-01-01
          相关资源
          最近更新 更多