`

ANTLR一个编译简单的两数相加的例子

阅读更多
如同程序设计语言入门大多采用“Hello World”一样,编译领域的入门往往选择计算器。一个只能计算两个数相加的计算器,也就是说,它可以计算“1+1”

编译过程分两步走:

1 先要能识别1+1这样的格式

检查输入的正确性,只有对正确的输入进行计算才是有意义的。如同写文章有形式和内容之分,这里的检查也要细分一下,这个过程叫做词法分析。在我们的计算器中,我们只接受整数和加号,其它的一概不理。这里我们说的是“整数”,而非 “1”、“2”……,对我们来说,它们代表着同一类的东西,编译原理称为叫做token

编写语法文件

制订好自己的语言规则之后,我们需要以Antlr的语言把它描述出来。
下面便是以Antlr的语言描述的语法:
class CaculatorParser extends Parser;
expr:   INT PLUS INT;

class CaculatorLexer extends Lexer;
PLUS  : '+' ;
INT   : ('0'..'9')+ ;

Antlr的语法文件通常会保存在一个“.g”的文件中,我们的语法文件叫做“caculator.g”。

先来看看Lexer部分,它便是我们前面所说的词法分析器。首先声明自己的Lexer:
class CaculatorLexer extends Lexer;
这句话有两个作用,其一,为生成代码中的词法分析器定义名字,其二,告诉Antlr,我要定义词法规则了。既然说到词法规则,紧接着我们就定义了两条词法规则:
PLUS  : '+' ;
INT   : ('0'..'9')+ ;
这里的规则很容易看懂:
* PLUS定义的token,就是一个单一的“+”
* INT定义的token,由从'0'到'9'之间任意的数字组成,后面的加号表示它是可以重复一次到多次

定义好Lexer之后,便轮到Parser了:
class CaculatorParser extends Parser;
它的作用同Lexer的定义一样,之后是语法规则:
expr:   INT PLUS INT;



编译语法文件

使用Antlr提供工具对我们的语法文件进行编译,不同 于日常的编译器输出可执行文件,这里的输出是程序语言的源文件。Antlr缺省目标语言是Java语言,它也可以支持C++和C#语言。

将antlr.jar加到classpath中,然后把语法文件的名称作为参数传给语法编译器:
java antlr.Tool caculator.g

在确保命令正确执行,且语法文件编写正确的情况下,Antlr为我们生成了几个文件:
CaculatorLexer.java
CaculatorLexerTokenTypes.java
CaculatorLexerTokenTypes.txt
CaculatorParser.java
CaculatorParserTokenTypes.java
CaculatorParserTokenTypes.txt

这里主要关心的是CaculatorLexer.java和CaculatorParser.java,它们就是我们在语法文件中定义的Lexer和Parser。其它几个文件只是定义了一些常量,让我们暂时忽略它们的存在。

运行程序
生成代码之后,就是如何使用这些生成的代码。下面就是我们的主程序,它负责将Lexer和Parser驱动起来:
public class Main {
    public static void main(String[] args) throws Exception {
        CaculatorLexer lexer = new CaculatorLexer(System.in);
        CaculatorParser parser = new CaculatorParser(lexer);
        try {
            parser.expr();
        } catch (Exception e) {
            System.err.println(e);
        }
    }
}
从这段代码中可以清晰的看出,Lexer的输入是一个字符流,而Parser则需要Lexer的协助来完成工作。我们可以输入一些内容,看它是否能够通过验证。事实证明,我们的程序可以轻松识别“1+1”,而对于不合法的东西,它会产生一些异常。

2 可以对其编译进行计算。

目标是计算出“1+1”的结果,而现在这个程序刚刚能够识别出“1+1”,还需要步骤。可以有两种方法来解析,分部是SAX和DOM方式:

SAX属于边解析边处理,而DOM则是把所有的内容解析全部解析完(在内存中形成语法树)之后,再统一处理。Antlr的SAX方式是在Parser中加入处理动作(Action)处理将随着解析的过程进行, 而DOM的伙伴则是解析形成一棵抽象语法树(Abstract Syntax Tree,AST),再对树进行处理。

SAX方式:

加入Action

因为处理动作是加在Parser中的,所以,我们的Lexer保持不变,下面是修改过的Parser。
class CaculatorParser extends Parser;
expr returns [int value=0]
      :  a : INT PLUS b : INT {
          int aValue = Integer.parseInt(a.getText());
          int bValue = Integer.parseInt(b.getText());
          value = aValue + bValue;
      };
这里有常用的字符串转整数的方法,这里定义Action的方法采用就是Java语言,因为我们生成的目标是Java,那这里的代码就要你需要的目标语言来编写。

action完全是在原有的规则基础上改造的来。首先用returns定义了这个Action的返回值,它将返回value这个变量的值,其类型是int,我们还顺便定义这个变量的初始值——“0”。接下来,用a、b拿住了两个token的值,我们前面说过,在检查的过程中,我们并 不关心每个token具体的内容,只要token的类型满足需要即可,但在action中,我们要计算结果,那必须使用token具体的内容,所以,我们 用变量拿住了token。在生成的代码中,a的类型antlr.Token,因此,我们通过a.getText()来获得token的具体值。剩下的动作 就很简单了,把文本转换为数字,进行加法运算。

然后生成全新的Parser。稍微修改一下主程序,就可以对1+1进行编译计算了
public class Main {
    public static void main(String[] args) throws Exception {
        CaculatorLexer lexer = new CaculatorLexer(System.in);
        CaculatorParser parser = new CaculatorParser(lexer);
        try {
            System.out.println(parser.expr());
        } catch (Exception e) {
            System.err.println(e);
        }
    }
}
在输入的时候 输入1+1 就可以得到结果了。



DOM方式
使用DOM方式,首先需建立一个AST语法树:
建立AST的方式很简单,只要我们Antlr一个建立AST的选项即可,下面就是新的Parser:
class CaculatorParser extends Parser;

options {
    buildAST=true;
}

expr:   INT PLUS^ INT;

稍微有些不同的地方在PLUS上面的“^”,这个符号用来告诉Antlr创建一个节点,以此作为当前树的根节点。

下面将DOM方式的重点部分TreeParser:
class CaculatorTreeParser extends TreeParser;

expr returns [int value = 0;]  //定义规则
      : #(PLUS a : INT b : INT) {
          int aValue = Integer.parseInt(a.getText());
          int bValue = Integer.parseInt(b.getText());
          value = aValue + bValue;
      };
Antlr 可以接受三种类型语法规范——Lexer、Parser和Tree-Parser。如果说Lexer处理的是字符流、Parser处理的是Token流, 那么TreeParser处理的则是AST。前面Action的处理方式中,我们看到,规则同处理放到了一起,显得有些混乱,而采用了AST的处理方式, 规则同处理就完全分离了:在Parser中定义规则,在TreeParser中定义处理,如果我们需要对同样的语法进行另外的处理,我们只要重新 TreeParser,从而降低耦合度,Hibernate采用的就是这种方式!!

可以参考前面ACTION,来看TreeParser如何编写也就简单许多,需要说明的就是:
#(PLUS a : INT b : INT)
除去变量的说明,简化一下这段代码
#(PLUS INT INT)
第一个符号PLUS对应了表示着根节点,两个INT则分别代表了两棵子树。

再来看看重新打造的主程序
public class Main {
    public static void main(String[] args) {
        CaculatorLexer lexer = new CaculatorLexer(System.in);
        CaculatorParser parser = new CaculatorParser(lexer);
        try {
            parser.expr();
            AST t = parser.getAST();
            CaculatorTreeParser treeParser = new CaculatorTreeParser();
            System.out.println(treeParser.expr(t));
        } catch (Exception e) {
            System.err.println(e);
        }
    }
}

在输入的时候 输入1+1 就可以得到结果了。



由此再参考Hibernate的处理方式,会发现很容易理解:

Session s = factory.openSession();

List auctions = s.createQuery("…");

createQuery()的调用过程

通过QueryPlanCache的getHQLQueryPlan()方法获得查询计划HQLQueryPlan的一个实例,而后者主要是调用了 QueryTranslator的compile方法,编译HQL语句。在QueryTranslator的继承类 QueryTranslatorImpl的doCompile观察这个过程:

PHASE 1 : Parse the HQL into an AST.

PHASE 2 : Analyze the HQL AST, and produce an SQL AST.

PHASE 3 : Generate the SQL.
分享到:
评论

相关推荐

    antlr入门 编译领域

    在这个例子中,我们定义了一个简单的语言文法,其中包括词法规则、语法规则和选项。ANTLR根据这些规则生成词法分析器和语法分析器。 #### 五、总结 ANTLR是一款非常实用的工具,尤其适用于编译原理的学习和实践。...

    antlr4入门例子

    在这个“antlr4入门例子”中,我们将会探讨如何使用ANTLR4创建一个简单的解析器来处理“hello world”这样的语句。"hello-antlr4"可能是项目或者示例代码的名称,它可能包含以下组件: 1. **ANTLR4 Grammar**:首先...

    基于ANTLR4的CMM语言编译器

    在本项目“基于ANTLR4的CMM语言编译器”中,开发人员使用ANTLR4来创建了一个针对CMM(可能是自定义中间表示或特定编程语言)的编译器。 编译器是计算机科学中的关键组成部分,它的主要任务是将源代码(程序员用高级...

    编译原理学习框架antlr4

    ANTLR4(ANTLR Version 4)是一个强大的解析器生成器,用于读取、处理、执行或翻译结构化文本或二进制文件。它广泛应用于构建语言、工具和框架,包括SQL解析器、Java代码分析器以及各种语法权限控制系统。ANTLR4支持...

    编译原理基于antlr的编译器

    编译原理是计算机科学中的一个重要领域,它研究如何将高级编程语言转换成机器可以理解的指令。ANTLR(ANother Tool for Language Recognition)是一个强大的解析工具,广泛用于构建语言、工具和框架,尤其在编译器和...

    ANTLR和Soot的完整例子

    ANTLR和Soot是两个在编译器领域广泛应用的工具,它们在软件开发和语言处理中起着关键作用。本实验将结合ANTLR与Soot,帮助我们深入理解编译原理,特别是语法规则的定义、语法树的生成以及中间代码的产生。 ANTLR是...

    编译原理课程设计有关antlr的词法分析和语法分析

    例如,对于一个简单的计算器,ANTLR的文法文件(calc.g)会定义表达式(Expr)、乘法表达式(mexpr)和原子(atom)等规则。词法分析器(CalcLexer)则负责识别并处理输入中的各种符号,如数字(INT)、加号(PLUS)...

    antlr 例子集 v3版

    ANTLR(ANother Tool for Language Recognition)是一个强大的解析器生成器,用于读取、处理、执行或翻译结构化文本或二进制文件。它广泛应用于构建语言、工具和框架,包括SQL、Java、C#、Python、JavaScript等。...

    antlr4应用例子

    基于antlr4的语义action和属性的编译器前端例子

    antlr3.12--工具+JAR+例子

    在提供的压缩包中,有两个关键文件: - `antlrworks-1.2.3.jar`:ANTLRWorks是一款集成开发环境(IDE),专门用于ANTLR的语法设计和调试。它提供了一个图形化的界面,可以直接编辑语法文件,进行语法错误检查,并且...

    Antlr4 C++ 计算器

    1. **语法定义**:首先,你需要为你的语言编写一个语法规则文件(通常为.g4扩展名),在这个例子中可能是`calculator.g4`。这个文件定义了计算器所能识别的表达式结构,例如数字、运算符和括号等。 2. **语法生成**...

    antlr 五分钟入门

    可能的例子如"age is 30",ANTLR会解析出"age"和"30"两个关键元素。 7. **错误处理**:介绍ANTLR如何处理语法错误,以及如何在代码中捕获并报告这些错误。 8. **源码分析**:可能会深入到ANTLR生成的Java源码中,...

    用Antlr 分析布尔表达式的例子

    用antlr分析处理布尔表达式的例子,包括:语法定义.g文件;生成的词法分析和语法分析器;带有图形界面的分析器调用代码。 其中带有GUI的分析器ParserFrame,可以用于任何.g文件生成的词法、语法分析器,只要通过改变...

    antlr3学习以及简单的应用--使用sql语句查询集合中的对象

    ANTLR3(ANTLR Version 3)是一个强大的解析器生成器,用于读取、处理、执行或翻译结构化文本或二进制文件。它广泛应用于构建语言、工具和框架,尤其是在处理结构化数据、语法分析和编译编译器领域。ANTLR 支持多种...

    ANTLR

    这个过程称为语法分析,包括词法分析和语法分析两个阶段。词法分析器(也称为分词器或词法器)将输入分解为一个个的词法单元,而语法分析器则将词法单元组合成符合语法规则的抽象语法树(AST)。 在Antlr初阶使用....

    antlr-3.0.1源码

    ANTLR, ANother Tool for Language ...作为一个翻译程序的 一部分,你可以给你的语法附上简单的操作符和行为并且告诉ANTLR如何构造AST并且如何输出它们。ANTLR知道如何使用Java,C++,C#或者Python来生成它们。

    基于 Antlr4 的 Hive SQL 解析.zip

    在本课程设计中,主题是“基于Antlr4的Hive SQL解析”,这涉及到了两个主要的技术领域:Antlr4和Hive SQL。Antlr4是一个强大的解析工具,用于生成解析器和词法分析器,它能处理各种语言的语法,包括SQL。而Hive SQL...

    用ANTLR实现一个简单加法计算器

    CSDN博客上不能添加附件,将文件放在这里,以供有兴趣的下载 加法器分析的地址:http://blog.csdn.net/evenfall/archive/2010/10/31/5978379.aspx

    antlr实现的计算器

    ANTLR的主要工作是生成解析器和词法分析器,这两个组件共同作用于输入文本,将它们转换为抽象语法树(AST,Abstract Syntax Tree)。在这个案例中,我们使用的描述文件很可能是用ANTLR的语法定义语言(通常称为ANTLR...

    ANTLRV3.0 探索(描述ANTLR3.0的应用开发流程)

    例如,以下是一个简单的ANTLR3.0语法文件示例,用于描述一个能处理两个整数相加的简单计算器: ```antlr grammar Calculator; expr: INT PLUS INT; PLUS : '+'; INT : ('0'..'9')+; ``` 在这个例子中,`expr`定义...

Global site tag (gtag.js) - Google Analytics