我正在尝试在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生成我对此案例所期望的令牌流?
答案 0 :(得分:2)
JavaCC将始终使用可用的最大令牌,否则无法配置它。实现此目的的唯一方法是添加一个词法状态,如果说是IGNORE_REGEX
,则排除令牌,在本例中为<REGEX_LITERAL>
。然后,当识别出<REGEX_LITERAL>
后不能跟随的标记时,必须将词法状态切换为IGNORE_REGEX
。
输入:
var y = a/b/c
会发生以下情况:
<VAR>
,词汇状态设置为DEFAULT
<IDENTIFIER>
,词汇状态设置为IGNORE_REGEX
<EQUALS>
,词汇状态设置为DEFAULT
<IDENTIFIER>
,词汇状态设置为IGNORE_REGEX
此时,语法中存在歧义,将消耗<DIV>
或<REGEX_LITERAL>
。由于词汇状态为IGNORE_REGEX
且状态与<REGEX_LITERAL>
不匹配,因此将使用<DIV>
。
<DIV>
,词汇状态设置为DEFAULT
<IDENTIFIER>
,词汇状态设置为IGNORE_REGEX
<DIV>
,词汇状态设置为DEFAULT
<IDENTIFIER>
,词汇状态设置为IGNORE_REGEX
答案 1 :(得分:0)
据我记得(我曾经和JavaCC一起工作过)
您编写每个规则的顺序是它将被解析的顺序,因此请按照始终生成所需表达式的顺序编写规则。
答案 2 :(得分:0)
由于JavaScript / EcmaScript执行相同的操作(即,它包含正则表达式文字和除了示例中的除法运算符之外),您可能希望查找现有的JavaCC语法以供学习。我找到一个与this blog entry链接的,可能还有其他人。