走近Lua ——嵌入式脚本在项目中的应用.

Slides:



Advertisements
Similar presentations
第二章 JSP 编译指令. 课程目标  JSP 编译指令  JSP 页面的表达式  JSP 页面的注释  JSP 页面的声明  Scriptlets.
Advertisements

While 迴圈 - 不知重複執行次數
普陀区税务局 营业税改征增值税试点 最新政策 货物和劳务税科 2013年7月.
第四章 保税货物的通关(上).
第1单元 操作系统概论 第一节 绪论 操作系统定义.
禁毒专题教案 一教学目标 1、增强青少年学生的禁毒意识,普及青少年禁毒知识,提高青少年自觉抵御毒品的能力
禁毒专题教案 一教学目标 1、增强青少年学生的禁毒意识,普及青少年禁毒知识,提高青少年自觉抵御毒品的能力
Loops.
Lua+wax在ios上的应用 白 衣.
個人投資理財分析 財務狀況匯總表 銀行存款 共同基金 外幣基金 股票投資 保險價值 黃金投資 支出預算 房貸計算 不動產價值 資源變化資料庫
年度校樹選拔秀 主辦單位:楊梅國小.
第九章日治時期的台灣(下).
補充: Input from a text file
科學科 污染 空氣 成因 的 : 題目 及 減少空氣污染的方法 陳玉玲 (4) 姓名 : 去到目錄.
第15章 Java数据库连接(JDBC) 15.1 创建数据源 15.2 JDBC-ODBC桥接器 15.3 顺序查询
C++程序设计 王希 图书馆三楼办公室.
ASP VBScript 基础知识.
2.1 基本資料型別 2.2 變數 2.3 運算式與運算子 2.4 輸出與輸入資料 2.5 資料型別轉換 2.6 實例
物件導向程式設計 (Object-Oriented rogramming)
If … else 選擇結構 P27.
第四章 程序设计初步 顺序结构:赋值语句、输出语句
STRUCTURE 授課:ANT 日期:2010/5/12.
Object-Oriented Programming in C++ 第一章 C++的初步知识
第12章 從C到C++語言 12-1 C++語言的基礎 12-2 C++語言的輸出與輸入 12-3 C++語言的動態記憶體配置
程式撰寫流程.
Chapter 2 Basic Elements of Fortran
新觀念的 VB6 教本 第 6 章 資料型別.
C++程序设计 string(字符串类) vector(容器类).
2019/1/17 Java语言程序设计-程序流程 教师:段鹏飞.
計數式重複敘述 for 迴圈 P
切換Dev c++顯示語言 工具->環境選項(V)->介面->language (Chinese TW)
電子音樂 通訊系 B 楊穎穆.
第1章 概述 本章要点: C语言程序结构和特点 C语言程序的基本符号与关键字 C语言程序的编辑及运行 学习方法建议:
C++ 程式設計 基礎篇 張啟中 Chang Chi-Chung.
《JAVA程序设计》 语音答疑 辅导老师:高旻.
第三课 标识符、关键字、数据类型.
第二章 基本数据类型及运算 C数据类型概述 基本数据类型 运算符和表达式 混合运算与类型转换 数据的输入输出 顺序程序设计举例.
程式結構&語法.
Java變數 2014/6/24.
C语言复习3----指针.
4 條件選擇 4.1 程式基本結構 循序式結構 選擇式結構 重複式結構 4-3
Chapter 2 基本語法.
QQ群 主要用于线下讨论答疑 用于发布一些通知公告 修该备注,如 经济学院_2019_张三. 刘东华 信息技术中心 敬宾楼1406
C语言环境配置.
保留字與識別字.
第二章 Java基本语法 讲师:复凡.
物件導向程式設計 CH2.
<编程达人入门课程> 本节内容 字符与字符串 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群: ,
C++语言程序设计 C++语言程序设计 第二章 基本数据类型与表达式 第十一组 C++语言程序设计.
C++程式設計入門 變數與運算子 作者:黃建庭.
第二章 Java语法基础.
第二章 类型、对象、运算符和表达式.
本节内容 Lua基本语法.
第三章 基本的輸出與輸入函數 (Basic Output & Input Function)
Review 1~3.
C/C++基礎程式設計班 C++: 物件的使用、參考、重載函式 講師:林業峻 CSIE, NTU 3/28, 2015.
第 9 章 建構函式與解構函式.
隨機數 (亂數) 10後,取餘數 n = rand(); 利用 Code::Block 驗證一下 n = rand() %10; 998
#include <iostream.h>
第二章 Java基本语法 讲师:复凡.
C++语言程序设计 C++语言程序设计 第二章 基本数据类型与表达式 第十一组 C++语言程序设计.
本章主題 C++的程式結構 資料型態與宣告 算術運算 簡易的輸入輸出指令 程式編譯(Compile)的過程與原理.
數學遊戲二 大象轉彎.
變數、資料型態、運算子.
第2章 Java语言基础.
基本資料型態 變數與常數 運算子 基本的資料處理 授課:ANT 日期:2014/03/03.
變數與資料型態  綠園.
第二章 Java基础语法 北京传智播客教育
隨機函數.
C++语言程序设计 C++语言程序设计 第二章 基本数据类型与表达式 第十一组 C++语言程序设计.
Presentation transcript:

