文档章节

Lua4.0 词法分析

晓寒
 晓寒
发布于 2015/08/13 14:09
字数 1344
阅读 146
收藏 5

在说语法分析之前,先说一下词法分析。

因为语法分析时会调用词法分析。

词法分析相关的文件为 llex.h,llex.c。

先来看一下词法分析的头文件。

RESERVED 保留字枚举。


Token 结构体,词法分析就是把输入源分析成一个个的 token。

这个词比较常见,不再翻译成中文,因为我也不知道它的准确的中文叫什么。


LexState 结构体,词法分析状态机,记录当前词法分析的状态以及一些相关的环境。


下面的是几个词分析的方法,注意 lua 中的命名约定。

lua*_ 开头的都是 lua 内部使用的 API。其中 * 表示不同的模块,比如这里的 luaX_ 表示的就是词法分析相关的接口。

而以 lua_ 开头的 API 则是对外的,比如 lua.h 中的那些。


下面来看下 llex.c 源代码文件。


next(LS) 宏从输入缓冲区中取得下一个字符, zgec 在之前的 ZIO 缓冲区中有介绍。


token2string 数组和 RESERVED 枚举一一对应。

注意它的注释,如果你要调整 RESERVED 枚举中的顺序,需要相应的也修改这里数组中元素的顺序。

这就是 RESERVED 上的注释的含义。

这个字符串数组 "while" 之前的元素都是保留字。

void luaX_init (lua_State *L) {
  int i;
  for (i=0; i<NUM_RESERVED; i++) {
    TString *ts = luaS_new(L, token2string[i]);
    ts->marked = (unsigned char)(RESERVEDMARK+i);  /* reserved word */
  }
}

词法分析的初始化,驻留保留的字符串。

设置 marked 标记以避免垃圾回收。

TString 数据结构和 luaS_new 后面再进行分析。


luaX_checklimit 通过名字可以看出,判断是否超限。


luaX_syntaxerror 语法错误。


luaX_error 出错了。


luaX_token2str 根据 token 取得相应的保留字符串。


luaX_invalidchar 非法字符。


inclinenumber 到下一行,如果行数过多,则出错。

void luaX_setinput (lua_State *L, LexState *LS, ZIO *z, TString *source) {
  LS->L = L;
  LS->lookahead.token = TK_EOS;  /* no look-ahead token */
  LS->z = z;
  LS->fs = NULL;
  LS->linenumber = 1;
  LS->lastline = 1;
  LS->source = source;
  next(LS);  /* read first char */
  if (LS->current == '#') {
    do {  /* skip first line */
      next(LS);
    } while (LS->current != '\n' && LS->current != EOZ);
  }
}

设置输入,包括 Lua 状态机,输入缓冲区,输入源名字,及其它的一些初始化。

程序最后判断首个字符是否为 '#',如果是,则跳过首行。

这是为了 linux 环境中 lua 程序做为可执行脚本时,跳过 #!/usr/bin/lua 这一行。

int luaX_lex (LexState *LS, SemInfo *seminfo);

这个方法才是词法分析程序里的主角。

每次调用这个方法都会返回一个 token。由语法分析 parser 来调用。

程序的主体是一个死循环里的一个 switch case 分支,以当前的字符为分析判断条件。

下面简单的看下它的各分支:

case ' ': case '\t': case '\r':  /* `\r' to avoid problems with DOS */
  next(LS);
  continue;

// 跳过空格,制表符,回车符。

case '\n':
  inclinenumber(LS);
  continue;

// 跳过换行,增加行号。

case '$':
  luaX_error(LS, "unexpected `$' (pragmas are no longer supported)", '$');
  break;

// 非法字符,报错。

case '-':
  next(LS);
  if (LS->current != '-') return '-';
  do { next(LS); } while (LS->current != '\n' && LS->current != EOZ);
  continue;

// 中划线,如果后接其它的字符,则返回它自己,也就是减号。

// 否则,就是注释,跳过注释行。

case '[':
  next(LS);
  if (LS->current != '[') return '[';
  else {
    read_long_string(LS, seminfo);
    return TK_STRING;
  }

// 单中括号,如果后面不是另一个单中括号,返回它。

// 否则,返回一个长字符串。

case '=':
  next(LS);
  if (LS->current != '=') return '=';
  else { next(LS); return TK_EQ; }

// 等号,如果后面不是等号,返回。

// 否则,返回相等。

case '<':
  next(LS);
  if (LS->current != '=') return '<';
  else { next(LS); return TK_LE; }

// 小于号,根据后面的字符决定它是小于还是小于等于。

case '>':
  next(LS);
  if (LS->current != '=') return '>';
  else { next(LS); return TK_GE; }

// 大于号,根据后面的字符决定它是大于还是大于等于。

case '~':
  next(LS);
  if (LS->current != '=') return '~';
  else { next(LS); return TK_NE; }

// 不等号,根据后面的字符决定它是非,或者是不等。

case '"':
case '\'':
  read_string(LS, LS->current, seminfo);
  return TK_STRING;

// 单引号或者双引号,返回字符串。

case '.':
  next(LS);
  if (LS->current == '.') {
    next(LS);
    if (LS->current == '.') {
      next(LS);
      return TK_DOTS;   /* ... */
    }
    else return TK_CONCAT;   /* .. */
  }
  else if (!isdigit(LS->current)) return '.';
  else {
    read_number(LS, 1, seminfo);
    return TK_NUMBER;
  }

