lua 语言如何 读取文本的每一行数字值,把每行得到的码行数字赋予给x1,x2,x3,x4,x5等?
local file=io.open("sth.txt")
local line_no=1
for line in file:lines() do
_G['x'..line_no]=tonumber(line)
end
Lua5.4 源码剖析——杂谈 之 如何调试Lua源码
我们有时候写了一段Lua代码,希望能通过断点调试的码行方式看一下我们的代码在执行过程中Lua虚拟机的状态与运行流程。本篇教程我将教大家Windows与Mac环境下如何配置Lua源码调试环境。码行
Lua调试环境需要有Lua源码,码行h5游戏网站源码我们从官网下载源码:
Windows下Lua源码调试环境搭建
1)下载Visual Studio,码行可自行在官网下载最新版本即可:
2)打开VIsual Studio,码行创建一个新的码行C++控制台工程,我这里以Visual Studio 版本进行举例:
项目可任意命名,码行本例中我们命名为TestLua:
3)工程中添加Lua源码文件:
3.1)拷贝源代码文件到项目的码行文件夹,Makefile文件可以不拷贝:
3.2)把上面这些文件导入工程:
"
.h
头文件导入:导入所有".h"后缀文件到头文件文件夹中(右键头文件->添加->现有项):
"
.c
源文件导入:导入所有".c"后缀文件到源文件的码行文件夹(右键源文件->添加->现有项):
4)生成exe可执行文件:
文件都导入完成了,这时候如果按"生成"或者"F5",码行会有如下的码行报错:
这是因为除了我们创建项目工程的时候自带源文件中的一个main函数以外,Lua源码中也定义了两个Main函数。码行他们分别对应的是luac编译工具的启动函数和lua运行工具的启动函数。要想编译通过,我们只需要根据自己要调试目的,从3个main里面把用不到的2个main删掉或者重命名即可。
本例中,我打算在自己的main里面实现通过dofile函数执行一个Lua文件的功能,所以我不需要启动lua和luac指令控制台,所以我把他们的操作系统源码分析main函数改名:
luac.c:把main函数改名为luac_main函数:
lua.c:把main函数改为lua_main:
上述源码中多余的2个main函数都改名了,这时候已经能编译通过并生成出exe可执行文件了。
接下来我们可以开始编写自己的main函数逻辑了,打开TestLua.cpp,输入以下内容,作用是运行一个在项目目录下名字为"testlua.lua"的lua文件:
5)testlua.lua文件创建与编写:
上述代码在运行时会执行testlua.lua文件,接下来我们就需要在工程目录下创建这个将要被执行的testlua.lua文件:
打开testlua.lua文件,添加任意lua代码,这里我们简单调用print打印一句信息:
6)在Visual Studio中按“F5”开启调试,可以看到控制台被成功运行,我们的lua文件也被成功执行,打印出了信息:
7)断点调试指令OpCode:
学习过我的《Lua源码剖析 之 虚拟机》系列教程的同学应该知道Lua的指令就是各种OpCode的执行,我们可以在《lvm.c》的下面这个地方加断点再按F5重新启动程序,程序在每执行一条OpCode指令就会在这处代码断点下来,这时候我们就能看到下一条要执行的OpCode是哪一条了:
在本例中的print函数最终会执行到OP_CALL这个调用分支:
Windows环境下搭建Lua源码调试环境的教程到此结束。
Mac下Lua源码调试环境搭建
因为大部分流程与上面Windows一样,所以我下面会省略一些重复步骤。
1)下载XCode,可自行在AppStore进行下载。
2)打开XCode,创建一个新的C++控制台工程,本例中命名为TestLua:
3)工程中添加Lua源码文件:
3.1)拷贝源代码文件到项目的文件夹,Makefile文件可以不拷贝:
3.2)把拷贝后的易语言刷流量源码文件导入工程:
不需要区分".h"和".cpp",全选导进来就好了:
4)与Windows流程同样,把源码自带的2个main函数改名:
luac.c:把main函数改名为luac_main函数:
lua.c:把main函数改为lua_main:
把源码中多余的2个main函数都改名了,接下来同样,开始编写我们的main.cpp,打开该文件并添加代码如下代码。为了在mac下文件读取代码更简洁,在下面的Lua文件我暂时先使用文件的绝对路径,暂时把testlua.lua文件放在我的mac的桌面上进行读取:
5)在mac的桌面上创建testlua.lua文件,添加任意lua代码:
6)同理可正常运行或者加断点进行调试,这里不再赘述:
总结
本文我们学习了如何在Windows与Mac下搭建Lua源码调试环境。另外,我们上述使用的例子是通过dofile运行一个lua文件,同学们也可以试试保留lua.c里面的main函数,删掉另外两个,此时按开始调试可启动lua的即时解析控制台,在控制台里面可自行输入任意Lua代码,并可断点查看即时运行状态或最终结果,感兴趣的同学可以自行试试。
不过,尽管能调试Lua源码,但如果之前没有学习过我的那些Lua源码剖析教程,可能很多地方会看不懂,易语言清理垃圾源码所以这里建议有空的同学还是可以先去学习一下的。
谢谢阅读。
求Lua 实现单词计数的代码
给你个全功能的wc (linux命令wc 即word count)
local BUFSIZE = 2^ -- 8K
local f = io.input(arg[1]) -- open input file
local cc, lc, wc = 0, 0, 0 -- char, line, and word counts
for lines, rest in io.lines(arg[1], BUFSIZE, "*L") do
if rest then lines = lines .. rest end
cc = cc + #lines
-- count words in the chunk
local _, t = string.gsub(lines, "%S+", "")
wc = wc + t
-- count newlines in the chunk
_,t = string.gsub(lines, "\n", "\n")
lc = lc + t
end
print(lc, wc, cc) --打印行数,单词数,字符数
示例来自 《Programming in Lua third edition》
Lua 5.4 String
在Lua 5.4中,字符串的基本实现是将字符串存储在contents变量中。由于Lua使用C语言编写,因此字符串末尾会添加一个“\0”,导致字符串的总大小增加。
正如之前Lua基础讲解中提到的,Lua将字符串分为short string和long string。其宏定义如下:
这意味着小于等于字节的是短字符串,而大于字节的是长字符串。在创建方式和存储上,它们存在差异。
下面通过代码来讲解字符串的创建过程:
在创建字符串时,会调用luaS_new()函数,该函数主要完成以下两项任务:
接下来,我们将介绍全局的stringcache。在global_State结构中,倒数第四个就是strcache,它是旅行社源码 php一个二维数组,其大小由STRCACHE_N和STRCACHE_M决定。STRCACHE_N是数组的行数,STRCACHE_M是列数。
接下来,我们将看看luaS_newlstr()函数的功能:
然后,我们再来探讨internshrstr()函数的作用:
在创建过程中,我们再次使用global_State结构中定义的另一个stringtable,在第7行stringtable strt;。这个哈希表用于保存当前所有创建的短字符串,并以开散列的方式进行管理。
创建过程如下:
为什么第一步只是将已有元素和桶数量进行比较?因为开散列有一个负载因子的概念,即已存放元素数量与桶数量之比。如果大于1,说明比较拥挤,在没有hash冲突的情况下,一个桶一个元素,但如果有hash冲突,一个桶可能对应多个元素,这会导致链表查询速度变慢,因此需要避免。控制负载因子的大小应小于1。
第二步,扩容操作实际上调用的是luaS_resize函数。luaS_resize是实际改变stringtable桶数量的函数。它目前只会被两个地方调用到:
当newsize > oldsize时,顺序是先进行扩容,然后进行rehash。扩容会调用realloc函数,而rehash的代码非常简洁,只需遍历每个桶,将每个桶中的元素重新哈希到正确的桶中。
当newsize < oldsize时,顺序是相反的,需要先根据newsize进行rehash,然后在确保所有元素已收缩到newsize个桶中后,才能进行shrink操作,这里也会调用realloc函数。
在了解了短string的生成后,我们来探讨长string的生成——luaS_createlngstrobj()。
最后,我们来看看长短字符串的hash计算,这两个在实现上存在差异:
这意味着:短字符串的所有字符都会用于计算hash,step = 1。然而,长字符串的hash计算并非如此。以长度为的字符串为例,其step为step = 2+1 = 3。
Lua字节码文件结构及加载过程
在探索Lua的世界中,字节码文件结构与加载过程是程序运行效率的关键。本文将为你揭示Lua 5.4.3的内部奥秘,从文件头到函数块,逐一剖析其构造与加载流程。让我们一起深入理解Lua的加载逻辑,通过luaU_undump函数,将源代码编织成二进制的指令织锦。
首先,Lua字节码文件由文件头和函数块两大部分组成,如同编织的经纬线,共同构建起程序的基石。文件头包含了Lua的签名("\x1bLua")、版本号(例如Lua 5.4.3的)、官方格式号(0)以及LUAC_DATA的校验信息。紧接着是指令、整型和浮点型大小的指示,每个部分都承载着特定的含义,确保文件的正确性。
深入解析luaU_undump函数,它是Lua加载阶段的灵魂,处理着二进制文件的字节码。这个函数首先会进行头检查,包括Lua签名、版本号、格式号等,随后是lua_Integer和lua_Number的长度指示。例如,Lua 5.4.3的头字节包含整型、浮点型校验和文件头信息,通过反编译,我们可以看到函数原型的细节,如函数名、参数、行数和指令数量等。
在Lua 5.4.3的loadFunction函数中,我们看到函数块被精细划分,包括源代码、行号、参数、可变参数、栈大小、字节码、常量、上值和闭包等元素。这些元素通过loadStringN、loadUnsigned等函数逐一加载,确保每个部分都按照特定规则组织。
文件结构的关键部分包括loadConstants(如main函数中的常量"a")、loadUpvalues(如全局表"_ENV"的加载)、loadProtos(函数内部原型的加载),以及loadDebug信息,如行号和变量名称。比如,main函数的4个指令和a函数的5个,以及upvalues数据" 5f 4e",都在这个过程中得到解析。
在Lua的实现中,lauxlib.c、lapi.c、ldo.c和lundump.c等核心文件,以及lua_load、f_parser、luaU_undump、checkHeader和loadFunction等核心函数,共同构建起字节码的编译和加载流程。从源代码到二进制,再到虚拟机的执行,每一个环节都经过精心设计,以达到高效的运行效率。
总的来说,Lua字节码文件结构的复杂性映射出其内在的执行效率。理解这些细节,不仅有助于我们编写更优化的脚本,也让我们对Lua的底层机制有了更深的认识。让我们继续探索luaU_undump的更多奥秘,揭开Lua字节码加载过程的神秘面纱。
2024-12-28 18:04
2024-12-28 17:46
2024-12-28 17:24
2024-12-28 17:16
2024-12-28 16:40