Yacc 是否过早地停止了词法分析器?

Yacc is prematurely stopping lexer?

我有一个包含这些规则的 yacc 文件:

%start program
.
.
.
statement
    : ';' { $$ = NULL; }
    | expression ';' { $$ = exprStmt(); }
    | compound ';' { $$ = cmpndStmt(); }
    ;

routine
    : routine statement { $$ = rtn(, ); }
    | { $$ = NULL; }
    ;

block
    : '{' routine '}' { $$ = ; }
    ;

compound
    : block { $$ = cmpnd(); }
    | if_cmpnd { $$ = ; }
    ;

if_cmpnd
    : IF expression compound { $$ = ifcmpnd(, ); }
    | if_cmpnd ELSE compound { $$ = elsecmpnd(, ); }
    ;

program
    : routine { printf("YACC finish\n"); exit(0); }
    ;

对于这个解析器,我给出了一个示例文本文件,其中包含:

var a := 6
var b := 5
if a<5 {
b = 2
}
else {
b = 20
}

但是在解析过程中,通过调试,我得到了这个输出

.
.
.
--accepting rule at line 47 ("if")
--accepting rule at line 62 (" ")
--accepting rule at line 47 ("a")
--accepting rule at line 56 ("<")
--accepting rule at line 29 ("5")
--accepting rule at line 62 (" ")
--accepting rule at line 57 ("{")
--accepting rule at line 60 ("
")
--accepting rule at line 47 ("b")
--accepting rule at line 56 (" = ")
--accepting rule at line 29 ("2")
--accepting rule at line 60 ("
")
--accepting rule at line 57 ("}")
--accepting rule at line 60 ("
")
--accepting rule at line 47 ("else")
YACC finish

可以看出else后面的块没有词法化。但是相反,如果我将“else”替换为“if a>8”之类的其他内容,文本将被词法化直到 EOF。我不明白它的原因。请有人帮助我。

您抱怨 YACC 过早终止。这很容易解释;您的解析器包括:(添加了重点)

program
    : routine { printf("YACC finish\n"); <b>exit(0);</b> }

exit(0) 的全部目的是提前终止。所以它正在做你要求它做的工作。但是,很难想象从解析器操作调用 exit() 是正确的用例,并且您得到的结果说明了原因。

特别重要的是要注意 bison/yacc 解析器(尤其是 bison 解析器)可能会在发出错误信号之前执行归约,即使在错误标记没有出现在被归约的产品的后续列表中的情况下.这里可能就是这种情况;如果你没有调用 exit(),你会得到一个语法错误指示,这至少不会那么神秘(并且可以用你的语法中的 error-处理产生式来处理)。

yyparse 将 return (return 值为 0)如果它设法解析整个输入;如果遇到语法错误,它将 return 1,如果检测到内存过度使用,则为 2。 (这些常量有预处理器符号,但通常足以测试 yyparse() 的 return 值是否为零。)您应该始终允许解析器正常地 return,让它有机会在 returning 之前清理分配的资源。

您没有显示您的扫描器,您提供的唯一痕迹是扫描器的痕迹,而不是解析器的痕迹。因此,当扫描器遇到 else 标记时,不可能知道解析器接收到的标记类型。启用 parser traces 而不是(或以及)扫描器跟踪将提供对调试解析器更有用的信息(包括传递给解析器的每个标记的标记类型)。

然而,令我震惊的是 ifelse 都由与您的标识符相同的扫描器操作处理(在您的扫描器描述的第 47 行)。这意味着您的扫描仪没有针对每个关键字的特定规则。据推测,您正在做一些低效且容易出错的事情,例如将标识符标记与每个可能的关键字进行比较,以便 return 解析器获得正确的标记类型。但由于缺乏信息,除了猜测之外很难做更多的事情。