




已阅读5页,还剩36页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
一、 Antlr 的主要类:Antlr 中有主要类有两种(其实还有一种 TreeLexer )Lexer: 文法分析器类。主要用于把读入的字节流根据规则分段。既把长面条根据你要的尺寸切成一段一段:)并不对其作任何修改。Parser: 解析器类。主要用于处理经过 Lexer 处理后的各段。一些具体的操作都在这里。二、 Antlr 文法文件形式:Antlr 文件是 *.g 形式,即以 g 为后缀名。例如: t.gclass P extends Parser;startRule: n:NAMESystem.out.println(Hi there, +n.getText();class L extends Lexer;/ one-or-more letters followed by a newlineNAME: ( az|AZ )+ NEWLINE;NEWLINE: r n / DOS| n / UNIX;具体成分分析:1 、总体结构Class P extends ParserClass L extends Lexer两行同 JAVA 继承一样, P 继承 Parser 类; L 继承 Lexer 类。每个 .g 文件只能各有一个。2 、 Lexer 类分析一般按照类型名:匹配的具体规则;的形式构成。是分隔字节流的依据。同时可以看到里面可以互相引用。如本例中的类型名 NEWLINE 出现在 NEW 的匹配规则中。3 、 Parser 类分析一般按照起始规则名:规则实例名:类型名或规则名Java 语句; ;的形式构成。起始规则名:任意。规则实例名:就象 Java 中“ String s ;”的 s 一样。规则实例名用于在之后的 JAVA 语句中调用。类型名或规则名:可以是在 Lexer 中定义的类型名,也可以是 Parser 中定义的规则名。感觉就像是 int 与 Integer 的区别。Java 语句:指当满足当前规则时所执行的语句。 Antlr 会自动嵌入生成的 java 类中。三、生成 Java 类1 、从 上下载 antlr-x.x.x.jar2 、配置环境变量: classpath=.;x:jdklibtools.jar;x:antlr-x.x.x.jar3 、在 t.g 所在目录下执行:java antlr.Tool t.g会在当前目录下生成如下文件:L.java : Lexer 文法分析器 java 类。P.java : Parser 解析器 java 类。PTokenTypes.java : Lexer 中定义的类型具体化,供 Parser 解析器调用。PTokenTypes.txt :当外部的(如 t2.g )要调用当前的类型或规则时要用到本文件。四、执行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);2 、执行c: javac *.javac: java MainTerenceZHi there, Terencec:antlr入门教程1一、 Antlr 的主要类: Antlr 中有主要类有两种(其实还有一种 TreeLexer ) Lexer: 文法分析器类。主要用于把读入的字节流根据规则分段。既把长面条根据你要的尺寸切成一段一段:)并不对其作任何修改。 Parser: 解析器类。主要用于处理经过 Lexer 处理后的各段。一些具体的操作都在这里。 二、 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 ; 具体成分分析: 1 、总体结构 Class P extends Parser Class L extends Lexer 两行同 JAVA 继承一样, P 继承 Parser 类; L 继承 Lexer 类。每个 .g 文件只能各有一个。 2 、 Lexer 类分析 一般按照 类型名: 匹配的具体规则 ; 的形式构成。是分隔字节流的依据。同时可以看到里面可以互相引用。如本例中的类型名 NEWLINE 出现在 NEW 的匹配规则中。 3 、 Parser 类分析 一般按照 起始规则名: 规则实例名:类型名或规则名 Java 语句。; ; 。 的形式构成。 起始规则名:任意。 规则实例名:就象 Java 中“ String s ;”的 s 一样。规则实例名用于在之后的 JAVA 语句中调用。 类型名或规则名:可以是在 Lexer 中定义的类型名,也可以是 Parser 中定义的规则名。感觉就像是 int 与 Integer 的区别。 Java 语句:指当满足当前规则时所执行的语句。 Antlr 会自动嵌入生成的 java 类中。 三、生成 Java 类 1 、从 /url 上下载 antlr-x.x.x.jar 2 、配置环境变量: classpath=.;x:jdklibtools.jar;x:antlr-x.x.x.jar 3 、在 t.g 所在目录下执行: java antlr.Tool t.g 会在当前目录下生成如下文件: L.java : Lexer 文法分析器 java 类。 P.java : Parser 解析器 java 类。 PTokenTypes.java : Lexer 中定义的类型具体化,供 Parser 解析器调用。 PTokenTypes.txt :当外部的(如 t2.g )要调用当前的类型或规则时要用到本文件。 四、执行 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); 2 、执行 c: javac *.javac: java MainTerenceZHi there, Terencec: 本文作者kingchou是CowNew开源团队SQL解析引擎项目组负责人。Antlr入门详细教程一、 Antlr 的主要类:Antlr 中有主要类有两种(其实还有一种 TreeLexer )Lexer: 文法分析器类。主要用于把读入的字节流根据规则分段。既把长面条根据你要的尺寸切成一段一段:)并不对其作任何修改。Parser: 解析器类。主要用于处理经过 Lexer 处理后的各段。一些具体的操作都在这里。二、 Antlr 文法文件形式:Antlr 文件是 *.g 形式,即以 g 为后缀名。例如: t.gclass P extends Parser;startRule: n:NAMESystem.out.println(Hi there, +n.getText();class L extends Lexer;/ one-or-more letters followed by a newlineNAME: ( az|AZ )+ NEWLINE;NEWLINE: r n / DOS| n / UNIX;具体成分分析:1 、总体结构Class P extends ParserClass L extends Lexer两行同 JAVA 继承一样, P 继承 Parser 类; L 继承 Lexer 类。每个 .g 文件只能各有一个。2 、 Lexer 类分析一般按照类型名:匹配的具体规则;的形式构成。是分隔字节流的依据。同时可以看到里面可以互相引用。如本例中的类型名 NEWLINE 出现在 NEW 的匹配规则中。3 、 Parser 类分析一般按照起始规则名:规则实例名:类型名或规则名Java 语句; ;的形式构成。起始规则名:任意。规则实例名:就象 Java 中“ String s ;”的 s 一样。规则实例名用于在之后的 JAVA 语句中调用。类型名或规则名:可以是在 Lexer 中定义的类型名,也可以是 Parser 中定义的规则名。感觉就像是 int 与 Integer 的区别。Java 语句:指当满足当前规则时所执行的语句。 Antlr 会自动嵌入生成的 java 类中。三、生成 Java 类1 、从 上下载 antlr-x.x.x.jar2 、配置环境变量: classpath=.;x:jdklibtools.jar;x:antlr-x.x.x.jar3 、在 t.g 所在目录下执行:java antlr.Tool t.g会在当前目录下生成如下文件:L.java : Lexer 文法分析器 java 类。P.java : Parser 解析器 java 类。PTokenTypes.java : Lexer 中定义的类型具体化,供 Parser 解析器调用。PTokenTypes.txt :当外部的(如 t2.g )要调用当前的类型或规则时要用到本文件。四、执行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);2 、执行c: javac *.javac: java MainTerenceZHi there, Terencec:探索Antlr是两年前写的一篇文章,如今,Antlr 3.0已经发布了,有了一些变化,为了反映这些变化,我决定重写这篇探索Antlr。探索Antlr(Antlr 3.0更新版)简介Antlr(ANother Tool for Language Recognition)是一个工具,它为我们构造自己的识别器(recognizers)、编译器(compiler)和转换器(translators)提供了一个基础。通过定义自己的语言规则,Antlr可以为我们生成相应的语言解析器,这样便可以省却了自己全手工打造的劳苦。目标如同程序设计语言入门大多采用“Hello World”一样,编译领域的入门往往选择计算器。而这里迈出的第一步更为简单:一个只能计算两个数相加的计算器,也就是说,它可以计算“1+1”。基础知识先来考虑一下如何下手,如果你曾经接受过编译原理的教育,权当忆苦思甜了。这个计算器工作的前提是有一个需要计算的东西,不管我们是以文件的形式提供,还是手工输入,至少我们可以让我们的计算器知道“1+1”的存在。有了输入之后,我们要先检查输入的正确性,只有对正确的输入进行计算才是有意义的。如同写文章有形式和内容之分,这里的检查也要细分一下,率先完成的检查当然是面子功夫形式上的东西,看看是否有错别字的存在,我们要做的是数值相加,结果人家给出了一个字母,这肯定不是我们希望得到的,所以我们有权力拒绝这个不合法的东西。对于程序员来说,如果在自己的程序里写了一个语言不接受的标识符,比如在Java里用“123r”做标识符,那编译器肯定会罢工,拒绝让程序通过编译的。在编译原理里面,这个过程叫做词法分析。在我们的计算器中,我们只接受整数和加号,其它的一概不理。这里我们说的是“整数”,而非 “1”、“2”,对我们来说,它们代表着同一类的东西,编译原理教导我们把这这种东西叫做token,那些数字对我们来说,都是一样的token,不同的仅仅是它们的值而已。形式说得过去并不代表内容就可以接受,南北朝时期许多骈体文让我们看到了隐藏在华丽的外表下的空虚灵魂。你可以说 “我吃饭”,如果说“饭吃我”,除非是在练习反正话的场合,否则没有人会认为它是有意义的,因为显然这不是我们习惯的主谓宾结构。只有在闯过了词法分析的关口,才能到达这里,在编译原理里面,我们把这个阶段叫做语法分析。如果说词法分析阶段的输入是字符流的话,那么语法分析阶段的输入就是token流词法分析的输出。我们这里接受的合法语法是“整数 加号 整数”。编写语法文件好了,制订好自己的语言规则之后,我们需要以Antlr的语言把它描述出来。下面便是以Antlr的语言描述的语法:grammar Calculator; expr: INT PLUS INT; PLUS : + ; INT : (0.9)+ ; Antlr的语法文件通常会保存在一个“.g”的文件中,我们的语法文件叫做“Caculator.g”。 我们来看看这里的定义: expr: INT PLUS INT; 这条语句定义了expr,它等价于“:”右边的部分,也就是说, * 一个INT,后面跟着一个PLUS,后面再接着一个INT。 至于INT和PLUS,它来自后面的定义: PLUS : + ; INT : (0.9)+ ; * PLUS定义的token,就是一个单一的“+”* INT定义的token,由从0到9之间任意的数字组成,后面的加号表示它是可以重复一次到多次 如果你曾经与Antlr 2.x有过一面之缘,你会发现,这个语法文件与Antlr 2.x的语法文件有着些许不同。首先,我们没有区分词法分析和语法分析,由上面的代码可以看出,二者在形式上是一致的,不同的是,对于词法分析的输入是字符,而语法分析的输入是词法分析的结果,也就是token。Antlr 2.x必须显式的区分这二者,而在Antlr 3.0之后,Antlr会替你料理这一切。再有,这里的语法文件名必须与grammar定义的名字保持一致,对于Java程序员,这是一个顺其自然的选择。 编译语法文件如同不编译的程序是无法发挥其威力一样,单单语法文件对我们来说,并没有很大的价值。我们的工作就是使用Antlr提供工具对我们的语法文件进行编译,不同于日常的编译器输出可执行文件,这里的输出是程序语言的源文件。Antlr缺省目标语言是Java语言,它也可以支持C,C#和Python语言,其他的语言尚在开发之中,从3.0发布包结构来看,Ruby的支持很快就会加进来。将Antlr提供的JAR文件加入到classpath中,其中包括Antlr 2.7.7,Antlr 3.0与其runtime,stringtemplate。你没看错,除了3.0,这里还包含着2.7.7。原因很简单,Antlr 3.0是基于之前版本开发的。 然后把语法文件的名称作为参数传给语法编译器:java org.antlr.Tool Caculator.g在确保命令正确执行,且语法文件编写正确的情况下,Antlr为我们生成了几个文件: * CalculatorLexer.java* CalculatorParser.java * Calculator_.g * Calculator.tokens 正如前面说过的,Antlr替我们料理好了词法分析和语法分析,其中, CalculatorLexer.java就是我们的词法分析器,而CalculatorParser.java中包含了语法分析器,它们是我们这里关注的主要对象。至于另外两个文件,Calculator_.g是一个自动生成的lexer语法文件,而Calculator.tokens则是列出了我们定义的token,我们并不会在程序中和它们直接打交道,所以,让我们暂时忽略它们的存在。 运行程序生成代码之后,就是如何使用这些生成的代码。下面就是我们的主程序,它负责将词法分析部分(Lexer)和语法分析部分(Parser)驱动起来:public class Main public static void main(String args) throws Exception ANTLRInputStream input = new ANTLRInputStream(System.in); CalculatorLexer lexer = new CalculatorLexer(input); CommonTokenStream tokens = new CommonTokenStream(lexer); CalculatorParser parser = new CalculatorParser(tokens); try parser.expr(); catch (RecognitionException e) System.err.println(e); 从这段代码中可以清晰的看出,Lexer的输入是一个字符流,而Parser则需要Lexer的协助来完成工作,用Lexer构造出的Token流作为其输入。一切就绪,我们让它跑起来,尝试输入一些内容,看它是否能够通过验证。事实证明,我们的程序可以轻松识别“1+1”,而对于不合法的东西,它会产生一些抱怨。计算结果还记得我们的目标吗?我们的目标是计算出“1+1”的结果,而现在这个程序刚刚能够识别出“1+1”,我们还要继续前进。熟悉XML解析的朋友对于SAX和DOM一定不陌生,二者之间差别在于SAX属于边解析边处理,而DOM则是把所有的内容解析全部解析完(在内存中形成一棵树)之后,再统一处理。Antlr也有与之类似的两种处理方式,SAX的朋友是在Parser中加入处理动作(Action)处理将随着解析的过程进行,而DOM的伙伴则是解析形成一棵抽象语法树(Abstract Syntax Tree,简称AST),再对树进行处理。加入Action先来看看SAX的朋友。因为处理动作是加在expr上,其它部分保持不变。下面是修改过的expr: expr returns int value=0 : a = INT PLUS b = INT int aValue = Integer.parseInt($a.text); int bValue = Integer.parseInt($b.text); value = aValue + bValue; ; 看到常用的字符串转整数的方法,熟悉Java的朋友想必已经露出了会心的微笑。没错,这里定义Action的方法采用就是Java语言,因为我们生成的目标是Java,如果你期待另辟蹊径,那这里的代码就要用你的目标语言来编写。仔细看一下不难发现,action完全是在原有的规则基础上改造的来。首先用returns定义了这个Action的返回值,它将返回value这个变量的值,其类型是int,我们还顺便定义这个变量的初始值“0”。接下来,我们用a、b拿住了两个token的值,我们前面说过,在检查的过程中,我们并不关心每个token具体的内容,只要token的类型满足需要即可,但在action中,我们要计算结果,那必须使用token具体的内容,所以,我们用变量拿住了token。这里我们用$a.text获取这个token的具体值。剩下的动作就很简单了,把文本转换为数字,进行加法运算。 再给旧版本一些忆苦思甜的时间,Antlr 2.x写法有一些细微差别。首先,Antlr 2.x用“a : INT”将一个Token赋给一个变量,而这里用的是“a = INT”。再有,我们用$a.text获取token的值,而在Antlr 2.x中,我们会用a.getText(),当然,在Antlr 3.0中,我们也可以这么写,不过,a.getText()这种写法显然太过于Java。 是不是对我们的计算器有些迫不及待了,那就挥动工具生成全新的Parser。不过,在新的体验之前,我们还要稍微修改一下主程序,以体现我们的劳动成果。 public class Main public static void main(String args) throws Exception ANTLRInputStream input = new ANTLRInputStream(System.in); CalculatorLexer lexer = new CalculatorLexer(input); CommonTokenStream tokens = new CommonTokenStream(lexer); CalculatorParser parser = new CalculatorParser(tokens); try System.out.println(parser.expr(); catch (RecognitionException e) System.err.println(e); 好了,让这个计算器来为我们求证“1+1”吧!ASTSAX的朋友表演完了,下面就是DOM的伙伴登场了。 建立AST的方式很简单,只要我们加上一个AST的选项即可,不过,同DOM的处理方式一样,前面的解析只是为了后面的处理做准备,所以,这里我们要修改一下之前编写的语法文件,下面就是我们的新语法文件:grammar Calculator; options output=AST; ASTLabelType=CommonTree; expr : INT PLUS INT; PLUS : + ; INT : (0.9)+ ;稍微有些不同的地方是,我们加上了两个选项,告诉Antlr,我们要输出的是一个普通的AST。再有,在PLUS上面的“”,这个符号用来告诉Antlr创建一个节点,以此作为当前树的根节点。你也许会有些疑问,怎么没看到计算的加法的地方?正如前面所说,这里只描述了语法结构,这是为了后面的处理在做准备,那么后面如何处理呢?别急,大戏要压轴。下面登场的是Antlr整个故事最后一个大角,TreeParser: tree grammar CalculatorTreeParser; options tokenVocab=Calculator; ASTLabelType=CommonTree; expr returns int value : (PLUS a=INT b=INT) int aValue = Integer.parseInt($a.text); int bValue = Integer.parseInt($b.text); value = aValue + bValue; ; Antlr 可以接受三种类型语法规范Lexer、Parser和Tree-Parser。如果说Lexer处理的是字符流、Parser处理的是Token流,那么TreeParser处理的则是AST。前面Action的处理方式中,我们看到,规则同处理放到了一起,显得有些混乱,而采用了AST的处理方式,规则同处理就完全分离了:在Parser中定义规则,在TreeParser中定义处理,如果我们需要对同样的语法进行另外的处理,我们只要重新 TreeParser,而不必在规则与Action混合的世界中苦苦挣扎。有了前面Action的基础,再来看TreeParser也就简单许多,需要说明的就是:(PLUS a=INT b=INT)除去变量的说明,简化一下这段代码(PLUS INT INT)第一个符号PLUS对应了表示着根节点,两个INT则分别代表了两棵子树,这样刚好与前面生成的语法树对应上。再来看看重新打造的主程序: public class Main public static void main(String args) throws Exception ANTLRInputStream input = new ANTLRInputStream(System.in); CalculatorLexer lexer = new CalculatorLexer(input); CommonTokenStream tokens = new CommonTokenStream(lexer); CalculatorParser parser = new CalculatorParser(tokens); try CommonTree t = (CommonTree)parser.expr().getTree(); CommonTreeNodeStream nodes = new CommonTreeNodeStream(t); CalculatorTreeParser walker = new CalculatorTreeParser(nodes); System.out.println(walker.expr(); catch (RecognitionException e) System.err.println(e); 结语体验过最简单的Antlr程序,我们就有了让它更为丰富的基础,接下来便是自己动手的时间了。参考资料ANTLR入门 2004年第三期程序员ANTLR Reference Manual The Definitive ANTLR Reference推荐使用antlr建立词法分析器本转贴综合了两个方面的内容,也是本文的两大部分,一个为antlr的安装,另一部分为antlr的使用实例 一.下载和安装1 下载antlr的二进制包/download/antlr-2.7.6.tar.gz解压到一个文件夹,比如f:antlr-2.7.6,在该目录下面,可以看到antlr.jar。这个正是antlr的工具包。2 设置环境变量我的电脑- 属性-高级- 环境变量, 确保PATH里面含有jdk的bin路径,如”C:Program FilesJavaj2sdk1.5.0bin;”,否则会提示找不到”java”命令环境变量CLASSPATH指明了java执行时,搜索class库文件的路径。如果CLASSPATH变量不存在,就需要自己新建一下了。在变量值里面添加.;F:antlr-2.7.6antlr.jar各个路径以;分割, 第一个.表示总是先在当前目录寻找,第二个指明了antlr包的所在”F:antlr-2.7.6antlr.jar”。3 这样就可以工作了。写一个简单的语法描述文件test.g, 运行命令java antlr.Tool test.gantlr就会为你自动生成lexer,parser,你只需要写一个test.java调用这些分析类一个简单的分析器就完成了。二.实例1、请在Eclipse中建立一个新的项目,名叫Simple2,在classpath中,要加入antlr.jar 2、再下载一个文件:simple2.g,放在这个项目的路径下 3、在DOS窗口下,输入antlr simple2.g 4、回到eclispe,按F5刷新,会看到多出不少文件来。 5、再新建一个类Main,输入以下代码: import java.io.*;public class Main public static void main(String args) FileInputStream f = null;try f = new FileInputStream(.test.txt); catch (FileNotFoundException e) e.printStackTrace();DataInputStream input = new DataInputStream(f);SimpleLexer lexer = new SimpleLexer(input);SimpleParser parser = new SimpleParser(lexer);try parser.entry(); catch(Exception e) 6、新建一个文本文件test.txt,输入内容: 06/06/82 Peter 20;03/04/83 Rosie 19;04/05/81 Mikey 21;7、运行Mainm,就能看到输出结果: Name: Peter, Age: 20, DOB: 06/06/82Name: Rosie, Age: 19, DOB: 03/04/83Name: Mikey, Age: 21, DOB: 04/05/81 下面来解释一下,这里面的原理。先来看simple2.g的内容: class SimpleParser extends Parser; entry : (d:DOB n:NAME a:AGE(SEMI) System.out.println(Name: + n.getText() +, Age: +a.getText() + , DOB: +d.getText();)*; class SimpleLexer extends Lexer; NAME : (a.z|A.Z)+; DOB: (0.9 0.9 /)= (0.9)(0.9)/)(0.9)(0.9)/)(0.9)(0.9) / $setType(DOB); | (0.9)+ $setType(AGE); ; WS:( | t | r n newline(); | n newline(); ) $setType(Token.SKIP); ; SEMI : ; ;要理解这个文件,我们得从下往上读,才能渐入佳境 最简单的是:SEMI : ; SEMI是一种符号,对于词法分析器来说,只要它读到一个字符是“;”,它就认为自己是读到了一个SEMI 第二简单的是: NAME : (a.z|A.Z)+; 当词法分析器读取一个一个的字符的时候,当他读到一个以上的字母(无论大小写),它都把它们连在一起,作为一个NAME。()+,就是出现一次以上的意思。()*,就是出现0次以上的意思。 第三简单的是: WS:( | t | r n newline(); | n newline(); ) $setType(Token.SKIP); ; 任何一个词法分析中定义的词,都有这样的格式: 名称 : 定义 ; 定义的格式,又可以是一个或多个定义,;就是一个定义, |t就是两个定义。 每个定义之后,都可以跟一段代码,在 其中处理程序部分是可以省略的。 对于WS的定义,就是( |t|rn|n) 。但是,我们在这个定义之中,发现了三个嵌有代码的地方:rn和n后面,都有一句话,newline(),这是告诉词法分析器,行号计数器加一。这样在出现词法、语法错误时,就能报告一个准确的行号了。 在整个定义完成之后,还有一行代码$setType(Token.SKIP);,这是代码调用一个antlr的内置函数,告诉词法分析器,以上遇到的这四种字符情况,都请一律跳过。 最难的一种: DOB: (0.9 0.9 /)= (0.9)(0.9)/)(0.9)(0.9)/)(0.9)(0.9) / $setType(DOB); | (0.9)+ $setType(AGE); ; 为什么说这个是最难的一种,因为这篇blog我本来按照每天一篇的进度,是该在昨天发出来的,结果我想了一天,才终于想通这个语法的意义。 DOB,是一种单词,但是这个单词不是一次分析出来的,而是有一个试错的过程。 DOB的格式是00/00/00,而AGE的格式是00。这样要区分两个单词,就相当困难。 而现在的这个定义,则分为三个部分 (.)=(.)|(.)。这相当于一般语言中的三元表达式: (1)?(2):(3)。如果式1为真,则返回式2的值,否则返回式3的值。 DOB与AGE的区别在于第三个字符,如果(0.9 0.9 /)的尝试判断无误,则进一步分析这剩下的字符,是否符合DOB的格式。那/注释后面的代码,之所以被注释起来,就是因为他其实不用执行,也是DOB类型了。而如果(0.9 0.9 /)的尝试判断出错,则只能按照 (0.9)+的判断来分析试一试,如果成立,就手工赋予一个类型AGE。下载:antlrworks-1.1.7.jar或者更高版本, 配置好 JDK后,直接在antlrworks-1.1.7.jar上编辑*.g文件,它就是词法语法分析的源文件, 这里有一个简单的文件,References: /wiki/display/ANTLR3/Expression+evaluatorHere is a complete grammar that evaluates expressions containing +, -, * and variable assignments. A simple hash table is used to store variable values.The tutorial requires the current depot version of ANTLR 3.0, i.e. the version must be later than 3.0 beta 5.grammar Expr;header import java.util.HashMap;members /* Map variable name to Int
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 教师招聘之《幼儿教师招聘》全真模拟模拟题附参考答案详解(达标题)
- 2025年教师招聘之《小学教师招聘》考前冲刺测试卷包附答案详解【夺分金卷】
- 教师招聘之《幼儿教师招聘》考前冲刺分析含答案详解(a卷)
- 教师招聘之《小学教师招聘》能力提升B卷题库含答案详解(巩固)
- 2025年教师招聘之《幼儿教师招聘》题库高频重点提升(共100题)及参考答案详解(夺分金卷)
- 2025年教师招聘之《小学教师招聘》考前冲刺练习题库及参考答案详解1套
- 教师招聘之《幼儿教师招聘》全真模拟模拟题含答案详解(b卷)
- 教师招聘之《幼儿教师招聘》考前冲刺试卷完整答案详解
- 2025年教师招聘之《小学教师招聘》试题一(综合卷)附答案详解
- 教师招聘之《小学教师招聘》【夺分金卷】附答案详解
- 《新编实用英语》教学方法的探讨与研究
- 阴式子宫全切术
- 军人常见心理问题
- 某大酒店弱电智能化系统清单报价
- 搅拌桩机使用说明书
- 2023年兴文县中医院康复医学与技术岗位招聘考试历年高频考点试题含答案解析
- GB/T 4852-2002压敏胶粘带初粘性试验方法(滚球法)
- 2023年太原市第二热力有限责任公司招聘笔试题库及答案解析
- DDI辅导员工迈向成功-辅导领导力系列
- 阿联酋法律体系
- 煤矿井筒装备安装方案
评论
0/150
提交评论