C语言实现轻量级表达式

码哥比特课程 2024-04-01 10:52:43
本文介绍开源C语言库Melon (github.com/Water-Melon/Melon) 的表达式组件,该组件实现了一个轻量级表达式,允许开发者定制化属于自己的专属变量和函数解析器。该模块可以用于文本模板内容替换以及一些简单的指令模式编程场景。 下面是该组件支持的语法: abc --这是一个变量"abc" --这是一个字符串常量'abc' --这也是字符串常量1 --整数1.2 --浮点数0xa --十六进制整数0311 --八进制整数concat(abc, bcd) --这是一个函数,参数有两个,都是变量concat(abc, "bcd") --这是一个函数,参数有两个,一个是变量,一个是常量concat(1, "bcd") --两个参数都是常量concat("abc", concat(bcd, "efg")) --这个例子展示了函数嵌套调用concat("abc", concat(bcd, "efg")) aaa concat("bcd", concat(efg, "hij")) --这个例子展示运行多个表达式简单来说,表达式语法支持三种类型内容: 常量变量函数并且函数支持嵌套调用。 此外,可以一次执行多个表达式,所有表达式的执行结果为最后一个表达式的结果。 我们分别对着三种类型分别说明: 常量这个比较好理解,就是字面量,主要支持:字符串、整数和浮点数。其中,整数支持十进制写法、八进制写法和十六进制写法。 变量变量顾名思义,就是其值可变。但由于表达式比较简单,且应用场景与常规编程语言不同,因此不是通过=来进行赋值的,而是通过回调函数,由使用者决定该返回何值作为该变量的值。 函数与变量一样,函数的行为完全由回调函数决定,也就是说由使用者自行定制。 例子我们看一个示例 #include "mln_expr.h"#include "mln_log.h"#include static mln_expr_val_t *func_expr_handler(mln_string_t *name, int is_func, mln_array_t *args, void *data){ mln_expr_val_t *v, *p; int i; mln_string_t *s1 = NULL, *s2, *s3; if (!is_func) return mln_expr_val_new(mln_expr_type_string, name, NULL); for (i = 0, v = p = mln_array_elts(args); i < mln_array_nelts(args); v = p + (++i)) { if (s1 == NULL) { s1 = mln_string_ref(v->data.s); continue; } s2 = v->data.s; s3 = mln_string_strcat(s1, s2); mln_string_free(s1); s1 = s3; } v = mln_expr_val_new(mln_expr_type_string, s1, NULL); mln_string_free(s1); return v;}int main(void){ mln_string_t func_exp = mln_string("concat('abc', concat(aaa, 'bbb')) ccc concat('eee', concat(bbb, 'fff'))"); mln_expr_val_t *v; v = mln_expr_run(&func_exp, func_expr_handler, NULL); if (v == NULL) { mln_log(error, "run failed\n"); return -1; } mln_log(debug, "%d %S\n", v->type, v->data.s); mln_expr_val_free(v); return 0;}这是一个综合一点的例子,这个例子中包含了函数嵌套调用、变量、多表达式执行。 表达式中的变量和函数都由func_expr_handler这个回调函数来解析。对于变量,回调函数直接返回变量的名字作为变量的值。而对于函数,回调函数则是将函数参数拼接成一个字符串作为函数的返回值。 由于本例中存在三个表达式: concat('abc', concat(aaa, 'bbb'))cccconcat('eee', concat(bbb, 'fff'))前面我们说到过,mln_expr_run的返回值是最后一个表达式的值,所以最终终端的输出就是: eeebbbfff也正如这个例子所示,表达式组件只是提供了一种对文本格式的规范,而具体有哪些函数和变量都完全交给回调函数来决定,也就是交给了使用者决定。并且这个组件并不像完整的编程语言那样功能繁重,因此比较适合一些小型功能整合或者模板替换之类的场景。 模板替换可以参考web前端的那些模板,例如:twig、mustache等。 小功能整合举个例子,例如在对某种网络通信中,我们需要对报文提取某些字段,然后对字段处理,然后再做验证。那么提取、处理、验证就可以被封装成三个函数。这三个函数是三种行为,而不是策略。我们可以将这三种行为应设成表达式组件中的三个函数,然后我们就可以通过对这三个函数的组合应用来实现策略。对于策略的改变,我们并不需要修改C代码,只需要将策略的文本内容(也就是这些表达式)做一些修改即可。 感谢阅读!
0 阅读:38

码哥比特课程

简介:感谢大家的关注