Lua1.1 语法分析

无论是 lua_dostring 或者是 lua_dofile,都调用了语法分析 lua_parse。
在 lua 里面语法分析器是用 yacc 生成的,就是y.tab.c 文件,lua.stx 就是 yacc 的输入文件。
这里说的东西基本上编译原理书里都有介绍,如需要进一步了解,请自行参阅。

在说语法分析之前,说下词法分析。
lua 的词法分析是手写的,手写的词法分析性能比较好,这个在 lua1.1 自带的文档里有说明,
文件名 lua.ps, 第 8 页 (或者 www.lua.org/semish94.html 的 Implementation 节 )
,手写的词法分析器性能提高了 2 倍。
(文件内部的标题为 :The design and implementation of a language for extending applications)。

词法分析的输入就是从 lua_setinput 过来的那个 Input 函数指针。
一些保留字做特殊处理,reserved 数组里存在着所有的保留字。
词法分析的主要函数为 yylex,它由语法分析调用,每次返回一个 token。它内部实现是一个大的 switch case。注意,当 token 的类型为 NAME 时,它要先调用方法 findReserved 检查一下其是否是保留字,如果是的话, 直接返回保留字 token。
token 分为两种,一种只有类型,一种有值和类型。
如果 token 的类型够以描述它自己的话,就不需要值,比如保留字,比较运算符,只有类型便足以识别它自己。
而像数值型就需要值,比方一个数为 789,词法分析会这样返回它:返回一个 NUMBER,它的值为 789。至于语法分析怎么用,是语法分析自己的事。
可以参考它的 Lex 输入文件(虽然该输入文件在 Lua1.1 里没有使用),就是在 src/yacc 目录里的 lua.lex。更容易看出 lex.c 里的那个 swith case 为什么要那样写。

接下来看下语法分析 lua_parse :
y.tab.c 文件

/*
** Parse LUA code and execute global statement.
** Return 0 on success or 1 on error.
*/
int lua_parse (void)
{
 Byte *init = initcode = (Byte *) calloc(GAPCODE, sizeof(Byte));
 maincode = 0; 
 maxmain = GAPCODE;
 if (init == NULL)
 {
  lua_error("not enough memory");
  return 1;
 }
 err = 0;
 if (yyparse () || (err==1)) return 1;
 initcode[maincode++] = HALT;
 init = initcode;
#if LISTING
 PrintCode(init,init+maincode);
#endif
 if (lua_execute (init)) return 1;
 free(init);
 return 0;
}

可以看到在语法分析 yyparse (这个就是由 yacc 生成的语法分析器的入口)之后,调用虚拟机执行指令 lua_execute。

PrintCode 打印字节码,它由 LISTING 宏控制。如果要打印字节码,需要保证 PrintCode 被正常的调用。具体修改请参见打印字节码那篇。

因为这里是由 yacc 生成的,关于 yacc 的内容不是我关注的重点,不再详细说明,感兴趣的可以自行查找相关资料。

我比较喜欢那个从 lua3.1 版本开始的手写的递归下降语法分析,有可能的话到那时再分析下语法分析过程吧。

虽然说 lua1.1 是栈式虚拟机,但是,从他生成的指令却不能保存下来直接使用,而必须从源代码解析后直接生成。可以认为它里面没有编译这一步,一边解释一边执行。到版本 Lua2.4 才可以保存生成的指令,有了独立的编译器,数据和代码的全部信息都保存到编译生成的字节码里。

语法分析的结果是一个字节码指令数组,也就是之前我们看到的字节码展示。
到此,字节码已经生成,编译器前端的工作算是做完了。

时间: 2024-10-24 00:11:22

Lua1.1 语法分析的相关文章

Lua1.0 代码分析 table.c

转载出处:http://my.oschina.net/xhan/blog/307961 table.c 代码分析 全局符号,常量,字符串,关联数组,文件列表的定义. 全局符号: 初始有 5 个基本的符号,Lua 预设的函数和库函数都注册在里面. 常量: 初始的几个常量是 Lua 中 type 的名字. 字符串表,关联数组表,文件列表 所有的这些在 table.c 中定义的这些数组可以认为是 Lua 的全局注册表空间,Lua 的环境. 函数分析 ? 1 2 3 4 5 6 7 8 9 10 11

