随笔- 250  评论- 66  文章- 3 

符号表的简单使用

符号表 (symbol table) 是一种供编译用于保存有关源程序构造的各种信息的数据结构。 这些信息在编译器的分析阶段被逐步收集并放入符号表,它们在综合阶段用于生成目标代码。符号表的每个条目包含与一个标识符相关的信息,比如它的字符串(或者词素)、它的类型、它的存储位置和其他相关信息。符号表通常需要支持同一标识符在一个程序中的多重声明.

 

每个带有声明的程序块都会有自己的符号表,这个块中的每个声明都在此符号表中有一个对应的条目。

 

例如下面的例子:

{ int x; char y; { bool y; x; y; } x; y; }

我们知道 第二个{}里面的 x、y 分别是 int、bool 类型, 外面的 x、y 分别是 int、char类型。

我们可以将上面的用下面的代表:

{ { x:int; y:bool; } x:int; y:char }

为了能够让程序生成这样的输出,必须要借助符号表。

 

本身这设计到词法分析,但为了简化操作,规定每一个部分用空格隔开,例如 {int x;} 要写成 { int x ; }

首先定义两个类,一个类代表符号,另一个代表标识符。

public class Token {
    public final String lexeme;
    public Token(String s) { lexeme = s; }
    public String toString() { return lexeme; }
}
public class Id extends Token {
    public final String type;
    public Id(String s, String t) { super(s); type = t; }
    public String toString() { return lexeme + ":" + type + ";"; }
}

 

接着就要创建一个符号表类。

符号表要能够存储当前符号表中的标识符,又能查询到标识符在哪一作用域。

为了存储标识符, 增加一散列表.

private Hashtable table;

代码如下:

public class Env {
    private Hashtable<String, Id> table;
    protected Env prev;
    public Env(Env p) { table = new Hashtable<>(); prev = p; }
    public void put(String s, Id id) { table.put(s, id); }

    public Id get(String s) {
        for (Env e=this; e != null; e = e.prev) {
            Id found = e.table.get(s);
            if (found != null) return found;
        }
        return null;
    }
}

 

接着就是翻译的工作了。

一开始要初始化一个符号表,让它的 pre 字段为空。每当遇到一个 '{' 就新建一个符号表, 用来表示当前作用域,每遇到一个 '}' 就要返回到上一作用域,遇到声明,则将标识符和该标识符的类型放入 符号表, 遇到表示符,就将该标识符的信息输出。

 

代码如下:

public class Lexer {
    public static void main(String[] args) {
        String s = "{ int x ; char y ; { bool y ; x ; y ; } x ; y ; }";
        Lexer lexer = new Lexer();
        try {
            lexer.trans(s);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    private Hashtable<String, Token> words = new Hashtable<String, Token>();
    
    public void reserve(Token t) { words.put(t.lexeme, t); }

    public Lexer() {
        reserve( new Token("int") ) ;
        reserve( new Token("float") );
        reserve( new Token("double") );
        reserve( new Token("char") );
        reserve( new Token("bool") );
    }
    
    public void print(String s) { System.out.print(s); }
    
    public void trans(String ss) throws IOException {
        Scanner in = new Scanner(ss);
        
        Env top = new Env(null);
        
        while (in.hasNext()) {
            String s = in.next();
            
            if (s.equals("{")) {
                top = new Env(top);
                print("{ ");
            } else if (s.equals("}")) {
                top = top.prev;
                print("} ");
            } else {
                Token w = words.get(s);
                if (w != null) {        // 类型
                    s = in.next();
                    top.put(s, new Id(s, w.lexeme));
                } else {                // 变量
                    Id id = top.get(s);
                    print(id.toString() + " ");
                }
                
                in.next();                // 去掉分号
            }
        }
    }
}

 

源代码: https://code.csdn.net/tanheaishui/simplesymboltable

posted on 2014-02-26 19:49  Still_Raining  阅读(10570)  评论(0编辑  收藏