zl程序教程

您现在的位置是:首页 >  工具

当前栏目

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

源码 分析 脚本 综合 第二 人生 112
2023-09-14 09:10:42 时间
 

前面介绍了分析脚本类的声明,下面来仔细地分析它的实现代码,理解它的实现过程,也就理解了脚本代码的编译过程,如下:

 

返回生成的代码大小为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] = '/0';

 

下面开始分析全局变量和全局函数的保存位置。

#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] = '/0';

#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, "GLOBALS/n");

#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 FUNCTIONS/n");

#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, "STATES/n");

#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.Object/n");

#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 managed/n");

#298         fprintf(fp, "{/n");

#299         fprintf(fp, ".entrypoint/n");

#300         fprintf(fp, ".maxstack 2/n");

#301         fprintf(fp, ".locals init (class LSL V_0)/n");

#302         fprintf(fp, "newobj instance void class LSL::.ctor()/n");

#303         fprintf(fp, "stloc.0/n");

#304         fprintf(fp, "ldloc.0/n");

#305         fprintf(fp, "callvirt instance void class LSL::defaultstate_entry()/n");

#306         fprintf(fp, "ret/n");

#307         fprintf(fp, "}/n");

#308 

#309         // Output ctor header.

#310         fprintf(fp, ".method public hidebysig  specialname  rtspecialname instance default void .ctor ()  cil managed/n");

#311         fprintf(fp, "{/n");

#312         fprintf(fp, ".maxstack 500/n");

#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.0/n");

#325         fprintf(fp, "call instance void valuetype [mscorlib]System.Object::.ctor()/n");

#326         fprintf(fp, "ret/n");

#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种的组合分析,才会真正地处理完脚本的编译,这是一个非常复杂漫长的过程。