0

我正在尝试在 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 生成我期望在这种情况下的令牌流?

4

3 回答 3

2

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

输入:

var y = a/b/c

会发生以下情况:

  1. <VAR>被消费,词法状态设置为DEFAULT
  2. <IDENTIFIER>被消费,词法状态设置为IGNORE_REGEX
  3. <EQUALS>被消费,词法状态设置为DEFAULT
  4. <IDENTIFIER>被消费,词法状态设置为IGNORE_REGEX

    此时,语法出现歧义,要么 a<DIV>要么 a<REGEX_LITERAL>将被消耗。由于词法状态 isIGNORE_REGEX并且该状态不匹配<REGEX_LITERAL>a<DIV>将被消耗。

  5. <DIV>被消费,词法状态设置为DEFAULT

  6. <IDENTIFIER>被消费,词法状态设置为IGNORE_REGEX
  7. <DIV>被消费,词法状态设置为DEFAULT
  8. <IDENTIFIER>被消费,词法状态设置为IGNORE_REGEX
于 2009-06-07T05:44:19.150 回答
0

据我记得(我曾经与 JavaCC 合作过)

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

于 2009-06-06T06:21:16.457 回答
0

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

于 2009-06-06T06:51:45.600 回答