处理JavaCC中的令牌歧义

时间:2009-06-06 05:24:58

标签: parsing javacc

我正在尝试在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生成我对此案例所期望的令牌流?

3 个答案:

答案 0 :(得分:2)

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

输入:

var y = a/b/c

会发生以下情况:

    消耗
  1. <VAR>,词汇状态设置为DEFAULT
  2. 消耗
  3. <IDENTIFIER>,词汇状态设置为IGNORE_REGEX
  4. 消耗
  5. <EQUALS>,词汇状态设置为DEFAULT
  6. 消耗
  7. <IDENTIFIER>,词汇状态设置为IGNORE_REGEX

    此时,语法中存在歧义,将消耗<DIV><REGEX_LITERAL>。由于词汇状态为IGNORE_REGEX且状态与<REGEX_LITERAL>不匹配,因此将使用<DIV>

  8. 消耗
  9. <DIV>,词汇状态设置为DEFAULT

  10. 消耗
  11. <IDENTIFIER>,词汇状态设置为IGNORE_REGEX
  12. 消耗
  13. <DIV>,词汇状态设置为DEFAULT
  14. 消耗
  15. <IDENTIFIER>,词汇状态设置为IGNORE_REGEX

答案 1 :(得分:0)

据我记得(我曾经和JavaCC一起工作过)

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

答案 2 :(得分:0)

由于JavaScript / EcmaScript执行相同的操作(即,它包含正则表达式文字和除了示例中的除法运算符之外),您可能希望查找现有的JavaCC语法以供学习。我找到一个与this blog entry链接的,可能还有其他人。