博客日历
2024年11月 | ||||||
一 | 二 | 三 | 四 | 五 | 六 | 七 |
28 | 29 | 30 | 31 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 1 |
存档
2024年03月 04月 05月 2021年
01月 02月 11月 12月 2020年
02月 03月 04月 05月 06月 07月
09月 2018年
09月 2017年
01月 02月 07月 2016年
01月 04月 07月 08月 11月 12月
2015年
01月 02月 03月 05月 09月 10月
11月 2014年
01月 02月 03月 04月 05月 06月
07月 08月 09月 10月 11月 12月
2013年
01月 02月 03月 04月 05月 06月
07月 08月 09月 10月 11月 12月
2012年
01月 02月 03月 04月 05月 06月
07月 08月 09月 10月 11月 12月
2011年
01月 02月 03月 04月 05月 06月
07月 08月 09月 10月 11月 12月
2010年
01月 02月 03月 04月 05月 06月
07月 08月 09月 10月 11月 12月
2009年
03月 04月 05月 06月 07月 08月
09月 10月 11月 12月
Antlr.1 语法分析工具Antlr简介,表达式计算器的实现
1.ANTLR简介
ANTLR的全称是ANother Tool for Language Recognition(另一种语言识别工具),他的前身是 PCCTS,和YACC,LEX,JavaCC, Coco/R等工具一样,也是编译器的编译器。
ANTLR是LL(K)文法的语法分析器生成器。
wikipedia:http://en.wikipedia.org/wiki/ANTLR
参考书籍:Definitive ANTLR Reference.pdf
2. ANTLR的下载与安装
ANTLR本身是用Java开发的,需要首先安装JDK(需要注意不同版本的ANTLR使用的Java版本也不同,本文所用的ANTLR需要JDK1.5及其以上版本)。
安装ANTLR很简单,只需要下载下来并解压即可。
ANTLRWorks是ANTLR的集成开发环境:
http://www.antlr.org/download/antlrworks-1.3.1.jar
http://www.antlr.org/download/antlrworks-1.3.1.jar
单独的ANTLR是一个命令行工具:
http://antlr.org/download/antlr-3.2.jar
可以将antlr-3.2.jar的路径加入到classpath中,通过命令java antlr.Tool来调用。
可以将antlr-3.2.jar的路径加入到classpath中,通过命令java antlr.Tool来调用。
3.初步使用体验
要使用ANTLR,首先需要编写一个扩展名为”.g”的文法描述文件,这是个文本文件。其中的内容是词法分析器和语法分析器的文法规则。
ANTLR通过分析这个文件来生成词法分析器和语法分析器的代码,ANTLR3.X支持生成Java,C#,JavaScript,C(antlr通过一些技巧用函数指针等模拟了面向对象的编程方法)几种代码,这些代码的结构是相似的。
下面通过开发一个很简单的表达式计算工具,来简要说明ANTLR的使用方法。
这个表达式计算器所支持的语法:
4.08/2.0+2*(3.2E-3+9.6); //不支持负数,计算结果为:21.2464
4.08/2.0+2*(3.2E-3+9.6); //不支持负数,计算结果为:21.2464
3.1 文法(词法规则与语法规则)描述文件
// Expr.g// 语法的名称要与文件名一致grammar Expr;//语法选项options{//输出C代码language=C;//生成抽象语法树output=AST;//语法树的类型为pANTLR3_BASE_TREEASTLabelType=pANTLR3_BASE_TREE;}tokens{PLUS = '+';MINUS = '-';MULT = '*';DIV = '/';}//表达式语句statments :expr ';'! //"!"表示将此节点在语法树中忽略;//加法和减法
//"^"表示将当前节点作为语法树的根节点
expr :mult_div_expr ((PLUS^ | MINUS^) mult_div_expr)*;//乘法与除法mult_div_expr :item ((MULT^ | DIV^) item)*;//表达式的因子item :INT| DOUBLE| '('! expr ')'!;//整数INT :'0'..'9'+;//浮点数DOUBLE :('0'..'9')+ '.' ('0'..'9')* EXPONENT?| '.' ('0'..'9')+ EXPONENT?| ('0'..'9')+ EXPONENT;//片段:指数fragmentEXPONENT :('e'|'E') ('+'|'-')? ('0'..'9')+;//空白WHITESPACE :(' '|'\t'|'\n'|'\r')+ {$channel=HIDDEN;};
3.2 使用生成的代码
这里我们使用了C语言作为我们生成的目标代码。相应的C运行时源码(需要使用VS2008编译)下载地址:
http://antlr.org/download/C/libantlr3c-3.1.tar.gz首先创建一个控制台应用程序(使用VS2008),注意:不要使用预编译头。将output目录中生成的文件添加到项目中,并在编译和连接选项中附加antlr的运行时(也可以通过VC++的include,lib目录选项来设置)。源代码如下:
// Expr.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include <iostream>#include <stack>using namespace std;#include <antlr3.h>#include "output/ExprLexer.h"#include "output/ExprParser.h"#pragma comment(lib,"antlr3c.lib")
//递归显示语法树void DisplayTree(pANTLR3_BASE_TREE tree){static int Level=0;Level++;int k = Level;while ((--k) > 0){cout<<"│";}cout<<"├" << tree->getText(tree)->chars<< endl;for (unsigned int i = 0; i < tree->getChildCount(tree); i++){pANTLR3_BASE_TREE tmp_tree = (pANTLR3_BASE_TREE)tree->getChild(tree,i);DisplayTree(tmp_tree);}Level--;}//存放中间结果的栈stack<double> numbers;
//计算void OP(UINT opType,double num1,double num2){double resault=0.0;switch(opType){case PLUS:{resault = num2 + num1;cout<<num2<<"+"<<num1<<"="<<resault<<";"<<endl;break;}case MINUS:{resault = num2 - num1;cout<<num2<<"-"<<num1<<"="<<resault<<";"<<endl;break;}case MULT:{resault = num2 * num1;cout<<num2<<"*"<<num1<<"="<<resault<<";"<<endl;break;}case DIV:{resault = num2 / num1;cout<<num2<<"/"<<num1<<"="<<resault<<";"<<endl;break;}default:break;}numbers.push(resault);}void CalcTree(pANTLR3_BASE_TREE tree){//cout<<(tree.Text);for (unsigned int i = 0; i < tree->getChildCount(tree); i++){pANTLR3_BASE_TREE tmp_tree = (pANTLR3_BASE_TREE)tree->getChild(tree,i);CalcTree(tmp_tree);}double resault=0;//当前节点类型switch (tree->getType(tree)){case PLUS:case MINUS:case MULT:case DIV:{double a1=numbers.top();numbers.pop();double a2=numbers.top();numbers.pop();OP(tree->getType(tree),a1,a2);break;}case INT:{numbers.push(atoi((char*)tree->getText(tree)->chars));break;}case DOUBLE:{numbers.push(atof((char*)tree->getText(tree)->chars));break;}default:{break;}}}int _tmain(int argc, _TCHAR* argv[]){//char *szExp="(4.08e-3)+6/(2.0+2*(4.6E+2-6+2)*5.15362)+1;";//1.00536//cout<<(4.08e-3)+6/(2.0+2*(4.6E+2-6+2)*5.15362)+1<<endl;char szBuf[512];cin>>szBuf;strcat(szBuf,";");//输入pANTLR3_INPUT_STREAM input= antlr3NewAsciiStringInPlaceStream((pANTLR3_UINT8)szBuf,strlen(szBuf),0);if ( input == NULL ){ANTLR3_FPRINTF(stderr,"Error to load Expression.");return -1;}//生成的词法分析器pExprLexer lexer=ExprLexerNew(input);if ( lexer == NULL ){ANTLR3_FPRINTF(stderr, "Unable to create the lexer due to malloc() failure1\n");return -1;}/*cout<<"\n---------tokens-------------------\n";pANTLR3_COMMON_TOKEN t;//合法的词法元素int i=1;do{t = TOKENSOURCE(lexer)->nextToken(TOKENSOURCE(lexer));if (t != NULL){if (t->channel!=HIDDEN &&
strcmp((char *)(t->getText(t)->chars),"<EOF>")!=0){cout<<i++<<": \t"<<t->type
<<"\t"<<t->getText(t)->chars<<endl;}}}while (t == NULL || t->getType(t) != ANTLR3_TOKEN_EOF);*///token流pANTLR3_COMMON_TOKEN_STREAM tstream = antlr3CommonTokenStreamSourceNew(ANTLR3_SIZE_HINT, TOKENSOURCE(lexer));if (tstream == NULL){ANTLR3_FPRINTF(stderr, "Out of memory trying to allocate token stream\n");return -1;}pExprParser parser = ExprParserNew(tstream); // CParserNew is generated by ANTLR3if (parser == NULL){ANTLR3_FPRINTF(stderr, "Out of memory trying to allocate parser\n");return -1;}ExprParser_statments_return statments = (ExprParser_statments_return)(parser->statments(parser));if(parser->pParser->rec->state->errorCount>0){ANTLR3_FPRINTF(stderr, "The parser returned %d errors, tree walking aborted.\n",parser->pParser->rec->state->errorCount);return -1;}pANTLR3_BASE_TREE tree=(pANTLR3_BASE_TREE)statments.tree;if (tree == NULL){ANTLR3_FPRINTF(stderr, "tree error.\n");return -1;}cout<<"\n---------Tree-------------------\n";DisplayTree(tree);cout<<"\n---------Calc-------------------\n";CalcTree(tree);return 0;}
3.3 执行结果
输入:
4.08/2.0+2*(3.2E-3+9.6);输出:---------Tree-------------------
├ +
│├ /
││├ 4.08
││├ 2.0
│├ *
││├ 2
││├ +
│││├ 3.2E-3
│││├ 9.6
---------Calc-------------------4.08/2=2.04;0.0032+9.6=9.6032;2*9.6032=19.2064;2.04+19.2064=21.2464;
4.源文件下载
上一篇: 用keybd_event模拟键盘按键
下一篇: 10分钟将SQLite应用到自己的项目中
分类:Win32/C++ 查看次数:14859 发布时间:2010/2/7 11:45:31