Parsing jison语法定义导致错误的标记识别

Parsing jison语法定义导致错误的标记识别,parsing,yacc,flex-lexer,jison,Parsing,Yacc,Flex Lexer,Jison,我最近找到了jison项目,并从其网站上修改了计算器示例 不幸的是,我不知道为什么找不到正确的TOKEN1。删除了无效的令牌后,我得到了解析错误 Unrecognized text. 我在上找到了关联错误的描述,导致类似的错误消息,但在代码中找不到类似的内容 这个问题的解决方案是什么?好问题 jison的lexer生成器有两种模式:默认模式和稍微兼容flex的模式。您可以通过在%lex行之后放置%options flex来选择后者 在默认模式下: 第一个匹配模式获胜,即使后面的模式将匹配更长的

我最近找到了jison项目,并从其网站上修改了计算器示例

不幸的是,我不知道为什么找不到正确的TOKEN1。删除了无效的令牌后,我得到了解析错误

Unrecognized text.
我在上找到了关联错误的描述,导致类似的错误消息,但在代码中找不到类似的内容

这个问题的解决方案是什么?

好问题

jison的lexer生成器有两种模式:默认模式和稍微兼容flex的模式。您可以通过在%lex行之后放置%options flex来选择后者

在默认模式下:

第一个匹配模式获胜,即使后面的模式将匹配更长的令牌;及

以字母或数字结尾的模式添加了隐式\b,这将限制匹配在单词边界上结束

在flex模式中,模式不会改变,并且应用正常的flex第一最长规则。但是,生成的lexer将较慢,请参见下文

因此,在lexer定义中,a将不匹配输入字符串中的第一个a,因为生成的lexer实际上是在尝试匹配a\b,即,a后跟单词边界

您可以通过简单地用括号围绕模式来解决此问题:

("a")    { return 'TOKEN1'; }
或者使用字符类而不是引号:

[a]      { return 'TOKEN1'; }
或者将%options flex添加到您的%lex部分

作为解释 与flex不同,jison不构建单个DFA lexer。相反,它将每个lex模式转换为锚定的javascript正则表达式,并在每次请求令牌时尝试所有模式,直到找到正确的匹配

为了实现flex first longest match规则,jison生成的lexer需要为每个标记尝试每个正则表达式,因为只有尝试所有正则表达式,它才能知道哪个是最长的匹配。第一个匹配规则可以快一点,特别是如果公共令牌模式放在文件开头附近

不幸的是,在通常情况下,第一个匹配规则要难处理得多,因为令牌可能是关键字或标识符,而恰好以关键字开头的标识符需要作为标识符进行匹配。对于第一个最长匹配,将关键字放在第一位就足够了,因为带有关键字前缀的标识符会更长。但对于第一个匹配,有必要将关键字或标识符或两者都限制在单词边界上

因此,上面描述的两个规则的组合意味着在标识符模式之前列出关键字的正常模式仍然有效。单词边界测试可以防止关键字模式出现虚假的前缀匹配

但是如果你有很多关键词,那仍然是很多模式,即使它们中的大多数很快就会失败。因此,与其使用flex约定,不如:

"do"                         { return DO; }
"end"                        { return END; }
/* ... */
[[:alpha:]][[:alnum:]_]*     { return "ID"; }
让关键字与其他固定标记(如运算符)一起表示它们自己要好得多,因为这样可以将所有关键字和多字符运算符模式组合到一个正则表达式中:

/* Keywords and multicharacter operators in a single enormous pattern */
/* For jison mode, I added a manual \b because it won't be added 
 * automatically. In flex mode, that won't hurt, but it could be
 * removed.
 */
("do"|"else"|"end"|"if"|"then"|"while")\b|[<>!=]"=" { return yytext; }
[[:alpha:]][[:alnum:]_]*                        { return "ID"; }
[[:digit:]]+("."[[:digit:]]*)?                  { return "NUMBER"; }
[[:space:]]+                                    ;
/* All single character tokens use a fallback rule */
.                                               { return yytext; }

这是一个JiSe-特定的成语,很多人认为Flex/BySin的风格很差。它允许生成的语法返回实际值,这是解析的结果

不要只是将规则添加到词汇规则中。如果您提供自己的EOF令牌,那么您负责在解析器中识别它。如果解析器没有与EOF令牌匹配的规则,则解析将失败

"do"                         { return DO; }
"end"                        { return END; }
/* ... */
[[:alpha:]][[:alnum:]_]*     { return "ID"; }
/* Keywords and multicharacter operators in a single enormous pattern */
/* For jison mode, I added a manual \b because it won't be added 
 * automatically. In flex mode, that won't hurt, but it could be
 * removed.
 */
("do"|"else"|"end"|"if"|"then"|"while")\b|[<>!=]"=" { return yytext; }
[[:alpha:]][[:alnum:]_]*                        { return "ID"; }
[[:digit:]]+("."[[:digit:]]*)?                  { return "NUMBER"; }
[[:space:]]+                                    ;
/* All single character tokens use a fallback rule */
.                                               { return yytext; }
%lex
%%
// ...
<<EOF>> { return "EOF"; }
/lex

%start input
%%
input: start EOF { return $1; }

start: /* The real start token */