Lua4.0 ZIO缓冲区

来看一下 ZIO 缓冲。

词法分析读一个一个的字符就是从它读的。

或者 umdump 时也是从它读字符(一个 char 字节)的。

缓冲区隔离了下层数据源的不同,对上层提供一致的读取接口。

相关的代码文件是 lzio.h 和 lzio.c 。

先看一下数据结构:

#ifndef ZBSIZE
#define ZBSIZE  256             /* buffer size */
#endif
struct zio { 
  size_t n;                     /* bytes still unread */
  const unsigned char* p;       /* current position in buffer */
  int (*filbuf)(ZIO* z);
  void* u;                      /* additional data */
  const char *name;
  unsigned char buffer[ZBSIZE]; /* buffer */
};

buffer 是缓冲区,数据就存在它里面。

n 是目前缓冲区还有多少没有读取的数据。

p 是缓冲区当前指针位置。

filbuf 是缓冲区数据为空是用来填充数据的。

看下它的接口,三个 open 接口,分别对应不同的源数据类型。

zread 读取下 n 个字节。

以及用宏定义出来的接口。

zgetc 取缓冲区当前字符,调整未读字符个数,及当前位置指针,如果缓冲区中没有可用的字符,则填充。

zungetc 放回缓冲区字符,也就是回退缓冲区当前位置指针,调整未读字符个数。

看下实现。

内存缓冲

static int zmfilbuf (ZIO* z) {
  (void)z;  /* to avoid warnings */
  return EOZ;
}
ZIO* zmopen (ZIO* z, const char* b, size_t size, const char *name) {
  if (b==NULL) return NULL;
  z->n = size;
  z->p = (const unsigned char *)b;
  z->filbuf = zmfilbuf;
  z->u = NULL;
  z->name = name;
  return z;
}

内存缓冲,就是把一个缓冲区当前指针指向内存块 b 。设置相关的参数。

缓冲区填直接返回结束。因为一个内存块读完了就结束了。不存在所谓的再次填充的问题。

字符串缓冲

ZIO* zsopen (ZIO* z, const char* s, const char *name) {
  if (s==NULL) return NULL;
  return zmopen(z, s, strlen(s), name);
}

调用上面的内存缓冲实现。

文件缓冲

static int zffilbuf (ZIO* z) {
  size_t n;
  if (feof((FILE *)z->u)) return EOZ;
  n = fread(z->buffer, 1, ZBSIZE, (FILE *)z->u);
  if (n==0) return EOZ;
  z->n = n-1;
  z->p = z->buffer;
  return *(z->p++);
}
ZIO* zFopen (ZIO* z, FILE* f, const char *name) {
  if (f==NULL) return NULL;
  z->n = 0;
  z->p = z->buffer;
  z->filbuf = zffilbuf;
  z->u = f;
  z->name = name;
  return z;
}

文件缓冲传入文件描述符,及文件名。

重点看下它的填充函数 zffilbuf。

从文件中读取 ZBSIZE 个字符放到 buffer 中。

如果文件结束,则返回 EOZ。

设置未读字符为实际从文件中读取的字符数。

例如,文件过小,或者是最后一次读取时,可能文件中不到 ZBSIZE 个字符。

fread 返回值就是实际读取的字符数。

读取后将返回第一个字符,同时调整未读字符数及当前的指针。这个返回值在 zgetc 中会用到。

从缓冲区读取 n 个字符

size_t zread (ZIO *z, void *b, size_t n) {
  while (n) {
    size_t m;
    if (z->n == 0) {
      if (z->filbuf(z) == EOZ)
        return n;  /* return number of missing bytes */
      zungetc(z);  /* put result from `filbuf‘ in the buffer */
    }
    m = (n <= z->n) ? n : z->n;  /* min. between n and z->n */
    memcpy(b, z->p, m);
    z->n -= m;
    z->p += m;
    b = (char *)b + m;
    n -= m;
  }
  return 0;
}

从缓冲区中读取 n 个字符。

如果缓冲区中没有字符可读,则调用填充函数。注意 zungetc 的使用,因为在填充函数最后,移动指针了。

读取缓冲区未读的和需要读入的字符个数的较小值。

拷贝到输出。

调整缓冲区未读的字符数,缓冲区当前指针及输出的当前指针,调整待读取字符串个数。

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

到目前为止的问题:

> 函数原型优化 luaU_optchunk

> 打印函数原型 luaU_printchunk

> dump 函数原型 luaU_dumpchunk

> 语法分析 luaY_parser

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

时间: 2024-11-10 13:58:58

Lua4.0 ZIO缓冲区的相关文章

Lua4.0 语法分析

