2011-12-16 20 views
6

Tenemos como tarea hacer un compilador. Ya hemos realizado el análisis léxico y de sintaxis, pero estamos estancados en la generación de código intermedio. Nos dimos cuenta de que tenemos que implementar una tabla de símbolos para proceder a la generación de código intermedio y no sabemos cómo hacerlo y qué contiene.Cómo hacer una tabla de símbolos

Dado el siguiente código, ¿qué debería contener la tabla de símbolos? (El código está escrito en un lenguaje educativo que se describe a continuación)

Además, ¿cómo podemos implementar ámbitos en nuestra tabla de símbolos?

<PROGRAM> ::= PROGRAM ID <BLOCK> ENDPROGRAM 
<BLOCK> ::= {<DECLARATIONS> <SUBPROGRAMS> <SEQUENCE>} 
<DECLARATIONS> ::= ε | DECLARE <VARLIST> ENDDECLARE 
<VARLIST> ::= ε | ID (, ID)* 
<SUBPROGRAMS> ::= (<PROCORFUNC>) * 
<PROCORFUNC> ::= PROCEDURE ID <PROCORFUNCBODY> ENDPROCEDURE | 
FUNCTION ID <PROCORFUNCBODY> ENDFUNCTION 
<PROCORFUNCBODY> ::= <FORMALPARS> <BLOCK> 
<FORMALPARS> ::= ε | (<FORMALPARLIST>) 
<FORMALPARLIST> ::= <FORMALPARITEM> (, <FORMALPARITEM>)* 
<FORMALPARITEM> ::= IN ID | INOUT ID 
<SEQUENCE> ::= <STATEMENT> (; <STATEMENT>)* 
<STATEMENT> ::= ε | <ASSIGNMENT-STAT> | 
<IF-STAT> | 
<WHILE-STAT> | 
<FOR-STAT> | 
<EXIT-STAT> | 
<CALL-STAT> | 
<RETURN-STAT> 
<ASSIGNMENT-STAT> ::= ID := <EXPRESSION> 
<IF-STAT> ::= IF <CONDITION> THEN <SEQUENCE> <ELSEPART> ENDIF 
<ELSEPART> ::= ε | ELSE <SEQUENCE> 
<WHILE-STAT> ::= DO {<SEQUENCE>} WHILE (<CONDITION>) 
<FOR-STAT> ::= (<ASSIGNMENT-STAT>; <CONDITION>;<ASSIGNMENT-STAT>;) 
{<SEQUENCE>} 
<EXIT-STAT> ::= EXIT 
<CALL-STAT> ::= CALL ID <ACTUALPARS> 
<ACTUALPARS> ::= (<ACTUALPARLIST>) | ε 
<ACTUALPARLIST> ::= <ACTUALPARITEM> (, <ACTUALPARITEM>)* 
<ACTUALPARITEM> ::= IN <EXPRESSION> | INOUT ID 
<RETURN-STAT> ::= RETURN <EXPRESSION> 
<CONDITION> ::= <BOOLTERM> (OR <BOOLTERM>)* 
<BOOLTERM> ::= <BOOLFACTOR> (AND <BOOLFACTOR>)* 
<BOOLFACTOR> ::= NOT [<CONDITION>] | [<CONDITION>] | 
<EXPRESSION> <RELATIONAL-OPER> <EXPRESSION> | 
TRUE | FALSE 
<EXPRESSION> ::= <OPTIONAL-SIGN> <TERM> (<ADD-OPER> <TERM>)* 
<TERM> ::= <FACTOR> (<MUL-OPER> <FACTOR>)* 
<FACTOR> ::= CONSTANT | (<EXPRESSION>) | ID <IDTAIL> 
<IDTAIL> ::= ε | <ACTUALPARS> 
<RELATIONAL-OPER> ::= = | < (ε | = | >) | > (ε | =) 
<ADD-OPER> ::= + | - 
<MUL-OPER> ::= * |/
<OPTIONAL-SIGN> ::= ε | <ADD-OPER> 
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 
+1

Odio que mi lenguaje de programación siempre me grite ... – Bobby

+0

@Bobby, entonces tienes suerte de no haber usado 'VT50'. –

+0

Eche un vistazo a [pilas de cactus] (http://en.wikipedia.org/wiki/Spaghetti_stack) –

Respuesta

6

Una tabla de símbolos mapea identificadores (normalmente el prefijo un nombre de alcance) a la información sobre ese identificador, tales como su tipo de símbolo (variable/parámetro/función local/clase etc.) , tipo de datos, su orden relativo a los otros identificadores en el mismo ámbito, su línea de código fuente, etc. La tabla de símbolos se puede generar atravesando el árbol de sintaxis abstracta, siempre manteniendo un registro del alcance en el que se encuentra y agregando información a la tabla de símbolos cada vez que tocas una declaración de variable. En su ejemplo, una parte de la tabla de símbolos podría tener este aspecto (mapeo de tipo de símbolo, tipo de datos, la posición y la línea de código fuente):

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} 

Ahora, usted puede resolver todas las referencias a variables. Por ejemplo, en la expresión A := A + 1, si sabe que su alcance actual es MULTIPLY.Aop, la tabla symnbol le permitirá saber que este A es un parámetro de entrada/salida del tipo INT, y que es el primer parámetro (esta información le permite generar un desplazamiento de dirección de pila para que pueda cargar/almacenar la variable).

Cuestiones relacionadas