Lemon Parser Generator
来源:互联网 发布:淘宝卖家怎么关闭店铺 编辑:程序博客网 时间:2024/04/28 06:23
lighttpd的配置文件需要用到lemon来分析,lemon是一个LALR(1)的语法分析生成器。
本来以为要用到LALR(1)的知识,刚好上个学期学了编译原理这门课,但是由于课时
不够,Bottom-Up Parsing只讲了LR(0)和SLR(1),LR(1)和LALR(1)没讲到,所以在
尝试使用lemon之前特意花了一个小时去看了LR(1)和LALR(1)的知识。好在基础的
知识还没有还给老师,所以理解起来没有什么困难。不过看完lemon的文档之后发现
只需要知道一点编译原理的知识就可以了,不熟悉也问题不大。
Prepare
先到这里把lemon.c和lempar.c下载下来,再打开Documentation来学习一下。
其中lemon.c就是整个lemon parser generator的源代码了,而lempar.c则是
lemon默认使用的代码生成模板(从源代码中看出来的),一般来说用这个就
可以了。编译的话很简单:
$gcc lemon.c -o lemon
The Parser Interface
其实要用到的接口只有下面三个:还有一个用来调试的接口:void *pParser = ParseAlloc( malloc );ParseFree(pParser, free);Parse(pParser, hTokenID, sTokenData, pArg);
ParseTrace(FILE *stream, char *zPrefix);使用的一般套路是这样:
ParseFile(){ pParser = ParseAlloc( malloc ); while( GetNextToken(pTokenizer,&hTokenId, &sToken) ){ Parse(pParser, hTokenId, sToken); } Parse(pParser, 0, sToken); ParseFree(pParser, free ); }其中GetNextToken的方法有很多,简单的话可以自己手动切Token。
详细的内容可以自行参考lemon的Documentation,其实看例子比看文档
要直观,看完一个例子基本上自己可以模仿着用了。
Example
网上介绍lemon的文章基本上都以实现一个简单的计算器作为例子,那我
就照般吧,呵呵。
使用lemon的主要工作其实就是根据需要编写自己的rules,下面我们看一下
一个简单的计算器的rules (parser.y):
%include {#include <assert.h> /* lemon需要用到assert这个宏 */ }%token_type {int} /* 变量的类型 */%syntax_error { /* 当出现语法错误的时候,{}里面的语句就会执行 */ fprintf(stderr, "Syntax error\n"); }/* left是左结合的意思, PLUS和MINUS放在TIMES和DIVIDE之前表示PLUS和MINUS的优先级比TIMES和DIVIDE低 */%left PLUS MINUS.%left TIMES DIVIDE./* 下面的第一条rule的左边(program)默认是start symbol, 每一条rule后面的{}里面的是C代码,这些C代码会在它们reduce的时候被执行。*/program ::= expr(A). { printf("Result = %d\n", A); }expr(A) ::= expr(B) PLUS expr(C). { A = B + C; }expr(A) ::= expr(B) MINUS expr(C). { A = B - C; }expr(A) ::= expr(B) TIMES expr(C). { A = B * C; }expr(A) ::= expr(B) DIVIDE expr(C). { if (C != 0) A = B / C; else fprintf(stderr, "divide by zero\n");}expr(A) ::= LPAR expr(B) RPAR. { A = (B); }expr(A) ::= INTEGER(B). { A = B; }
然后让lemon来生成我们需要的代码:
$./lemon parser.y没有错误的话就会生成三个文件,parser.h, parser.c, parser.out
然后我们还需要自己编写一个main函数(calc.c)来调用上面提到的那些接口函数。
#include <stdio.h>#include <stdlib.h>#include "parser.h"int main(int argc, char *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 ' ': /* ignore whitespace */ break; default: fprintf(stderr, "Unknown symbol: %c\n", *c); return -1; } } Parse(pParser, 0, 0); ParseFree(pParser, free); return 0;}main函数除了调用那些接口之外,主要就是要自己手动切Token了,也很简单。
最后我们就可以编译得到我们的计算器了哦:
$gcc calc.c parser.c -o calc好的,如无意外我们的计算器就做好了哦。现在回想起我大一写计算器的时候,
面对那些表达式调试了好几天才做好呢,现在估计半个小时就可以了,^_^
试用一下看看:
$./calc "(123 + 456) * 10 + 9"Result = 5799
- Lemon Parser Generator
- The LEMON Parser Generator
- Parser Generator
- ABNF parser generator
- Parser Generator使用说明
- Parser Generator 安装
- Parser Generator的使用说明
- Parser Generator的使用说明
- Parser Generator的使用说明
- a Tiny Parser Generator
- Parser Generator的使用说明
- Parser Generator配置方法
- Parser Generator (Lex &Yacc)
- Parser Generator 和vc++6.0的配置
- yacc/lex windows 下 Parser Generator 使用指南
- VC6.0 + Parser Generator 2 详细设置
- Parser Generator 配置方法
- 在VS2013上配置parser generator
- C/C++中static关键字详解
- VCN的使用
- Ajax的常用技巧(1)----实现表单数据验证
- 添加警报视图UIAlertView
- 转:可怕的90后:被互联网公司忽视的一代
- Lemon Parser Generator
- ServletConfig 接口和ServletContext 接口
- 盖世兔I9100刷机心得
- 采用通用管理界面简化IT管理
- Nios II 定时器内核
- 加密算法
- Ajax的常用技巧(2)---实现Web页面中的级联菜单
- 云端的使用
- text-indent属性缩进无效解决方法