文法定义基础
规则的表示: ANTLR用A:a; 来表示规则。ANTLR的规则要以分号“;”结束。在规则中有几种运算关系,
选择、连接、重复、可选。
→连接“ ”:规则A : a b c; a、b、c之间用空格分隔。此规则接收句型abc,符号a、
b、c是按顺序连接起来的关系。
→选择“| ”:规则A : a | b| c; “|”表示“或”的关系,符号A可以推导出a或b
或c,也就是在a、b、c中选择。这要比写成A : a; A : b; A : c;方便得多。连接和选择
可以联合起来使用,如A : ab c |c d e;。有进也会使句型的数量增多如:A : B D; B :
a | b; D : c | d;这时符号A推导出的句型有 ac、ad、bc、bd四种。
→重复“*,+”:规则A : a*;“*”表示a可以出现0次或多次。A : a*; 相当于A : A a |
;。这样可以避免递归的定义,可文法定义中递归往往引起文法的二义性。如果a至少要出
现一次可以表示为A : a+;“+”表示a可以出现1次或多次。相当于A : A a | a;。重复
可以和连接、选择一起使用如:A : a*b | c+d;。
→可选“?”:规则A : a?;“?”表示a可以出现0次或1次,即a可有可无。相当于A : a |
;。可选可以和连接、选择、重复一起使用如:A : a* b?| c+ d?;。
→子规则“()”:规则A : (a b) | b; a与b在括号中,这样“(ab)”形成了一个子规
则,也就是说可以把规则写成A : B| b; B : a b;两个规则表示,我们把B规则用括号括
起来放到A规则中这样就是A规则的子规则了。利用子规则也可以把多个符一起进行描述,
A : (a b c)* 规则中a、b、c三个符号可以一起重复0次或多次。子规则有利于我们把很
复杂的多个规则写到一起,有时这样写会使文法既简练又直观。子规则和前面的各种特性用
到一起可以把复杂的文法写的很浓缩。如:A : (a b c)* | (c d)+ e?;。
值得注意的是如果我们的规则中有“()”的字符该如何表示?因为子规则也是用“()”
表示的。在ANTLR中表示字符要用“’”单引号括起来,用‘(’‘)’来表示括号字符。前
面讲到的表示文法规则的符号“| * + () ?”叫做文法的元符号。
→注释“// /**/”:和一般编程语言一样,ANTLR在文法定义中也可以添加注释。用//
来添加单行注释,如规则E : ‘(’ E ‘)’ | INT // E表示算术表达式。用/*…*/添加
多行注释,与C++相同。
→“..”符号,从上面的LETTER示例可以看出,定义一个表示英文字母的符号写起来非
常繁琐。为了让定义变得简单ANTLR加入“..”符号通过指定首尾的字符可以很方便的定义
一定范围内的字符。
LETTER : ‘A’ .. ‘Z’| ‘a’ .. ‘z’;
→“~”符号,如果我们想表示除某些符号以外的符号时,可以使用“~”符号。“~”代表
取反的意思。
A : ~ ‘B’;
符号A匹配除字符“B”以外的所有字符。
A : ~ (‘A’ |‘B’); B : ~(‘A’.. ‘B’); C : ~‘\u00FF';
上面的例子中定义三个符号。符号A匹配除字符“A”和“B”以外的所有字符,符号B
匹配除大写字符母以外的所有字符。符号C匹配除编码为“u00FF”的字符以外的所有字符。
→“.”符号,ANTLR中可以用“.”表示单个任意字符,起通配符的作用。
A : .; B : .*; C : .*‘C’; D : ~ .;//error
上面的例子中符号A匹配一个任意字符,符号B符号匹配0到多个任意字符,符号C
匹配0到多个任意字符直到遇到字符“C”为止。D的定义是错误的,不能定义任意字符以
外的字符。
→skip()方法
有些字符是不属于源程序范畴内的,这些字符在分析过程中应该忽略掉。在ANTLR中可
以在词法定义中加入skip();,(如果是C#为目标语言为Skip();)。在规则的定义的之后与
表示定义结束的分号之前加入“{skip();}”。例如下面定义了一个跳过空白的词法定义。
WS : ( ' ' | '\t' | '\n' | '\r' ) + {skip();} ;
空白符号WS中有空格符、制表符、回车和换行符,当遇到这些字符时词法分析程序会
调用skip()方法跳过这些字符。
B : 'A' | 'B'{Skip();} | 'C' ;
上面的例子中符号B只在匹配字符“B”时跳过,从这个例子可以看出{Skip();}要写在
忽略内容的后面,如果它处于某选择分支中那么它只对某分支起作用。下面我们定义一些实
际中经常出现的词法定义。
→$channel=HIDDEN
有时象注释这样的部分在编译时并不是完全放弃的,如java中在/**….*/的注释形式
中可以添加说明最终生成程序的文档,在.NET中使用 /// 注释形式也有类似的功能。也就
是说我们在编译代码时忽略这些注释,而在分析生成文档时又要用到这些注释。这样的话就
不能使用skip();方法了,skip()方法是抛弃其内容。所以ANTLR中加入了channel属性用
来指定当前匹配的内容是属于哪一个频道,分析过程中关心哪个频道就可以只接收哪个频道
的内容。ANTLR中定义有两个频道常量DEFAULT_CHANNEL和HIDDEN_CHANNEL,一般情况下匹
配的内容都中放到DEFAULT_CHANNEL中。我们可以指定让当前匹配的内容放到哪个频道中。
前面示例中的词法规则可以改成如下形式。
COMMENT : '/*' . * '*/' {$channel=HIDDEN;} ;
LINE_COMMENT :'//' ~ ('\n'| '\r') * '\r'?'\n' {$channel=HIDDEN;} ;
WS : ( ' ' | '\t' | '\n' | '\r' ) + {$channel=HIDDEN;};
COMMENT、LINE_COMMENT和WS词法规则后面加入{$channel=HIDDEN;},这样匹配的字
符就会被存放到HIDDEN频道中。下面将这个修改后的文法编译运行,其结果和使用skip()
方法时是一样的。这就是说存在于HIDDEN频道中的内容被语法分析器忽略了,因为在默认
情况下ANTLR语法分析程序只分析DEFAULT_CHANNEL中的内容。
→options{greedy=false;}
ANTLR词法分析中还可以加入greedy设置项,当greedy=true时当前规则会尽可能的
匹配可以匹配的输入。ANTLR中默认情况greedy为true,所以COMMENT : '/*' . * '*/'
{$channel=HIDDEN;} ;规则中符号“.”可以匹配“*/”字符,也就是说当遇到“*/”字符
时它是匹配“.”还是匹配’*/’出现了二义的情况,前面的例子中已经显示出在这种情况
下分析器是可以正确分析的,但加入greedy=false后可以消除这种二义性,就是说
greedy=false时分析器遇到“*/”字符时会很确定的做为注释结束符号来匹配,这样的话
就消除了二义性。
COMMENT : '/*' ( options {greedy=false;} : . ) * '*/'
{$channel=HIDDEN;} ;
→ +=的用法
修改SimpleAction文法,使能够在类型标识符后可以定义多个变量。这文法中加入了
“+=”操作符功能是将所有定义的变量收集到一个集合当中。
grammar SimpleAction;
variable : type ids+=ID (',' ids+=ID)* ';'
{ System.out.println($type.text);
for(Object t : $ids)
System.out.print(" " + ((Token)t).getText()); }
;
运行此示例输入:intx, y,z; 输出:intx y z 我们来看一下生成的代码。
public final void variable() throws RecognitionException {
Tokenids=null;
Listlist_ids=null;
type_return type1= null;
try{
pushFollow(FOLLOW_type_in_variable9);
type1=type();
_fsp--;
ids=(Token)input.LT(1);
match(input,ID,FOLLOW_ID_in_variable13);
if (list_ids==null) list_ids=newArrayList();
list_ids.add(ids);
loop1:
do{ int alt1=2;
int LA1_0= input.LA(1); if ( (LA1_0==6) ) { alt1=1; }
switch (alt1) {
case1 : {
match(input,6,FOLLOW_6_in_variable16);
ids=(Token)input.LT(1);
match(input,ID,FOLLOW_ID_in_variable20);
if (list_ids==null) list_ids=newArrayList();
list_ids.add(ids);
} break;
default: break loop1;
}
} while (true);
match(input,7,FOLLOW_7_in_variable24);
System.out.println(input.toString(type1.start,type1.stop));
for(Object t : list_ids) System.out.print(" " +
((Token)t).getText());
}
catch (RecognitionException re) ……
}
代码中添加了一个List类型的list_ids对象,每匹配一个ID符号时就加入到list_ids
中。List中存放的是Object类型所以我们输出时要加类型转换
→ @header用法
ANTLR中每一个文法规则都生成对应的函数,这些函数是分析器类的方法。第一章已经
介绍过语法分析器和词法分析器都分别生成XXXParser类和XXXLexer类。当需要向类的顶
端加入代码时可以用@header定义。一般情况下(如java)用@header来加入包名和导入
imports其它java类。
grammar SimpleMember;
@options { language=Java; }
@header { package Simple;}
……
@header在默认的情况下会设置XXXParser类代码,也就是语法分析类。我们也可以显
示的指明设置词法类还是设置语法类。
@parser::header { package Simple.Parser; }
@lexer::header { package Simple.Lexer; }
@header用法
ANTLR中每一个文法规则都生成对应的函数,这些函数是分析器类的方法。第一章已经
介绍过语法分析器和词法分析器都分别生成XXXParser类和XXXLexer类。当需要向类的顶
端加入代码时可以用@header定义。一般情况下(如java)用@header来加入包名和导入
imports其它java类。
grammar SimpleMember;
@options { language=Java; }
@header { package Simple;}
……
@header在默认的情况下会设置XXXParser类代码,也就是语法分析类。我们也可以显
示的指明设置词法类还是设置语法类。
@parser::header { package Simple.Parser; }
@lexer::header { package Simple.Lexer; }
@header用法
ANTLR中每一个文法规则都生成对应的函数,这些函数是分析器类的方法。第一章已经
介绍过语法分析器和词法分析器都分别生成XXXParser类和XXXLexer类。当需要向类的顶
端加入代码时可以用@header定义。一般情况下(如java)用@header来加入包名和导入
imports其它java类。
grammar SimpleMember;
@options { language=Java; }
@header { package Simple;}
……
@header在默认的情况下会设置XXXParser类代码,也就是语法分析类。我们也可以显
示的指明设置词法类还是设置语法类。
@parser::header { package Simple.Parser; }
@lexer::header { package Simple.Lexer; }
→@members用法
在文法中可以用@members定义分析器类的成员,和@header、Actions一样并没有具体
的限制,你可以在其中任何内容如属、方法、事件、内部类和注释等,还有一个重要的应用
是可以用@members重写基类的方法实现一些高级功能。
下面请看示例:
grammar SimpleMember;
options {
language=CSharp;
}
@header {
using System.Collections.Generic;
}
@members {
private List<IToken>RetList = new List<IToken>();
private int Count= 0;
}
variable : type idList
{
foreach(IToken t in RetList)
System.Console.WriteLine(t.Text);
System.Console.WriteLine(Count);
}';';
idList
:ids+=ID (',' ids+=ID)*
{
RetList= new List<IToken>();
foreach(objectt in $ids)
RetList.Add((IToken)t);
Count= $ids.Count;
};
type : 'int' |'float';
INT : ('0'..'9')+;
FLOAT :('0'..'9')+ ('.' ('0'..'9')+)?;
ID : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')* ;
WS : ( ' ' |'\t' |'\r' | '\n' )+ { $channel = HIDDEN; } ;
这个示例实现了与之前的示例相同的功能,但没有使用返回值,idList()函数中利用分
析器类的成员RetList和Count来保存变量的信息,然后在variable()函数中输出。类成
员是在不同的成员函数间传递信息的一种方法,但要注意对类成员赋值和取值的先后顺序,
不然会在分析过程中出现异常。
分享到:
相关推荐
ANTLR(Another Tool for Language Recognition)是一个强大的解析器生成器,用于读取、处理、执行或翻译结构化文本或二进制文件。它被广泛应用于编程语言、协议、表达式、脚本和其他语言的定义。ANTLR 4是ANTLR系列...
### ANTLR4读书笔记七八章详解 #### 第七章:从特定于应用程序的代码解耦语法 在学习了如何使用ANTLR定义语言语法后,我们了解到语法本身虽然能够验证一个输入句子是否符合语言规范,但对于实际开发语言应用程序来...
这本书的学习笔记将帮助读者深入理解ANTLR4的工作原理和实践应用。 ANTLR4的核心功能包括: 1. **语法定义**:ANTLR4允许用户使用EBNF(扩展巴科斯范式)来定义语法规则,这是一种形式化的语法描述语言。这些规则...
例如,Terence Parr本人就使用ANTLR开发了一个名为TML(Terence's Markup Language)的简单标记语言,用于撰写课程笔记和其他文档。TML被设计为易于编写,通过ANTLR转换成HTML或PDF格式,从而简化了文档创作的过程。...
ANTLR 4简明教程是一本介绍ANTLR 4使用方法的书籍,内容基于最新版ANTLR 4的语法编写,作者在阅读官方参考书时整理了自己的读书笔记,并在此基础上增加了新的内容。这本书以开源形式编写,源码托管在GitHub上,方便...
7. **antlr-2.7.6rc1.jar**:ANTLR是一个强大的解析器生成器,用于读取、处理、执行或翻译结构化文本或二进制文件。在DWR中,它可能用于解析配置文件或生成动态Java代码。 8. **standard-1.1.2.jar**:可能是用于...
【CXF Webservice初学笔记】 Apache CXF 是一个开源的 Web 服务框架,它允许开发者创建和消费各种类型的 Web 服务。CXF 整合了 XFire 和 Celtix 两个项目,提供了一套全面的工具和服务接口,支持 SOAP、RESTful、WS...
【Hibernate学习笔记(1-13)】是传智播客李勇的教程,涵盖了Hibernate框架的基础到进阶内容。Hibernate是一个流行的ORM(对象关系映射)框架,它旨在解决Java面向对象编程与关系型数据库之间的模型不匹配问题,即...
### Hibernate初学笔记知识点概述 #### 一、Hibernate环境的搭建 - **1.1 引入基础Jar包** - **hibernate3.jar**:这是Hibernate的核心库,可以在Hibernate项目的根目录下找到。 - **Required Jars**:位于`lib/...
根据给定的文件信息,以下是对“hibernate笔记”的详细知识点解析: ### Hibernate简介与配置 #### 一、Hibernate的引入与环境搭建 在Java项目中集成Hibernate框架,首先需要将Hibernate相关的JAR包添加到项目的...
UniVR-informatica 注释和为学士学位的计算机科学硕士学位在工程和计算机科学课程摘要。 内容 ...为ANTLR语言课程详述 高手 Magistrale I anno硕士学位(AY 2020-2021): 编程基础和规范语言(第
- `antlr-2.7.6.jar`:用于解析 HQL 语句。 - `commons-collections-3.1.jar`:提供集合类的扩展功能。 - `dom4j-1.6.1.jar`:XML 解析工具。 - `javassist-3.9.0.jar`:动态字节码生成工具。 - `jta-1.1.jar`...
【Hibernate学习笔记】 Hibernate是一个流行的Java ORM(对象关系映射)解决方案,它允许开发者通过对象模型与数据库进行交互,而无需直接编写SQL语句。在深入学习Hibernate之前,需要了解其基本配置和依赖。 首先...
为了搭建 Spring 开发环境,我们需要在项目中引入必要的库文件,如 Ant、ANTLR、AOP Alliance、ASM、DOM4J、JTA、Jakarta Commons、CGLIB 和 Log4j 等。同时,还需要在 XML 配置文件中指定 DTD(Document Type ...