WEB开发网
开发学院网页设计JavaScript 第二人生的源码分析(111)脚本的综合分析 阅读

第二人生的源码分析(111)脚本的综合分析

 2010-09-14 13:09:55 来源:WEB开发网   
核心提示:当语法分析一个脚本完成时,那么就会把整个脚本的分析结果保存起来,第二人生的源码分析(111)脚本的综合分析,在第二人生里把脚本的结果保存到那里呢?现在就来分析这个问题,先来看看语法分析的文件里,#017 LSCP_EOF#018} LSCRIPTCompilePass;因此一个脚本代码需要经过上面13种的组合分析,才会

当语法分析一个脚本完成时,那么就会把整个脚本的分析结果保存起来,在第二人生里把脚本的结果保存到那里呢?现在就来分析这个问题,先来看看语法分析的文件里,有如下的代码:#001  case 3:
#002 #line 277 "indra.y"
#003   {
#004     (yyval.script) = new LLScriptScript(NULL, (yyvsp[(1) - (1)].state));
#005     gAllocationManager->addAllocation((yyval.script));
#006     gScriptp = (yyval.script);
#007   }
#008   break;
第4行里就创建一个LLScriptScript脚本程序保存对象,这个对象保存在全局变量gScriptp里。并且创建时就保存脚本的开始状态(yyvsp[(1) - (1)].state),比如脚本里关键字default的开始,就会创建一个开始状态LLScriptState对象。下面就来分析类LLScriptScript是怎么样保存脚本和分析脚本的,它的声明如下:#001 class LLScriptScript : public LLScriptFilePosition
#002 {
#003 public:
构造函数保存全局储存对象,保存脚本的开始状态。
#004   LLScriptScript(LLScritpGlobalStorage *globals,
#005          LLScriptState *states);
#006 
析构函数删除全局对象。
#007   ~LLScriptScript()
#008   {
#009     delete mGlobalScope;
#010   }
#011 
递归遍历处理语法分析、输出汇编代码、输出字节码等等。
#012   void recurse(FILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg, LLScriptScope *scope, LSCRIPTType &type,
#013 LSCRIPTType basetype, U64 &count, LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize, LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata);
获取生成代码的大小,这里设置返回0。
#014   S32 getSize();
#015 
设置脚本目标生成文件。
#016   void setBytecodeDest(const char* dst_filename);
#017 
脚本程序开始状态保存成员。
#018   LLScriptState      *mStates;
脚本程序的全局作用域。
#019   LLScriptScope      *mGlobalScope;
脚本程序的全局变量。
#020   LLScriptGlobalVariable *mGlobals;
脚本程序的全局函数。
#021   LLScriptGlobalFunctions *mGlobalFunctions;
保存函数属性是否代理能执行。
#022   BOOL          mGodLike;
#023 
#024 private:
保存生成字节码的目标文件。
#025   char mBytecodeDest[MAX_STRING];   /*Flawfinder: ignore*/
#026 };
#027 
通过上面分析,了解了脚本保存的结构,下一次再仔细地分析它是怎么进行脚本处理。
前面介绍了分析脚本类的声明,下面来仔细地分析它的实现代码,理解它的实现过程,也就理解了脚本代码的编译过程,如下:
返回生成的代码大小为0.
#001 S32 LLScriptScript::getSize()
#002 {
#003   return 0;
#004 }
#005 
脚本类的构造函数,主要进行初始化的工作。
#006 LLScriptScript::LLScriptScript(LLScritpGlobalStorage *globals,
#007                LLScriptState *states) :
#008   LLScriptFilePosition(0, 0),
#009   mStates(states), mGlobalScope(NULL), mGlobals(NULL), mGlobalFunctions(NULL), mGodLike(FALSE)
#010 {
设置缺省生成字节码的文件名称。
#011   const char DEFAULT_BYTECODE_FILENAME[] = "lscript.lso";
#012   strncpy(mBytecodeDest, DEFAULT_BYTECODE_FILENAME, sizeof(mBytecodeDest) -1); /*Flawfinder: ignore*/
#013   mBytecodeDest[MAX_STRING-1] = '';
下面开始分析全局变量和全局函数的保存位置。
#014   LLScriptGlobalVariable *tvar;
#015   LLScriptGlobalFunctions *tfunc;
#016   LLScritpGlobalStorage *temp;
#017 
#018   temp = globals;
#019   while(temp)
#020   {
#021     if (temp->mbGlobalFunction)
#022     {
#023       if (!mGlobalFunctions)
#024       {
#025         mGlobalFunctions = (LLScriptGlobalFunctions *)temp->mGlobal;
#026       }
#027       else
#028       {
#029         tfunc = mGlobalFunctions;
#030         while(tfunc->mNextp)
#031         {
#032           tfunc = tfunc->mNextp;
#033         }
#034         tfunc->mNextp = (LLScriptGlobalFunctions *)temp->mGlobal;
#035       }
#036     }
#037     else
#038     {
#039       if (!mGlobals)
#040       {
#041         mGlobals = (LLScriptGlobalVariable *)temp->mGlobal;
#042       }
#043       else
#044       {
#045         tvar = mGlobals;
#046         while(tvar->mNextp)
#047         {
#048           tvar = tvar->mNextp;
#049         }
#050         tvar->mNextp = (LLScriptGlobalVariable *)temp->mGlobal;
#051       }
#052     }
#053     temp = temp->mNextp;
#054   }
#055 }
#056 
这个函数主要实现设置字节码保存的文件名称。
#057 void LLScriptScript::setBytecodeDest(const char* dst_filename)
#058 {
#059   strncpy(mBytecodeDest, dst_filename, MAX_STRING);  /*Flawfinder: ignore*/
#060   mBytecodeDest[MAX_STRING-1] = '';
#061 }
#062 
#063 void print_cil_globals(FILE* fp, LLScriptGlobalVariable* global)
#064 {
#065   fprintf(fp, ".field private ");
#066   print_cil_type(fp, global->mType->mType);
#067   fprintf(fp, " ");
#068   fprintf(fp, global->mIdentifier->mName);    /*Flawfinder: ignore*/
#069   fprintf(fp, "n");
#070   if(NULL != global->mNextp)
#071   {
#072     print_cil_globals(fp, global->mNextp);
#073   }
#074 }
#075
开始递归处理所有脚本树。
#076 void LLScriptScript::recurse(FILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg, LLScriptScope *scope, LSCRIPTType &type,
#077 LSCRIPTType basetype, U64 &count, LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize, LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata)
#078 {
如果分析有出错,就不再处理。
#079   if (gErrorToText.getErrors())
#080   {
#081     return;
#082   }
根据不同的编译遍来作不同的树遍历处理。
#083   switch(pass)
#084   {
输出合适的说明文字。
#085   case LSCP_PRETTY_PRINT:
#086     if (mGlobals)
#087     {
#088       fdotabs(fp, tabs, tabsize);
#089       mGlobals->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount,
#090 NULL);
#091     }
#092 
#093     if (mGlobalFunctions)
#094     {
#095       fdotabs(fp, tabs, tabsize);
#096       mGlobalFunctions->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry,
#097 entrycount, NULL);
#098     }
#099 
#100     fdotabs(fp, tabs, tabsize);
#101     mStates->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL);
#102     break;
进行代码优化,主要删除不需要的代码。
#103   case LSCP_PRUNE:
#104     if (mGlobalFunctions)
#105     {
#106       mGlobalFunctions->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry,
#107 entrycount, NULL);
#108     }
#109     mStates->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL);
#110     break;
全局的作用域检查。
#111   case LSCP_SCOPE_PASS1:
#112     {
#113       mGlobalScope = new LLScriptScope(gScopeStringTable);
#114       // zeroth, add library functions to global scope
#115       S32 i;
#116       char *arg;
#117       LLScriptScopeEntry *sentry;
#118       for (i = 0; i < gScriptLibrary.mNextNumber; i++)
#119       {
#120         // First, check to make sure this isn't a god only function, or that the viewer's agent is a god.
#121         if (!gScriptLibrary.mFunctions[i]->mGodOnly || mGodLike)
#122         {
#123           if (gScriptLibrary.mFunctions[i]->mReturnType)
#124             sentry = mGlobalScope->addEntry(gScriptLibrary.mFunctions[i]->mName,
#125 LIT_LIBRARY_FUNCTION, char2type(*gScriptLibrary.mFunctions[i]->mReturnType));
#126           else
#127             sentry = mGlobalScope->addEntry(gScriptLibrary.mFunctions[i]->mName,
#128 LIT_LIBRARY_FUNCTION, LST_NULL);
#129           sentry->mLibraryNumber = i;
#130           arg = gScriptLibrary.mFunctions[i]->mArgs;
#131           if (arg)
#132           {
#133             while (*arg)
#134             {
#135               sentry->mFunctionArgs.addType(char2type(*arg));
#136               sentry->mSize += LSCRIPTDataSize[char2type(*arg)];
#137               sentry->mOffset += LSCRIPTDataSize[char2type(*arg)];
#138               arg++;
#139             }
#140           }
#141         }
#142       }
#143       // first go and collect all the global variables
#144       if (mGlobals)
#145         mGlobals->recurse(fp, tabs, tabsize, pass, ptype, prunearg, mGlobalScope, type, basetype, count, chunk, heap,
#146 stacksize, entry, entrycount, NULL);
#147       // second, do the global functions
#148       if (mGlobalFunctions)
#149         mGlobalFunctions->recurse(fp, tabs, tabsize, pass, ptype, prunearg, mGlobalScope, type, basetype, count, chunk, heap,
#150 stacksize, entry, entrycount, NULL);
#151       // now do states
#152       mStates->recurse(fp, tabs, tabsize, pass, ptype, prunearg, mGlobalScope, type, basetype, count, chunk, heap, stacksize, entry,
#153 entrycount, NULL);
#154       break;
#155     }
第二次作用域检查,主要检查跳转、函数调用和状态转换。
#156   case LSCP_SCOPE_PASS2:
#157     // now we're checking jumps, function calls, and state transitions
#158     if (mGlobalFunctions)
#159       mGlobalFunctions->recurse(fp, tabs, tabsize, pass, ptype, prunearg, mGlobalScope, type, basetype, count, chunk, heap, stacksize, entry,
#160 entrycount, NULL);
#161     mStates->recurse(fp, tabs, tabsize, pass, ptype, prunearg, mGlobalScope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL);
#162     break;
对脚本的类型进行检查。
#163   case LSCP_TYPE:
#164     // first we need to check global variables
#165     if (mGlobals)
#166       mGlobals->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount,
#167 NULL);
#168     // now do global functions and states
#169     if (mGlobalFunctions)
#170       mGlobalFunctions->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry,
#171 entrycount, NULL);
#172     mStates->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL);
#173     break;
确定所有脚本需的资源大小。
#174   case LSCP_RESOURCE:
#175     // first determine resource counts for globals
#176     count = 0;
#177     if (mGlobals)
#178       mGlobals->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount,
#179 NULL);
#180     // now do locals
#181     if (mGlobalFunctions)
#182       mGlobalFunctions->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry,
#183 entrycount, NULL);
#184     mStates->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL);
#185     break;
输出汇编代码。
#186   case LSCP_EMIT_ASSEMBLY:
#187 
#188     if (mGlobals)
#189     {
#190       fprintf(fp, "GLOBALSn");
#191       fdotabs(fp, tabs, tabsize);
#192       mGlobals->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount,
#193 NULL);
#194       fprintf(fp, "n");
#195     }
#196 
#197     if (mGlobalFunctions)
#198     {
#199       fprintf(fp, "GLOBAL FUNCTIONSn");
#200       fdotabs(fp, tabs, tabsize);
#201       mGlobalFunctions->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry,
#202 entrycount, NULL);
#203       fprintf(fp, "n");
#204     }
#205 
#206     fprintf(fp, "STATESn");
#207     fdotabs(fp, tabs, tabsize);
#208     mStates->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL);
#209     fprintf(fp, "n");
#210     break;
输出虚拟机可以运行的字节码。
#211   case LSCP_EMIT_BYTE_CODE:
#212     {
#213       // first, create data structure to hold the whole shebang
#214       LLScriptScriptCodeChunk *code = new LLScriptScriptCodeChunk(TOP_OF_MEMORY);
#215 
#216       // ok, let's add the registers, all zeroes for now
#217       S32 i;
#218       S32 nooffset = 0;
#219 
#220       for (i = LREG_IP; i < LREG_EOF; i++)
#221       {
#222         if (i < LREG_NCE)
#223           code->mRegisters->addBytes(4);
#224         else if (LSL2_CURRENT_MAJOR_VERSION == LSL2_MAJOR_VERSION_TWO)
#225           code->mRegisters->addBytes(8);
#226       }
#227       // global variables
#228       if (mGlobals)
#229         mGlobals->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, code->mGlobalVariables,
#230 code->mHeap, stacksize, entry, entrycount, NULL);
#231 
#232       // put the ending heap block onto the heap
#233       U8 *temp;
#234       S32 size = lsa_create_data_block(&temp, NULL, 0);
#235       code->mHeap->addBytes(temp, size);
#236       delete [] temp;
#237 
#238       // global functions
#239       // make space for global function jump table
#240       if (mGlobalFunctions)
#241       {
#242       code->mGlobalFunctions->addBytes(LSCRIPTDataSize[LST_INTEGER]*mGlobalScope->mFunctionCount +
#243 LSCRIPTDataSize[LST_INTEGER]);
#244         integer2bytestream(code->mGlobalFunctions->mCodeChunk, nooffset, mGlobalScope->mFunctionCount);
#245         mGlobalFunctions->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, code-
#246 >mGlobalFunctions, NULL, stacksize, entry, entrycount, NULL);
#247       }
#248 
#249 
#250       nooffset = 0;
#251       // states
#252       // make space for state jump/info table
#253       if (LSL2_CURRENT_MAJOR_VERSION == LSL2_MAJOR_VERSION_TWO)
#254       {
#255       code->mStates->addBytes(LSCRIPTDataSize[LST_INTEGER]*3*mGlobalScope->mStateCount + LSCRIPTDataSize
#256 [LST_INTEGER]);
#257       }
#258       else
#259       {
#260       code->mStates->addBytes(LSCRIPTDataSize[LST_INTEGER]*2*mGlobalScope->mStateCount + LSCRIPTDataSize
#261 [LST_INTEGER]);
#262       }
#263       integer2bytestream(code->mStates->mCodeChunk, nooffset, mGlobalScope->mStateCount);
#264       mStates->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, code->mStates, NULL, stacksize, entry,
#265 entrycount, NULL);
#266 
#267       // now, put it all together and spit it out
#268       // we need
#269       FILE* bcfp = LLFile::fopen(mBytecodeDest, "wb");    /*Flawfinder: ignore*/
#270      
#271       code->build(fp, bcfp);
#272       fclose(bcfp);
#273                    
#274       delete code;
#275     }
#276     break;
输出CIL的汇编代码。
#277   case LSCP_EMIT_CIL_ASSEMBLY:
#278 
#279     // Output dependencies.
#280     fprintf(fp, ".assembly extern mscorlib {.ver 1:0:5000:0}n");
#281     fprintf(fp, ".assembly extern LScriptLibrary {.ver 0:0:0:0}n");
#282 
#283     // Output assembly name.
#284     fprintf(fp, ".assembly 'lsl' {.ver 0:0:0:0}n");
#285 
#286     // Output class header.
#287     fprintf(fp, ".class public auto ansi beforefieldinit LSL extends [mscorlib]System.Objectn");
#288     fprintf(fp, "{n");
#289 
#290     // Output globals as members.
#291     if(NULL != mGlobals)
#292     {
#293       print_cil_globals(fp, mGlobals);
#294     }
#295 
#296     // Output "runtime". Only needed to allow stand alone execution. Not needed when compiling to DLL and using embedded runtime.
#297     fprintf(fp, ".method public static hidebysig default void
Main
() cil managedn");
#298     fprintf(fp, "{n");
#299     fprintf(fp, ".entrypointn");
#300     fprintf(fp, ".maxstack 2n");
#301     fprintf(fp, ".locals init (class LSL V_0)n");
#302     fprintf(fp, "newobj instance void class LSL::.ctor()n");
#303     fprintf(fp, "stloc.0n");
#304     fprintf(fp, "ldloc.0n");
#305     fprintf(fp, "callvirt instance void class LSL::defaultstate_entry()n");
#306     fprintf(fp, "retn");
#307     fprintf(fp, "}n");
#308 
#309     // Output ctor header.
#310     fprintf(fp, ".method public hidebysig specialname rtspecialname instance default void .ctor () cil managedn");
#311     fprintf(fp, "{n");
#312     fprintf(fp, ".maxstack 500n");
#313 
#314     // Initialise globals as members in ctor.
#315     if (mGlobals)
#316     {
#317       fdotabs(fp, tabs, tabsize);
#318       mGlobals->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount,
#319 NULL);
#320       fprintf(fp, "n");
#321     }
#322 
#323     // Output ctor footer.
#324     fprintf(fp, "ldarg.0n");
#325     fprintf(fp, "call instance void valuetype [mscorlib]System.Object::.ctor()n");
#326     fprintf(fp, "retn");
#327     fprintf(fp, "}n");
#328 
#329     // Output functions as methods.
#330     if (mGlobalFunctions)
#331     {
#332       fdotabs(fp, tabs, tabsize);
#333       mGlobalFunctions->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry,
#334 entrycount, NULL);
#335       fprintf(fp, "n");
#336     }
#337 
#338     // Output states as name mangled methods.
#339     fdotabs(fp, tabs, tabsize);
#340     mStates->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL);
#341     fprintf(fp, "n");
#342 
#343     // Output class footer.
#344     fprintf(fp, "}n");
#345 
#346     break;
下面进行缺省的处理。
#347   default:
#348     if (mGlobals)
#349       mGlobals->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount,
#350 NULL);
#351     if (mGlobalFunctions)
#352       mGlobalFunctions->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry,
#353 entrycount, NULL);
#354     mStates->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL);
#355     break;
#356   }
#357 }
#358 
通过上面的代码,看到对脚本代码完整的分析过程,其实它是依照下面的状态来进行不同的阶段处理的,如下:#001 typedef enum e_lscript_compile_pass
#002 {
非法编译状态。
#003   LSCP_INVALID,
输出合适的说明文字
#004   LSCP_PRETTY_PRINT,
进行代码化减和优化。
#005   LSCP_PRUNE,
对脚本代码进行全局的作用域检查。
#006   LSCP_SCOPE_PASS1,
对脚本代码进行跳转等作用域检查。
#007   LSCP_SCOPE_PASS2,
对脚本代码进行类型检查。
#008   LSCP_TYPE,
对脚本代码进行需要的资源分配。
#009   LSCP_RESOURCE,
对脚本代码进行汇编输出处理。
#010   LSCP_EMIT_ASSEMBLY,
对脚本代码进行字节码编译输出。
#011   LSCP_EMIT_BYTE_CODE,
对脚本代码进行事件处理计数。
#012   LSCP_DETERMINE_HANDLERS,
输出LIB数据。
#013   LSCP_LIST_BUILD_SIMPLE,
对于栈进行处理。
#014   LSCP_TO_STACK,
函数声明参数处理。
#015   LSCP_BUILD_FUNCTION_ARGS,
对脚本代码进行CIL汇编输出。
#016   LSCP_EMIT_CIL_ASSEMBLY,
脚本处理结束状态。
#017   LSCP_EOF
#018 } LSCRIPTCompilePass;
因此一个脚本代码需要经过上面13种的组合分析,才会真正地处理完脚本的编译,这是一个非常复杂漫长的过程。

Tags:第二 人生 源码

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接