• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >Android > 编译器开发系列--Ocelot语言2.变量引用的消解,编译器--ocelot

编译器开发系列--Ocelot语言2.变量引用的消解,编译器--ocelot

作者:网友 字体:[增加 减小] 来源:互联网 时间:2017-05-26

网友通过本文主要向大家介绍了ocelot巧克力,ocelot,ocelot是什么意思,michel ocelot,ocelot life等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

编译器开发系列--Ocelot语言2.变量引用的消解,编译器--ocelot


“变量引用的消解”是指确定具体指向哪个变量。例如变量“i”可能是全局变量i,也可能是静态变量i,还可能是局部变量i。通过这个过程来消除这样的不确定性,确定所引用的到底是哪个变量。

为了消除这样的不确定性,我们需要将所有的变量和它们的定义关联起来,这样的处理称为“变量引用的消解”。具体来说,就是为抽象语法树中所有表示引用变量的VariableNode 对象添加该变量的定义(Variable 对象)的信息。

LocalResolver就是用来处理变量引用消解的类,继承自Visitor(“变量引用的消解”和“静态类型检查”等一连串的处理)。入口方法为:

    /*入口
     * 生成了以ToplevelScope 为根节点的
		Scope 对象的树,并且将所有VariableNode 和其定义关联起来了。
     */
    // #@@range/resolve{
    public void resolve(AST ast) throws SemanticException {
    	/*
    	 * 第1 部分先生成ToplevelScope 对象, 然后将生成的ToplevelScope 对象用
			scopeStack.add(toplevel) 添加到scopeStack。这样栈里面就有了1 个Scope 对象
    	 */
        ToplevelScope toplevel = new ToplevelScope();
        scopeStack.add(toplevel);

        /*变量定义的添加.
         * 两个foreach 语句都是将全局变量、函数以及类型添加到ToplevelScope 中。
         * 两者都是调用ToplevelScope#declareEntity 往ToplevelScope 对象中添加定义或声明。
         * 第1个foreach 语句添加导入文件(*.hb)中声明的外部变量和函数
         * 第2 个foreach 语句用于导入所编译文件中定义的变量和函数
         */
        // #@@range/declareToplevel{
        for (Entity decl : ast.declarations()) {
            toplevel.declareEntity(decl);
        }
        for (Entity ent : ast.definitions()) {
            toplevel.defineEntity(ent);
        }
        // #@@}
        // #@@range/resolveRefs{
        resolveGvarInitializers(ast.definedVariables());//遍历全局变量
        resolveConstantValues(ast.constants());//遍历常量的初始化表达式
        resolveFunctions(ast.definedFunctions());//最重要的
        // #@@}
        toplevel.checkReferences(errorHandler);
        if (errorHandler.errorOccured()) {
            throw new SemanticException("compile failed.");
        }

        /*
         * 在最后部分中,将在此类中生成的ToplevelScope 对象和ConstantTable 对象保存到
			AST 对象中。这两个对象在生成代码时会用到,为了将信息传给下一阶段,所以保存到AST 对
			象中。
         */
        ast.setScope(toplevel);
        ast.setConstantTable(constantTable);
        /*
         * 至此为止变量引用的消解处理就结束了,上述处理生成了以ToplevelScope 为根节点的
			Scope 对象的树,并且将所有VariableNode 和其定义关联起来了。
         */
    }

先往栈中添加ToplevelScope,ToplevelScope表示程序顶层的作用域,保存有函数和全局变量。

然后往这个顶层的作用域添加各种全局变量和函数。

这里着重说下resolveFunctions(ast.definedFunctions());这个方法,对抽象语法树中的所有函数的消解:

    /*
     * 函数定义的处理.
     */
    // #@@range/resolveFunctions{
    private void resolveFunctions(List<DefinedFunction> funcs) {
        for (DefinedFunction func : funcs) {
        	//调用pushScope 方法,生成包含函数形参的作用域,并将作用域压到栈(scopeStack)中
            pushScope(func.parameters());
            //用resolve(func.body()) 方法来遍历函数自身的语法树
            resolve(func.body());
            //调用popScope 方法弹出刚才压入栈的Scope 对象,将该Scope 对象用func.setScope
            //添加到函数中
            func.setScope(popScope());
        }
    }

遍历所有的函数节点,首先将单个函数节点里的所有形参或者已定义的局部变量压入一个临时变量的作用域。然后再将这个临时变量的作用域LocalScope压入scopeStack:

    //pushScope 方法是将新的LocalScope 对象压入作用域栈的方法
    // #@@range/pushScope{
    private void pushScope(List<? extends DefinedVariable> vars) {
    	//生成以currentScope() 为父作用域的LocalScope 对象
    	//currentScope 是返回当前栈顶的Scope 对象的方法
        LocalScope scope = new LocalScope(currentScope());
        /*
         * 接着用foreach 语句将变量vars 添加到LocalScope 对象中。也就是说,向LocalScope
			对象添加在这个作用域上所定义的变量。特别是在函数最上层的LocalScope 中,要添加形参
			的定义。
         */
        for (DefinedVariable var : vars) {
        	//先用scope.isDefinedLocally 方法检查是否已经定义了同名的变量
            if (scope.isDefinedLocally(var.name())) {
                error(var.location(),
                    "duplicated variable in scope: " + var.name());
            }
            //然后再进行添加。向LocalScope 对象添加变量时使用defineVariable 方法
            else {
                scope.defineVariable(var);
            }
        }
        /*
         * 最后通过调用scopeStack.addLast(scope) 将生成的LocalScope 对象压到作用域
			的栈顶。这样就能表示作用域的嵌套了。
         */
        scopeStack.addLast(scope);
    }

