//标签A://条件不满足 && $goto(B);//A代码段//$goto(END);//标签B://条件不满足 && $goto(C);//B代码段//$goto(END);//标签C://条件不满足 && $goto(END);//C代码段//条件END://空代码
不同的宿主语言的语法形式和底层的支持不同, 如果我们的翻译的目标是lua, 众所周知在lua中是没有switch 语句的, 也没有goto或者jmp
这种跳转命令的。
如果在lua中我们要使用状态转移类似的指令可以通过字典的hash特性,每个标识是字典的一个key, 执行字典的内联函数来替换多个if的丑陋的代码。 因为swich的分支是可以预测的, 所以我们在做分析预测的时候要加入一个如果全部都不命中分支。
对比之前的代码:
cls.SwitchCase = function (e) { var test; if(e.test) { test = exports.GetValueByType( e.test.type, e.test); } var codes = []; if(e.consequent) { var consequent = e.consequent; var len = consequent.length; for(var i =0;i< len;i++) { codes.push(exports.GetValueByType( consequent[i].type, consequent[i]) + "\n"); } } var code = ""; var len = exports.stack_switch.length; if(!exports.stack_switch[0]) { console.log("[error] switch stack error."); } if(!test) { var label = exports.stack_switch.pop(); code += label+":\n"; code += codes.join(""); } else { if(codes.length == 0) { exports.merge_switch.push("$istrue("+exports.stack_switch[0]+"!="+test+")"); return ""; } var label = exports.stack_switch.pop(); code += label+":\n"; if(len-1 < 0) { var next = exports.stack_switch[0]; }else { var next = exports.stack_switch[exports.stack_switch.length-1]; } if(exports.merge_switch.length != 0) { test = exports.merge_switch.join("&&") + "&& $istrue("+exports.stack_switch[0]+"!="+test+")"; exports.merge_switch = []; } else { test = "$istrue("+exports.stack_switch[0]+"!="+test+")"; } code += test + " && $goto("+next+");\n " + codes.join(""); } return code; } ///end of SwitchCaseCODE318790496971174301H:$istrue(a!=1) && $goto(CODE318790431625819229L); print (1)CODE318790431625819229L:$istrue(a!=1) && $goto(CODE31879087087226576H); print (2)
利用hash的代码性能要比这种顺序分支的性能要好。特别是在分支条件很多的情况。测试代码。。。
switch (a) { case 1: print(1) break; case 2: print(2) break; default: print(3) break;}
生成:
local exports=exportslocal CODE080090262481404737L = {[1]="CODE080090481865709301H",[2]="CODE080090448711626623L",["default"]="CODE08009020260687113H"}if exports["CODE08009020260687113H"] == nil thenexports["CODE080090481865709301H"]=function ()print (1)endexports["CODE080090448711626623L"]=function ()print (2)endexports["CODE08009020260687113H"]=function ()print (3)endendlocal __indexer__ = CODE080090262481404737L[a]if __indexer__ == nil then __indexer__=CODE080090262481404737L["default"]endexports[__indexer__]()
好了。。这个问题就解决了。 其实我们可以预处理这些函数块, 并且让这些函数脱离标准流水线, 作为预处理的代码,但是为了得到函数生命周期内的上下文(只在定义的时候继承) 必须定义在代码自省的位置。 如果是这样就不得不加上一个code 缓存的判断。 多次一举。