引用

Terence Parr. The Definitive ANTLR Reference, Building Domain Specific Languages(antlr3 version).
 
前言
[1]为什么有了lex/yacc(flex/bison),为什Parr还要写个ANTLR?
C语言是拿着剃须刀在滑冰,Java是“隐藏”了指针的支持OO的C语言族中相对简单的语言,随着Martin的DSL概念深入人心,不管怎样,还是印证了那句话:模仿是最大的恭维。尽管这对有10+编译器方向工作的Parr来说,这样评价有点不公平。
[2]现在ANTLR已有版本4了,为什么还看版本3的参考指南?
Parr的另一本书《编程语言实现模式》中是用的版本3。
 
内容
不阐述编译器、DSL方面的概念,纯粹从该书的示例说起。
AntlrWorks工具在后面笔记中记录。
一个带变量的简单算术表达式语言的解释器两种实现方式:
(1)文法(词法、语法)识别器(recognizer)——>在文法中融入动作(action)实现解释器(translator)
(2)构建文法的AST(抽象语法树)中间表示——>编写树文法(tree grammer),遍历AST实现解释器
 
正文
依赖:antlr-3.5-complete.jar
语言样例:
a=12
b=23
2 + a*b
2 * (a + b)
 
1 动作驱动的解释器
1.1 文法识别器
//Expr.g,文件名称必须与grammar后名称一致,后缀名为.g
grammar Expr;

prog : stat+
;

stat : expr NEWLINE
| ID '=' expr NEWLINE
| NEWLINE
;

expr : multExpr (('+' | '-') multExpr)*
;
multExpr : atom ('*' atom)*
;
atom : INT
| ID
| '(' expr ')'
;

ID : ('a'..'z'|'A'..'Z')+;
INT :('0'..'9')+;
NEWLINE : '\r'?'\n';
WS : (' '|'\t'|'\n'|'\r')+ {skip();}; 
 
生成parser、lexer和tokens命令
java -classpath antlr-3.5-complete.jar org.antlr.Tool Expr.g
生成文件ExprLexer.java、ExpreParser.java、Expr.tokens
 
编写识别测试类(test rig)Test
package impatient;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import org.antlr.runtime.*;

public class Test {
public static void main(String[] args) throws Exception {
InputStream is = new FileInputStream(new File("D:/workspace/maven/antlrv3/language/impatient.test"));//impatient.test中包含语言样例
// create a CharStream that reads from standard input
// ANTLRInputStream input = new ANTLRInputStream(System.in);
ANTLRInputStream input = new ANTLRInputStream(is);

// create a lexer that feeds off of input CharStream
ExprLexer lexer = new ExprLexer(input);

// create a buffer of tokens pulled from the lexer
CommonTokenStream tokens = new CommonTokenStream(lexer);

// create a parser that feeds off the tokens buffer
ExprParser parser = new ExprParser(tokens);
// begin parsing at rule r
parser.prog();
}
}
 
1.2 文法+动作
直接在文法中添加动作(java代码,用{}包含),严重影响文法的可读性!
//添加动作后的Expr.g
grammar Expr;

@header {
import java.util.HashMap;
}

@members {
HashMap memory = new HashMap();
}

prog : stat+
;

stat : expr NEWLINE {System.out.println($expr.value);}
| ID '=' expr NEWLINE {memory.put($ID.text, new Integer($expr.value));}
| NEWLINE
;

expr returns [int value]
: e=multExpr {$value = $e.value;}
('+' e=multExpr {$value += $e.value;}
| '-' e=multExpr {$value -= $e.value;}
)*
;
multExpr returns [int value]
: e=atom {$value = $e.value;} ('*' e=atom {$value *= $e.value;})*
;
atom returns [int value]
: INT {$value = Integer.parseInt($INT.text);}
| ID
{
Integer v = (Integer) memory.get($ID.text);
if(v != null) $value = v.intValue();
else System.err.println("undefined variable " + $ID.text);
}
| '(' expr ')' {$value = $expr.value;}
;

ID : ('a'..'z'|'A'..'Z')+;
INT :('0'..'9')+;
NEWLINE : '\r'?'\n';
WS : (' '|'\t'|'\n'|'\r')+ {skip();}; 

重新生成parser、lexer和tokens,仍采用test rig Test运行

 
 
