野牛语义类型检查分析

So *_*ins 3 compiler-construction yacc bison semantic-analysis

我一直在尝试到处寻找示例,但是却徒劳无功。

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

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

我的语法文件包含例如:

arg : arg '+' arg 
Run Code Online (Sandbox Code Playgroud)

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

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

%type <intval> arg
Run Code Online (Sandbox Code Playgroud)

其中“ intval”在联合类型中,并且与int C类型相对应。

但这仅适用于整数,我不确定如何使该规则对浮点数有效。我考虑过要制定两个不同的规则,一个用于整数,一个用于浮点数,例如:

argint : argint '+' argint
argfloat : argfloat '+' argfloat
Run Code Online (Sandbox Code Playgroud)

但是我敢肯定,这样做的方法要好得多,因为这种拙劣的行为要求我制定规则,允许在浮点数和整数之间进行加法运算。

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

如何实现指定诸如加法之类的规则可以将int和float用作参数的方法?

非常感谢你。

Dav*_*ine 5

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

顺便说一句,鉴于您在问题中重现的语法片段,我不太了解您如何解析表达式。

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

考虑这个玩具示例,该示例分析可使用标识符,数字常量和四个桌面计算器运算符的简单赋值语句。NUMBER令牌可以是整数(例如42)或浮点数(例如3.14)。假设IDENTIFIER是一个字母AZ。

%token IDENTIFIER NUMBER

%%

stmt : IDENTIFIER '=' expr
     ;

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

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

factor : '(' expr ')'
       | '-' factor
       | NUMBER
       | IDENTIFIER
       ;
Run Code Online (Sandbox Code Playgroud)

现在,让我们尝试介绍输入规则。我们将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 ;
Run Code Online (Sandbox Code Playgroud)

就目前的语法而言,这是有冲突的:解析器无法判断是将IDENTIFIER识别为a int_identifier还是a flt_identifier。因此,它不知道是否减少A = Bas IDENTIFIER = int_exprIDENTIFIER = flt_expr

(在这里,我对Ruby的理解有些柔和:) Ruby(像大多数语言一样)在词法级别上没有提供一种确定标识符的数字类型的方法。将其与老式BASIC进行对比,其中A表示数字,A $表示字符串。换句话说,如果您发明了一种语言,例如,A#表示整数,而A @表示浮点数,则可以完成此工作。

如果您想允许有限的混合类型表达式(例如)int_term '*' flt_factor,则语法会变得更加复杂。

可能存在解决这些问题的方法。使用yacc / bison以外的技术构建的解析器可能会更容易。至少,也许我的草图可以为您提供一些进一步的想法。