词法分析实例
在《递归下降算法》一节里,介绍过数学表达式的词法分析,现在正式开始lua语言的词法分析。
以一段简单的lua代码为例:
-- 输出最大值
local a, b = 10.5, 20.00
local c = math.max(a, b)
local d = string.format(
"maxval(%f,%f)=%f", a, b, c)
print(d)
代码逻辑为取a和b的最大值,赋给c,再打印a、b、c的值。
词法分析结果:
local a , b = 10.50 , 20.00
local c = math . max ( a , b
) local d = string . format
( maxval(%f,%f)=%f , a ,
b , c ) print ( d ) <eof>
可以看出,lua的词法分析是按照以下几种类型区分的:
- 标识符:如 local、a、b、math
- 标点符号:如 , = ( )
- 数字:如10.5、20.00
- 字符串:如 "maxval(%f,%f)=%f"
- 注释:以--开头的为注释
词法分析逻辑
lua的词法分析模块将源码文件作为一个字符流读入,每次取出一个字符,根据字符值做不同的处理,用代码实现就是一个超大switch语句。下面逐一介绍各个字符的处理逻辑。
\r 或 \n
linux系统里换行符为"\n",Windows系统换行符为"\r\n",为保证lua代码在两种系统行数一致,将 "\r\n" 和 "\n\r" 作为一行。
减号 -
在lua里'-'有多种可能的意义,如负号、减号、注释、多行注释。
- 若下个字符不为'-',表示负号或减号,如 -100, a-b
- 若下个字符为'-',且下下个字符为'[',按照多行注释处理,如 --[[ 多行注释 ]]
- 否则按照单行注释处理,如 -- 单行注释
左方括号 [
可能为多行字符串,也可能为table取key操作。
- 若为"[[" 或 "[=[" 等格式,读取多行字符串,如 [[ string ]]
- 否则,表示取key操作,如 a["data"]=1
等号 =
- 若下个字符为'=',表示相等比较,如 a==b
- 否则,表示赋值操作,如 a=1
< 或 > 或 ~
- 若下个字符为'=',表示小于等于、大于等于、不等于,如 <= >= ~=
- 否则表示小于、大于
" 或 '
- 表示字符串开始,如 "abc" 或 'abcd'
点号 .
- 若为"...",表示变长参数,如 print(fmt, ...)
- 若为"..",表示字符串连接符,如 a .. b
- 若为".123",表示浮点数 0.123
- 若为"a.b",表示table成员引用,等价于a["b"]
-1
- 文件结束符EOZ
空白字符
- 如 ' ' '\t'
数值
- 如 123、2.2、32e+1、0.2e-2
标识符
- 以字母或下划线开头,后面为字母、数字、下划线,如 abc123, _data
单操作符
- 如 + - * / %
数据结构
typedef union {
lua_Number r;
TString *ts;
} SemInfo;
typedef struct Token {
int token;
SemInfo seminfo;
} Token;
Token结构体用来表示一个分词,token表示分词类型,seminfo存储分词值
分词类型 | token枚举 | 数值存储 | 举例 |
保留字 | TK_FOR | | for |
保留字 | TK_ELSE | | else |
数值 | TK_NUMBER | seminfo.r | 123 |
标识符 | TK_NAME | seminfo.ts | myname |
字符串 | TK_STRING | seminfo.ts | "abc" |
不同于常规的先做词法分析,再做语法分析的步骤,lua以语法分析为主,在需要的时候取出一个分词继续分析,所以取词函数luaX_next在许多地方被调用。
lua词法分析本身比较简单,核心逻辑在 llex.c 文件,代码量不足500行,感兴趣的可以看看。