如何制作符号表
我们有一个编译器的作业。 我们已经进行了词法和语法分析,但我们仍然坚持生成中间代码。 我们意识到我们必须实现一个符号表,以便进行中间代码生成,我们不知道,如何做以及它包含什么。
鉴于下面的代码,符号表应包含什么? (代码用教育语言编写,如下所述)
另外我们如何在符号表中实现范围?
::= PROGRAM ID ENDPROGRAM ::= { } ::= ε | DECLARE ENDDECLARE ::= ε | ID ( , ID )* ::= ( ) * ::= PROCEDURE ID ENDPROCEDURE | FUNCTION ID ENDFUNCTION ::= ::= ε | ( ) ::= ( , )* ::= IN ID | INOUT ID ::= ( ; )* ::= ε | | | | | | | ::= ID := ::= IF THEN ENDIF ::= ε | ELSE ::= DO {} WHILE () ::= (; ;;) {} ::= EXIT ::= CALL ID ::= ( ) | ε ::= ( , )* ::= IN | INOUT ID ::= RETURN ::= (OR )* ::= (AND )* ::= NOT [] | [] | | TRUE | FALSE ::= ( )* ::= ( )* ::= CONSTANT | () | ID ::= ε | ::= = | ) | > ( ε | = ) ::= + | - ::= * | / ::= ε |
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
类型的输入/输出参数,并且它是第一个参数(此信息将允许您生成堆栈地址偏移量,以便您可以加载/存储变量)。