符號表 (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(); // 去掉分號 } } } }