// 点,根据点的多少返回相应的操作,如果是单个点后面接数字,返回数字。

case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
  read_number(LS, 0, seminfo);
  return TK_NUMBER;

// 数字

case EOZ:
  return TK_EOS;

// 结束

case '_': goto tname;

// 下划线,跳到 tname 标号。

default:
  if (!isalpha(LS->current)) {
    int c = LS->current;
    if (iscntrl(c))
      luaX_invalidchar(LS, c);
    next(LS);
    return c;
  }

// 如果不是字母,判断是否为控件字符,如果是,返回非法字符。

// 否则返回字。

  tname: {  /* identifier or reserved word */
    TString *ts = luaS_new(LS->L, readname(LS));
    if (ts->marked >= RESERVEDMARK)  /* reserved word? */
      return ts->marked-RESERVEDMARK+FIRST_RESERVED;
    seminfo->ts = ts;
    return TK_NAME;
  }

// 根据是否是保留字符串返回保留字符串,或者返回一个标志符。

static const char *readname (LexState *LS);

读取标志符。

static void read_number (LexState *LS, int comma, SemInfo *seminfo);

读取数字

static void read_long_string (LexState *LS, SemInfo *seminfo);

读取长字符串

static void read_string (LexState *LS, int del, SemInfo *seminfo);

读取字符串


后记

本来想写得很详细。

可是写着写着,觉得很没有必要。

或者,我应该尝试着换一种方式去写。

我得想想,接下来到底该如何?

----------------------------------------

到目前为止的问题:

> TString 数据结构和 luaS_new 

> 函数原型优化 luaU_optchunk

> 打印函数原型 luaU_printchunk

> dump 函数原型 luaU_dumpchunk

> 语法分析 luaY_parser

----------------------------------------


© 著作权归作者所有

上一篇: Lua4.0 语法分析
下一篇: Lua4.0 ZIO缓冲区
晓寒
粉丝 35
博文 119
码字总数 133745
作品 0
海淀
私信 提问
编译原理-词法分析器,语法分析器-课程设计

这是偶然翻出来的一段大学时的代码——词法分析器又称扫描器。词法分析是指将我们编写的文本代码流解析为一个一个的记号,分析得到的记号以供后续语法分析使用。词法分析器的工作是低级别的分...

城邑耕夫
2012/04/10
5.8K
4
C++模板”>>”编译问题与词法消歧设计

原文出处:文艺复兴记,2013-10-09 在编译理论中,通常将编译过程抽象为5个主要阶段:词法分析(Lexical Analysis),语法分析(Parsing),语义分析(Semantic Analysis),优化(Optimization),代...

文艺复兴记,2013-10-09
2017/01/06
0
0
Jsoup代码解读之五-parser(中)

上一篇文章讲到了状态机和词法分析的基本知识,这一节我们来分析Jsoup是如何进行词法分析的。 代码结构 先介绍以下parser包里的主要类: Jsoup parser的入口facade,封装了常用的parse静态方...

黄亿华
2013/08/28
2K
0
Lua4.0 参考手册(二)4.1-4.4

(接上篇) -------------------------------------- 4 语言 -------------------------------------- 这节描述 Lua 的词法,语法和语义。 ------------------- 4.1 词法约定 --------------......

晓寒
2014/11/03
209
0
Go 源码阅读笔记 text/template/parse

文件组成 lex.go 词法定义与解析 node.go node 定义与创建 parse.go 生成 template 语法树 tree lex.go 要点 itemType 常量表次序规则:itemKeyword 用来分界词法中的关键字和其他词法元素,...

喻恒春
2013/05/17
510
0

没有更多内容

加载失败,请刷新页面

加载更多

堆”和“栈

C++作为一款C语言的升级版本,具有非常强大的功能。它不但能够支持各种程序设计风格,而且还具有C语言的所有功能。我们在这里为大家介绍的是其中一个比较重要的内容,C++内存区域的基本介绍。...

SibylY
27分钟前
2
0
总结:Https

一、介绍 简单理解,https即在http协议的基础上,增加了SSL协议,保障数据传输的安全性。 它由以前的http—–>tcp,改为http——>SSL—–>tcp;https采用了共享密钥加密+公开密钥加密的方式 ...

浮躁的码农
29分钟前
3
0
数据库表与表之间的一对一、一对多、多对多关系

表1 foreign key 表2 多对一:表 1 的多条记录对应表 2 的一条记录 利用foreign key的原理我们可以制作两张表的多对多,一对一关系 多对多: 表1的多条记录可以对应表2的一条记录 表2的多条记...

Garphy
今天
7
0
MySQL 表崩溃修复

MySQL日志报错 2019-10-19 13:41:51 19916 [ERROR] /usr/local/mysql/bin/mysqld: Table './initread_hss/user_info' is marked as crashed and should be repaired2019-10-19 13:41:51 1......

雁南飞丶
今天
6
0
Error和Exception

1.Error类和Exception类都是继承Throwable类 2.Error(错误)是系统中的错误,程序员是不能改变的和处理的,是在程序编译时出现的错误,只能通过修改程序才能修正。一般是指与虚拟机相关的问...

大瑞清_liurq
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部