2 树文法驱动的解释器
2.1 AST
//生成输出中间表示(IR)的Expr.g
grammar Expr;

options {
output = AST;
ASTLabelType = CommonTree;
}

prog : (stat {System.out.println($stat.tree.toStringTree());})+
;

stat : expr NEWLINE -> expr
| ID '=' expr NEWLINE -> ^('=' ID expr)
| NEWLINE ->
;

expr returns [int value]
: multExpr (('+'^ | '-'^) multExpr)*
;
multExpr : atom ('*'^ atom)*
;
atom : INT
| ID
| '('! expr ')'!
;

ID : ('a'..'z'|'A'..'Z')+;
INT :('0'..'9')+;
NEWLINE : '\r'?'\n';
WS : (' '|'\t'|'\n'|'\r')+ {skip();}; 

两个后缀符号:!不输入AST、^作为AST的子根节点

->符号用于说明生成的AST结构
 
重新生成parser、lexer和tokens,仍采用test rig Test运行
结果输出AST的一维串行表示
 
2.2 树文法
//树文法Eval.g,与Expr.g共用tokens
tree grammar Eval;

options {
tokenVocab=Expr;
ASTLabelType=CommonTree;
}

@header {
import java.util.HashMap;
}

@members {
HashMap memory = new HashMap();
}

prog : stat+;

stat : expr {System.out.println($expr.value);}
| ^('=' ID expr) {memory.put($ID.text, new Integer($expr.value));}
;

expr returns [int value]
: ^('+' a=expr b=expr) {$value = a + b;}
| ^('-' a=expr b=expr) {$value = a - b;}
| ^('*' a=expr b=expr) {$value = a * b;}
| ID
{
Integer v = (Integer)memory.get($ID.text);
if(v!=null) $value = v.intValue();
else System.err.println("undefined variable " + $ID.text);
}
| INT {$value = Integer.parseInt($INT.text);}
;
生成treeparser命令
 
java -classpath antlr-3.5-complete.jar org.antlr.Tool Eval.g

生成文件Eval.java、Eval.tokens

 
AST遍历程程解释器test rig ASTTest
package impatient;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import org.antlr.runtime.*;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.CommonTreeNodeStream;
public class ASTTest {
public static void main(String[] args) throws Exception {
InputStream is = new FileInputStream(new File("D:/workspace/maven/antlrv3/language/impatient.test"));
// create a CharStream that reads from standard input
// ANTLRInputStream input = new ANTLRInputStream(System.in);
ANTLRInputStream input = new ANTLRInputStream(is);

// create a lexer that feeds off of input CharStream
ExprLexer lexer = new ExprLexer(input);

// create a buffer of tokens pulled from the lexer
CommonTokenStream tokens = new CommonTokenStream(lexer);

// create a parser that feeds off the tokens buffer
ExprParser parser = new ExprParser(tokens);

// get rule prog return value structure
ExprParser.prog_return r = parser.prog();

// WALKING RESULTING TREE
CommonTree tree = r.getTree();
// one dimensional tree node stream
CommonTreeNodeStream nodes = new CommonTreeNodeStream(tree);
// tree parser
Eval walker = new eval_r(nodes);
walker.prog();
}
}
 
3 遗憾
ANTLR文法也是一种DSL,其语法和标识需要在后面的笔记中记录。
 

