分析antlr4是否有间接左递归递归

基于Antlr4编写DSL - IBYoung - ITeye技术网站
博客分类:
最近新的模块DSL和UITemplate,都或多或少涉及到Antlr,特别在使用DSL的时候特别有感触,能否设计的像SQL那样的领域驱动型语言呢?我的对于DSL的理解:
1.是用来解决复杂的业务模型而产生的,假设以计算机为例,采用代码的方式,可能就需要一大堆的判断,用来跟踪是否有有括号、是否有左括号没右括号、是否加减乘除优先制度等很多条件,那如果是业务模型像支付流程,比起计算机更加复杂,如果一大堆if、else等代码复杂不算,仅仅是代码样子都要吐了,其二,假设采用XML这种可读性极强的方式,个人感觉问题不大,唯一不好的层次太多,以及需要一大堆节点,最后如果采用antlr4类似g4格式文件,好处一目了然
grammar Mu;
: block EOF
: assignment
| while_stat
| OTHER {System.err.println("unknown char: " + $OTHER.text);}
assignment
: ID ASSIGN expr SCOL
: IF condition_block (ELSE IF condition_block)* (ELSE stat_block)?
condition_block
: expr stat_block
stat_block
: OBRACE block CBRACE
while_stat
: WHILE expr stat_block
: LOG expr SCOL
: expr POW&assoc=right& expr
| MINUS expr
#unaryMinusExpr
| NOT expr
| expr op=(MULT | DIV | MOD) expr
#multiplicationExpr
| expr op=(PLUS | MINUS) expr
#additiveExpr
| expr op=(LTEQ | GTEQ | LT | GT) expr #relationalExpr
| expr op=(EQ | NEQ) expr
#equalityExpr
| expr AND expr
| expr OR expr
: OPAR expr CPAR #parExpr
| (INT | FLOAT)
#numberAtom
| (TRUE | FALSE) #booleanAtom
#stringAtom
OR : '||';
AND : '&&';
EQ : '==';
NEQ : '!=';
GTEQ : '&=';
LTEQ : '&=';
PLUS : '+';
MINUS : '-';
MULT : '*';
DIV : '/';
MOD : '%';
POW : '^';
NOT : '!';
SCOL : ';';
ASSIGN : '=';
OPAR : '(';
CPAR : ')';
OBRACE : '{';
CBRACE : '}';
TRUE : 'true';
FALSE : 'false';
NIL : 'nil';
IF : 'if';
ELSE : 'else';
WHILE : 'while';
LOG : 'log';
: [a-zA-Z_] [a-zA-Z_0-9]*
: [0-9]+ '.' [0-9]*
| '.' [0-9]+
: '"' (~["\r\n] | '""')* '"'
: '#' ~[\r\n]* -& skip
: [ \t\r\n] -& skip
2.Antlr的方式能够进一步规避一些语法的错误,假设你的表达式是2+(1+2,语法分析器就会parse解析时候,得到missing')',显著得提升我们解决问题
3.Antlr4采用visit观察者模式,在每一个context都有accept(Context ctx)的方式,通过visitor接口,对于抽象语法树AST进行解析的工作
import org.antlr.v4.runtime.misc.NotN
import java.util.HashM
import java.util.L
import java.util.M
public class EvalVisitor extends MuBaseVisitor&Value& {
// used to compare floating point numbers
public static final double SMALL_VALUE = 0.;
// store variables (there's only one global scope!)
private Map&String, Value& memory = new HashMap&String, Value&();
// assignment/id overrides
public Value visitAssignment(MuParser.AssignmentContext ctx) {
String id = ctx.ID().getText();
Value value = this.visit(ctx.expr());
return memory.put(id, value);
public Value visitIdAtom(MuParser.IdAtomContext ctx) {
String id = ctx.getText();
Value value = memory.get(id);
if(value == null) {
throw new RuntimeException("no such variable: " + id);
// atom overrides
public Value visitStringAtom(MuParser.StringAtomContext ctx) {
String str = ctx.getText();
// strip quotes
str = str.substring(1, str.length() - 1).replace("\"\"", "\"");
return new Value(str);
public Value visitNumberAtom(MuParser.NumberAtomContext ctx) {
return new Value(Double.valueOf(ctx.getText()));
public Value visitBooleanAtom(MuParser.BooleanAtomContext ctx) {
return new Value(Boolean.valueOf(ctx.getText()));
public Value visitNilAtom(MuParser.NilAtomContext ctx) {
return new Value(null);
// expr overrides
public Value visitParExpr(MuParser.ParExprContext ctx) {
return this.visit(ctx.expr());
public Value visitPowExpr(MuParser.PowExprContext ctx) {
Value left = this.visit(ctx.expr(0));
Value right = this.visit(ctx.expr(1));
return new Value(Math.pow(left.asDouble(), right.asDouble()));
public Value visitUnaryMinusExpr(MuParser.UnaryMinusExprContext ctx) {
Value value = this.visit(ctx.expr());
return new Value(-value.asDouble());
public Value visitNotExpr(MuParser.NotExprContext ctx) {
Value value = this.visit(ctx.expr());
return new Value(!value.asBoolean());
public Value visitMultiplicationExpr(@NotNull MuParser.MultiplicationExprContext ctx) {
Value left = this.visit(ctx.expr(0));
Value right = this.visit(ctx.expr(1));
switch (ctx.op.getType()) {
case MuParser.MULT:
return new Value(left.asDouble() * right.asDouble());
case MuParser.DIV:
return new Value(left.asDouble() / right.asDouble());
case MuParser.MOD:
return new Value(left.asDouble() % right.asDouble());
throw new RuntimeException("unknown operator: " + MuParser.tokenNames[ctx.op.getType()]);
public Value visitAdditiveExpr(@NotNull MuParser.AdditiveExprContext ctx) {
Value left = this.visit(ctx.expr(0));
Value right = this.visit(ctx.expr(1));
switch (ctx.op.getType()) {
case MuParser.PLUS:
return left.isDouble() && right.isDouble() ?
new Value(left.asDouble() + right.asDouble()) :
new Value(left.asString() + right.asString());
case MuParser.MINUS:
return new Value(left.asDouble() - right.asDouble());
throw new RuntimeException("unknown operator: " + MuParser.tokenNames[ctx.op.getType()]);
public Value visitRelationalExpr(@NotNull MuParser.RelationalExprContext ctx) {
Value left = this.visit(ctx.expr(0));
Value right = this.visit(ctx.expr(1));
switch (ctx.op.getType()) {
case MuParser.LT:
return new Value(left.asDouble() & right.asDouble());
case MuParser.LTEQ:
return new Value(left.asDouble() &= right.asDouble());
case MuParser.GT:
return new Value(left.asDouble() & right.asDouble());
case MuParser.GTEQ:
return new Value(left.asDouble() &= right.asDouble());
throw new RuntimeException("unknown operator: " + MuParser.tokenNames[ctx.op.getType()]);
public Value visitEqualityExpr(@NotNull MuParser.EqualityExprContext ctx) {
Value left = this.visit(ctx.expr(0));
Value right = this.visit(ctx.expr(1));
switch (ctx.op.getType()) {
case MuParser.EQ:
return left.isDouble() && right.isDouble() ?
new Value(Math.abs(left.asDouble() - right.asDouble()) & SMALL_VALUE) :
new Value(left.equals(right));
case MuParser.NEQ:
return left.isDouble() && right.isDouble() ?
new Value(Math.abs(left.asDouble() - right.asDouble()) &= SMALL_VALUE) :
new Value(!left.equals(right));
throw new RuntimeException("unknown operator: " + MuParser.tokenNames[ctx.op.getType()]);
public Value visitAndExpr(MuParser.AndExprContext ctx) {
Value left = this.visit(ctx.expr(0));
Value right = this.visit(ctx.expr(1));
return new Value(left.asBoolean() && right.asBoolean());
public Value visitOrExpr(MuParser.OrExprContext ctx) {
Value left = this.visit(ctx.expr(0));
Value right = this.visit(ctx.expr(1));
return new Value(left.asBoolean() || right.asBoolean());
// log override
public Value visitLog(MuParser.LogContext ctx) {
Value value = this.visit(ctx.expr());
System.out.println(value);
// if override
public Value visitIf_stat(MuParser.If_statContext ctx) {
List&MuParser.Condition_blockContext& conditions =
ctx.condition_block();
boolean evaluatedBlock =
for(MuParser.Condition_blockContext condition : conditions) {
Value evaluated = this.visit(condition.expr());
if(evaluated.asBoolean()) {
evaluatedBlock =
// evaluate this block whose expr==true
this.visit(condition.stat_block());
if(!evaluatedBlock && ctx.stat_block() != null) {
// evaluate the else-stat_block (if present == not null)
this.visit(ctx.stat_block());
return Value.VOID;
// while override
public Value visitWhile_stat(MuParser.While_statContext ctx) {
Value value = this.visit(ctx.expr());
while(value.asBoolean()) {
// evaluate the code block
this.visit(ctx.stat_block());
// evaluate the expression
value = this.visit(ctx.expr());
return Value.VOID;
用户关注点已经有从编写流程文件,到visitor对于AST树的控制,到使用我们的DSL
MuLexer lexer = new MuLexer(new ANTLRFileStream(args[0]));
MuParser parser = new MuParser(new CommonTokenStream(lexer));
ParseTree tree = parser.parse();
EvalVisitor visitor = new EvalVisitor();
visitor.visit(tree);
浏览: 174462 次
来自: 杭州
大神,膜拜!
lionld23 写道等着看呢,速度速度我是抽空再写的,整篇文 ...
等着看呢,速度速度
龘龘龘 写道没了?没了?没了?没了?没了?没了?我想哭啊,没保 ...本文主要介绍了ANTLR方面的内容,包括ANTLR是什么,如何进行ANTLR的开发,总结了ANTLR的语法知识,整理了ANTLR的相关的开发工具,总结了ANTLR常见问题及解决办法,然后总结了ANTLR的一些内容等等
本文提供多种格式供:
HTML版本的在线地址为:
有任何意见,建议,提交bug等,都欢迎去讨论组发帖讨论:
把之前教程的地址整理过来
本文章遵从:
1. 本文目的
本文目的在于,介绍ANTLR是什么,以及如何用ANTLR开发自己的解析器,以及总结常见的ANTLR错误的原因和解决办法。
2. 学习ANTLR之前
需要了解一些相关背景概念和知识:
然后后续再去学习ANTLR,才会更加清楚相关的原理和概念。
第 1 章 ANTLR简介
1.1. ANTLR是什么
ANTLR==ANother Tool for Language Recognition
ANTLR是和语言有关的工具
ATNLR是一个框架
你可以用ANLTR去构建一个识别器,解析器,编译器,转换器
1.2. ANTLR版本历史
总结一下ANTLR的发展历史,历史版本:
1.3. ANTLR的应用领域
ANTLR可以用在很多领域中,主要是涉及到解析器,解析特定的语法的,都可以去实现。
1.4. ANTLR技术的优势
1.5. 和ANTLR相关的一些概念
折腾ANTLR之前,需要对于和ANTLR相关的一些概念,有所了解:
第 2 章 ANTLR的开发流程
2.1. ANTLR的开发流程
关于ANTLR的基本的开发流程和示例,详见:
2.2. ANTLR v4的开发流程
关于ANTLR v4的环境搭建,可参考:
期间,可能会出现一些问题,详见:
2.3. 把ANTLR整合到自己的程序中
对于搞清楚了基本的ANTLR开发流程后,
写好了ANTLR的.g的语法文件,生成了对应的lexer和parser的代码
比如xxxLexer.java和xxxParser.java
接下来,就是要搞清楚,如何去将对应的代码,集成到自己的程序中,为程序所用了:
这方面,可以参考:
第 3 章 ANTLR的语法Grammar详解
ANTLR的语法,虽然有ANTLR作者写的书,其中有解释,但是感觉还是解释的不够详细。
其中,很多内容,还是需要经过自己的实践,才能更好的理解的。
下面,总结一下,目前对ANTLR中部分的语法的理解:
3.1. 完整的ANTLR语法的解释
这个是看了作者的书籍后,总结出来的,相对比较全面的语法的解释:
3.2. 详解部分ANTLR语法
3.2.1. ANTLR中的lexer和parser的header的含义
另外关于header方面的含义,总结如下:
3.2.2. antlr v2和antlr v3的语法对比
3.2.3. ANTLR中的fragment
至今,对于fragment,没有真正透彻的了解,所以可能会导致一些问题:
其他的,还有一些心得:
第 4 章 ANTLR的开发工具
总结ANTLR的相关开发工具或环境:
目前已知有几种常见方式:
命令行式开发ANTLR
用ANTLRWorks去开发ANTLR
基于Eclipse去开发ANTLR
下面分别介绍:
4.1. ANTLR开发环境之命令行
基于命令行下去开发ANTLR
自己使用对应的命令,去从antlr的.g的文件,生成对应的lexer和parser等相关的代码
然后再继续去用对应的代码,写测试代码去测试。
4.2. ANTLR开发环境之ANTLRWorks
ANTLRWorks是IDE,是用Java写的。
是官网提供的,官方推荐的ANTLR的开发环境。
4.2.1. ANTLRWorks v1:可运行的单独的jar包
相关总结:
4.2.2. ANTLRWorks v2:基于Netbeans的IDE
ANTLRWorks v2,截至目前,感觉是:真心不好用。
4.3. ANTLR开发环境之Eclipse+ANTLR的插件
基于成熟的Eclipse这个通用的IDE框架,加上对应的ANTLR插件,也是可以用来开发ANTLR的。
只是效果貌似不是那么好而已。
第 5 章 ANLTR常见问题及解答
ANTLR开发期间,常常会遇到各种错误,现在总结如下:
5.1. ANTLR的语法方面常见问题及解决办法
5.1.1. The following token definitions can never be matched because prior tokens match the same input
在写ANTLR的grammar时,经常会遇到:
The following token definitions can never be matched because prior tokens match the same input
对于这样的问题,之前遇到过很多。
后来,算是有点明白了,所以专门整理出来其原因和一般的解决思路:
另外,之前遇到过很多次,有需要的可以去参考:
5.1.2. Decision can match input such as xxx using multiple alternatives
在写ANTLR的grammar时,经常会遇到,多重匹配的问题:
一般的小问题,都可以自己慢慢修改代码,而搞定的。
其他的,也有之前不够熟悉antlr时,没有解决的问题:
但是实际上,经过后来的折腾,早就解决了的。
但是,有时候,也会遇到比较难处理而始终搞不定的,比如:
5.1.3. MismatchedSetException和mismatched input xxx expecting set yyy
写antlr语法期间,调试期间,遇到最多的,可能就属不匹配的问题了。
对于不匹配的问题,其原因有各种各样,而导致不匹配的。
目前已经遇到的,大致有这几类:
后面所要匹配的内容,被前面已经匹配掉了,所以后面会报错,无法匹配
自己语法写错了,的确不匹配
如果是自己语法不小心写错了,自己仔细调试后,还是可以发现。
然后改为正确的所要匹配的内容,即可。
ANTLR v4中,由于一些语法的变化,导致语法检查更严格,有时候也会导致此类mismatch的问题:
5.1.4. syntax error: unterminated rule detected at xxx while looking for lexer rule element
5.1.5. NoViableAltException和no viable alternative at input xxx
5.1.6. Cannot generate the grammar because, duplicate token type xxx when collapsing subrule into set
如果ANTLR语法写的有问题的话,则是无法生成对应的代码的。
错误有多种可能:
比如是由于符号类型冲突而无法生成代码,详见:
5.1.7. rewrite syntax or operator with no output option xxx
有时候,是在ANTLR的option中,添加了一些不支持的参数或选项,则导致此错误。
5.1.8. UnwantedTokenException(found=xxx)
5.1.9. org.antlr.runtime.EarlyExitException
5.1.10. reference to rewrite element include without reference on left of -&
5.2. ANTLRWorks方面常见问题及解决办法
ANTLRWorks使用期间,也常会遇到很多问题,比如:
5.2.1. Compiler exception: java.io.IOException Cannot run program javac
5.2.2. Cannot launch the debuggerTab. Time-out waiting to connect to the remote parser
5.2.3. xxxParser.java error: &xxx& expected
5.2.4. Compiler failed with result code 1
由于antlrworks本身版本的问题,而导致编译出错的:
第 6 章 ANTLR开发经验总结
对于ANLTR开发方面的经验总结如下:
6.1. ANTLRWorks使用心得
在使用ANTLR的最主要的开发工具:ANTLRWorks期间,遇到很多问题,也总结出很多相关技巧。
现整理如下,供参考:
6.1.1. ANTLRWorks有时候会挂掉
比如之前遇到的:
6.2. ANTLR的预处理Preprocess
6.2.1. ANTLR自身是不支持预处理功能的
ANTLR本身,对于预处理方面是否支持,答案是不支持的。
6.2.2. 可以使用ANTLR去实现预处理的功能
而对于,真正的用ANTLR去实现预处理这个功能,可以参考之前我的一些折腾:
6.3. ANTLR的异常处理
ANTLR中,对于异常处理,支持的很好,功能很丰富了。
对此,我们可以利用ANTLR的异常方面的信息,去实现一些自己所需要的功能,比如:
其中,关于异常处理的方面的经验和心得,可以先去参考:
其他的一些,关于异常处理方面的折腾,供参考:
对于ANTLR的异常处理方面,有更多可以扩展和利用的空间:
6.3.1. ANTLR出错异常时就退出(不继续恢复错误和继续运行)
ANTLR遇到错误,出现异常时,其默认的机制中,就已经支持:自动尝试恢复错误,然后回退到前一步,继续选择别的分支路径,继续执行下去
而希望实现:当ANTLR解析出错时,就退出,则也是支持的。
ANTLR的API变化导致部分函数失效
之前遇到的,由于ANTLR的API的变化,导致函数接口变化
导致参考别人的ANTLR的示例代码时,会出错。需要去找到最新的API,才能继续使用的。
6.3.2. ANTLR出错异常时显示更多详细信息
ANTLR解析期间,遇到错误,会自动抛出异常,会打印出一些错误信息。
其默认的异常出错信息,已经相对比较全面了。
但是如果想要输出更多的,其他方面的,详细出错信息,则可以参考:
6.4. ANTLR的递归
ANTLR中,ANTLR v4之前,是不支持左递归的。
当然,在有些时候,也是可以使用递归的。
而对于ANTLR中的递归的话,尤其是在Lexer中,有时候会很难实现自己所要的效果。
6.5. ANTLR解析性能
关于ANTLR的解析性能,相对很不错了。
只是,有时候,自己的实现不够好的话,还是需要想办法,再去优化性能的:
6.6. ANTLR中的条件性匹配
6.7. ANTLR相关资源下载
6.7.1. ANTLR语法示例参考代码
一些可供参考的antlr的语法源码:
6.7.2. ANTLR相关开发工具下载
6.7.3. ANTLR相关资料和文档下载
6.8. ANTLR中debug和非debug版本
ANTLR中,对于用.g所生成的代码,有两种模式:debug版本和非debug版本
是否是debug,会有很大区别:
比如就会导致后续测试代码出错还是正常运行:
比如会影响到是否可以获得生成的AST中节点之间的父子关系:
6.8.1. ANTLR生成的AST中没有节点的父子关系
之前遇到的问题:对于ANTLR来说,默认所生成的AST中,没有节点的父子关系。
经过一番折腾,最终是找到了,如何获得节点的父子关系:What is ANTLR?
ANTLR (ANother Tool for Language Recognition) is a
powerful parser generator for reading, processing, executing, or
translating structured text or binary files. It's widely used to build
languages, tools, and frameworks.
From a grammar, ANTLR generates a
parser that can build and walk parse trees.
Looking for ?
Terence Parr is the maniac behind ANTLR and has been
working on language tools since 1989. He is a professor of computer
science at the .
Quick Start
$ cd /usr/local/lib
$ sudo curl -O http://www.antlr.org/download/antlr-4.6-complete.jar
$ export CLASSPATH=".:/usr/local/lib/antlr-4.6-complete.jar:$CLASSPATH"
$ alias antlr4='java -jar /usr/local/lib/antlr-4.6-complete.jar'
$ alias grun='java org.antlr.v4.gui.TestRig'
$ cd /usr/local/lib
$ wget http://www.antlr.org/download/antlr-4.6-complete.jar
$ export CLASSPATH=".:/usr/local/lib/antlr-4.6-complete.jar:$CLASSPATH"
$ alias antlr4='java -jar /usr/local/lib/antlr-4.6-complete.jar'
$ alias grun='java org.antlr.v4.gui.TestRig'
Download .
Add antlr4-complete.jar to CLASSPATH, either:
Permanently: Using System Properties dialog > Environment variables > Create or append to CLASSPATH variable
Temporarily, at command line:
SET CLASSPATH=.;C:\Javalib\antlr4-complete.%CLASSPATH%
Create batch commands for ANTLR Tool, TestRig in dir in PATH
antlr4.bat: java org.antlr.v4.Tool %*
java org.antlr.v4.gui.TestRig %*
prog: (expr NEWLINE)* ;
expr: expr ('*'|'/') expr
| expr ('+'|'-') expr
| '(' expr ')'
NEWLINE : [\r\n]+ ;
: [0-9]+ ;
$ antlr4 Expr.g4
$ javac Expr*.java
$ grun Expr prog -gui
Latest News
Kudos. I'm actually really liking ANTLR! I have a pretty darn good
velocity with a rapid prototyping project I am doing in my Google 20%
time. For example, I just discovered a feature in rewrite rules that
does exactly what I need (referencing previous rule ASTs, p. 174 in
your book). It took me about 5 minutes to get this to work and remove
an ugly wart from my grammar. Hats off!
Guido van Rossum, Inventor of Python
ANTLR is an exceptionally powerful and flexible tool for parsing
formal languages. At Twitter, we use it exclusively for query parsing
in Twitter search. Our grammars are clean and concise, and the
generated code is efficient and stable. The
is our go-to
reference for ANTLR v4 -- engaging writing, clear descriptions and
practical examples all in one place.
Samuel Luckenbill, Senior Manager of Search Infrastructure, Twitter, inc.
Just wanted to take the opportunity to say thanks. ANTLR is a BIG
improvement over yacc/lex, and your support for it most
commendable. Managed to get my tired old brain around it in a
day. Nice work!
Brad Cox, Inventor of Objective-C9625人阅读
读书笔记(1)
技术书翻译(1)
写在前面的话:
&&&&&&此文档是对伟大的的著作《》的翻译本,致敬!欢迎转载,请注明原地址,请尊重劳动成果。翻译有误的地方,欢迎指正。
欢迎进入ANTLR的世界!
是一款您可以用来阅读,处理,执行,或转化成结构化的文本或二进制文件的强大的解析生成器。它在学术界和工业界被广泛地用来建立各种语言,工具和框架。推特搜索使用的查询解析,一天超过多个查询。,,数据仓库以及的分析系统的语言都是用了。用从合乎规则的文本中进行信息抽取。在及其迁移工具中用到了。用解析。中语言用搭建映射框架。
除了这些大牌,高知名度的项目,你可以建立各种有用的工具,如配置文件的读取,遗留代码转换器,标记的渲染器以及解析器。我为关系数据库映射创建的一些小工具,描述虚拟,并注入分析代码转换为源代码,我甚至为演讲做了一个简单的模式匹配的例子。
通过语法的语言描述,可以生成这种语言解析器并自动生成解析树(一种代表语法如何去匹配输入的的数据结构)。也可自动生成树的,你可以访问那些树的节点来执行应用程序特定的代码。
这本书是为第版本作为参考,同时也用它来解决语言识别问题的一个指导。你将学习如何做如下的事情:
从给出的例子中和参考手册中去识别语法的语言模式,学以致用。最终达到建立自己语法的要求。
从简单的语言(如)一直到复杂的编程语言(像语言)慢慢去构建语法,你将会解决和一些棘手的识别问题。
基于那些语法通过自动生成的解析树来实现语言应用。
为特定应用领域自定义识别错误处理方法和错误报告。
通过在语法中嵌入代码实现对解析的绝对控制。
与教科书的偏理论不同,本书以案例驱动的讨论是为了使内容更加具体形象,方便你为建立自己的语言应用提供一些工具集。
这本书是为谁写的
这本书是专门针对有兴趣学习如何建立数据的读取器,语言解释与转换的程序员们。这本书的内容就是如何用去构建这些事情,当然,但你一般要了解词法分析器和解析器的知识。初学者和专家都需要用这本书来高效地使用。在你看到第三部分高级主题的内容之前,你最好通过看前面几章来获得关于的一些经验。读者也应该了解一些方面的知识。
的版本有一些重要的新功能,可以让学习少走一些弯路,使开发语法和语言应用更加容易。最重要的一点是,欣然接受你定义的每一个语法(对于间接左递归来说是例外)。在翻译你的语法成为可执行文件、可读分析的代码的时候是没有语法冲突或出现模糊警告的情况。
如果你给你的生成的解析器一个有效输入,无论多么复杂的语法,解析器都将正确识别。当然,这首先依赖于你确保语法对问题是准确的描述。
解析器使用了我跟开发的一个全新的解析技术,称为或者说是。()是的()技术的一个扩展,在生成的解析器执行之前,动态地完成语法分析而不是之前的静态分析。因为()解析器获取实际的输入序列,他们总是能想出如何通过适当地编织语法去识别序列。而相比静态分析,必须考虑到所有可能的无限长输入序列。
实际上,使用()意味着你不必扭曲你的文法去迎合其他大多数解析器生成器工具的基本分析策略,包括。如果你曾经为的模糊警告或在中的一个降低或者减少的冲突而伤透脑筋的话,那么正是你想要的!
小知识:,是上一个用来生成的编译器(编译器代码生成器)。生成的主要是用语言写成的语法解析器(),需要与词法解析器一起使用,再把两部份产生出来的程序一并编译。本来只在系统上才有,但现时已普遍移植往及其他平台。
下一个新特点,大大简化了用于匹配的语法结构的语法规则,比如像编程语言算术表达式。表达式需要用文法(用递归下降分析器去手动识别)来指定已然成了一件麻烦的事情。识别表达式的最自然的语法对像这样传统的自上而下的分析器生成器来说是无效的。现在,用,你可以用如下这样的规则去匹配表达式:
expr &&// match subexpressions joined with '*'operator
expr &&&&&&// match subexpressions joined with '+' operator
&// matches simple integer atom
像这样的自引用的规则就是递归,特别是,左递归因为在其选择至少一个立即指向本身。
自动重写了左递归规则,如把变成一个非左递归等价物。唯一的限制是,左递归在规则引用自己必须是直接的。不可能指向于另一个可替代规则方案。
除了这两个语法相关的改进,使构建语言应用程序更容易。生成的解析器自动建立输入的方便表示,称为解析树,这样应用程序可以根据自己的兴趣去遍历触发代码片段。此前,用户不得不增加施工作业的语法树。除了自动构建树,还可以在和模式实现中自动生成解析树的遍历器。类似于文档处理解析器触发的事件的响应对象。
学习容易得多,因为那些新功能是不能从继承的。
最大的变化是,不再强调在语法中中嵌入的动作(代码),取而代之的是和。方便从应用程序代码中解耦语法。没有嵌入的动作,你也可以在不同的应用程序复用同样的语法而不用重新编译生成语法分析器。仍然允许嵌入的动作,但这样做是的高级应用。这样的行为需要控制的最高水平,并且是以失去语法复用成本为代价的。
因为自动生成语法分析树和树的遍历器,你不需要在建立树文法。你可以使用这样熟悉的设计模式代替。这意味着,一旦你已经学会了语法,你可以回到舒适和熟悉的编程语言领域去实现实际的语言应用。
的()分析策略是弱于的(),所以有时依靠回溯法来正确解析输入短语。回溯很难通过生成的解析器去调试文法因为解析器解析相同的输入可能会出现多次(由于递归的存在)。而且回溯对解析器遇到无效输入时很难反馈满意的错误信息。
,是我在读研究生时绕的一个小弯的成果,一晃都有二十五年了。我想我要改变我的座右铭咯。
由于的正是我追求的一个解析器生成器,这个问题,本来想在上世纪年代就解决的,年来我最终如愿。现在,那些时光已近模糊。
这本书讲了什么
本书分为四个部分。
第一部分介绍了,提供了一些语言背景知识,并且带你开始一场的性能之旅。你会初尝语法的滋味,知道用它能做些什么。
第二部分是通过提供的语法和树遍历器的组合使用,来进行语法设计、构建语言应用。
第三部分开始向你展示如何自定义分析器的错误处理。接下来,您将学习如何在语法中嵌入动作,因为有时候它比在构建树并去遍历要简单和更有效的多。相关的动作,你也会学到如何使用语义去改变分析器行为来处理一些具有挑战性的识别问题。最后一章解决了一些具有挑战性的语言识别问题,如中和上下文敏感的换行符识别。
第四部分是参考部分,并列出了语法的元语言和运行依赖库的使用规则。
在这本书中所有例子的源代码是在线可用的。如果你正在阅读本文这个版本的书,或者只想获取一个完整的代码包,你可以点开在本书的网站。你能找到重点讨论的关键要素和书中大多数的的代码段。下载后注意,所有文件头部都有版权声明,输入的文件也是一样。如在子目录下的,在使用它们作为输入前,请移除版权申明。电子版的读者也可以从本书中粘贴和复制,不显示版权声明的代码,如下所示:
更多关于在线学习
在网站上,你会发现的下载接口,图形用户界面()的开发环境,文档,预建的文法,实例,文章,和文件共享区。技术支持邮件列表是对新手来说是非常有好处的。
Terence Parr
旧金山大学, 2012
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:181214次
积分:1892
积分:1892
排名:第17046名
原创:72篇
转载:19篇
评论:40条
(1)(2)(3)(1)(1)(5)(67)(3)(2)(3)(1)(1)(1)}

我要回帖

更多关于 间接递归调用 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信