Pregunta

Después de crear el árbol de análisis, ahora tengo que completar la tabla de símbolos.

Tengo que almacenar información como

Tipo, Alcance, Compensación, etc. para los identificadores.

Ahora, ¿cómo sé el tipo y el alcance de los identificadores, ya que todo lo que sé es el valor del lexema y el número de línea para esa identificación en particular (después del análisis léxico)?

¿Cómo me enteré de todo esto?gracias.

¿Fue útil?

Solución

Ahora, ¿cómo sé el tipo, el alcance de los identificadores, ya que todo lo que sé es el valor de lexeme y el número de línea para esa ID en particular (después del análisis léxico)?

Como mencionó EJP, es necesario recorrer el árbol de análisis.Su árbol debería haber sido creado para que pueda realizar un recorrido en orden, visitando cada nodo en el mismo orden en que se evalúan las declaraciones y expresiones del código fuente.Los nodos de su árbol también deben corresponder con una construcción de lenguaje específica, p. WhileStmtNode, MethodDeclNode, etc.

Supongamos que estoy construyendo la tabla de símbolos, recorriendo el árbol de forma recursiva y acabo de ingresar un nodo del cuerpo del método.Podría tener algo como lo siguiente:

public void doAction(MethodBodyNode methodBody) {
    currScope = 2;
    methodBody.getExpr().applyAction(this);
    currScope = 2;
}

Mantengo una variable global para gestionar el alcance.Cada vez que entro a un bloque donde cambia el alcance, incremento currScope.Del mismo modo, mantendría currClass y currMethod variables para almacenar con el nombre del símbolo, tipo, desplazamiento, etc.para fases posteriores.

Actualizar:

Ahora digamos, estoy atravesando el árbol, cada vez que me encuentro con una identificación tendría que ingresar el valor a la tabla de símbolos junto con el tipo, scope y otros, digamos que para scope compruebo si me encuentro con '{' o nombre de la función, pero ¿cómo sé qué tipo de ID es este?

Cada nodo del árbol debe contener toda la información necesaria para toda la construcción.Si está utilizando un generador de analizadores, como CUP o Bison, puede especificar cómo construir el árbol en las acciones gramaticales.P.ej.

variableDeclaration::= identifier:i identifier:i2 SEMICOLON {: RESULT = new VarDeclNode(i, i2, null); :};
identifier::= ID:i {: RESULT = new IdNode(i.getLineNum(), i.getCharNum(), i.getStringValue()); :};

Esas producciones coincidirían Foo f; y agregue un nodo de declaración de variable al árbol.Ese nodo encapsula dos nodos identificadores que contienen el número de línea, el número de carácter y el valor de cadena del lexema.El primer nodo identificador es el tipo y el segundo es el nombre de la variable. ID es un símbolo terminal devuelto por el lexer al hacer coincidir un identificador.Supongo que estás familiarizado con esto hasta cierto punto.

public class VarDeclNode extends StmtNode {

    private IdNode id;
    private IdNode type;
    private ExprNode expr;

    public VarDeclNode(IdNode id, IdNode type, ExprNode expr) {
        super();
        this.id = id;
        this.type = type;
        this.expr = expr;
    }

}

Cuando tienes un árbol de sintaxis con nodos como este, tienes toda la información que necesitas.

Segunda actualización:

No importa si está utilizando un analizador personalizado o uno generado, hay un punto distinto en el que agrega un nodo al árbol al hacer coincidir una producción.Y no importa qué idioma estés usando.Las estructuras C funcionarán bien.

si se trata de un no terminal tiene la información como nombre de Nonterminals, y si es un terminal, es decir,un token, luego la información en el token, es decirvalor del lexema, El nombre del token y el número de línea se almacenan

Debe tener nodos especializados en el árbol, p.ClassNode, TypeNode, MethodDeclNode, IfStmtNode, ExprNode.No se puede simplemente almacenar un tipo de nodo y colocar terminales y no terminales en él.Un no terminal se representa como un nodo de árbol, no hay otra información que almacenar sobre él además de las partes que lo componen, que generalmente son no terminales en sí.No almacenarías ninguna información simbólica.Sólo hay unos pocos casos en los que realmente almacenarías el valor de cadena de un lexema:para un identificador y para un literal de cadena/booleano/entero.

Mira esto este ejemplo.Durante la primera reducción cuando S se reduce a (S + F), agregas un ParenExprNode a la raíz del árbol.También agregas un AddExprNode como hijo del ParenExprNode.Esa lógica debe estar codificada en su analizador al aplicar una reducción según la regla 2 de la gramática.

El árbol:

    ExprNode (root)
       |
  ParenExprNode
       |
   AddExprNode
   /         \
ExprNode   ExprNode

El código:

struct ExprNode { void* exprNode; };
struct ParenExprNode { void* exprNode; };
struct AddExprNode { void* op1, * op2; };
struct IdNode { char* val; int line; int charNum; };
struct IntLiteralNode { int val; int line; int charNum; };

void reduce_rule_2(ExprNode* expr) {

    //remove stack symbols

    //create nodes
    struct ParenExprNode* parenExpr = malloc(sizeof(struct ParenExprNode));
    struct AddExprNode* addExpr = malloc(sizeof(struct AddExprNode));
    addExpr->op1 = malloc(sizeof(struct ExprNode));
    addExpr->op2 = malloc(sizeof(struct ExprNode));

    //link them
    parenExpr->exprNode = (void*)addExpr;
    expr->exprNode = (void*)parenExpr;
}

En el siguiente paso, se elimina el paréntesis izquierdo de la entrada.Después, S está en la parte superior de la pila y se reduce a F por la regla 1.Desde F es el no terminal de un identificador, está representado por IdNode.

El árbol:

    ExprNode
       |
  ParenExprNode
       |
   AddExprNode
   /         \
ExprNode   ExprNode
   |
 IdNode

El código:

reduce_rule_2(addExpr->op1);

void reduce_rule_1(ExprNode* expr) {
    //reduce stack symbols
    struct IdNode* id = malloc(sizeof(struct IdNode));
    id->val = parser_matched_text();
    id->lineNum = parser_line_num();
    id->charNum = parser_char_num();
    expr->exprNode = (void*)id;
}

Etcétera...

Otros consejos

Todo lo que sé es el valor del lexema y el número de línea para esa ID particular

Eso no es cierto.Sabes dónde se declara en el árbol de parse, que le dice todo lo que necesita.Usted hace este paso por procesando el árbol de parse.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top