我最近一直在研究 ANTLR 和 Java,我构建了一个简单的语法来解析这段代码并生成一个 AST。我还编写了一个内置解释器来执行这段代码,它似乎运行良好:
关于我的玩具语言的一些注释:
- 我的语言只有一种可变的“双”
- 所有变量都在赋值时隐式声明。
- 所有变量都具有全局范围。即,即使在分配它的块之外,我也可以在分配变量之后使用它。
/* 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
然后我将代码生成函数写入 AST 以将其从我的 AST 类输出到 C,我得到了这个结果(美化):
#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);
}
在代码生成期间,我首先检查变量名称是否在 HashMap 中可用。对于赋值语句/输入语句,我在赋值之前添加了变量声明,如您所见。对于赋值以外的变量的使用,我会在使用前抛出一个非初始化变量的异常。
一切都很好。上面的代码适用于这个例子,因为在我的源程序中,我没有在声明它的范围之外使用任何变量。
但是有一个问题。由于我正在初始化块内的某些变量(就像while
它们不能在范围外使用),我需要一种方法来收集源程序中使用的所有变量作为 C 中的全局变量(或至少在 main() 函数的顶部)。如果在块外的程序中使用该变量,则在 C 中使用之前声明变量将导致源语言中的有效程序无法在 C 中编译。
我想我可以通过首先解析所有变量并在 C 程序开始时声明它们然后生成代码来解决它。
但是如果我在生成代码之前更新符号表(HashMap),我将无法知道变量是否在使用前被实际分配。
重新设计它以确保:
- 代码生成器应在使用前检查分配。即,如果它在赋值之前发现了一个用法,它应该抛出一个异常/编译错误。
- 同时,我的代码中的所有变量都应该在 C 生成的源代码中作为全局变量可用。因此,如果之前在内部块中分配变量,则即使在块外使用变量也是可能的,因为在我的源语言中它是可以接受的。
这是我第一次尝试这样的事情。请为我提供任何可能的解决方案的指针。