走近Lua ——嵌入式脚本在项目中的应用

什么是Lua Lua是一种脚本编程语言,于1994年,由巴西里约热内卢天主教大学的研究人员设计开发,“Lua”这个名字是葡萄牙语单词 “月亮”。 与一般脚本语言如 PHP、Perl、JavaScript 等不同,Lua被称为是一种嵌入式 脚本语言,Lua最著名的应用是在暴雪公司的网络游戏 魔兽世界 中。 Lua最引人注目的特点: 以极小 的体积和简单 的语法提供相对全面的功能。 以简洁 的API实现与宿主语言最方便 的接口。

为什么称为“嵌入式” Lua语言可以独立进行编程,但这不是其主要的使用方式。Lua虽然有动态、灵活的语法提供强大的功能,但并不像 Java、Python 等一样有一个完善的库(但仍存在一定数量的第三方库),这不是缺陷,而是和其定位有关。 Lua最典型的用法,是作为一个库,嵌入 到其他大型语言(称之为宿主语言 )的应用程序之中,为应用程序提供参数配置或逻辑描述等功能,带来前所未有的灵活性。 Lua常见的宿主语言有:C/C++,Java,.NET,甚至脚本语言如PHP,Ruby等。

Lua的典型使用方式 Lua作为配置文件,为宿主语言应用提供参数 宿主语言作为底层库,Lua作为逻辑描述 宿主语言 Lua 宿主语言 Lua

Lua与相似解决方案的比较 Lua的体积是如此之小,以至于往往使用静态 链接完全嵌入到程序内部,这样在发布应用时不需要 附带任何额外的运行时支持。

工作流程 1.宿主语言建立Lua解释器对象。 2.将宿主语言实现的Lua扩展(若有),如函数等,注册到Lua解释器中,供其使用。

Lua与宿主语言的交互方式 宿主语言通过虚拟机,对Lua脚本中的变量实现增、删、读、写 宿主语言通过虚拟机调用Lua脚本中的函数

一个简单的例子:demo1.c #include <lua.h> //Lua语言解析器 #include <lualib.h> //Lua标准库 #include <lauxlib.h> //Lua辅助工具 char *code = "for i=0, 5 do print(\'Hello, world!\') end"; int main() { lua_State *s = luaL_newstate(); //建立一个虚拟机 luaL_openlibs(s); //打开Lua附加库 luaL_dostring(s, code); //执行字符串中的源代码 lua_close(s); //关闭虚拟机 return 0; }

编译及运行 编译:gcc –o demo1 demo1.c –llua 运行:./demo1 结果输出: Hello, world! Hello, wordl! 可见Lua是一种简便的工具,利用其API,宿主语言极易实现Lua解析器,这是一般脚本语言无法比拟的。

更深入的交互 上例只实现了对Lua脚本的解析,并没有实现Lua与宿主语言的数据交换和互操作。 和典型的脚本语言引擎相同,Lua虚拟机是一个堆栈机,其一切运算基本都在堆栈上完成,这个堆栈也是Lua API的关键部分,是Lua与宿主语言交换数据的手段。 题外:宿主语言可以用字符串构建任意Lua脚本,实现向Lua程序传递任意数据,就像构建SQL语句一样,也不失是最“笨”的交互方式。

堆栈机原理示意 计算:f (a, b, c) c b 调用lua_call(s, 3, 1)后: a f f(a, b, c) … … 先将函数压栈 再将参数依次压栈 函数执行后将参数弹出 并将结果压栈

通过堆栈的交互 Lua虚拟机内部有一个堆栈,Lua API提供了对其的操作,不仅有出入栈操作,还可以以数组的形式,通过索引值随机读写栈元素,这是双方交换数据的主要方式。 用宿主语言可以编写供Lua调用的函数,宿主语言需要遵守调用约定,从栈中取得参数,最后也将结果入栈。将宿主函数通过lua_register注册入Lua虚拟机(这一过程实质为向Lua语言添加全局变量),就可以被Lua语言所调用。 宿主语言也可以将Lua函数压栈,再将参数依次压栈,最后使用lua_call,完成对Lua函数的调用。

Lua虚拟机的堆栈 若Lua虚拟机堆栈里有N个元素,则可以用 1 ~ N 从栈底向上索引,也可以用 -1 ~ -N 从栈顶向下索引,一般后者更加常用。 堆栈的每个元素可以为任意复杂的Lua数据类型,堆栈中没有元素的空位,隐含为包含一个“空”类型数据。 -1 6 <用户类型> -2 5 <函数> -3 4 {1, "ab", nil} -4 3 "hello" -5 2 false -6 1 123