然后resolve(func.body());是消解当前函数的函数体,也就是BlockNode节点,根据java的多态特性,最终是调用以下方法:

    /*
     * 添加临时作用域.
     * C 语言(C?)中的程序块({...}block)也会引入新的变量作用域。
     */
    // #@@range/BlockNode{
    public Void visit(BlockNode node) {
    	/*
    	 * 首先调用pushScope 方法,生成存储着这个作用域上定义的变量的Scope 对象,然后压
			入作用域栈。
    	 */
        pushScope(node.variables());
        /*
         * 接着执行super.visit(node);,执行在基类Visitor 中定义的处理,即对程序块的
			代码进行遍历。
			visit(VariableNode node)
         */
        super.visit(node);
        /*
         * 最后用popScope 方法弹出栈顶的Scope 对象,调用BlockNode 对象的setScope 方
			法来保存节点所对应的Scope 对象。
         */
        node.setScope(popScope());
        return null;
    }

又是一个pushScope(node.variables());将函数体中的临时变量声明的列表保存在一个LocalScope中,然后将这个LocalScope压入scopeStack栈中。然后最关键的来了,super.visit(node);调用Visitor类中的visit方法来对函数体中的局部变量进行消解,

    public Void visit(BlockNode node) {
        for (DefinedVariable var : node.variables()) {
            if (var.hasInitializer()) {
                visitExpr(var.initializer());
            }
        }
        visitStmts(node.stmts());
        return null;
    }

visitStmts是关键,因为变量的引用是保存在VariableNode节点中,最终会调用:

    /*
     * 建立VariableNode 和变量定义的关联.
     * 使用之前的代码已经顺利生成了Scope 对象的树,下面只要实现树的查找以及引用消解的
		代码就可以了。
     */
    // #@@range/VariableNode{
    public Void visit(VariableNode node) {
        try {
        	//先用currentScope().get 在当前的作用域中查找变量的定义
            Entity ent = currentScope().get(node.name());
            /*
             * 取得定义后,通过调用ent.refered() 来记录定义的引用信息,这样当变量没有被用到
				时就能够给出警告。
             */
            ent.refered();
            /*
             * 还要用node.setEntity(ent) 将定义保存到变量节点中,以便随时能够从VariableNode
				取得变量的定义。
				建立VariableNode 和变量定义的关联
             */
            node.setEntity(ent);
        }
        /*
         * 如果找不到变量的定义,currentScope().get 会抛出SemanticException 异常,
			将其捕捉后输出到错误消息中。
         */
        catch (SemanticException ex) {
            error(node, ex.getMessage());
        }
        return null;
    }

首先查找离栈最近的一层currentScope(),如果找到了就调用setEntity建立VariableNode 和变量定义的关联。这里比较关键的是这个get方法,它首先调用LocalScope的get:

    /*从作用域树取得变量定义.
     * LocalScope#get 是从作用域树获取变量定义的方法。
     * 首先调用variables.get 在符号表中查找名为name 的变量,如果找到的话就返回
		该变量,找不到的话则调用父作用域(parent)的get 方法继续查找。如果父作用域是
		LocalScope 对象,则调用相同的方法进行递归查找。
		如果父作用域是ToplevelScope 的话,则调用ToplevelScope#get
     */
    // #@@rang



 
分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • 编译器开发系列--Ocelot语言6.静态类型检查,编译器--ocelot
  • 编译器开发系列--Ocelot语言2.变量引用的消解,编译器--ocelot
  • 编译器开发系列--Ocelot语言3.类型名称的消解,编译器--ocelot

相关文章

  • 2017-05-26Android Scroll详解(一):基础知识
  • 2017-05-26centos7 系统cache的一例故障及解决
  • 2017-05-26Android提权漏洞CVE-2014-7920&amp;CVE-2014-7921分析,android提权漏洞
  • 2017-05-26Android的动画类型
  • 2017-05-26Android开发学习——画横线竖线,android横线
  • 2017-05-26React-Native系列Android——Touch事件原理及状态效果
  • 2017-05-26android实现无限轮播,android实现轮播
  • 2017-05-26解析View的getDrawingCache方法,getdrawingcache
  • 2017-05-26暂停和恢复Activity Android,activityandroid
  • 2017-05-26一个规范的自定义View——Android开发艺术探索笔记

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • 安卓开发之RecyclerView,安卓recyclerview
    • 安卓开源项目周报0329,安卓开源项目0329
    • Android学习过程中的一些基础笔记,android笔记
    • [android] 手机卫士自定义对话框布局,android卫士
    • Android Studio 快捷键
    • 2.3.3 Button(按钮)与ImageButton(图像按钮)
    • Android中开发工具Android Studio修改created用户(windows环境),androidcreated
    • 硅谷社交14--选择联系人页面,硅谷社交14--联系人
    • Android Studio 错误解决办法
    • android 5.X Toolbar+DrawerLayout实现抽屉菜单

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有