代码生成

语法解析流程简述

lua之类的脚本语言先把源代码翻译成字节码,而后再使用虚拟机执行字节码。
而从源代码到字节码要经过多个过程:

词法解析,语法解析,语义解析,代码生成。
源代码->单词流->语法树->带语义的语法树->字节码。

语义解析主要是完善语法树,添加语义信息:

  1. 设置变量作用域。
  2. 设置break和continue对应的循环语句。

lua的官方实现做了优化,将4步流程压缩成一个。词法解析提供接口供语法解析调用,语法解析、语义解析压缩成一个流程,代码生成提供接口供语法解析使用。这也造成解析代码难以看懂修改。

luna的实现:词法解析还是提供接口,语法解析,语义解析,代码生成是分开的,就好懂很多了。(其中的观察者模式用的不适合)

oms的实现中语义解析合并代码生成中。

词法解析,语法解析,代码生成。
源代码->单词流->语法树->字节码。

指令生成

遍历语法树生成代码的过程比较无脑,对每个语法树节点类型写一个解析函数。
一个例子。

void HandleBlock(Block tree)
{
    foreach(var stmt in tree.statements)
    {
        if (stmt is DoStatement)
            HandleDoStatement(stmt as DoStatement);
        else if (stmt is WhileStatement)
            HandleWhileStatement(stmt as WhileStatement);
        else if (stmt is IfStatement)
            HandleIfStatement(stmt as IfStatement);
        else if (stmt is ForStatement)
            HandleForStatement(stmt as ForStatement);
        else if (stmt is ForEachStatement)
            HandleForEachStatement(stmt as ForEachStatement);
        else if (stmt is ForInStatement)
            HandleForInStatement(stmt as ForInStatement);
        else if (stmt is FunctionStatement)
            HandleFunctionStatement(stmt as FunctionStatement);
        else if (stmt is LocalFunctionStatement)
            HandleLocalFunctionStatement(stmt as LocalFunctionStatement);
        else if (stmt is LocalNameListStatement)
            HandleLocalNameListStatement(stmt as LocalNameListStatement);
        else if (stmt is ReturnStatement)
            HandleReturnStatement(stmt as ReturnStatement);
        else if (stmt is BreakStatement)
            HandleBreakStatement(stmt as BreakStatement);
        else if (stmt is ContinueStatement)
            HandleContinueStatement(stmt as ContinueStatement);
        else if (stmt is AssignStatement)
            HandleAssignStatement(stmt as AssignStatement);
        else
            HandleExpRead(stmt);
    }
}

指令系统和局部变量分配

lua的指令是带寄存器地址的,最多3地址,一个地址一个字节,也就限制了局部变量的总数不可能超过256个。
自己实现时,指令也是带寄存器地址的,最直接的好处是,指令能少很多。然后局部变量分配就是基于栈的了,简单方便。
简化的指令bit分配。

code: int32_t
A   : uint8_t
B   : uint8_t
C   : uint8_t
Bx  : int16_t (B+C)

局部变量每个函数单独分配,从0开始,定义一个局部变量就+1,退出block时回收当前作用域内的。
临时分配的也要及时回收,如

void HandleAssignStatement(AssignStatement tree)
{
    HandleExpList(tree.exp_list, tree.var_list.Count);
    // var list
    int register = GetNextRegisterId();
    ResetRegisterId(register + tree.var_list.Count);
    for(int i = 0; i < tree.var_list.Count; ++i)
    {
        HandleVarWrite(tree.var_list[i], register + i);
    }
    ResetRegisterId(register);// 回收临时分配的局部变量。
}

语义分析部分

在遍历语法树时,要维护作用域树循环结构链表

//"while" exp "do" block "end"
void HandleWhileStatement(WhileStatement tree)
{
    EnterLoop();// 进入循环
    EnterBlock();// 进入新的作用域
    HandleExpRead(tree.exp);
    // jump to loop tail when expression return false
    var f = GetCurrentFunction();
    var code = Instruction.ABx(OpType.OpType_JmpFalse, GetNextRegisterId(), 0);
    int index = f.AddInstruction(code, -1);
    AddLoopJumpInfo(JumpType.JumpTail, index);
    HandleBlock(tree.block);// 变量循环block
    LeaveBlock();// 退出作用域
    // jump to loop head
    code = Instruction.Bx(OpType.OpType_Jmp, 0);
    index = f.AddInstruction(code, -1);
    AddLoopJumpInfo(JumpType.JumpHead, index);
    LeaveLoop();// 退出循环
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容

  • 指令集 lua_capture_error_log lua_use_default_type lua_malloc...
    吃瓜的东阅读 11,965评论 0 2
  • 上次我们翻译了由Unity开发人员JOSH PETERSON所写的、IL2CPP深入讲解系列的第一期,现在第二期的...
    IndieACE阅读 9,398评论 0 11
  • 前面讲过语法的解析之后,代码生成方面就简单很多了。虽然myc是一个简单的示例编译器,但是它还是在解析的过程中生成了...
    懿民阅读 463评论 0 1
  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,174评论 11 349
  • 姓名:顾君 单位:宁波大发化纤有限公司 学习组:第234期努力一组 【日精进打卡第140天】 【知~学习】 《六项...
    JASONGU_2f28阅读 218评论 0 0