当前位置:七道奇文章资讯编程技术VC/C++编程
日期:2011-03-22 13:54:00  来源:本站整理

<b>手把手教你写脚本引擎(五)——简单的高级语言(3,标记表)</b>[VC/C++编程]

赞助商链接



  本文“<b>手把手教你写脚本引擎(五)——简单的高级语言(3,标记表)</b>[VC/C++编程]”是由七道奇为您精心收集,来源于网络转载,文章版权归文章作者所有,本站不对其观点以及内容做任何评价,请读者自行判断,以下是其具体内容:

标记表的构造的复杂度跟语言的语义法则的复杂度有关.关于C#来说,每一个标记都附带了一大堆信息,比方位置啦,所在的namespace啦,范例啦什么的.关于JavaScript来说,标记表几近是不需求的,因为东西都动态了,编译时几近不查抄内容.语义解析的输出是标记表,代码生成的输入是标记表和语法树.因此语法树除了放语法相关的内容,语义相关的内容最好放到标记表里面(比方说表达式的范例啦,语句的scope后果啦).关于一个实际中的标记表组织可以看CMinus的语义解析后果.

首先我们要办理范例的表达问题.一门复杂的语言的范例有很多种.这里的种类指的不是int和string的辨别,而是函数范例、构造范例这种辨别.每一种范例还有很多附带的属性.在语义解析的历程中,我们常常要对比两个范例能否一致.于是标记表的范例表达要计划成易于读取、改正和对比.

我们普通由两种办理办法.第一种办法是用一个担当构造来表达.定义一个基类TypeBase,然后底下一堆担当.乍一看很OOP,实际不然.语义解析的时刻我们对每一种特别的范例都有一些特别的操作,我们还是举那个判断范例能否相等的操作来阐明一下.我们知道OOP里面的虚函数办理了一维的分配问题.我们拿到一个Base,对Base->Method求值,老是可以按照Base的实际范例来求值.假如我们需求对两个范例同时举行分配呢?比方说Equal(Base1,Base2),这种操作当且仅当Base1和Base2的实际种类相同才有对比的意义.这个时刻我们改革成Base1->Equal(Base2)的话,也是免不了对Base2举行一下dynamic_cast还是什么近似的操作的.

所以我个人对比偏向于第二种做法.我们为每一个范例成立一个唯一的ID.比方说int 是0啦,int(int,int)是1啦,int*是2什么的.对比两个范例能否相等就直接拿ID去对比,ID相等则范例相等,ID不相等则范例不相等.在实际操作上怎么做呢?我们知道语义解析的历程中会产生出一堆(理论上可认为无穷多的)新范例.每一种范例都有一些属性.比方说基本范例是有限的,可以用enum来表达.而函数范例需求返回值和参数范例表.于是我们拿属性去要一个ID的时刻,标记表首先查抄这个范例能否已经存在,存在则返回对应的ID,不存在则成立一条新的记录,然后绑定一个新的ID.比方CMinus的范例表采取以下接口分配ID:

class VL_CMinusTypeTable : public VL_Base
{
public:
VInt GetPrimitiveType(VLE_CMinusPrimitiveType Type);
VInt GetPointer(VInt Type);
VInt GetArray(VInt Type , VInt Count);
VInt GetFunction(VInt ReturnType , VL_List<VInt , true>& ParameterTypes);
VInt CreateStruct();
VL_CMinusTypeSlot* GetType(VInt Type);
};

假如我们已知一个范例的ID,求其指针范例的ID,就调用GetPointer(TypeID).经过这一套函数的处理,我们老是可以不用耽忧能否在什么地方让两个ID指向了相同的范例,大概一个范例不当心拥有了多个ID,非常好管理.

第二个问题就是要保存每一个表达式的范例和语句的Scope了.我不倡议将这些信息保存在语法树里面.缘由对比复杂,因为一份代码在差别的上下文中大概有差别的意思,然后我们有一天忽然有需求将这些环境中的这份代码的语义解析后果保存下来的话,假如东西本来是存在语法树里面的,那就完蛋了,只能去复制语法树了.于是我倡议将语法解析得不到的信息通通存进标记表.因为表达式和语句都是指针,我们只需求一些map便可以将表达式和语句的附加信息存起来了.

第三个问题是scope.一个变量或参数的作用范围是有限的,于是我们只好成立一个scope树,此中每一个节点都看得到父节点,至于能不能看到子节点我认为是无所谓的.于是关于一个具体的scope来说,一个scope就变成了一个链表,保存了当前scope的全部标记名,然后还能知道直接或间接的父scope.下面举个直观的例子.假定我们有代码:

int A=0;
int B(int C,int D)
{
  int E=0;
}

为了处理这份代码,我们成立了三个scope.第一个是全局scope,记录了A和B.第二个是函数scope,记录了C和D.第三个是属于语句的一个scope,记录了E.于是我们用一个链表把他们串起来:语句scope -> 函数scope -> 全局scope.

这样做的好处是我们查找scope会变得很便利.比方目前的上下文是语句scope,那么它理应可以瞥见变量、参数、全局函数和全局变量.增添一个标记也很便利,只要当前的scope没有这个名字,不管上面的scope有没有我们都可以增添,增添完就把上面的scope的同名标记给覆盖了.

一个scope其实还可以记录其他的东西的,比方距离近来的循环表达式啦(用来判断break能否应当存在),所属的函数啦(return背面要不要接表达式),还有其他的很多杂七杂八的东西.

第四个问题是若何成立标记表.之前的文章我们把语句和表达式都成立成了两个大型的担当构造.表达式增添一个函数叫GetType,返回一个ID.语句成立一个函数叫Validate,用来考证语句能否合理.他们的参数都是标记表和当前的scope,这样的话,表达式为了成立范例就会产生出一堆ID,语句为了让表达式可以知道每一个变量的范例就要成立scope.这么一递归下去,标记表也有了,范例也查抄完了.所以上文才会说语义解析产生标记表.

标记表就介绍到这里了.一个高级语言所碰到的基本的问题其实都讲得差不多了.接下来的文章就针对具体的问题举行讲授了,比方担当、反射、垃圾汇集等等的跟具体语言相关的问题.


  以上是“<b>手把手教你写脚本引擎(五)——简单的高级语言(3,标记表)</b>[VC/C++编程]”的内容,如果你对以上该文章内容感兴趣,你可以看看七道奇为您推荐以下文章:
  • <b>hosts是什么 hosts文件在什么位置 若何改正hosts</b>
  • <b>在 Windows 8 中手动安装语言包</b>
  • <b>五个常见 PHP数据库问题</b>
  • Windows中Alt键的12个高效快速的利用本领介绍
  • <b>MySQL ORDER BY 的实现解析</b>
  • <b>详解MySQL存储历程参数有三种范例(in、out、inout)</b>
  • <b>Win8系统恢复出来经典的开始菜单的办法</b>
  • <b>Win8系统花屏怎么办 Win8系统花屏的办理办法</b>
  • <b>Windows 7系统下无线网卡安装</b>
  • <b>为什么 Linux不需求碎片整理</b>
  • <b>Windows 8中删除账户的几种办法(图)</b>
  • <b>教你如安在win7下配置路由器</b>
  • 本文地址: 与您的QQ/BBS好友分享!
    • 好的评价 如果您觉得此文章好,就请您
        0%(0)
    • 差的评价 如果您觉得此文章差,就请您
        0%(0)

    文章评论评论内容只代表网友观点,与本站立场无关!

       评论摘要(共 0 条,得分 0 分,平均 0 分) 查看完整评论
    Copyright © 2020-2022 www.xiamiku.com. All Rights Reserved .