第二人生的源码分析(109)脚本的语法分析(3)

系统 1720 0
 

下面来详细地分析语法分析相关的类,以便了解整个语法分析的过程和细节,这样也方便地复用第二人生里的脚本编译器,达到源码复用的目标。先来分析类 LLScriptFilePosition ,它的声明代码如下:

#001   class LLScriptFilePosition

#002   {

#003   public:

 

构造函数,保存脚本所在的行号和列号。

#004      LLScriptFilePosition(S32 line, S32 col)

#005          : mLineNumber(line), mColumnNumber(col), mByteOffset(0), mByteSize(0)

#006      {

#007      }

#008  

 

析构函数。

#009      virtual ~LLScriptFilePosition() {}

#010  

 

下面函数接口实现递归处理。

#011      virtual void recurse(FILE *fp, S32 tabs, S32 tabsize,

#012                          LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg,

#013                          LLScriptScope *scope, LSCRIPTType &type, LSCRIPTType basetype, U64 &count,

#014                          LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize,

#015   LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata) = 0;

 

获取代码的大小。

#016      virtual S32 getSize() = 0;

#017  

 

输出对齐字符。

#018      void fdotabs(FILE *fp, S32 tabs, S32 tabsize);

#019  

 

保存当前的行号。

#020      S32 mLineNumber;

 

保存当前的列号。

#021      S32 mColumnNumber;

#022  

 

字节偏移位置。

#023      S32 mByteOffset;

 

字节的大小。

#024      S32 mByteSize;

#025   };

 

通过上面这个类来实现代码行号和列号的保存,并且可以递归调用生成代码。这个类是基类,后面会有很多类都继承它,用它来保存单词是出现在那里的,下面就来看看单词出现的类型,它的声明如下:

#001   class LLScriptType : public LLScriptFilePosition

从这里可以看到它是继承上面介绍的类 LLScriptFilePosition

 

#002   {

#003   public:

 

构造函数,可以初始化保存行号,列号和单词的类型。

#004      LLScriptType(S32 line, S32 col, LSCRIPTType type)

#005          : LLScriptFilePosition(line, col), mType(type)

#006      {

#007      }

#008  

 

析构函数。

#009      ~LLScriptType() {}

#010  

 

递归函数接口的实现。

#011      void recurse(FILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg, LLScriptScope *scope, LSCRIPTType &type,

#012   LSCRIPTType basetype, U64 &count, LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize, LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata);

 

获取大小的实现。

#013      S32 getSize();

#014  

 

只存单词的类型。

#015      LSCRIPTType mType;

#016   };

#017  

 

在第 15 行里定义一个类型 LSCRIPTType ,这是脚本文件里出现的类型,它的定义如下:

#001   typedef enum e_lscript_types

#002   {

 

空类型。

#003      LST_NULL,

 

整数类型。

#004      LST_INTEGER,

 

浮点数类型。

#005      LST_FLOATINGPOINT,

 

字符串类型。

#006      LST_STRING,

 

关键字类型。

#007      LST_KEY,

 

数组类型。

#008      LST_VECTOR,

 

四元数类型。

#009      LST_QUATERNION,

 

列表类型。

#010      LST_LIST,

 

未有定义类型。

#011      LST_UNDEFINED,

 

结束类型。

#012      LST_EOF

#013   } LSCRIPTType;

 

因此,上面的类里只能保存这几种类型,下面再来看类 LLScriptType 的实现代码:

#001   void LLScriptType::recurse(FILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg, LLScriptScope *scope, LSCRIPTType &type,

#002   LSCRIPTType basetype, U64 &count, LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize, LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata)

#003   {

 

如果脚本代码有错,就不用处理。

#004      if (gErrorToText.getErrors())

#005      {

#006          return;

#007      }

 

根据编译那一遍进行不同的处理。

#008      switch(pass)

#009      {

 

这两遍是输出类型名称。

#010      case LSCP_PRETTY_PRINT:

#011      case LSCP_EMIT_ASSEMBLY:

根据类型 mType 从数组 LSCRIPTTypeNames 里获取相应的类字符串输出。

#012          fprintf(fp,"%s",LSCRIPTTypeNames[mType]);

#013          break;

 

获取类型。

#014      case LSCP_TYPE:

#015          type = mType;

#016          break;

 

输出 CIL 的汇编。

#017      case LSCP_EMIT_CIL_ASSEMBLY:

#018          print_cil_type(fp, mType);

#019          break;

#020      default:

#021          break;

#022      }

#023   }

#024  

 

获取类型的大小,比如整数是 4 字节。

#025   S32 LLScriptType::getSize()

#026   {

#027      return LSCRIPTDataSize[mType];

#028   }

 

数组 LSCRIPTDataSize 具体值如下:

#001   const S32 LSCRIPTDataSize[LST_EOF] =

#002   {

#003      0,   // VOID

#004      4,   // integer

#005      4,   // float

#006      4,   // string

#007      4,   // key

#008      12, // vector

#009      16, // quaternion

#010      4,   // list

#011      0    // invalid

#012   };

#013  

 

这个数组就是定义每一个类型占用内存的大小。到这里就把类型分析完成了,下一次再来分析其它的代码。

第二人生的源码分析(109)脚本的语法分析(3)


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论