Compiler construction 使用flex和bison的编译器的IF-ELSE语句

Compiler construction 使用flex和bison的编译器的IF-ELSE语句,compiler-construction,bison,flex-lexer,yacc,Compiler Construction,Bison,Flex Lexer,Yacc,我不知道为什么我的方法失败了: if_stmt: CONTROL_IF '(' expr ')' '{' lines '}' { if(($3.int_value != 0)||($3.float_value != 0)){ yyerror("hello"); } } 测试代码: line14 if(b == 1){ line15 print(b); line16 } 错误输出: Sy

我不知道为什么我的方法失败了:

if_stmt: 
    CONTROL_IF '(' expr ')' '{' lines '}'
    {
        if(($3.int_value != 0)||($3.float_value != 0)){
            yyerror("hello");
        }
    }
测试代码:

line14 if(b == 1){
line15    print(b);
line16 }
错误输出:

Syntax error at line 15
yacc文件成功编译,但在使用if-else代码对其进行测试后,它总是说有语法错误。我在yacc if语句中输入yyerror的另一个原因是我没有执行应该是$6的行,但是yacc说它没有声明的类型。所以我想知道如何执行YY错误,如果可以解决,如果表达式为真(!=0),如何执行这些行。

注意:如果不看语法,您的直接问题--“我的语法为什么会产生语法错误”--就无法回答。所以这个答案集中在另一个问题上,你确实需要理解:“为什么我不能在我的动作中使用
行的语义值作为
if
语句呢

与生产相关的操作在识别生产的右侧时执行。为了识别右侧,必须已识别所有包含的非终端,因此在运行生产操作之前已执行其操作

因此,你不能在一部作品中决定是否执行其子作品的动作。这需要时间旅行

非终端可能具有关联的语义值,并且该值至少在最初由识别的产品的操作计算。操作函数通过将其分配给
$$
来注册该值。如果操作未分配给
$$
,则非终端没有值。如果没有操作,e> 使用{$$=$1;}

Bison/yacc生成C程序,这些程序必须符合C规则。在C中,每个值都有一个类型,编译器必须知道该类型。与Python等语言不同,您不能声明一个变量,该变量的类型稍后决定。
int i;
意味着
i
int
。当程序运行时,它不能更改
i
>作为一个
双重
。作为
int
它诞生了,作为
int
它将死去

Bison/yacc非终端——有时称为“语法变量”——没有区别(或者只是略有不同)。包含值的非终端必须具有编译器(和解析器生成器)已知的类型。以后无法确定变量的类型,并且它不能在解析器的两次不同执行之间变化

Bison/yacc实际上使用一个C并集类型来实现这一点,它有效地允许多个不同的变量使用相同的内存(但不能同时使用)。联合不会真正避免在编译时必须知道值的类型,因为您只能使用特定的联合成员引用联合的值。该联合成员有一个类型,就像任何其他变量一样。因此,当您使用联合时,您实际上有两个任务:必须为每个成员指定一个固定类型,并且需要记住哪一个类型不是工会成员目前正在使用。由于编译器不知道,它不会帮助你,也不会修复你的错误。与编写C程序的许多方面一样,你只能靠自己。如果你不犯错误,程序就会工作。如果你真的犯了错误,几乎任何事情都可能发生

Bison/yacc可以帮助解决使用联合的一些不便。它首先使用联合是出于内部目的:各种活动非终端的语义值存储在堆栈中,堆栈是给定类型的C值数组。通过使用联合类型,Bison/yacc可以使用不同unio的不同成员n个值,只要它知道每个堆栈插槽的哪个成员正在使用。而且,它确实知道这一点,因为它知道每个堆栈插槽对应的非终端。所有这些都意味着您可以将bison/yacc的语法变量视为普通C变量,每个变量都有一个已知的类型

Bison/yacc还允许你拥有没有任何价值的非终端“这不是一个合法的价值观。联合会将有一些价值,从上次使用特定内存时遗留下来的。但只要您从未尝试引用非终结符的值,它未初始化的事实就无关紧要。初始化变量失败不是错误。尝试使用未初始化变量的值是错误的

因此,如果您试图使用非终端的值,而该非终端没有声明的类型(即,它没有出现在任何
%type
声明中),那么Bison会抱怨您试图使用未声明类型的非终端,这实际上是说您从未为该非终端分配过值。此外,如果您尝试将值分配给没有声明类型的变量(通过在该非终端的生产操作中分配给
$
),那么bison会抱怨您没有为该非终端声明类型。它必须这样做,因为它必须将
$
的赋值编译为工会某个成员的赋值,而您还没有告诉它使用哪个成员

这就是bison/yacc在抱怨
$6
没有声明类型时所指的问题
$6
非终端的实例,并且您尚未为
声明
%类型
。仅仅声明一个类型是不够的:如果要在某些产品中使用
的值,必须在创建时设置
的值,因此,所有可用于创建
行的产品必须具有
$
的赋值,或者必须使用默认的
$=$1操作(然后
$1
必须是正确类型的值)

不幸的是,野牛不知道你是否有