Lua1.0 脚本初步印象

转载出处:http://my.oschina.net/xhan/blog/305949 先来个 hello, world! 看看解释器是否能正常工作:print("hello, world") 可以正常输出,说明解释器能正常干活.再看看几个官方自带的测试文件是干什么的: array.lua $debug a = @() i=0 while i<10 do  a[i] = i*i  i=i+1 end r,v = next(a,nil) while r ~= nil do  pri

Lua1.1 Lua 的设计和实现 (二)

转载出处:http://my.oschina.net/xhan/blog/309615 (接上篇) -------------------------------------- 实现 -------------------------------------- 扩展语言总是由应用程序以某种方式解释执行的.简单的扩展语言可以直接从源代码进行解释执行.另一方面,嵌入式语言通常是强大的编程语言,具有复杂的语法和语义.一个更有效的嵌入式语言实现技术是设计适合语言需求的虚拟机,编译扩展程序成虚拟机的字节码

Lua1.1 公开发布的第一版

Lua1.1 是官方公开发布的第一版,是事实上的第一版 ,也是最早发布的一版. 代码从这里 www.lua.org/ftp/lua-1.1.tar.gz 下载,事实上在 www.lua.org/versions.html 页面,有所有的可以下下载到的版本. 代码下载下来之后,解压,可以看到这次多了不少目录(和 Lua1.0 的一个孤零零的目录相比). 目录介绍: clients, include, src 目录中是代码. test 目录中是一些测试文件. doc 目录中是文档. 编译: 看目录中

Lua1.0 写在最初

为什么是 Lua忘记是什么时候接触到 Lua 的了,也忘记是为什么接触到她的.现在想想,也许是因为下面两个原因:WOW 里有用到她,我上学的时候,玩过一段时间 WOW,了解一点 WOW 插件的编写,当时觉得这个语言挺有意思的.她是由 C 代码实现的,下载代码看了一下,发现她的官方实现的 C 代码写得很好,我是一个代码爱好者,面对这么优秀的代码,有种相见恨晚之感. 为什么是 Lua1.0我是一个代码爱好者,总觉得看代码的最初实现会比较容易把握作品的脉络.我不知道这种学习方法对不对,不过,或许是强迫

Atitit 表达式原理 语法分析&#160;原理与实践 解析java的dsl &#160;递归下降是现阶段主流的语法分析方法

Atitit 表达式原理 语法分析 原理与实践 解析java的dsl  递归下降是现阶段主流的语法分析方法 于是我们可以把上面的语法改写成如下形式:1 合并前缀1 语法分析有自上而下和自下而上两种分析方法2 递归下降是现阶段主流的语法分析方法,2 于是我们可以把上面的语法改写成如下形式: 1)       Operator="+" | "-" | "*" | "/" 2)       Expression=<数字>

编写语法分析程序

编写语法分析程序 Note: Mr.JY的编译原理! 文法改造 1.文法 1) <program>→{<declaration_list><statement_list>} 2) <declaration_list>→<declaration_list><declaration_stat> | ε 3) <declaration_stat>→int ID; 4) <statement_list>→<sta

atitit.自己动手开发编译器and解释器(2) ------语法分析,语义分析,代码生成--attilax总结

atitit.自己动手开发编译器and解释器(2) ------语法分析,语义分析,代码生成--attilax总结 1. 建立AST 抽象语法树 Abstract Syntax Tree,AST) 1 2. 建立AST 语法树----递归下降(recursive descent)法 2 3. 语法分析概念 2 3.1. 上下文无关语言,非终结符(nonterminal symbol),终结符(terminal symbol).注 2 3.2. 最左推导.当然也有最右推导 3 3.3. 分支预测的

Lua1.1 程序分析一

先试下 globals.lua, 这个是从 Lua1.0 那里拷贝过来的.因为在 Lua1.0 里对这个程序的输出有点疑问,所以这里再执行一下它. 源代码如下:---------------------------$debugk,v=nextvar(k)while k do print(k) k,v=nextvar(k)end---------------------------执行一下输出:typetonumbernextnextvarprintdofiledostringreadfromwr