【轻松掌握数据结构与算法】符号表(Symbol Tables)

符号表(Symbol Tables)是编译器和解释器中的一个关键组件,用于存储代码中的所有符号及其对应的类型和属性。符号表在语法分析和语义分析阶段起着至关重要的作用,帮助编译器或解释器理解代码中的变量、函数、类型等符号的定义和使用。本文将详细介绍符号表的实现和使用,包括解题思路、示例代码和性能分析。

1. 符号表的基本概念

符号表是一个存储符号及其属性的数据结构。每个符号可以是一个变量、函数、类型等。符号表通常包含符号的名称、类型、作用域、存储位置等信息。

2. 符号表的常规实现

2.1 符号类(Symbol Class)

符号类是符号表中的基本单元,用于存储符号的名称和类型。我们可以定义一个基类 Symbol,并为不同的符号类型(如变量、内置类型)定义继承自 Symbol 的子类。

#pragma once
#include <string>
#include <memory>

class Symbol;
typedef std::shared_ptr<Symbol> SymbolPtr;
typedef Symbol* const SymbolRawPtr;

class Symbol {
protected:
    std::string symbolName;
    SymbolPtr symbolType;
public:
    virtual SymbolRawPtr getType() = 0;
    std::string getName() const { return symbolName; }
};

2.2 内置类型符号(BuiltinTypeSymbol)

内置类型符号表示预定义的类型,如 INTEGERREAL。这些类型在符号表中作为常量存在。

#pragma once
#include "Symbol/Symbol.h"

class BuiltinTypeSymbol : public Symbol {
public:
    BuiltinTypeSymbol(std::string sName) : symbolName(sName) {}
    SymbolRawPtr getType() override { return this; }
};

2.3 变量符号(VarSymbol)

变量符号表示代码中的变量,存储变量的名称和类型。

#pragma once
#include "Symbol/Symbol.h"

class VarSymbol : public Symbol {
public:
    VarSymbol(std::string varName, SymbolPtr varType) : symbolName(varName), symbolType(varType) {}
    SymbolRawPtr getType() override { return symbolType; }
};

2.4 符号表类(SymbolTable)

符号表类负责管理所有符号,提供定义和查找符号的方法。

#pragma once
#include <map>
#include <string>
#include "Symbol/Symbol.h"

class SymbolTable {
private:
    std::map<std::string, SymbolPtr> symbols;
public:
    SymbolTable() {
        define(std::make_shared<BuiltinTypeSymbol>("INTEGER"));
        define(std::make_shared<BuiltinTypeSymbol>("REAL"));
    }
    void define(SymbolPtr symbolPtr) {
        symbols[symbolPtr->getName()] = symbolPtr;
    }
    SymbolPtr lookup(std::string symbolName) {
        if (symbols.find(symbolName) == symbols.end()) {
            throw "Symbol not found";
        }
        return symbols[symbolName];
    }
    std::map<std::string, SymbolPtr> getAll() const {
        return symbols;
    }
};

3. 符号表的使用

3.1 符号表构建器(SymbolTableBuilder)

符号表构建器用于遍历抽象语法树(AST),并在符号表中定义符号。它继承自 NodeVisitor,为每种节点类型实现 visit 方法。

#pragma once
#include "NodeVisitor/NodeVisitor.h"
#include "ASTNodes/ProgramNode.h"
#include "Symbol/SymbolTable.h"

class SymbolTableBuilder : public NodeVisitor {
private:
    SymbolTable symTable;
public:
    SymbolTableBuilder() {}
    SymbolTable getSymbolTable() const { return symTable; }
    void visit(ProgramNode* node) override {
        // 处理程序节点
    }
    void visit(VarDeclNode* node) override {
        auto typeName = std::get<std::string>(node->getType()->getTokenPtr()->getValue());
        auto typeSymbol = symTable.lookup(typeName);
        std::string varName = std::get<std::string>(node->getVar()->getTokenPtr()->getValue());
        symTable.define(std::make_shared<VarSymbol>(varName, typeSymbol));
    }
    // 其他节点的 visit 方法
};

4. 示例代码

4.1 构建符号表

int main() {
    std::string text = R"(
        PROGRAM Part8;
        VAR
        number : INTEGER;
        a, b   : INTEGER;
        y      : REAL;

        BEGIN {Part8}
        number := 2;
        a := number ;
        b := 10 * a + 10 * number DIV 4;
        y := 20 / 7 + 3.14
        END.  {Part8}
        )";
    ASTParser parser(text);
    SymbolTableBuilder symtableBuilder;
    symtableBuilder.visit(parser->parse());
    for (const auto& pair : symtableBuilder.getSymbolTable().getAll()) {
        std::cout << pair.first << " : " << pair.second->getType()->getName() << std::endl;
    }
    return 0;
}

4.2 输出结果

INTEGER : INTEGER
REAL : REAL
a : INTEGER
b : INTEGER
number : INTEGER
y : REAL

5. 性能分析

符号表的性能主要取决于查找和插入操作的复杂度。使用哈希表实现的符号表,查找和插入操作的平均复杂度为 O(1)。在最坏情况下,哈希表可能会退化为链表,复杂度为 O(n)。为了优化性能,可以使用平衡二叉搜索树或跳表等数据结构。

6. 符号表的不同实现方式及特点

符号表(Symbol Table)是编译器和解释器中的一个关键组件,用于存储代码中的所有符号及其对应的类型和属性。符号表在语法分析和语义分析阶段起着至关重要的作用,帮助编译器或解释器理解代码中的变量、函数、类型等符号的定义和使用。本文将详细介绍符号表的不同实现方式及其特点,包括它们的解题思路、示例代码和性能分析。

1 无序数组实现(Unordered Array Implementation)

1.1 实现方式

仅维护一个数组,数组中的每个元素是一个键值对,键是符号的名称,值是符号的属性。

1.2 性能
  • 搜索操作:在最坏情况下,时间复杂度为 O(n)。

  • 插入操作:在最坏情况下,时间复杂度为 O(1)。

  • 删除操作:在最坏情况下,时间复杂度为 O(n)。

1.3 示例代码
#include <vector>
#include <string>
#include <iostream>

struct Symbol {
    std::string name;
    std::string type;
};

class SymbolTable {
private:
    std::vector<Symbol> symbols;
public:
    void insert(const std::string& name, const std::string& type) {
        symbols.push_back({name, type});
    }

    std::string lookup(const std::string& name) {
        for (const auto& symbol : symbols) {
            if (symbol.name == name) {
                return symbol.type;
          
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值