野牛中的语义类型检查分析

时间:2012-06-26 01:50:24

标签: compiler-construction bison yacc semantic-analysis

我一直试图在各处找到例子,但这是徒劳的。

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

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

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

arg : arg '+' arg 

这应该是整数和浮点数的有效规则。

根据我所读到的,我可以指定非终端的类型,例如arg,如下所示:

%type <intval> arg

其中“intval”在类型union中,对应于int C类型。

但这只适用于整数,我不知道如何使规则对浮点数有效。 我想过有两个不同的规则,一个用于整数,一个用于浮点数,如:

argint : argint '+' argint
argfloat : argfloat '+' argfloat

但我确信这样做会有更多更好的方法,因为这种暴行要求我有规则允许在浮点数和整数之间添加。

我发现的所有例子只有一种类型(通常是计算器式例子中的整数)。

如何指定添加规则可以将int和float作为参数?

非常感谢。

1 个答案:

答案 0 :(得分:4)

这不是你希望的答案。我认为你没有看到你想要的例子的原因是在语法文件(.y)中强制执行输入规则是不切实际的。相反,开发人员在程序性.c或.cpp代码中完成此任务。通常,您无论如何都会对已解析的输入进行一些分析,因此这是执行语义规则的副产品。

顺便说一句,我不太明白你是如何解析表达式的,因为你在你的问题中重现了你的语法片段。

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

考虑这个解析简单赋值语句的玩具示例,它可以使用标识符,数字常量和四个桌面计算器运算符。 NUMBER标记可以是42之类的整数,也可以是3.14之类的浮点数。让我们说IDENTIFIER是一个字母,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
       ;

现在让我们尝试介绍输入规则。我们会将NUMBER标记分为FLT_NUMBER和INT_NUMBER。我们的exprtermfactor非终端也分为两个:

%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 ;

由于我们的语法在这一点上存在,所以存在冲突:解析器无法判断是否将IDENTIFIER识别为int_identifierflt_identifier。因此,它不知道是否将A = B缩减为IDENTIFIER = int_exprIDENTIFIER = flt_expr

(这里我对Ruby的理解有点软:) Ruby(像大多数语言一样)没有在词法层面提供的方式来确定标识符的数字类型。将其与旧学校BASIC进行对比,其中A表示数字,A $表示字符串。换句话说,如果你发明了一种语言,比如A#表示一个整数而A @表示浮点数,那么你可以使它工作。

如果你想允许有限的混合型表达式,比如int_term '*' flt_factor,那么你的语法就会变得更加复杂。

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