lemon的简单使用

news/2024/7/5 4:01:44

lemon概述

lemon是LALR(1)的用于c或c++的解析器与生成器,与大名鼎鼎的bison与yacc做类似的工作,但又不是简单复制它们的功能,lemon使用了设计了不同的语法格式来减少编码的错误,lemon还使用了比yacc和bison更快的更复杂的解析引擎,它既可重入又线程安全。

lemon的简述

官方文档可知,首先要编译lemon.c文件,并且需要配置同级目录下lempar.c文件,此时在终端中编译lemon.c文件

gcc -o lemon lemon.c

接着在终端中输入并检查lemon;

$ lemon -v
Command line syntax error: undefined option.
lemon -v^-- here
Valid command line options for "lemon" are:-b           Print only the basis in report.-c           Don't compress the action table.-d<string>   Output directory.  Default '.'-D<string>   Define an %ifdef macro.-f<string>   Ignored.  (Placeholder for -f compiler options.)-g           Print grammar without actions.-I<string>   Ignored.  (Placeholder for '-I' compiler options.)-m           Output a makeheaders compatible file.-l           Do not print #line statements.-O<string>   Ignored.  (Placeholder for '-O' compiler options.)-p           Show conflicts resolved by precedence rules-q           (Quiet) Don't print the report file.-r           Do not sort or renumber states-s           Print parser stats to standard output.-x           Print the version number.-T<string>   Specify a template file.-W<string>   Ignored.  (Placeholder for '-W' compiler options.)

至此,lemon就配置完成。

编写规则文件

%include {#include <assert.h>
}%token_type {int}%syntax_error {fprintf(stderr, "Syntax error\n");
}%left PLUS MINUS.
%left TIMES DIVIDE.program ::= expr(A). { printf("Result = %d\n", A);}
expr(A) ::= expr(B) PLUS expr(C). { A = B + C;printf("PLUS  : A : %d, B : %d, C : %d\n", A, B, C);}
expr(A) ::= expr(B) MINUS expr(C). { A = B - C;printf("MINUS  : A : %d, B : %d, C : %d\n", A, B, C);}
expr(A) ::= expr(B) TIMES expr(C). { A = B*C; printf("TIMES  : A : %d, B : %d, C : %d\n", A, B, C);}
expr(A) ::= expr(B) DIVIDE expr(C). {printf("DIVIDE  : A : %d, B : %d\n", A, B);if (C !=0 )A = B/C;elsefprintf(stderr, "divide by zero\n");
}
expr(A) ::= LPAR expr(B) RPAR. { printf("LPAR and RPAR  : A : %d, B : %d\n", A, B);A = (B);}
expr(A) ::= INTEGER(B). { printf("INTERGER(B)  : A : %d, B : %d\n", A, B);A=B;}

保存改文件命名为first_lemon.y,然后终端输入,

lemon first_lemon.y

此时就会生成三个文件first_lemon.c(生成的词法解析调用的函数),first_lemon.h(头部文件),first_lemon.out(生成的规则树信息)文件。

编写调用函数

此时编写的c函数需要调用生成的first_lemon.c中的函数,此时调用函数如下;

#include <stdio.h>
#include <stdlib.h>
#include "first_lemon.h"int main(int argc, char const *argv[])
{void *pParser;char *c;int value;if (argc != 2){fprintf(stderr, "usage: %s <expression> \n", argv[0]);exit(EXIT_FAILURE);}pParser = (void *) ParseAlloc(malloc);for(c = argv[1]; *c; c++){switch(*c){case '0': case '1': case '2': case '3': case '4':case '5': case '6': case '7': case '8': case '9':for(value = 0; *c && *c >= '0' && *c <= '9'; c++)value = value*10 + (*c - '0');c--;Parse(pParser, INTEGER, value);break;case '+':Parse(pParser, PLUS, 0);break;case '-':Parse(pParser, MINUS, 0);break;case '*':Parse(pParser, TIMES, 0);break;case '/':Parse(pParser, DIVIDE, 0);break;case '(':Parse(pParser, LPAR, 0);break;case ')':Parse(pParser, RPAR, 0);break;case ' ':break;default:fprintf(stderr, "Unknown symbol: %c\n", *c);return -1;}}Parse(pParser, 0, 0);ParseFree(pParser, free);return 0;
}

此时,保存为first_lemon_cal.c并在终端中编译运行,

gcc -o first_lemon_cal first_lemon_cal.c first_lemon.c

如果出现语法错误;

first_lemon_cal.c:15:21: warning: implicit declaration of function 'ParseAlloc' is invalid in C99[-Wimplicit-function-declaration]pParser = (void *) ParseAlloc(malloc);

由于c语言的规则为C99,此时需要手动讲定义的头文件添加到first_lemon.h文件中,最终first_lemon.h的文件内容如下;

