我们要分配一个编译器。我们已经进行了词法分析和语法分析,但是我们停留在中间代码的生成上。我们意识到,必须执行一个符号表才能进行中间代码的生成,但我们不知道该如何做以及它所包含的内容。
给定以下代码,符号表应包含什么? (该代码以教育性语言编写,如下所述)
另外,我们如何在符号表中实现作用域?
PROGRAM MULTIPLY
{
DECLARE
A, B, C
ENDDECLARE
PROCEDURE Aop(INOUT A)
{
A=A+1;
}
ENDPROCEDURE
FUNCTION Bop(IN B){
IF [NOT[[TRUE AND FALSE]OR[TRUE]]] THEN B := 100 / 2;
ELSE B := 100;
ENDIF;
RETURN B;
}
ENDFUNCTION
CALL Aop(INOUT A);
CALL Bop(IN B);
A := 40;
C := A * B;
}
ENDPROGRAM
最佳答案
符号表将标识符(通常以作用域名称为前缀)映射到有关该标识符的信息,例如其符号类型(本地变量/参数/函数/类等),数据类型,相对于同一标识符的其他标识符的顺序可以通过遍历抽象语法树来生成符号表,方法是始终跟踪您所处的范围,并在每次遇到变量声明时将信息添加到符号表中。在您的示例中,符号表的一部分可能看起来像这样(映射到符号类型,数据类型,位置和源代码行):
MULTIPLY.A -> {"LOCAL", "INT", 0, 4}
MULTIPLY.B -> {"LOCAL", "INT", 1, 4}
MULTIPLY.C -> {"LOCAL", "INT", 2, 4}
MULTIPLY.Aop -> {"FUNCTION", "INT", 3, 4}
MULTIPLY.Aop.A -> {"INOUTPARAM", "INT", 0, 6}
现在,您可以解析所有变量引用。例如,在表达式
A := A + 1
中,如果您知道当前范围是MULTIPLY.Aop
,则symnbol表将使您发现此A
是INT
类型的输入/输出参数,并且它是第一个参数(此信息将让您生成堆栈地址偏移量,以便您可以加载/存储变量)。