zoukankan      html  css  js  c++  java
  • 符号表的简单使用

    符号表 (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

  • 相关阅读:
    全站仪定向距离差 方向不差 这样敢放线吗
    关于老王
    cad巧用插件自定义填充图形
    老王教你永不会错的测量坐标方位角计算方法
    jqgrid 点击列头的超链接或按钮时,不触发列排序事件
    jqgrid 将列头设置为超链接或按钮
    jqgrid 设置隔行换色
    jqgrid 设置行编辑为本地端编辑状态
    jqgrid 让隐藏的列在编辑状态时出现且可编辑
    jqgrid 设置编辑行中的某列为下拉选择项
  • 原文地址:https://www.cnblogs.com/tanhehe/p/3570033.html
Copyright © 2011-2022 走看看