`

antlr使用教程

阅读更多
我从以下几个问题入手介绍ANTLR的相关知识。
1 ANTLR是什么?
ANTLR, ANother Tool for Language Recognition, 是一个可以接受含有语法描述的语言描述符并且生成程序能够识别这些语言所产生的句子。作为一个翻译程序的 一部分,你可以给你的语法附上简单的操作符和行为并且告诉ANTLR如何构造AST并且如何输出它们。ANTLR知道如何使用Java,C++,C#或者Python来生成它们。
ANTLR知道如何构造识别程序并且将语法结构应用到三种不同的输入上:(i) 字符流, (ii) 标记(token)流,(iii) 二维树结构。本质上这些对应了词法分析器(Lexer),解析器(Parser)和Tree Walker。用于制定这些语法(Grammar)的句法(Syntax),被称 为meta-language,在所有情况下是独立的。
一旦你适应了ANTLR或者相应的工具,你将会以另一种眼光来看待编程。很多任务期待一种不同于传统编程语言流派的语言解决方案。举个例子,这些课程的笔记就是用TML编写 的,Terence's Markup Language。我讨厌输入HTML所以我用ANTLR编写了一个简单的翻译程序来转换文本成为HTML或者PDF或者其他我讨厌直接编写的东西。
(以上摘自http://www.cs.usfca.edu/~parrt/course/652/lectures/antlr.html)
2 ANTLR能做些什么?
ANTLR仅仅是一个工具!它帮你通过自动生成单调乏味的组件来构造程序,但并不试图让你创造一个完整的编译器,举个例子,单行的描述。
3 ANTLR怎么搭建环境?
我安装的是插件形式的ANTLR,它的版本为2.7.6.
当其他插件安装一样,比较简单。
或者:
1 、从 http://www.antlr.org/ 上下载 antlr-x.x.x.jar
2 、配置环境变量: classpath=.;x:\jdk\lib\tools.jar;x:\antlr-x.x.x.jar
3 、在命令提示符环境里在 t.g 所在目录下执行:
java antlr.Tool t.g

4 ANTLR语法文件怎么写?
4.1 Antlr 的主要类:
Antlr 中有主要类有两种(其实还有一种 TreeLexer )
Lexer: 文法分析器类。主要用于把读入的字节流根据规则分段。既把长面条根据你要的尺寸切成一段一段:)并不对其作任何修改。
Parser: 解析器类。主要用于处理经过 Lexer 处理后的各段。一些具体的操作都在这里。
4.2 Antlr 文法文件形式:
Antlr 文件是 *.g 形式,即以 g 为后缀名。
例如: t.g
class P extends Parser;
startRule
:   n:NAME
{System.out.println("Hi there, "+n.getText());}
class L extends Lexer;
// one-or-more letters followed by a newline
NAME:   ( 'a'……'z'|'A'……'Z' )+ NEWLINE
NEWLINE
:   '\r' '\n'   // DOS
|   '\n'        // UNIX 网管u家u.bitsCN.com

4.3 具体成分分析:
1 、总体结构
Class P extends Parser
Class L extends Lexer
两行同 JAVA 继承一样, P 继承 Parser 类; L 继承 Lexer 类。每个 .g 文件只能各有一个。
2 、 Lexer 类分析
一般按照:
类型名:匹配的具体规则的形式构成。是分隔字节流的依据。同时可以看到里面可以互相引用。如本例中的类型名 NEWLINE 出现在 NEW 的匹配规则中。
4.4 Parser 类分析
一般按照
起始规则名:
规则实例名:类型名或规则名
{Java 语句……; };
……
的形式构成。
起始规则名:任意。
 规则实例名:就象 Java 中“ String s ;”的 s 一样。规则实例名用于在之后的 JAVA 语句中调用。
 类型名或规则名:可以是在 Lexer 中定义的类型名,也可以是 Parser 中定义的规则名。感觉就像是 int 与 Integer 的区别。
Java 语句:指当满足当前规则时所执行的语句。 Antlr 会自动嵌入生成的 java 类中。
三、生成 Java 类
会在当前目录下生成如下文件:
L.java : Lexer 文法分析器 java 类。
P.java : Parser 解析器 java 类。
PTokenTypes.java : Lexer 中定义的类型具体化,供 Parser 解析器调用。
PTokenTypes.txt :当外部的(如 t2.g )要调用当前的类型或规则时要用到本文件。
4.5 执行
1 、编写 Main 类
import java.io.*;
class Main {
public static void main(String[] args) {
try {
L lexer = new L(new DataInputStream(System.in));
P parser = new P(lexer);
parser.startRule();
} catch(Exception e) {
System.err.println("exception: "+e);
}
5 再从编写一个表达式解析器文件介绍一下ANTLR语法:
表达式是几乎所有高级编程语言中,都会出现的重要组成部分。因此,如何准确的理解一个表达式,可以说是各种不同的语言所共同面临的问题。表达式千变万化,真正要想正确解释C/C++那样的复杂表达式,是非常困难的,我们这里只从最简单的表达式做起。
假设一个表达式中,只有常量,没有变量。所有的运算只有:“+”、“-”、“*”、“/”、“^”、“%”六种,而且没有括号,只有整数,没有小数。就这么简单,要解释这样的表达式,我们如果要想自己写个程序来解释,只怕也是非常麻烦的吧,而且要写一个功能全面且BUG很少的解释器势必要大费周折。
现在有了ANTLR,我们只需要将定义写清楚,程序就会自动帮我们生成了。可以先下载一个人家现成的文件来看看:expression.g,然后再antlr expression.g生成一堆java文件。
接下来的步骤和前面的也差不多,建一个Main.java,
import java.io.*;
import antlr.CommonAST;
import antlr.collections.AST;
import antlr.debug.misc.ASTFrame;
public class Main {
  public static void main(String args[]) {
    try {
      DataInputStream input = new DataInputStream(System.in);
ExpressionLexer lexer = new ExpressionLexer(input);
    ExpressionParser parser = new ExpressionParser(lexer);

      parser.expr();
      CommonAST parseTree = (CommonAST)parser.getAST();
      System.out.println(parseTree.toStringList());
      ASTFrame frame = new ASTFrame("The tree", parseTree);
      frame.setVisible(true);

      ExpressionTreeWalker walker = new ExpressionTreeWalker();
      double r = walker.expr(parseTree);
      System.out.println("Value: "+r);
    } catch(Exception e) { System.err.println("Exception: "+e); }
  }
}
执行这个Main.class,输入个表达式给它试一试,比如: 1+2-3*4/5^6;系统应该就能给出正确的答案了:
( - ( + 1 2 ) ( / ( * 3 4 ) ( ^ 5 6 ) ) ) ;
Value: 2.999232

咱们来一句一句的解释一下这个expression.g文件。还是从最简单的几行开始:

class ExpressionLexer extends Lexer; //这是用来声明一个词法分析器,名字叫
                                                   //ExpressionLexer

PLUS  : '+' ;                                   //加号
MINUS : '-' ;                                   //减号
MUL   : '*' ;                                   //乘号
DIV   : '/' ;                                    //除号
MOD   : '%' ;                                 //求余
POW   : '^' ;                                 //开方
SEMI  : ';' ;                                    //结束号
                                                   //上面这些都太简单了,简直就不需要说明

protected DIGIT : '0'..'9' ;               //数字,这是一个受保护的单词,只能被
                                                   //词法分析器内部使用
INT   : (DIGIT)+ ;                           //出现了一次以上的数字的词,就是整数,
                                                   //它通过受保护的单词:“数字”来定义自己。
//如果DIGIT不是被保护的单词,则词法分析器就会
                                                   //无法分辨究竟是数字还是整数了

接下来看语法分析器的代码:

class ExpressionParser extends Parser;   //定义一个语法分析器,名字叫ExpressionParser
options { buildAST=true; }                  //告诉ANTLR,要帮我生成一棵抽象语法树,
                                                       //留着以后有用

//接下来的部分就非常复杂了,主要是多出来了两个特殊的符号“!”、“^”
//这两个符号,不是EBNF原有的,而是ANTLR为了生成AST而增加的符号
//“!”,是告诉AST生成程序,不要把自己算进去
//“^”,是告诉AST生成程序,把这个符号,放在一颗树的根部,或者一颗子树的根部
//另外,“*”表示出现0次以上,“+”表示出现一次以上,“?”表示出现0或1次

/*以下为定义一个语法的规则,一般采用递归的形式来规定。
即就是它描述了一个表达式的表达形式。解析和计算表达式的方式有很多种。在使用递归下降的解析器时,表达式被视为递归的数据结构—— 表达式由其本身来定义。假定表达式只能使用+、-、*、/和圆括号,那么所有的表达式可以用下面的规则来定义:
表达式 项 [+项] [–项]
项因数[*因数] [/因数]
因数变量、数字或者(表达式)
方括号里面表示可选元素,而箭头表示箭头前面的元素由箭头后面的元素定义产生。实际上,该规则通常被称为表达式的生成规则。因此,对于项的定义可以这样表述:“项由因数乘以因数或者因数除以因数产生。”需要注意的是,运算符的优先级已经隐含在表达式的定义中。 */
expr     : sumExpr SEMI!;                                  //“;”作为结束符,不放入AST
sumExpr  : prodExpr ((PLUS^|MINUS^) prodExpr)* ;     //“+”“-”作为计算符号
                                                                              //放在树的顶部
prodExpr : powExpr ((MUL^|DIV^|MOD^) powExpr)* ; //剩下的就不解释了,都能明白的
powExpr  : atom (POW^ atom)? ;
atom     : INT ;

再来看AST计算器的代码。这“AST计算器”是我起的名字,也就是通过对一个生成的抽象语法树,递归求值,得到最后的结果。

{import java.lang.Math;}                                     //ExpressionTreeWalker要用到的
class ExpressionTreeWalker extends TreeParser;    //声明一个树计算器
expr returns [double r]                                      //有一个方法叫expr
                                                                      //它的返回值是double类型
  {double a,b; r=0; }                                         //嵌入的代码,后面要用到

  : #(PLUS a=expr b=expr)  { r=a+b; }               //以下就是计算各种算符,不用多说了
  | #(MINUS a=expr b=expr) { r=a-b; }
  | #(MUL  a=expr b=expr)  { r=a*b; }
  | #(DIV  a=expr b=expr)  { r=a/b; }
  | #(MOD  a=expr b=expr)  { r=a%b; }
  | #(POW  a=expr b=expr)  { r=Math.pow(a,b); }
  | i:INT { r=(double)Integer.parseInt(i.getText()); }
  ;
5.1 完整的expression.g文件:
class ExpressionParser extends Parser;
options { buildAST=true; }

expr     : sumExpr SEMI;
sumExpr  : prodExpr ((PLUS^|MINUS^) prodExpr)*;
prodExpr : powExpr ((MUL^|DIV^|MOD^) powExpr)* ;
powExpr  : atom (POW^ atom)? ;
atom     : INT ;

class ExpressionLexer extends Lexer;

PLUS  : '+' ;
MINUS : '-' ;
MUL   : '*' ;
DIV   : '/' ;
MOD   : '%' ;
POW   : '^' ;
SEMI  : ';' ;
protected DIGIT : '0'..'9' ;
INT   : (DIGIT)+ ;

{import java.lang.Math;}
class ExpressionTreeWalker extends TreeParser;

expr returns [double r]
  { double a,b; r=0; }

  : #(PLUS a=expr b=expr)  { r=a+b; }
  | #(MINUS a=expr b=expr) { r=a-b; }
  | #(MUL  a=expr b=expr)  { r=a*b; }
  | #(DIV  a=expr b=expr)  { r=a/b; }
  | #(MOD  a=expr b=expr)  { r=a%b; }
  | #(POW  a=expr b=expr)  { r=Math.pow(a,b); }
  | i:INT { r=(double)Integer.parseInt(i.getText()); }
6 ANTLR使用中的一些使用心得:
1):在此法分析中,比如要描述一个“>=”与”>”时,如果用
BEQUAL:('>''=');
BIGER:”>”;
当语法文件进行此法分析的时,当扫描到一个”>”形式时,不知道是将其当BEQUAL还是当BIGER符号处理,即出现了冲突,那么可以采用以下这种形式定义:
BEQUAL:('>''=')=>('>''=')|'>'{ $setType(BIGER); };//它的形式为: (...)=>(...)|(...)。这相当于一般语言中的三元表达式:(1)?(2):(3)。如果式1为真,则返回式2的值,否则返回式3的值。
2):在ANTLR中一个规则相当与JAVA语言中的一个函数,因此它可以有传参和返回值,例如:
expr[HashMap hm] returns [String s]//即相当于JAVA中的:
public String expr(HashMap hm){…}
3):ANTLR中可以内嵌生成的目标语言 如:{import java.lang.Math;}
3
1
分享到:
评论

相关推荐

    编译器的编译器antlr的教程

    在后续章节中,教程将深入ANTLR的使用,包括如何定义语法、处理语义动作、生成解析树、以及如何利用ANTLR生成的解析器进行实际的输入处理。此外,还将讨论ANTLR的优化技巧、错误处理策略,以及如何结合其他工具进行...

    ANTLR 4简明教程.epub

    ANTLR 4简明教程.epub

    The Definitive ANTLR Reference

    2. **ANTLR使用教程**:详细讲解ANTLR的基本使用方法,包括如何定义文法、生成解析器代码等。 3. **高级主题**:涉及ANTLR的高级特性,如错误处理、树解析等。 4. **案例研究**:通过具体实例展示ANTLR的应用场景和...

    antlr-v4jar包和使用教程

    在本教程中,我们将专注于ANTLR 4,特别是其jar包的使用以及如何通过它来生成词法分析器和语法分析器的Java代码。 ANTLR 4 使用LL(1)解析技术,这是一种自上而下的解析策略,其中LL代表“Left-to-Right,Leftmost...

    antlr经典教程,The definitive antlr reference(英文)

    《The Definitive ANTLR Reference》是一本经典的ANTLR教程,该书对ANTLR的关键概念和技术进行了深入浅出的讲解,是ANTLR学习者不可或缺的参考书籍之一。 #### 三、核心知识点 ##### 1. Grammar(文法规则) - **...

    ANTLR入门详细教程定稿.pdf

    ANTLR入门详细教程定稿.pdf

    Antlr教程文法分析器

    - 使用 Antlr 工具,如 `antlr Tool t.g` 命令,可以将文法文件转换成对应的 Java 源代码。这会产生如 L.java 和 P.java 两个类,分别对应 Lexer 和 Parser,以及 PTokenTypes.java 和 PTokenTypes.txt 文件,用于...

    antlr-2.7.7.jar

    - **文档和示例**:虽然资源可能较少,但仍可以在网上找到一些关于ANTLR 2的教程和示例代码,帮助你理解和使用它。 - **升级考虑**:如果可能,考虑升级到ANTLR 4,因为新版本提供了更多功能和性能优化,且有更好的...

    Antlr入门详细教程

    - 使用Antlr的`antlr.Tool`命令,可以将`.g`文法文件转换为Java源代码。生成的文件包括Lexer类(如`L.java`)、Parser类(如`P.java`)以及Token类型文件(如`PTokenTypes.java`和`PTokenTypes.txt`)。 - Token...

    The Definitive ANTLR 4 Reference.pdf_antlr_

    10. **社区支持**:ANTLR有一个活跃的社区,提供了大量的语法文件示例、教程和工具,方便用户快速上手和解决问题。 通过阅读《Definitive ANTLR 4 Reference》这本书,读者可以深入理解ANTLR 4的工作原理,学习如何...

    antlr 五分钟入门

    6. **示例解析**:教程会通过一个具体的例子,如解析年龄相关的语句,来演示如何使用ANTLR解析器。可能的例子如"age is 30",ANTLR会解析出"age"和"30"两个关键元素。 7. **错误处理**:介绍ANTLR如何处理语法错误...

    antlr开发eclipse插件

    在压缩包文件中,你可能会找到一些示例ANTLR语法文件、Eclipse插件安装指南、配置教程以及使用示例。通过学习和实践这些文件,你可以更好地理解如何在Eclipse中配置ANTLR开发环境,使用ANTLR 4 IDE和Xtext来构建和...

    ANTLR的一些资料

    ANTLR的学习资源包括官方文档、教程、示例代码以及社区论坛,初学者可以通过这些资源快速上手。在实际项目中使用ANTLR时,需要编写语法规则文件,然后使用ANTLR工具生成解析器和词法分析器代码,最后集成到自己的...

    antlr-python-runtime-3.1.3.zip

    这通常意味着你可能找到有关ANTLR 3的文档、教程或者示例,对于学习和理解ANTLR如何工作非常有帮助。 ANTLR的工作流程大致如下: 1. **语法定义**:首先,你需要用ANTLR的语法定义语言(通常扩展名为.g或.grammar)...

    antlr-2.7.6.jar

    描述中的链接指向了iteye博客上的一篇文章,虽然具体内容未给出,但通常这类博客文章会包含ANTLR的使用教程、示例代码或者在特定项目中如何应用ANTLR的说明。博主FKSHL可能分享了如何利用ANTLR 2.7.6进行语法解析、...

    ANTLR参考手册

    8. **社区支持**:ANTLR拥有活跃的社区和丰富的资源,包括教程、示例、讨论论坛等,对于新手和高级开发者都是很好的学习平台。 ANTLR的使用流程通常包括以下步骤: 1. **定义语法**:编写ANTLR语法文件(.g4扩展名...

    收集的一些antlr资源

    Antlr入门详细教程.doc 利用ANTLR生成C 描述的分析程序.htm 使用 Antlr 处理文本.htm 使用 Antlr 开发领域语言.htm 强悍的ANTLR Lexer.htm a little madness » Blog Archive » ANTLR By Example Part 1 The ...

    antlr v2.7.5

    3. 文档:可能包含ANTLR的用户指南、API文档以及有关如何使用ANTLR的教程。 4. 示例:演示如何使用ANTLR创建和运行解析器的示例项目。 5. Ant任务:如果包含,可能有支持Apache Ant构建工具的任务定义,以便于集成到...

    antlr+stringtemplate示例

    在这个案例中,"log.txt"可能是记录生成过程的日志文件,而"using antlr+stringtemplate to generate method chaining"可能是一个包含详细实现步骤、代码示例或教程的文档。 总之,ANTLR和StringTemplate结合使用,...

Global site tag (gtag.js) - Google Analytics