Compiler construction 野牛的语义类型检验分析

Compiler construction 野牛的语义类型检验分析,compiler-construction,bison,yacc,semantic-analysis,Compiler Construction,Bison,Yacc,Semantic Analysis,我一直在到处寻找例子,但都没有成功 我正在尝试编写一个基本的Ruby解释器。为此,我编写了一个flex词汇文件,其中包含标记识别语句和一个语法文件 我希望我的语法包含语义类型检查 我的语法文件包含,例如: arg : arg '+' arg 这应该是整数和浮点数的有效规则 根据我读到的内容,我可以为非终端(如arg)指定类型,如下所示: %type <intval> arg 但我相信有一种更好的方法可以做到这一点,因为这种暴行需要我制定规则,允许在浮点和整数之间进行加法 我发现

我一直在到处寻找例子,但都没有成功

我正在尝试编写一个基本的Ruby解释器。为此,我编写了一个flex词汇文件,其中包含标记识别语句和一个语法文件

我希望我的语法包含语义类型检查

我的语法文件包含,例如:

arg : arg '+' arg 
这应该是整数和浮点数的有效规则

根据我读到的内容,我可以为非终端(如arg)指定类型,如下所示:

%type <intval> arg
但我相信有一种更好的方法可以做到这一点,因为这种暴行需要我制定规则,允许在浮点和整数之间进行加法

我发现的所有示例只有一种类型(在类似计算器的示例中通常是整数)

我如何实现指定一个规则(如加法)可以使用int和float作为参数


非常感谢。

这不是您希望的答案。我认为您没有看到想要的示例的原因是在语法文件(the.y)中强制执行键入规则是不切实际的;相反,开发人员在过程.c或.cpp代码中完成这项工作。通常,您必须对解析后的输入进行一些分析,因此在执行这些操作时强制执行语义规则是一个副产品

另一方面,考虑到你在问题中重现的语法片段,我不太理解你是如何解析表达式的

这就是为什么我认为这是不切实际的。(1) 您的类型信息必须渗透到语法的所有非终端。(2) 更糟糕的是,它必须反映在变量名中

考虑这个解析简单赋值语句的玩具示例,它可以使用标识符、数值常量和四个桌面计算器运算符。数字标记可以是像42这样的整数,也可以是像3.14这样的浮点。假设标识符是一个字母,A-Z

%token IDENTIFIER NUMBER

%%

stmt : IDENTIFIER '=' expr
     ;

expr : expr '+' term
     | expr '-' term
     | term
     ;

term : term '*' factor
     | term '/' factor
     | factor
     ;

factor : '(' expr ')'
       | '-' factor
       | NUMBER
       | IDENTIFIER
       ;
现在我们来介绍一下打字规则。我们将数字标记分为FLT_编号和INT_编号。我们的
expr
术语
,和
因子
非终端也分为两部分:

%token IDENTIFIER FLT_NUMBER INT_NUMBER

stmt : IDENTIFIER '=' int_expr
     | IDENTIFIER '=' flt_expr
     ;

int_expr : int_expr '+' int_term
         | int_expr '-' int_term
         | int_term
         ;

flt_expr : flt_expr '+' flt_term
         | flt_expr '-' flt_term
         | flt_term
         ;

int_term : int_term '*' int_factor
         | int_term '/' int_factor
         | int_factor
         ;

flt_term : flt_term '*' flt_factor
         | flt_term '/' flt_factor
         | flt_factor
         ;

int_factor : '(' int_expr ')'
           | '-' int_factor
           | INT_NUMBER
           | int_identifier
           ;

flt_factor : '(' flt_expr ')'
           | '-' flt_factor
           | FLT_NUMBER
           | flt_identifier
           ;

int_identifier : IDENTIFIER ;

flt_identifier : IDENTIFIER ;
就我们的语法而言,存在一个冲突:解析器无法判断是将标识符识别为
int\u标识符
还是
flt\u标识符
。因此它不知道是将
A=B
减少为
IDENTIFIER=int\u expr
还是
IDENTIFIER=flt\u expr

(我对Ruby的理解有点软:)Ruby(和大多数语言一样)没有在词汇层面上提供一种方法来确定标识符的数字类型。这与老式的BASIC形成对比,其中A表示数字,A$表示字符串。换句话说,如果你发明了一种语言,比如说,a#表示一个整数,a@表示一个浮点,那么你就可以实现这一点

如果您希望允许有限的混合类型表达式,例如
int_term'*'flt_factor
,那么您的语法将变得更加复杂


也许有办法解决这些问题。使用yacc/bison以外的技术构建解析器可能会更容易。至少,也许我的素描会给你一些进一步的想法。

你误解了%type的用途。它用于控制您自己的语法终端和非终端的类型,以便在YYUNION中使用,因此您不必为$$、$1等编写类型转换:不允许您控制正在解析的程序中的语义类型。回答得好。将类型语义构建到语法中的想法在20世纪60年代的Algol-68项目中得到了全面的突破。现在人们普遍认为这是不可行的。是的,这就是我最后所做的,最后,我还没有决定如何检查返回函数的类型,但这基本上是我的结论,谢谢!它是。。。但令人遗憾的是,直到今天,只有语言的语法(通过BNF)在代码中正式化,而不是语义(通过vWG)。
%token IDENTIFIER FLT_NUMBER INT_NUMBER

stmt : IDENTIFIER '=' int_expr
     | IDENTIFIER '=' flt_expr
     ;

int_expr : int_expr '+' int_term
         | int_expr '-' int_term
         | int_term
         ;

flt_expr : flt_expr '+' flt_term
         | flt_expr '-' flt_term
         | flt_term
         ;

int_term : int_term '*' int_factor
         | int_term '/' int_factor
         | int_factor
         ;

flt_term : flt_term '*' flt_factor
         | flt_term '/' flt_factor
         | flt_factor
         ;

int_factor : '(' int_expr ')'
           | '-' int_factor
           | INT_NUMBER
           | int_identifier
           ;

flt_factor : '(' flt_expr ')'
           | '-' flt_factor
           | FLT_NUMBER
           | flt_identifier
           ;

int_identifier : IDENTIFIER ;

flt_identifier : IDENTIFIER ;