Lua 最初使用的是 Yacc 生成的语法分析器,后来改为手写的递归下降语法分析器(Recursive descent parser).因为一般在语言发展的早期,语言的语法还没有稳定下来,变动可能会比较多,用工具可以快速的验证自己的想法.当语法稳定下来之后,一般都会采用手写的语法分析器.因为这样程序员是调试可控的,并且一般也能有更好的性能表现.递归下降的语法分析对编程语言的语法有要求.因 Lua 的语法比较简单,是 LL(1) 文法.所以,手工编写语法分析也就是情理之中的事了. 关于递归下降的语

Lua4.0 词法分析

在说语法分析之前,先说一下词法分析. 因为语法分析时会调用词法分析. 词法分析相关的文件为 llex.h,llex.c. 先来看一下词法分析的头文件. RESERVED 保留字枚举. Token 结构体,词法分析就是把输入源分析成一个个的 token. 这个词比较常见,不再翻译成中文,因为我也不知道它的准确的中文叫什么. LexState 结构体,词法分析状态机,记录当前词法分析的状态以及一些相关的环境. 下面的是几个词分析的方法,注意 lua 中的命名约定. lua*_ 开头的都是 lua 内

Lua4.0 开篇

标题说是 4.0,其实这里分析的是 4.0.1.不过按照 Lua 的版本号规则,小号只做 bug fix .所以,下面的所说的 4.0 指的就是 release 4.0.1(在不引起混淆的情况下). 4.0 发布于 2000 年 11 月,4.0.1 发布于 2002.7,我们看的上一个版本 2.4 则是发布于 1996 年 5 月,怎么说这个版本也是二十一世纪的了. 4.0 算是比较新的版本了,因为它有在线版的代码和文档.在线文档在 http://www.lua.org/manual/,其实从

Lua4.0 参考手册(一)1-3

说明:这个文档是 doc 目录里的 manual.html 文件.原文版权归原作者所有,这篇翻译只是作为学习之用.如果翻译有不当之处,请参考原文.-------------------以下是正文-------------------编程语言 Lua4.0 的参考手册--------------------------------------1 简介--------------------------------------Lua 是一个扩展编程语言,支持通用编程功能与数据描述功能.作为一个强大

Lua4.0 lua_dofile,lua_dostring

这两个函数的定义都位于 ldo.c 中,看看这两个函数都做了什么事儿? 先来看一下 lua_dofile 执行文件 LUA_API int lua_dofile (lua_State *L, const char *filename) {   int status = parse_file(L, filename);   if (status == 0)  /* parse OK? */     status = lua_call(L, 0, LUA_MULTRET);  /* call mai

Lua4.0 编译入口

解决上一篇的问题,上代码了. C 语言程序的入口为 main 函数,Lua 编译器的入口为 luac.c 文件里的 main 函数. 先来看一下 main 函数: int main(int argc, const char* argv[]) {  Proto** P,*tf;  int i=doargs(argc,argv);  argc-=i; argv+=i;  if (argc<=0) usage("no input files given",NULL);  L=lua_o

Lua4.0 代码

这个标题是 2014.11.13 号写的,今天总算是写入内容了. 离上次写代码分析时间有点长,都忘记自己之前是如何写的了. 不管这些历史包袱了,这次轻装上阵,想到哪就写到哪. 开始. 参照 4.0 的 INSTALL 文档内容,编译下.在 Linux 机器上比较简单,make 一下就好了. 在 Windows 上建工程的话,也算是比较容易.这部分之前有描述,这里就不再重复了. 简单的说一下这次的代码分析可能会写什么内容.(注意,这里用"可能"的原因的是,依目前的想法,最大程度上会这么写

Lua4.0 字符串相关

这节看一下字符串相关的: TString 数据结构如下所示,可以看到,TString 不单用于处理字符串,还可用于处理用户自定义数据. /* ** String headers for string table */ /* ** most `malloc' libraries allocate memory in blocks of 8 bytes. TSPACK ** tries to make sizeof(TString) a multiple of this granularity, t

Lua4.0 翻译小结

4.0 手册翻译完了,小结一下. 这一次从 2.4 跳到 4.0,手册绝大部分都得从头翻译.以前的 2.4 的只参考了一小部分,所以,翻译得进度比较慢.不过,好在现在已经翻译完了. 翻译过程中,有几节内容不太熟悉,翻译的可能不好.也有的是因为英语的意思没有太明白.不过,如果遇到不了解的,还是以英文为主. 另外,有一点需要解释一下.为什么一个完整的手册要分这么多篇?一个主要的原因是发博客时的字数限制.博客的字数限制是一万字.为了不破节,就自己这么分篇儿了.再者,觉得一篇太长的话, 每次看后面的内容