通过堆栈交互的例子:demo2.c #include <lua.h> #include <lualib.h> #include <lauxlib.h> int divide(lua_State *s) { //供Lua使用的函数通用原型 double a = lua_tonumber(s, -2); //取得第一个参数 double b = lua_tonumber(s, -1); //取得第二个参数 int quot = (int)a / (int)b; int rem = (int)a % (int)b; lua_pushnumber(s, quot); //将第一个返回值入栈 lua_pushnumber(s, rem); //将第二个返回值入栈 return 2; //返回值为结果个数 }

续demo2.c及demo2.lua int main() { lua_State *s = luaL_newstate(); luaL_openlibs(s); lua_register(s, "div“, divide); //向虚拟机注册变量 luaL_dofile(s, "demo2.lua"); //执行文件中的源代码 lua_close(s); return 0; } demo2.lua: a = 13 b = 5 q, r = div(a, b) //多重赋值 print(q, r)

运行结果及分析 输出: 2 3 由上例可见,可被Lua调用的宿主函数具有统一的原型:int f(lua_State *s),数据传递不通过其参数,而是通过堆栈;整型返回值指明了该函数真正向Lua返回的值的个数,即压栈的结果个数。函数返回后,Lua虚拟机会自动进行清栈工作,不需在函数内部来做。 显然,在Lua中函数可以有不止一个返回值,这在Lua语法中也有体现,可以将函数返回赋值给多个变量。

另一个交互的示例:demo3.c #include <lua.h> #include <lualib.h> #include <lauxlib.h> int main() { lua_State *s = luaL_newstate(); luaL_openlibs(s); luaL_dofile(s, "demo3.lua"); lua_getglobal(s, "show"); //将Lua全局变量压栈 lua_pushstring(s, "It is from C"); //将字符串压栈 lua_call(s, 1, 1); //调用Lua函数

续demo3.c及demo3.lua demo2.lua: show = function(m) const char *result = lua_tostring(s, -1); //取得栈顶的返回值 printf("C has got: %s\n", result); lua_pop(1); //弹出栈顶值 lua_close(s); return 0; } demo2.lua: show = function(m) print('Lua has got: ' .. m) return 'It is from Lua' end

运行结果及分析 输出: Lua has got: It is from C C has got: It is from Lua 可见,宿主语言可以通过名称方便的取得Lua的全局变量,而Lua中显然把函数也当成了一种数据。这一特性,可以使Lua源代码成为功能最强的配置文件,这也是项目中最容易的引入Lua的方式。

Lua语言特性 动态语言,可控的垃圾收集,支持数值、字符串、布尔等简单类型的基本运算 以哈希表为基础,以原型的方式,构建复杂的数据结构,和支持面向对象 支持宿主语言中自定义的数据类型的操作 将函数作为普通数据类型,支持词法定界、尾递归 通过协程的方式支持并发程序设计

动态语言/基本类型 赋值:a = 3 x, y, z = 12, 'Hello', true 基本类型: 其他通用运算符: 空类型 nil nil 数值 number 123 3.14159 1.6e-9 运算:+ - * / % ^(乘幂) -(负) 布尔 boolean true false 运算:or and not 字符串 string 'www.feedsky.com' "宇智波佐助" 运算:..(连接) # (长度) 其他通用运算符: == ~= > < >= <=

表 Lua使用表(table)类型作为一切数据结构的基础: t = {1234, nil, 'something', true, {'nested', 1.414}} table本质为哈希表,保存键-值对的集合,若不指定键,则默认为从1开始的整数。也可显式指定键: rec = {[‘name’] = ‘漩涡鸣人', favorite = '一乐拉面', [3+2] = true} 引用表的元素: rec.name rec['favorite'] rec[8-3] 活用表类型,可以构成结构体、链表、数组、对象等各种复杂数据结构。

函数 因为函数是Lua的普通类型,所以不具有名称,要想使用名称来调用函数,必须将函数本身赋值给一个变量: 调用函数: r2p = function(x, y) abs = math.sqrt((x * x) + (y * y)) arg = math.atan2(x, y) return abs, arg end 调用函数: rho, theta = r2p(3, 4) 若表的元素为函数,则可以作为对象的方法。

协程:轻量级并发 协程(coroutine)和线程的区别在于调度方式的差异,即让出CPU给别的执行绪(切换)的时机不同: 线程:主动让出(yield)、I/O阻塞、时间片到 协程:主动让出(yield)、I/O(协程间通信)阻塞 可见,最大的区别在于协程没有“时间片”的概念,一个协程若得到执行权,一般除非自己让出,否则不会让别的协程有执行机会。 优点:创建和切换开销小,可以同时运行远大于允许线程数量的协程;且因为不存在不可知的执行绪切换,所以共享资源的并发访问控制大为简化;另外协程实现简单,不依赖OS的线程支持。 缺点:要求编程者自己控制各协程之间的同步,在合适的地方主动让出执行权,增加了逻辑设计难度。

总结 Lua是功能强大、体积小巧、使用方便的脚本语言,专为嵌入应用程序而设计。

http://lych.yo2.cn 边缘独行者 ——最后,按惯例宣传一下blog