创建解析树后,我现在必须填充符号表。

我必须存储信息,如

标识符的类型、范围、偏移量等。

现在我如何知道标识符的类型,范围,因为我所知道的只是该特定ID的词素值和行号(在词法分析之后)。

我是怎么知道整件事的。谢谢.

有帮助吗?

解决方案

现在我如何知道标识符的类型,范围,因为所有我 知道是该特定ID的词素值和行号(后 词法分析)。

正如EJP所提到的,您需要逐步完成解析树。您的树应该已经创建,以便您可以执行按顺序遍历,以计算源代码语句和表达式的相同顺序访问每个节点。您的树节点也应该与特定的语言结构相对应,例如 WhileStmtNode, MethodDeclNode, 等。

假设我正在构建符号表,递归地遍历树,并且我刚刚进入了一个方法体节点。我可能有类似以下内容:

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

我保留一个全局变量来管理范围。每次我进入范围发生变化的块时,我都会递增 currScope.同样,我会坚持 currClasscurrMethod 用符号名称、类型、偏移量等存储的变量.为以后的阶段。

更新资料:

现在说,我正在遍历树,每次我遇到一个ID我 必须将值与类型一起输入到符号表, 范围和其他人,比如范围我检查我是否遇到'{'或 函数名,但我怎么知道这是什么类型的ID。

每个树节点应该包含整个构造的所有必要信息。如果您正在使用解析器生成器(如CUP或Bison),则可以在语法操作中指定如何构建树。例如。

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

那些作品将匹配 Foo f; 并将变量声明节点追加到树中。该节点封装了包含lexeme的行号、字符号和字符串值的两个标识符节点。第一个标识符节点是类型,第二个是变量名。 ID 是词法分析器在匹配标识符时返回的终端符号。我假设你在某种程度上熟悉这一点。

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;
    }

}

当你有一个像这样的节点的语法树时,你就得到了你需要的所有信息。

第二次更新:

无论您是使用自定义解析器还是生成解析器,都有一个明显的点,您可以在匹配生产时将节点添加到树中。你用的是什么语言并不重要。C结构会做得很好。

如果它是一个非终端有信息作为Nonterminals名称,如果它 是终端即一个令牌,然后是令牌中的信息,即词素值, 存储令牌名称和行号

您必须在树中有专门的节点,例如ClassNode,TypeNode,MethodDeclNode,IfStmtNode,ExprNode。您不能只存储一种类型的节点并将非终端和终端放入其中。一个非终端被表示为一个树节点,在组成它的部分(通常是非终端本身)旁边没有其他信息可以存储它。您不会存储任何令牌信息。只有少数几个实例可以实际存储lexeme的字符串值:用于标识符和字符串/布尔值/整数字面值。

看看 例子。在第一次减少时 S 被降低到 (S + F), ,你追加一个 ParenExprNode 到树根。你还附加了一个 AddExprNode 作为孩子的 ParenExprNode.当应用语法规则2的缩减时,该逻辑必须硬编码到解析器中。

树:

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

守则:

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;
}

在下一步中,左括号将从输入中删除。之后, S 在堆栈的顶部,它被减少到 F 根据规则1。自 F 是标识符的非终端,它由 IdNode.

树:

    ExprNode
       |
  ParenExprNode
       |
   AddExprNode
   /         \
ExprNode   ExprNode
   |
 IdNode

守则:

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;
}

等等。..

其他提示

我所知道的是该特定ID的Lexeme值和行号

这不是真的。您知道它在解析树中声明的位置,它告诉您所需的一切。您通过处理解析树来完成此步骤。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top