Compiler construction 传输/代码生成-变量声明问题
我最近一直在研究ANTLR和Java,我构建了一个简单的语法来解析这些代码并生成AST。我还编写了一个内置的解释器来执行这段代码,它似乎工作得很好: 关于我的玩具语言的一些注释:Compiler construction 传输/代码生成-变量声明问题,compiler-construction,antlr,abstract-syntax-tree,transpiler,implicit-declaration,Compiler Construction,Antlr,Abstract Syntax Tree,Transpiler,Implicit Declaration,我最近一直在研究ANTLR和Java,我构建了一个简单的语法来解析这些代码并生成AST。我还编写了一个内置的解释器来执行这段代码,它似乎工作得很好: 关于我的玩具语言的一些注释: 我的语言只有一种“double” 所有变量都在赋值时隐式声明 所有变量都具有全局范围。也就是说,我可以在分配变量后使用变量,即使在分配该变量的块之外 /*示例程序*/ 开始 j:=1; 而在一般情况下,在分配前检测使用是不可能的。考虑以下(不是很好)C代码: int-sum;/*未初始化*/ 对于(i=0;i
- 我的语言只有一种“double”
- 所有变量都在赋值时隐式声明
- 所有变量都具有全局范围。也就是说,我可以在分配变量后使用变量,即使在分配该变量的块之外
/*示例程序*/
开始
j:=1;
而在一般情况下,在分配前检测使用是不可能的。考虑以下(不是很好)C代码:
int-sum;/*未初始化*/
对于(i=0;i
如果check(i)
是,比如说,i%10==0
,那么肯定会初始化sum
。但是如果它是i%10==1
,则在第一次迭代中未初始化地使用sum
。通常,是否未初始化地使用sum
,取决于检查(0)
的值。但可能没有办法知道那是什么<代码>检查()
可能是一个外部函数。或者其返回值可能取决于输入。或者它可能是基于一个困难的计算
这并不意味着你不应该试图发现问题。例如,您可以使用来尝试计算未定义用途的保守估计。如果可以证明未定义的用法,则可以抛出异常;如果无法证明所有用法都已定义,则可以发出警告。(许多编译器使用这种技术的变体。)这在控制流分析中可能是一个有趣的练习
但对于现实世界的解决方案,鉴于所有变量都是数字,我建议将所有变量自动初始化为0,作为语言语义的一部分。在一般情况下,在赋值之前检测使用是不可能的。考虑以下(不是很好)C代码:
int-sum;/*未初始化*/
对于(i=0;i
如果check(i)
是,比如说,i%10==0
,那么肯定会初始化sum
。但是如果它是i%10==1
,则在第一次迭代中未初始化地使用sum
。通常,是否未初始化地使用sum
,取决于检查(0)
的值。但可能没有办法知道那是什么<代码>检查()可能是一个外部函数。或者其返回值可能取决于输入。或者它可能是基于一个困难的计算
这并不意味着你不应该试图发现问题。例如,您可以使用来尝试计算未定义用途的保守估计。如果可以证明未定义的用法,则可以抛出异常;如果无法证明所有用法都已定义,则可以发出警告。(许多编译器使用这种技术的变体。)这在控制流分析中可能是一个有趣的练习
但对于现实世界的解决方案,考虑到所有变量都是数字,我建议将所有变量自动初始化为0,作为语言语义的一部分。我已经解决了这个问题,从各个赋值节点中删除变量声明,只需将赋值节点中使用的变量添加到全局hashmap中,然后在遍历树后生成声明 它的工作原理是这样的:
- 沿着小路走。如果我遇到变量的用法(在赋值/输入语句中除外),则生成异常/错误
- 如果我遇到赋值/输入语句,请将变量添加到全局hashmap中,但不要在特定节点的代码生成中声明它
- 生成整个代码后,运行全局hashmap并生成声明
- 通过连接声明语句和生成的代码来组合主程序
开始
i:=输入;
如果我<10,那么
j:=MUL i,10;
恩迪夫
打印j;
结束
它吐出了这个C代码(美化)
#包括
#包括
int main(int argc,char*argv[])
{
双i;
双j;
scanf(“%lf”、&i);
如果(i<10.0)
{
j=i*10.0000;
}
printf(“%g\n”,j);
}
在这种情况下,如果未到达并编译if
块,即i>=10
(因为j
将保持未初始化状态),我的内置解释器将抛出异常但是,等效的C代码是正确生成和编译的,但是j
将是一个未初始化的变量,导致运行时行为
但现在,我认为我可以接受这种行为,因为在任何情况下,使用潜在的未初始化变量都是程序本身设计的问题
我认为另一种选择是使用隐式NULL(或NaN)初始化变量值,并检查它。我已经解决了这个问题,从各个赋值节点中删除变量声明,只需将赋值节点中使用的变量添加到全局hashmap中,然后在遍历树后生成声明 这有点管用,李
/* A sample program */
BEGIN
j := 1;
WHILE j <= 5 DO
PRINT "ITERATION NO: "; PRINTLN j;
sumA1 := 0;
WHILE 1 = 1 DO
PRINT "Enter a number, 0 to quit: ";
i := INPUT;
IF i = 0 THEN
BREAK;
ENDIF
sumA1 := ADD sumA1, i;
ENDWHILE
j := ADD j, 1;
PRINT "The sum is: "; PRINTLN sumA1;
ENDWHILE
j := MINUS j;
PRINTLN j;
END
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char * argv[]) {
double j;
j = 1.00000;
while (j <= 5.0) {
printf("ITERATION NO: ");
printf("%g\n", j);
double sumA1;
sumA1 = 0.00000;
while (1.0 == 1.0) {
printf("Enter a number, 0 to quit: ");
double i;
scanf("%lf", & i);
if (i == 0.0) {
break;
}
sumA1 = sumA1 + i;
}
j = j + 1.00000;
printf("The sum is: ");
printf("%g\n", sumA1);
}
j = -j;
printf("%g\n", j);
}
int sum; /* uninitialised */
for (i = 0; i < n; ++i) {
if (check(i)) sum = 0;
sum += val[i]; /* Is sum initialised here? */
process(sum);
}
BEGIN
i := INPUT;
IF i < 10 THEN
j := MUL i, 10;
ENDIF
PRINT j;
END
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
double i;
double j;
scanf("%lf", &i);
if (i < 10.0)
{
j = i *10.0000;
}
printf("%g\n", j);
}