1.ANTLR简介
ANTLR的全称是ANother Tool for Language Recognition(另一种语言识别工具),他的前身是 PCCTS,和YACC,LEX,JavaCC, Coco/R等工具一样,也是编译器的编译器。
ANTLR是LL(K)文法的语法分析器生成器。
官方网站:http://www.antlr.org/
wikipedia:http://en.wikipedia.org/wiki/ANTLR
百度百科:http://baike.baidu.com/view/1268934.html
参考书籍: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

单独的ANTLR是一个命令行工具:
http://antlr.org/download/antlr-3.2.jar
可以将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
3.1 文法(词法规则与语法规则)描述文件  
// Expr.g
// 语法的名称要与文件名一致
grammar Expr;
 
//语法选项
options
{
    //输出C代码
language=C;
//生成抽象语法树
    output=AST;
    //语法树的类型为pANTLR3_BASE_TREE
    ASTLabelType=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     
    ;
 
//片段:指数
fragment
EXPONENT :
    ('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 ANTLR3
    if (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.源文件下载

        点击下载此文件


本文链接地址: Antlr.1 语法分析工具Antlr简介,表达式计算器的实现
https://blog.qingfengju.com/index.asp?id=195

上一篇: 用keybd_event模拟键盘按键
下一篇: 10分钟将SQLite应用到自己的项目中

分类:Win32/C++ 查看次数:14859 发布时间:2010/2/7 11:45:31