符号表的简单使用
符号表 (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(); // 去掉分号 } } } }