ANTLR3 简介及示例
ANTLR(pronounced
Antler) 是一个语言识别工具,Another
Tool forLanguage Recognition 的缩写。ANTLR由旧金山大学(University of San Francisco)的教授 Terence Parr 开发并维护的,其始于1989年,到了现在过了20多年,一直都是一个很活跃的项目。
ANTLR
一般用于构建
Domain-Specific Languages (DSL)。用户编写好特定语言的语法文件后,ANTLR 会根据该语法文件生成相应的源代码来识别该语言。ANTLR
3.4 (截至2011-10-15最新的版本) 支持的编程语言(runtime)包括:ActionScript, Csharp2,
Delphi, JavaScript, Perl5, Ruby , C, CSharp3, Java, ObjC, Python。其中 C runtime 由 Jim Idle 维护,C runtime 也是本文关注的部分。在早期的版本中提供有C++ 的runtime,但是在最新的版本中只提供
C 语言的 runtime。
很多的开源的软件都使用了ANTLR 作为自己的DSL 解析工具,比如:
Hibernate,一个在javaEE 中运用非常广泛的ORM 框架,使用ANTLR解析 HQL
–一种类似于SQL 的面向对象的数据库查询语言;Apache
Hive,一个建于 Hadoop 之上的数据仓库查询语言,使用ANTLR解析HiveQL;TOra,Toolkit for Oracle,一个用 Qt写的Oracle 数据库管理工具,使用ANTLR解析Oracle SQL 和 PL/SQL。还有其他很多的软件也使用了ANTLR,比如
Esper,StreamBase,这两个都是用 Java 写的数据流处理引擎。
本文主要基于一个例子简单的讲解如果使用 ANTLR,介绍一些ANTLR的基本概念,本文不包括语言识别的理论知识,和ANTLR的一些高级应用,想了解这些知识应该学习编译理论相关知识,并阅读Terence Parr编写的The Definitive ANTLR
Reference 。
ANTLR支持生成词法分析器,语法解析器和树解析器,同时也支持把代码和语法规则混合在一起编写,个人觉得两者混合在一起写对于开发会很方便,可是这样会影响语法的可读性,所以在本文中语法与代码不会混合在一起写。
本文将一步步的从头开始使用C语言构造一个简单的StreamSQL 解析器。该StreamSQL 解析器实现对 CREATE
INPUT STREAM,CREATE OUTPUT STREAM,CREATE SCHEMA,CREATE
WINDOW,SELECT 等语句的解析。
工具准备
1.首先下载 ANTLR3.4。http://www.antlr.org/download.html 我们要下载的是ANTLR 3.4 distribution (Source for tools, targets,
complete binaries)
2. 下载 ANTLRWorks。 ANTLRWorks 是一个可视化的开发工具,为语法的编写和调试提供了很大的方便。
3. 下载 ANTLR
v3 plugin for eclipse。这是一个Eclipse的插件,可以在Eclipse 里为ANTLR语法文件提供语法高亮,也可以作为语法的调试工具,不过它的调试功能没有
ANTLRWorks 强大。
语法描述
我们要解析的语言如下表所示。
CREATE INPUT STREAM Packet PacketTuple;
CREATE OUTPUT STREAM Aggregate AggregateTuple;
CREATE SCHEMA PacketTuple (time INT,price DOUBLE );
CREATE SCHEMA AggregateTuple(
time INT,
maxprice DOUBLE ,
currenttime INT);
CREATE WINDOW Dimension1(SIZE 180 ADVANCE 10 ON time);
SELECT max(price) AS maxprice, max(time) AS currenttime
FROM Packet[Dimension1] INTO Aggregate;
|
用来解析上面语言的ANTLR语法。
grammar StreamSQL;
options {
language=C;
ASTLabelType=pANTLR3_BASE_TREE;
output=AST;
}
tokens {
TOK_CREATE_SCHEMA;
TOK_CREATE_STREAM;
TOK_CREATE_WINDOW;
TOK_SELECT;
TOK_SCHEMA_LIST;
TOK_NAME_TYPE;
TOK_SELEXPR;
TOK_SELITEM;
TOK_SELLIST;
}
statement
: selectStatement EOF
| createStatement EOF
;
selectStatement
: KW_SELECT selectList
KW_FROM instreamName=Identifier LSQUARE
windowName=Identifier RSQUARE KW_INTO outstreamName=Identifier
-> ^(KW_SELECT selectList $instreamName $windowName $outstreamName)
;
selectList
: selectColumn (COMMA selectColumn)*
-> ^(TOK_SELLIST selectColumn+)
;
selectColumn
: selectItem
| selectExpression
;
selectItem
: Identifier KW_AS Identifier
-> ^(TOK_SELITEM Identifier Identifier)
;
selectExpression
: functionName=Identifier LPAREN
itemName=Identifier RPAREN KW_AS asName=Identifier
-> ^(TOK_SELEXPR $functionName $itemName $asName)
;
createStatement
: KW_CREATE KW_SCHEMA Identifier schemaList
-> ^(TOK_CREATE_SCHEMA Identifier schemaList)
| KW_CREATE streamType KW_STREAM streamName=Identifier schemaName=Identifier
-> ^(TOK_CREATE_STREAM streamType $streamName $schemaName)
| KW_CREATE KW_WINDOW
windowName=Identifier LPAREN KW_SIZE
Number KW_ADVANCE Number KW_ON onWhat=Identifier RPAREN
-> ^(TOK_CREATE_WINDOW $windowName Number Number $onWhat)
;
schemaList
: LPAREN columnNameType (COMMA columnNameType)* RPAREN
-> ^(TOK_SCHEMA_LIST columnNameType+)
;
streamType
: (KW_INPUT | KW_OUTPUT)
;
columnNameType
: coluName=Identifier dataType
-> ^(TOK_NAME_TYPE $coluName dataType)
;
dataType
: KW_INT
| KW_DOUBLE
;
// Keywords
KW_FROM : 'FROM';
KW_AS : 'AS';
KW_SELECT : 'SELECT';
KW_ON : 'ON';
KW_CREATE: 'CREATE';
KW_INT: 'INT';
KW_DOUBLE: 'DOUBLE';
KW_INTO: 'INTO';
KW_SCHEMA: 'SCHEMA';
KW_INPUT: 'INPUT';
KW_OUTPUT: 'OUTPUT';
KW_STREAM: 'STREAM';
KW_WINDOW: 'WINDOW';
KW_SIZE: 'SIZE';
KW_ADVANCE: 'ADVANCE';
// Operators
// NOTE: if
you add a new function/operator, add it to sysFuncNames so that describe
function _FUNC_ will work.
DOT : '.'; // generated as a part of Number rule
COMMA : ',' ;
SEMICOLON : ';' ;
LPAREN : '(' ;
RPAREN : ')' ;
LSQUARE : '[' ;
RSQUARE : ']' ;
MINUS : '-';
PLUS : '+';
// LITERALS
fragment
Letter
: 'a'..'z' | 'A'..'Z'
;
fragment
Digit
: '0'..'9'
;
fragment
Exponent
: 'e' ( PLUS|MINUS )? (Digit)+
;
fragment
Number
: (Digit)+ ( DOT (Digit)* (Exponent)? |
Exponent)?
;
Identifier
: (Letter | Digit) (Letter | Digit | '_')*
;
WS : (' '|'\r'|'\t'|'\n') {$channel=HIDDEN;}
;
|
将该语法文件保存,文件名为 StreamSQL.g 文件名必须与语法名相同。
java -cp
/opt/java_lib/antlr-3.4-complete.jar org.antlr.Tool StreamSQL.g
|
运行上面的命令,ANTLR就会生成相应的词法和语法解析代码。
ls | egrep
Lexer\|Parser\|tokens
StreamSQLLexer.c
StreamSQLLexer.h
StreamSQLParser.c
StreamSQLParser.h
StreamSQL.tokens
|
代码实现
pANTLR3_INPUT_STREAM input;
pSQLLexer lxr;
pANTLR3_COMMON_TOKEN_STREAM tstream;
pSQLParser psr;
const char * inputString = sqlStatement.c_str();
input = antlr3StringStreamNew((uint8_t *) inputString, ANTLR3_ENC_UTF8,
strlen(inputString), (uint8_t *) "test_statement");
lxr =
SQLLexerNew(input);
tstream = antlr3CommonTokenStreamSourceNew(ANTLR3_SIZE_HINT,
TOKENSOURCE(lxr));
psr =
SQLParserNew(tstream);
SQLParser_statement_return statementAST = psr->statement(psr);
/* get the AST
root */
pANTLR3_BASE_TREE root = statementAST.tree;
pANTLR3_BASE_TREE treeNode;
treeNode = (pANTLR3_BASE_TREE) root->getChild(root, 0);
ANTLR3_UINT32 treeType = treeNode->getType(treeNode);
string result;
switch (treeType)
{
case TOK_CREATE_SCHEMA:
result = parseCreateSchema(treeNode);
break;
case TOK_CREATE_STREAM:
result = parseCreateStream(treeNode);
break;
case TOK_CREATE_WINDOW:
result = parseCreateWindow(treeNode);
break;
case TOK_SELECT:
result = parseSelect(treeNode);
break;
default:
WARN << "Unknown
tree type... " << treeType;
break;
}
input->close(input);
lxr->free(lxr);
tstream->free(tstream);
psr->free(psr);
|
ANTLR 的 runtime 会根据输入生成对应的抽象语法树AST,我们只要从根节点遍历该AST 即可以完成该语句的解析。下图为CREATE
SCHMEA 的一个抽象语法树:
未完成的章节
1. 出错提示:当遇到无法解析的语句时,应该可以给出提示在那一行那一个字符解析的时候出错了。
2. ANTLR的高级特性:backtracking,
memoization, syntactic predicates, LL(*) parsing
同类的工具
1. flex/bison PostgreSQL 用的是这个。
2. JavaCC
3. Yacc MySQL 用的是这个
4. Lemon 一个小巧的词法语法解析器,SQLite 用的是这个。
参考资料
1. The Definitive ANTLR Reference Building
Domain-Specific Languages – Terence Parr
2. http://www.antlr.org/wiki/display/ANTLR3/ANTLR+3+Wiki+Home
3. http://en.wikipedia.org/wiki/ANTLR
- 大小: 4.9 KB
分享到:
相关推荐
3. **解析输入**: 在程序中,使用ANTLR生成的解析器读取和解析用户输入的"method chaining"字符串。 4. **处理解析结果**: 解析器会生成抽象语法树(AST),这是对输入表达式的结构化表示。你可以遍历这个树,收集...
### ANTLR简介 ANTLR(ANother Tool for Language Recognition)是一个强大的开源工具,主要用于构建解析器、词法分析器和编译器等语言处理组件。它最初由Terence Parr教授开发,其前身是PCCTS(Parr’s Compiler ...
在实际应用中,ANTLR3的这个示例可能会涉及以下步骤: 1. **解析SQL**:使用ANTLR3生成的`QuerySql`解析器对用户输入的SQL语句进行解析,将其转化为抽象语法树(AST)。 2. **SQL语句转换**:遍历AST,根据NoSQL...
- **丰富的社区支持**:ANTLR拥有活跃的社区,提供了许多教程、示例和插件,方便开发者学习和使用。 总结来说,“antlr-2.7.5H3.jar.zip”是一个包含ANTLR特定版本库和许可信息的压缩包,适用于Java环境下的解析器...
3. **编译生成的代码**:将 ANTLR4 生成的源代码编译成可执行文件或库,以便在你的项目中使用。 4. **解析输入**:使用生成的解析器和词法分析器来解析输入文本,将其转换为抽象语法树(AST)。AST 是一个数据结构...
7. **ANTLR的应用示例**:提供简单的语言或表达式解析示例,如计算器程序,展示ANTLR的实际应用。 8. **ANTLR的高级特性**:可能涉及错误恢复、自定义语义动作、树遍历和转换等高级话题,帮助开发者更深入地掌握...
- 解压后,会在目录中包含ANTLR的文档、示例和库文件。 2. **配置环境变量**: - 将ANTLR的`.jar`文件路径添加到系统的`CLASSPATH`环境变量中。 - 对于Windows系统,路径分隔符使用`;`。 3. **运行ANTLR**: - ...
- **文档和示例**:虽然资源可能较少,但仍可以在网上找到一些关于ANTLR 2的教程和示例代码,帮助你理解和使用它。 - **升级考虑**:如果可能,考虑升级到ANTLR 4,因为新版本提供了更多功能和性能优化,且有更好的...
- 示例与实践:通过实例演示ANTLR的使用,包括从简单的示例到复杂的语言解析。 - 性能优化:讨论如何提高ANTLR解析器的效率,减少资源消耗。 - 扩展与自定义:介绍ANTLR的高级特性,如自定义属性、动作和重载操作。 ...
1. **ANTLR简介**:简述ANTLR的基本概念,如解析器、词法分析器的作用,以及ANTLR在软件开发中的应用。 2. **安装ANTLR**:指导读者如何下载ANTLR库,如antlr-3.2.jar,并将其添加到开发环境(例如Java的类路径)中...
7. **测试用例和示例**: 通常源码仓库会包含一些测试用例和示例,用于验证ANTLR4的正确性和展示其使用方法。 通过阅读和研究"antlr4-master"源码,我们可以学到以下关键知识点: - **ANTLR4的语法定义**:学习如何...
在antlr4-master这个压缩包中,很可能包含的是ANTLR 4.6项目的源代码、示例、文档和其他资源。这些资源可以帮助开发者快速上手,理解ANTLR的工作机制,并进行实际项目中的应用。通过学习和使用这些资料,可以深入...
3. **LL(*)和预测LL(*)解析**:ANTLR 4使用预测LL(*)算法,这是一个自适应的左到右解析策略,能够处理许多复杂的上下文无关语法,包括左递归和右递归。 4. **树解析器**:ANTLR 4不仅生成词法分析器和语法解析器,...
通过这些示例,学习者可以理解ANTLR的工作原理,掌握如何定义语法规则,编写词法分析器和解析器,以及如何生成目标代码。这些实例是学习ANTLR的宝贵资源,帮助开发者快速上手并应用于实际项目中。
3. **词法分析**:ANTLR 4同时处理词法和语法分析。词法分析阶段将输入分解成词法符号,书里会讲解如何定义词法规则和创建词法分析器。 4. **语法分析**:ANTLR 4使用LL(*)解析策略,能处理左递归和右递归的语法。...
在这个“antlr-examples”项目中,我们看到一个ANTLR用于构建的计算器示例,这为我们提供了学习ANTLR语法和用法的一个很好的起点。 ANTLR的工作原理是通过解析输入的语法文件(通常以.g4为扩展名)来生成解析器和...