lemon的简单使用
发布日期:2021-07-25 13:05:02 浏览次数:21 分类:技术文章

本文共 5388 字,大约阅读时间需要 17 分钟。

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 -vCommand line syntax error: undefined option.lemon -v       ^-- hereValid command line options for "lemon" are:  -b           Print only the basis in report.  -c           Don't compress the action table.  -d
Output directory. Default '.' -D
Define an %ifdef macro. -f
Ignored. (Placeholder for -f compiler options.) -g Print grammar without actions. -I
Ignored. (Placeholder for '-I' compiler options.) -m Output a makeheaders compatible file. -l Do not print #line statements. -O
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
Specify a template file. -W
Ignored. (Placeholder for '-W' compiler options.)

至此,lemon就配置完成。

编写规则文件

%include {	#include 
}%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; else fprintf(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 
#include
#include "first_lemon.h"int main(int argc, char const *argv[]){ void *pParser; char *c; int value; if (argc != 2){ fprintf(stderr, "usage: %s
\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 : 1INTERGER(yymsp[0].minor.yy0)  : yylhsminor.yy0 : -289395680, yymsp[0].minor.yy0 : 2PLUS  : yylhsminor.yy0 : 3, yymsp[-2].minor.yy0 : 1, yymsp[0].minor.yy0 : 2INTERGER(yymsp[0].minor.yy0)  : yylhsminor.yy0 : -289395680, yymsp[0].minor.yy0 : 3PLUS  : yylhsminor.yy0 : 6, yymsp[-2].minor.yy0 : 3, yymsp[0].minor.yy0 : 3LPAR and RPAR  : yymsp[-2].minor.yy0 : 0, yymsp[-1].minor.yy0 : 6INTERGER(yymsp[0].minor.yy0)  : yylhsminor.yy0 : -289395680, yymsp[0].minor.yy0 : 2TIMES  : yylhsminor.yy0 : 12, yymsp[-2].minor.yy0 : 6, yymsp[0].minor.yy0 : 2Result = 12

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

总结

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

转载地址:https://blog.csdn.net/qq_33339479/article/details/96978832 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Linux内核网络栈1.2.13-有关tcp/ip协议的基础入门
下一篇:sqlite-1.0.0源码执行的基本流程概述

发表评论

最新留言

留言是一种美德,欢迎回访!
[***.207.175.100]2024年04月15日 09时51分37秒