ANTLR3完全参考指南读书笔记[01]的更多相关文章

  1. ANTLR3完全参考指南读书笔记[06]

    前言 这段时间在公司忙的跟狗似的,但忙的是没多少技术含量的活儿. 终于将AST IR和tree grammar过了一遍,计划明天写完这部分的读书笔记.   内容 1 内部表示AST构建 2 树文法   ...

  2. ANTLR3完全参考指南读书笔记[02]

    前言 程序语言是什么? 用wiki上的描述,程序语言是一种人工设计的语言,用于通过指令与机器交互:程序语言是编程程序的标记,而程序是一种计算或算法的描述.详细介绍和背景信息参考: Programmin ...

  3. ANTLR3完全参考指南读书笔记[08]

    前言 不要让用户被那些“专业术语”吓住! 用心设计的提示和反馈信息是软件设计者的“职业良心”.   内容 1 存在哪些错误? 2 美化错误提示 3 错误恢复策略   1 存在哪些错误? 在DSL语言开 ...

  4. ANTLR3完全参考指南读书笔记[07]

    前言 真正意义上的程序员都很懒,懒的连多余的一行代码也不写. 如果能将底层满手油污的活儿都可以交给别人去做,自己就扮演个智囊团成员的角色,生活会比想象中的还要惬意. 严格的按照指令执行长时间不知疲倦的 ...

  5. ANTLR3完全参考指南读书笔记[05]

    前言 仅生成给出true/false的识别器是没有多大用处的,自然的就有在识别过程中遇到某一结构时执行一段代码.存储该结构中信息的想法. ANTLR提供了在文法中嵌入属性和动作超级混合“文法”,可以生 ...

  6. ANTLR3完全参考指南读书笔记[04]

    前言 学习框架或第三方库的方法是什么 (1)少量的浏览manual或tutoral,只关注程序所需的特征,再完善其详细内容和特征的认识? (2)花大量的时间研究详细内容,再考虑程序实现? 这是个先有鸡 ...

  7. ANTLR3完全参考指南读书笔记[03]

    前言 文中第4章内容有点多,有点枯燥,但不坚持一下,之前所做的工作就白做了. 再次确认一下总体目标: protege4编辑器中Class Definition中语法解析和错误提示: Java虚拟机规范 ...

  8. 《The Linux Command Line》 读书笔记01 基本命令介绍

    <The Linux Command Line> 读书笔记01 基本命令介绍 1. What is the Shell? The Shell is a program that takes ...

  9. HTTP权威指南读书笔记

    HTTP权威指南笔记 读书有两种境界,第一种境界是将书读薄,另一种是读厚.本篇文章就是HTTP权威指南的读书笔记,算是读书的第一重境界,将厚书读薄.文章对HTTP的一些关键概念做了比较详细的概述,通读 ...

随机推荐

  1. DML数据操作语言练习

    --创建表T_HQ_BM2 --create table t_hq_bm2 as select * from t_hq_bm; commit; --添加行内容 --insert into t_hq_b ...

  2. 二模 (8) day1

    第一题: 题目大意: 梦幻城市每年为全市高中生兴办一次运动会.为促使各校同学之间的交流,采用特别的分队方式:每一个学校的同学,必须被均匀分散到各队,使得每一队中该校的人数皆相同.为增加比赛的竞争性,希 ...

  3. Javascript——Math对象

    Math 对象是一个固有的对象,无需创建它,直接把 Math 作为对象使用就可以调用其所有属性和方法.这是它与Date,String对象的区别  Math 对象属性 Math 对象方法  

  4. 蓝桥杯 2015年省赛最后一题 生命之树(树形dp)

    题目描述: 生命之树 在X森林里,上帝创建了生命之树. 他给每棵树的每个节点(叶子也称为一个节点)上,都标了一个整数,代表这个点的和谐值.上帝要在这棵树内选出一个非空节点集S,使得对于S中的任意两个点 ...

  5. CodeForces 546B C(Contest #1)

    Description Colonel has n badges. He wants to give one badge to every of his n soldiers. Each badge ...

  6. MSP430x1_4_6x之问题总结

    01:MSP430端口上电复位的初始值是不确定的:所以使用是都要初始化:比如加下面的语句或者加你使用的端口就行了:  /*下面六行程序关闭所有的IO口*/    P1DIR = 0XFF;P1OUT ...

  7. iphone获取当前流量信息

    通过读取系统网络接口信息,获取当前iphone设备的流量相关信息,统计的是上次开机至今的流量信息. 代码 悦德财富:https://yuedecaifu.com 1 2 3 4 5 6 7 8 9 1 ...

  8. springmvc----struts2比较

    method=requestMethod.GETorPOST  vs  addInput+add 用抛异常处理密码验证和用户名重复与否验证 +js303 @validate   判断输入格式(jque ...

  9. git——学习笔记(二)远程仓库

    GIT杀手锏之一——远程仓库 拥有远程仓库的两个办法 1:搭一个Git服务器  2:在GitHub上免费托管的Git仓库 本地仓库   远程仓库 一.在GitHub上免费托管的Git仓库 电脑: 1. ...

  10. 认真对待每一道算法题 之 两个排序好的数组寻找的第k个大的数

    转载博客:http://www.cnblogs.com/buptLizer/archive/2012/03/31/2427579.html 题目意思:给出两个排好序的数组 ,不妨设为a,b都按升序排列 ...