# fscript 脚本引擎 ## 1. 介绍 fscript 是一个极简的脚本引擎,借鉴了函数语言中一些思路,主要用于低端嵌入式系统,让用户轻松扩展现有系统,而不需要重新编译和下载固件。 * 特色: * 小内存。最低开销小于 400 字节。 * 小巧。核心代码 1000 行,扩展函数 700 行。 * 灵活。支持多条语句、函数嵌套调用和变量定义。 * 简单。只有函数调用和表达式,熟悉任何一种编程语言的人,5分钟内即可学会。 * 强大。超过 60 个内置函数,支持条件语句和循环语句,支持复杂的表达式,支持用 C 语言扩展函数。 > 如果不需要数学函数,可以定义 AWTK_LITE 宏。 > keil -O1 编译结果: ``` Code (inc. data) RO Data RW Data ZI Data Debug Object Name 7108 134 1051 0 0 27871 fscript.o ``` * 限制: * 不支持函数定义。 ## 2. 示例 ```c print("hello fscript") ``` 在 PC 上测试运行: ``` ./bin/runFScript 'print("hello fscript")' ``` ## 3. 语法 ### 数据类型 * 浮点数类型 (double)。 * 整数类型 (int32)。支持十进制、二进制和十六进制。 * 字符串类型 (string)。UTF-8 字符串,用英文双引号扩起来。 * 布尔类型 (bool)。标准取值为:true 和 false,非 0 的数值视为 true。 ### 函数调用 ``` print(0xff) print(100) print(0b1010) print("hello fscript") print("hello", 123) ``` > 函数之间可以用空格、换行和英文分号分隔。 ### 定义变量 ``` set(a, 123) ``` ### 获取变量 ``` a ``` > 获取变量时,如果变量不存在,自动当成字符串处理。不希望当成字符串,可以加上$前缀。 ### 函数嵌套调用 ``` print(join(",", 1, 2, 3)) print(join(",", +(1, 2), -(5, 2), *(2, 3), /(9, 3))) ``` ### 条件执行 ``` if(false, print("a"), print("b")) ``` ``` if(true, print("a"), print("b")) ``` ### 循环执行 ``` set(a, 0) while(a < 10, print(a), set(a, a+1)) ``` ### 表达式 #### 支持的操作符 * 四则运算:+ - * / % * 逻辑运算: || && ! * 位运算:| & ~ * 比较运算:< <= > >= == * 条件运算: (p) ? a : b > 对于加法运算(+),参数中有字符串时,进行字符串连接。 #### 示例 ``` set(a, 10); set(b, 20); ``` ``` ab a>=b (1+2)*(2+3) (1+2)*(2+3) sin(a) + sin(b) a 注释 ---------------------------- ##### 原型 ``` #(comment) ``` #### 示例 ``` #(this is a comment) ``` #### print > 打印调试信息到控制台。 ---------------------------- ##### 原型 ``` print(str) ``` #### 示例 ``` print("hello fscript") print("hello", "fscript") print(1) print(true) set(a, 100) set(b, 200) print(a+b) print(join(",", a, b)) ``` #### noop > 空函数。什么也不做,主要给 if 函数用。 ---------------------------- ##### 原型 ``` noop() ``` #### seq > 把组合多条语句组合成一条语句。方便在if语句中执行多条语句。 ---------------------------- ##### 原型 ``` seq(s1, s2, s3, ...) ``` 示例 ```js if( msg.topic == "eof", seq( print(msg.topic), set(aborted, true), #("文件读取完毕,关闭定时器"), set(flow.timer.enable, false) ), seq( print(str(msg.payload, true)), set(msg.payload, toupper(str(msg.payload, true))) ) ) ``` #### if > 条件执行。如果第一个参数为 true,执行第二个参数,否则执行第三个参数。 ---------------------------- ##### 原型 ``` if(p, s1, s2) ``` #### 示例 ``` set(a, 1) if(<(a, 0), print(" a < 0"), print("a >= 0")) ``` #### while > 循环执行。如果第一个参数为 true,循环执行后面参数的各个语句,直到第一个参数返回 false 为止。 ---------------------------- ##### 原型 ``` while(p, s1, ...) ``` #### 示例 ``` set(a, 0) while(a < 10, print(a), set(a, a+1)) ``` ``` set(a, 0) set(b, 0) while(a < 10, print(a, ",", b), set(b, b+a), set(a, a+1)) ``` #### set > 设置变量的值。 ---------------------------- ##### 原型 ``` set(var, value) ``` #### 示例 ``` set(a, 1) ``` #### unset > 清除变量。 ---------------------------- ##### 原型 ``` unset(var) ``` #### 示例 ``` unset(a) ``` #### int > 转换为整数类型。 ---------------------------- ##### 原型 ``` int(var) ``` #### 示例 ``` int("123") ``` #### i8 > 转换为 int8_t 类型。 ---------------------------- ##### 原型 ``` i8(var) ``` #### 示例 ``` i8("123") ``` #### i16 > 转换为 int16_t 类型。 ---------------------------- ##### 原型 ``` i16(var) ``` #### 示例 ``` i16("123") ``` #### i32 > 转换为 int32_t 类型。 ---------------------------- ##### 原型 ``` i32(var) ``` #### 示例 ``` i32("123") ``` #### u8 > 转换为 unt8_t 类型。 ---------------------------- ##### 原型 ``` u8(var) ``` #### 示例 ``` u8("123") ``` #### u16 > 转换为 unt16_t 类型。 ---------------------------- ##### 原型 ``` u16(var) ``` #### 示例 ``` u16("123") ``` #### u32 > 转换为 unt32_t 类型。 ---------------------------- ##### 原型 ``` u32(var) ``` #### 示例 ``` u32("123") ``` #### f32 > 转换为单精度类型。 ---------------------------- ##### 原型 ``` f32(var) ``` #### 示例 ``` f32("123") ``` #### float > 转换为浮点数类型。 ---------------------------- ##### 原型 ``` float(var) ``` #### 示例 ``` float("123") ``` #### str > 转换为字符串类型。 ---------------------------- ##### 原型 ``` str(var [,force_pointer_as_str]) ``` > force\_pointer\_as\_str 如果输入参数是POINTER类型,是否将强制转换成字符串。 #### 示例 ``` str(int(123)) str(msg.payload, true) ``` #### iformat > 对整数进行格式化(生成的字符串长度不超过 63) ---------------------------- ##### 原型 ``` iformat(format, value) ``` #### 示例 ``` iformat("hello:%d", 123) ``` #### fformat > 对浮点数进行格式化(生成的字符串长度不超过 63) ---------------------------- ##### 原型 ``` fformat(format, value) ``` #### 示例 ``` fformat("hello:%lf", 123) ``` #### exec > 执行 object 里的一个命令。 ---------------------------- ##### 原型 ``` exec(cmd, arg) ``` #### 示例 ``` exec("clear", "all") ``` > 具体功能与 object 的实现有关。 ### 4.2 字符串函数 #### join > 将多个变量用指定的分隔符拼接起来(最多 7 个字符串),形成一个字符串。 ---------------------------- ##### 原型 ``` join(seperator, s1, s2, s3...) ``` #### 示例 ``` join(",", 1, 2, 3, "abc") ``` #### len > 取字符串的长度。 ---------------------------- ##### 原型 ``` len(str) ``` #### 示例 ``` len("abc") ``` #### toupper > 将字符串转换成大写。 ---------------------------- ##### 原型 ``` toupper(str) ``` #### 示例 ``` touppper("abc") ``` #### tolower > 将字符串转换成小写。 ---------------------------- ##### 原型 ``` tolower(str) ``` #### 示例 ``` tolower("ABC") ``` #### trim > 将字符串转换成小写。 ---------------------------- ##### 原型 ``` trim(str) ``` #### 示例 ``` trm(" abc ") ``` #### substr > 取子字符串。 ---------------------------- ##### 原型 ``` substr(str, from, len) ``` #### 示例 ``` substr("abcd", 1, 2) ``` #### replace > 替换子字符串。 ---------------------------- ##### 原型 ``` replace(str, old, new) ``` #### 示例 ``` replace("ab cd", "ab", "hello") ``` #### contains > 检查是否包含指定的子字符串。 ---------------------------- ##### 原型 ``` contains(str, substr) ``` #### 示例 ``` contains("ab cd", "ab") ``` ### 4.3 运算函数 #### sum > 对多个数值类型的参数求和。 ---------------------------- ##### 原型 ``` sum(n1,n2...) +(n1,n2...) ``` #### 示例 ``` print(sum(1, 2, 3)) ``` 运行: ``` ./bin/runFScript 'print(sum(1, 2, 3))' ``` 输出: ``` 6.000000 ``` #### sub > 计算两个数之差。 ---------------------------- ##### 原型 ``` sub(n1,n2) 或 -(n1,n2) ``` #### 示例 ``` print(sub(2, 1)) print(-(2, 1)) ``` 运行: ``` ./bin/runFScript 'print(sub(2, 1))' ``` 输出: ``` 1.000000 ``` #### mul > 计算两个数之积。 ---------------------------- ##### 原型 ``` mul(n1,n2) 或 *(n1,n2) ``` #### 示例 ``` print(mul(2, 1)) print(*(2, 1)) ``` 运行: ``` ./bin/runFScript 'print(mul(2, 1))' ``` 输出: ``` 2.000000 ``` #### div > 计算两个数之商。 ---------------------------- ##### 原型 ``` div(n1,n2) 或 /(n1,n2) ``` #### 示例 ``` print(div(2, 1)) print(/(2, 1)) ``` 运行: ``` ./bin/runFScript 'print(div(2, 1))' ``` 输出: ``` 2.000000 ``` #### % > 计算两个数的模。 ---------------------------- ##### 原型 ``` %(n1,n2) ``` #### 示例 ``` print(%(23, 7)) ``` 运行: ``` ./bin/runFScript 'print(%(23, 7))' ``` 输出: ``` 2.000000 ``` #### and > 逻辑与运算。 ---------------------------- ##### 原型 ``` and(n1,n2) &&(n1,n2) ``` #### 示例 ``` print(&&(true, false)) print(&&(true, true)) ``` 运行: ``` ./bin/runFScript 'print(and(true, true))' ``` 输出: ``` true ``` #### or > 逻辑或运算。 ---------------------------- ##### 原型 ``` or(n1,n2) ||(n1,n2) ``` #### 示例 ``` print(and(true, false)) print(||(true, true)) ``` 运行: ``` ./bin/runFScript 'print(or(true, false))' ``` 输出: ``` true ``` #### not > 逻辑非运算。 ---------------------------- ##### 原型 ``` not(n1) !(n1) ``` #### 示例 ``` print(not(true)) print(!(false)) ``` 运行: ``` ./bin/runFScript 'print(not(false))' ``` 输出: ``` true ``` #### & > 位与运算。 ---------------------------- ##### 原型 ``` &(n1,n2) ``` #### 示例 ``` print(&(1, 1)) ``` 运行: ``` ./bin/runFScript 'print(&(1, 2))' ``` 输出: ``` 0 ``` #### | > 位或运算。 ---------------------------- ##### 原型 ``` |(1,2) ``` #### 示例 ``` print(|(1, 2)) ``` 运行: ``` ./bin/runFScript 'print(|(1, 2))' ``` 输出: ``` 3 ``` #### ~ > 按位取反运算。 ---------------------------- ##### 原型 ``` ~(n1) ``` #### 示例 ``` print(~(1)) ``` 运行: ``` ./bin/runFScript 'print(iformat("0x%x", ~(1)))' ``` 输出: ``` 0xfffffffe ``` ### 比较函数 > 支持字符串比较。 #### < ---------------------------- > 小于。 ##### 原型 ``` <(a,b) less(a,b) a 小于等于。 ---------------------------- ##### 原型 ``` <=(a,b) le(a,b) a<=b ``` #### > > 大于。 ---------------------------- ##### 原型 ``` >(a,b) great(a,b) a>b ``` #### >= > 大于等于。 ---------------------------- ##### 原型 ``` >=(a,b) ge(a,b) a>=b ``` #### == > 等于。 ---------------------------- ##### 原型 ``` ==(a,b) eq(a,b) a==b ``` #### != > 不等于。 ---------------------------- ##### 原型 ``` !=(a,b) a != b ``` ### 4.4 数学函数 #### random > 产生随机数。 ---------------------------- ##### 原型 ``` random() random(min, max) ``` #### round > 四舍五入。 ---------------------------- ##### 原型 ``` round(v) ``` #### 示例 ``` round(4.5) ``` #### floor > 返回小于等于指定数值的最大整数。 ---------------------------- ##### 原型 ``` floor(v) ``` #### 示例 ``` floor(4.5) ``` #### ceil > 返回大于等于指定数值的最小整数。 ---------------------------- ##### 原型 ``` ceil(v) ``` #### 示例 ``` ceil(4.5) ``` #### sin > sin 函数。 ---------------------------- ##### 原型 ``` sin(a) ``` #### 示例 ``` sin(0) ``` #### cos > cos 函数。 ---------------------------- ##### 原型 ``` cos(a) ``` #### 示例 ``` cos(0) ``` #### tan > tan 函数。 ---------------------------- ##### 原型 ``` tan(a) ``` #### 示例 ``` tan(1) ``` #### asin > asin 函数。 ---------------------------- ##### 原型 ``` asin(a) ``` #### 示例 ``` asin(1) ``` #### acos > acos 函数。 ---------------------------- ##### 原型 ``` acos(a) ``` #### 示例 ``` acos(1) ``` #### atan > atan 函数。 ---------------------------- ##### 原型 ``` atan(a) ``` #### 示例 ``` atan(1) ``` #### abs > abs 函数。 ---------------------------- ##### 原型 ``` abs(a) ``` #### 示例 ``` abs(1) ``` #### min > min 函数。 ---------------------------- ##### 原型 ``` min(a, b) ``` #### max > max 函数。 ---------------------------- ##### 原型 ``` max(a, b) ``` #### 示例 ``` max(1, 2) ``` #### 示例 ``` min(1, 2) ``` #### clamp > clamp 函数。 ---------------------------- ##### 原型 ``` clamp(a, min, max) ``` #### 示例 ``` clamp(2, 1, 3) ``` ### 4.5 时间函数 #### time_now > 获取当前时间函数 (s)。 ---------------------------- ##### 原型 ``` time\_now() ``` #### 示例 ``` time_now() ``` #### time\_now\_ms > 获取当前时间函数 (ms)。 ---------------------------- ##### 原型 ``` time_now_ms() ``` #### 示例 ``` time\_now\_ms() ``` #### time_now_us > 获取当前时间函数 (us)。 ---------------------------- ##### 原型 ``` time_now_us() ``` #### 示例 ``` time_now_us() ``` ### 5. 自定义函数 #### 5.1 定义函数 ```c static ret_t func_foo(object_t* obj, fscript_args_t* args, value_t* v) { value_set_int(v, 123); return RET_OK; } ``` #### 5.2 注册和使用私有函数 ```c value_t v; object_t* obj = object_default_create(); object_set_prop_pointer(obj, "function.foo", (void*)func_foo); fscript_eval(obj, "foo()", &v); value_reset(&v); OBJECT_UNREF(obj); ``` #### 5.3 注册全局函数 * 初始化时调用 ``` fscript_register_func("foo", func_foo); ``` #### 5.1 定义私有函数 ### 6. 性能测量与优化 runFScript 的第二个参数可以指定运行次数,方便测量某个函数的运行时间。 比如: ``` ./bin/runFScript '123+234' 100000 ``` 通常设置变量和获取变量相对来说比较费时,为此 fscript 提供了 4 个寄存器变量:a,b,c,d。如果需要临时保存计算结果,优先使用寄存器变量。 比如: ``` ./bin/runFScript 'set(a, 2); set(b, 3); print(a+b)' ```