Flex/Bison mini C编译器词法和语义分析转移/减少冲突

Flex/Bison mini C编译器词法和语义分析转移/减少冲突,bison,flex-lexer,Bison,Flex Lexer,我想使用flex和bison为mini C语言编写一个编译器。我的语言示例如下所示: /* This is an example uC program. */ int fac(int n) { if (n < 2) return n; return n * fac(n - 1); } int sum(int n, int a[]) { int i; int s; i = 0; s = 0; while (i <

我想使用flex和bison为mini C语言编写一个编译器。我的语言示例如下所示:

/* This is an example uC program. */
int fac(int n)
{
    if (n < 2)
        return n;
    return n * fac(n - 1);
}

int sum(int n, int a[])
{
    int i;
    int s;

    i = 0;
    s = 0;
    while (i < n) {
        s = s + a[i];
        i = i + 1;
    }
    return s;
}

int main(void)
{
    int a[2];

    a[0] = fac(5);
    a[1] = 27;
    return 0;
}
我得到一个错误,语法错误发生在它区分第二个
i
(我在flex文件中打印标记,这样我知道它在到达赋值字符之前没有问题)

或者作为另一个例子,当通过这条线时:

int fac(int n);
在第一个偏执之后,我得到了相同的语法错误(第1行:语法错误),这意味着它将第二个
int
视为语法错误,这是不应该的,因为我的语法看起来很好

此外,bison发出的警告如下(flex和gcc可以):

任何建议或更正都将不胜感激:)提前感谢

int i;
i = 0;
不是有效的C程序,您的语法正确地拒绝了它。(如语法所示,程序是一系列声明,
i=10;
不是声明。)


您提到的第二个问题与移位-减少冲突有关,这是由于您的语法坚持认为
int fac(int n)
中的第一个
int
必须减少为
funtype
,而
int i中的
int
是一个
类型名
。在解析器需要决定是将
IDENT
移动还是将
typename
减少为
funtype
时,它无法知道要采取哪一个操作,因为它只能看到一个先行标记--
IDENT
,而该决定取决于下一个先行标记(可能是也可能不是开括号)。默认情况下,yacc/bison通过移位来解决移位减少冲突,这意味着
int fac
不能作为
topdec
第二个产品的前缀;因此,
将触发错误。

您在生成解析器时没有提到yacc/bison生成的警告。谢谢您@rici我刚刚添加。哦,我理解,我的第一个程序确实不正确。因此,这意味着我必须在topdec语句中集成最后的标记(而不是一个funtype,而是int | char | void)?如果你想让你的语法正常工作,你必须修正移位以减少冲突。请注意,bison实际上告诉你“funtype:typename”规则是无用的,这基本上就是我在回答中所说的。@mazhar:简单的解决办法是在语法中添加
void
,这样你的语法就不会需要区分变量类型和函数返回类型。您可以在相关的缩减操作中检查
void x;
。我对shift/reduce问题理解得不够透彻。但是您的描述很清楚,谢谢。
int i;
i = 0;
int fac(int n);
semantic_analyzer.y: warning: 26 shift/reduce conflicts [-Wconflicts-sr]
semantic_analyzer.y:78.10-17: warning: rule useless in parser due to conflicts [-Wother]
 funtype: typename
          ^^^^^^^^
int i;
i = 0;