#define PLUS                             1
#define MINUS                            2
#define TIMES                            3
#define DIVIDE                           4
#define LPAR                             5
#define RPAR                             6
#define INTEGER                          7#ifndef YYMALLOCARGTYPE
# define YYMALLOCARGTYPE size_t
#endif
#define ParseCTX_PDECL
#define ParseARG_PDECL
#define ParseTOKENTYPE intvoid *ParseAlloc(void *(*mallocProc)(YYMALLOCARGTYPE) ParseCTX_PDECL);
void ParseFree(void *p,                    /* The parser to be deleted */void (*freeProc)(void*)     /* Function used to reclaim memory */
);
void Parse(void *yyp,                   /* The parser */int yymajor,                 /* The major token code number */ParseTOKENTYPE yyminor       /* The value for the token */ParseARG_PDECL               /* Optional %extra_argument parameter */
);

再继续在终端中编译。

$ ./first_lemon_cal  "(1+2+3)*2"
INTERGER(yymsp[0].minor.yy0)  : yylhsminor.yy0 : -289395680, yymsp[0].minor.yy0 : 1
INTERGER(yymsp[0].minor.yy0)  : yylhsminor.yy0 : -289395680, yymsp[0].minor.yy0 : 2
PLUS  : yylhsminor.yy0 : 3, yymsp[-2].minor.yy0 : 1, yymsp[0].minor.yy0 : 2
INTERGER(yymsp[0].minor.yy0)  : yylhsminor.yy0 : -289395680, yymsp[0].minor.yy0 : 3
PLUS  : yylhsminor.yy0 : 6, yymsp[-2].minor.yy0 : 3, yymsp[0].minor.yy0 : 3
LPAR and RPAR  : yymsp[-2].minor.yy0 : 0, yymsp[-1].minor.yy0 : 6
INTERGER(yymsp[0].minor.yy0)  : yylhsminor.yy0 : -289395680, yymsp[0].minor.yy0 : 2
TIMES  : yylhsminor.yy0 : 12, yymsp[-2].minor.yy0 : 6, yymsp[0].minor.yy0 : 2
Result = 12

至此,最简单的使用方式就如上所示。

总结

本文作为sqlite源码分析中有关lemon的使用的一个简单的展示,但是简单展示的内容还不足以完全了解到sqlite中的parse.y的内容,大家可查看lemon的官方文档继续了解。由于本人才疏学浅,如有错误请批评指正。


http://lihuaxi.xjx100.cn/news/258068.html

相关文章

为何我的BLOG不能DIY?

今天想把MODULE调整一下&#xff0c;居然搞不定。估计是服务器又出问题了........不知道51CTO有没有备份我们的博克呀&#xff1f;

如何利用神经网络结合遗传算法进行非线性函数极值寻优(2)

如何利用神经网络结合遗传算法进行非线性函数极值寻优

阿里云发布第四代神龙架构云计算首次进入5微秒时延时代

10月20日&#xff0c;2021云栖大会上&#xff0c;阿里云宣布推出第四代神龙架构&#xff0c;这是飞天云操作系统新一代虚拟化技术&#xff0c;首次搭载全球唯一的大规模弹性RDMA加速网络&#xff0c;网络延迟整体降低80%以上。神龙4.0带来的计算架构革新&#xff0c;将云计算首…

王茂霖:特征工程方法总结!

↑↑↑关注后"星标"Datawhale每日干货 & 每月组队学习&#xff0c;不错过Datawhale干货 作者&#xff1a;王茂霖&#xff0c;华中科技大学&#xff0c;Datawhale成员内容概括1.经典特征工程构造2.特征工程案例实践PPT完整下载&#xff1a;后台回复“210501”可获…

首次在智能手机上训练BERT和ResNet,能耗降35%

视学算法报道机器之心编辑部研究者表示&#xff0c;他们将边缘训练看作一个优化问题&#xff0c;从而发现了在给定内存预算下实现最小能耗的最优调度。目前&#xff0c;智能手机和嵌入式平台等边缘设备上已经广泛部署深度学习模型来进行推理。其中&#xff0c;训练仍然主要是在…

POJ 1144 Network (求割点)

题意&#xff1a; 给定一幅无向图&#xff0c; 求出图的割点。 割点模板&#xff1a;http://www.cnblogs.com/Jadon97/p/8328750.html 分析&#xff1a; 输入有点麻烦&#xff0c; 用stringsteam 会比较简单 #include<cstdio> #include<iostream> #include<queu…

如何教计算机认识手写数字(中)

本文详细介绍了如何利用Matlab编写KNN代码进行手写数字的识别。

Linux内核网络栈1.2.13-有关tcp/ip协议的基础入门

参考资料 <<linux内核网络栈源代码情景分析>>Linux内核网络栈的基础内容 主要分析tcp/ip相关的基本构成&#xff0c;概述了socket的系统调用进入内核的一个流程&#xff0c;并了解了协议的执行流程。为后续的理解学习做铺垫。 应用程序调用进入内核的过程 Tcp/…