惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Recent Announcements
Recent Announcements
Martin Fowler
Martin Fowler
MongoDB | Blog
MongoDB | Blog
Engineering at Meta
Engineering at Meta
Stack Overflow Blog
Stack Overflow Blog
Google DeepMind News
Google DeepMind News
Microsoft Security Blog
Microsoft Security Blog
aimingoo的专栏
aimingoo的专栏
I
InfoQ
B
Blog
WordPress大学
WordPress大学
Jina AI
Jina AI
小众软件
小众软件
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园_首页
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
酷 壳 – CoolShell
酷 壳 – CoolShell
阮一峰的网络日志
阮一峰的网络日志
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
G
Google Developers Blog
C
Check Point Blog
月光博客
月光博客
L
LangChain Blog
GbyAI
GbyAI

C

C 语言快速通关教程 2026(共 96 集) - V2EX 各位大佬, C 語言該怎麼練習啊 分享一个代码优化导致的死循环 人再笨还能写不出内存安全的 C? 想念 C C11 的 _Generic,现实当中用得多不多?(尤其是公司项目) 坑爹的 GBK:大家都应该去用 UTF-8 分享一个用 AI 学习 C 语言的例子 一个简单的 C 程序,但是不明白区别在哪里 我这段 C 代码可以在编译时候输出结构体的大小,你们还有什么好点子, show me the code! 这段话是否正确?「取余这个运算,只有 Python 是对的。当初 C 这个老师教错了,那么一大票学生也就只敢跟着老师错。只有 Python 敢于站出来坚持正确答案。」 C 中可变参数如何直接传递到 printf() C 的内存打印实现 函数能否实现透传不定长度参数,最终由 printf 打印 请大佬帮忙修改一份 elf 文件里的数值 Linux 上 C 的程序遇到个异常退出问题,局部变量大小有限制?? C 语言新手求助:如何在 vscode 中使用第三方库? 将资源嵌入到可执行文件中并保持目录结构 一个简单实用的 C 工程示例, 附简洁的 Makefile 关于 C 语言的相关问题 轮子更新: C/C++ 跨平台小工具库 为什么下列程序进行的是无符号乘法? 用 riscv64- Linux -gnu-gcc 编译的 c 文件为啥能在 x8664 下运行? char *s = "0123"和 char s[] = "0123"的区别 有人能完整地解释一下 int (*daytab) [13]和 int *daytab[13]吗 在 c 语言中, int a;是 declaration 还是 definition 一个简单(奇怪)的 C 语言问题 c 语言中打印指针的值打印的是 OS 分配的虚拟地址的值吗?要怎么知道 OS 给这个 c 程序进程分配的虚拟地址的大小呢? gcc 是怎么找到 system 函数的定义(实现)的? c 语言是如何给汉字编码的?
用 C 实现轻量级表达式完成策略定制化和模板内容生成
monkeyNik · 2024-03-19 · via C

本文介绍开源 C 语言库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 <stdio.h>

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'))
  • ccc
  • concat('eee', concat(bbb, 'fff'))

前面我们说到过,mln_expr_run的返回值是最后一个表达式的值,所以最终终端的输出就是:

eeebbbfff

也正如这个例子所示,表达式组件只是提供了一种对文本格式的规范,而具体有哪些函数和变量都完全交给回调函数来决定,也就是交给了使用者决定。并且这个组件并不像完整的编程语言那样功能繁重,因此比较适合一些小型功能整合或者模板替换之类的场景。

模板替换可以参考 web 前端的那些模板,例如:twig 、mustache 等。

小功能整合举个例子,例如在对某种网络通信中,我们需要对报文提取某些字段,然后对字段处理,然后再做验证。那么提取、处理、验证就可以被封装成三个函数。这三个函数是三种行为,而不是策略。我们可以将这三种行为应设成表达式组件中的三个函数,然后我们就可以通过对这三个函数的组合应用来实现策略。对于策略的改变,我们并不需要修改 C 代码,只需要将策略的文本内容(也就是这些表达式)做一些修改即可。

感谢阅读!