自己动手实现脚本语言
本文使用 C 语言+Melon 库实现一个简易脚本语言解析器。
为了便于阅读和理解,解析器不会生成抽象语法树结构,只是对脚本文件的语法进行解析。 第三方库
Melon 是一个 C 语言库,其中提供了一个用宏封装好的脚本解释器相关的套件,如词法分析器和语法解析器生成器。使用非常简单,最简单的使用仅需非常简短的代码即可。
安装如下: $ git clone https://github.com/Water-Melon/Melon.git $ cd Melon $ ./configure [--prefix=....] $ make && make install解释器程序
下面直接上代码,这里我对代码进行了完全注释。 //test.c #include #include #include "mln_core.h" #include "mln_log.h" #include "mln_lex.h" #include "mln_alloc.h" #include "mln_parser_generator.h" //声明语法解析器生成器,函数作用域为 static ,函数与结构体名称前缀为 test ,词素前缀为 TEST 。本例没有自定义词素。 MLN_DECLARE_PARSER_GENERATOR(static, test, TEST); //定义语法解析器生成器,函数作用域为 static ,函数与结构体名称前缀为 test ,词素前缀为 TEST 。本例没有自定义词素。 MLN_DEFINE_PARSER_GENERATOR(static, test, TEST); //产生式表,产生式的原理与代数非常相似,就是将同名的部分代入展开。start 为所有语法的启始,xxx_TK_EOF 表示语言读取完毕处 //本例中 stm 表示语句( statement ),exp 表示表达式( expression ),addsub 表示加减法表达式。 //TEST_TK_SEMIC 为分号(;),TEST_TK_ID 为变量名(以下划线字母起始,后续自符有字母数字下划线组成),TEST_TK_DEC 为整数。 //这里使用了词法分析器的默认词素切分规则生成的词素,开发者可根据自己需求对关键字、特殊运算符进行扩展。 // //每一个产生式结构的第二个参数为一个处理函数,该函数会在本产生式冒号(:)右侧所有词素(确切的叫终结符与非终结符)都获取到时被调用。 //我们可以在这些回调函数中生成抽象语法树结构。 static mln_production_t prod_tbl[] = { {"start: stm TEST_TK_EOF", NULL}, {"stm: exp TEST_TK_SEMIC stm", NULL}, {"stm: ", NULL}, {"exp: TEST_TK_ID addsub", NULL}, {"exp: TEST_TK_DEC addsub", NULL}, {"addsub: TEST_TK_PLUS exp", NULL}, {"addsub: TEST_TK_SUB exp", NULL}, {"addsub: ", NULL}, }; int main(int argc, char *argv[]) { struct mln_core_attr cattr; mln_lex_t *lex = NULL; struct mln_lex_attr lattr; mln_alloc_t *pool; mln_string_t path; struct mln_parse_attr pattr; mln_u8ptr_t ptr, ast; mln_lex_hooks_t hooks; //框架初始化 cattr.argc = argc; cattr.argv = argv; cattr.global_init = NULL; cattr.worker_process = NULL; if (mln_core_init(&cattr) < 0) { fprintf(stderr, "Melon init failed. "); return -1; } //设置自定义语言文本文件路径 mln_string_set(&path, argv[1]); //创建内存池,用于语法分析过程中使用,使用后可进行释放。这里需要注意,生成的抽象语法树结构尽量不要使用该内存池, //开发者可能会习惯性按本示例一样在解析后进行释放。则在后续处理抽象语法树时就会发生越界访问。 if ((pool = mln_alloc_init()) == NULL) { mln_log(error, "init memory pool failed. "); return -1; } //设置词法分析器内存池 lattr.pool = pool; //本例没有自定义关键字 lattr.keywords = NULL; //本例没有对运算符进行扩展 memset(&hooks, 0, sizeof(hooks)); lattr.hooks = &hooks; //启用预编译机制,启用后,自定义语言中可使用#include 、#def 、#endif 等预编译宏 lattr.preprocess = 1; //设置为文件路径名类型。待解析内容可以直接给出字符串内容,也可以是文本路径,可参考词法分析器中的定义。 lattr.type = M_INPUT_T_FILE; //若 type 为 M_INPUT_T_FILE ,则 data 为文件路径,否则为自定义语言字符串。 lattr.data = &path; //初始化词法分析器 mln_lex_init_with_hooks(test, lex, &lattr); if (lex == NULL) { mln_log(error, "init lexer failed. "); return -1; } //生成状态转换表 ptr = test_parser_generate(prod_tbl, sizeof(prod_tbl)/sizeof(mln_production_t)); if (ptr == NULL) { mln_log(error, "generate state shift table failed. "); return -1; } //设置语法解析器内存池 pattr.pool = pool; //设置产生式 pattr.prod_tbl = prod_tbl; //设置词法解析器,待解析的语言由词法分析器拆解后交由本解析器处理 pattr.lex = lex; //设置状态转换表 pattr.pg_data = ptr; //本例没有自定义数据 pattr.udata = NULL; //执行解析 ast = test_parse(&pattr); //...对自定义的抽象语法树结构进行处理,本例中没有定义相关结构,因此会保持为 NULL //销毁词法分析器 mln_lex_destroy(lex); //释放内存池 mln_alloc_destroy(pool); return 0; }
下面对程序进行编译 $ cc -o test test,c -I /path/to/melon/include -L /path/to/melon/lib -lmelon -lpthread
然后我们编辑一个文本a.test,其中包含我们的脚本语言: a + 1; 1 + 1; _b + a;
然后用我们的脚本解释器来对脚本文件进行解析: $ ./test a.test
这时可以看到什么都没有输出,这代表语法通过了检查。
下面我们对a.test进行修改,故意将其改为违反语法规则的文本: a * 1; b + a; c - b;
再次运行程序去解析脚本文件,可得到如下输出: a.test:1: Parse Error: Illegal token nearby "*".结语
这个例子只是简单地展示了一个可以解析语法规则的解析器,对该内容感兴趣的读者可以自行对其扩展实现更多语法和抽象语法树等内容。
感谢阅读!
宋PLUS新能源售14。68万元起欢迎试驾驭见皆引领!全球首款宽体超混SUV领航上市!宋PLUSDMi上市价14。68万起(综合补贴后)创新采用骁云插混专用1。5L高效发动机高效EHS电混系统,达到短途用电经济节省,长途用
钢筋网片有哪些用途深度聊一聊钢筋网片用途和优势钢筋网片其实在很多的行业中都有所应用,由于成本低施工方便,所以施工过程中获得了大家的青睐。但是大家知道钢筋网片有具体的用途吗?鸿天祥网业小编就和大家一起聊一聊关于钢筋网片那些不为人
使用Win10系统的玩家们请注意安装该系统更新微软终于发布了与Windows10游戏模式相关的性能修复。该更新旨在解决3月份以来,部分用户在游玩游戏时遇到的相关问题。以下将帮助受此困扰的玩家们如何在你的电脑上安装这些更新内容。
婴儿奶粉怎么选?一位新手妈妈的心酸选购历程最近收到了很多妈妈的投稿,有分享开心的,也有存在焦虑不知道怎么办的。我认真看过后,在这么多投稿当中,发现了一个比较典型的关于婴儿奶粉怎么选的问题的投稿,这也是众多妈妈投稿当中比较典
囤货必备维达棉韧软抽,擦鼻子不泛红抽纸是大家生活中的必需品,有的人对纸巾没有什么要求,会选择比较便宜的纸巾,但便宜的纸巾相比较下来质量方面也不好,更显得粗糙,有的还会添加荧光增白剂,这对身体也不好。当初我也有因为贪
世界金融控股集团成功协助平湖尚珠完成1亿知识产权增资2021年10月25日,平湖尚珠体育用品有限公司董事王俊锋一行莅临世界金融控股集团全资子公司上海控本企业管理有限公司,正式签署知识产权出资合作协议。据悉,双方此次达成签约合作,将由
决策参考优酷世界杯网络直播权花16亿小米有望成CDR试点首单1优酷世界杯网络直播权花16亿,每场花费是南非100倍事件在优酷2018世界杯战略发布会上,阿里文娱集团轮值总裁兼大优酷总裁阿里音乐CEO杨伟东回应了优酷世界杯版权16亿人民币的传
决策参考互联网女皇报告中国报告娱乐和零售创新引领世界1互联网女皇报告中国报告娱乐和零售创新引领世界事件5月31日凌晨,被称为互联网女皇的玛丽米克尔发布2018年互联网趋势报告。这份报告中关于中国市场的部分连续数年由高瓴资本研究撰写,
致命愿望11月3日开播,期待值拉满爱奇艺重磅出击,由冯绍峰文淇范丞丞郭子凡主演,邵兵杨蓉特别出演的致命愿望定档,该剧是迷雾剧场的第二季以来的第二部作品,11月3日迷雾剧场,敬请期待!致命愿望最吸引人的是它的剧情结构
用iQOONeo3拍了几张照片,突然觉得单反就不香了!如果一部小小的手机就能帮你拍出好照片,你还会带着笨重的专业相机吗?iQOONeo3就是这样一款在摄影方面很有门道的手机,该机有着4800万像素主镜头800万像素超广角镜头200万像
京东健康,做互联网医疗的探路人我们看见的不仅是一个海角,而是一个新的世界。五百年前,历史学家巴若斯记录了他在抵达好望角时的感受1488年,巴若思乘坐葡萄牙航海家迪亚士率领的船队,从非洲西海岸南亚出发抵达这片海域