您的位置:首页 > 其它

antlr 介绍以及脚本编写(一)

2017-04-16 22:40 176 查看
1、 介绍

ANTLR—Another Tool for Language Recognition,antlr是指可以根据输入自动生成语法树并可视化的显示出来的开源语法分析器。

antlr主要内容有三个: 词法分析器(Lexer)、语法分析器(Parser)、树分析器 (tree parser)。无论是Lexer还是Parser都是一种识别器,Lexer是字符序列识别器而Parser是Token序列识别器。他们在本质上是类似的东西,而只是在分工上有所不同而已;树分析器可以用于对语法分析生成的抽象语法树进行遍历,并能执行一些相关的操作

一般分成两个阶段;

第一阶段: 大脑会下意识的将字符组成单词,然后像查询字典一样识别它们的意思(词法分析 lexical analysis: lex)

第二阶段:大脑会根据已识别的单词去识别句子的结构(parser 默认为antlr会构建出一棵分析树(parser tree)或叫语法树(syntax tree));

2、 启动ui和运行

需要jar包为: antlr-3.1.3.jar(运行包)、antlrworks-1.4.jar(ui界面包)

启动ui: java -cp jar包的路径 org.antlr.works.IDE

运行: java -cp jar包的路径 org.antlr.Tool *.g

3、 运行计算方法:

1. 脚本里加入action

2. 构建AST(abstract syntax tree);

3、 脚本编写实例

实例1:

parser和lexer结合

grammar Expr;
//parser rule
expr returns [int value=0]: a=INT PLUS b=INT {
int aValue = Integer.parseInt(a.getText());
int bValue = Integer.parseInt(b.getText());
$value = aValue + bValue;
}

// lexer rule
PLUS: '+';
INT: ('0'..'9')+;

备注: lexer rule 要求字符首字母大写,一般默认整个单词都大写
parser rule 要求首字母小写,一般默认整个单词小写
字符串一般加单引号
每行结束符需要加分好
执行命令后会生成 Expr.tokens/ExprLexer.java/ExprParser.java


实例2:

parser lexer tree三个结合

// 分为两个.g文件
// 1. parser和lexer  Expr.g
grammar Expr;

options {
ASTLabelType = CommonTree;
language = Java;
output = AST;
}
// tokens 分词  构建AST需要
tokens {
PROG;
STAT;
NUM;
VAR;
// AND = 'and';
}

//parser rule
prog: stat -> ^(PROG stat); //构建语法树
stat: expr EOF -> ^(STAT expr);
expr: multiExpr (('+'^|'-'^) multiExpr)*;
multiExpr : atom (('*'^|'/'^) atom)*;
atom: '('expr')' -> expr
|   INT ->^(NUM INT)
|   ID -> ^(VAR ID );

// lexer rule
ID: ('a'..'z'|'A'..'Z')+;
INT: ('0'..'9')+;
NEWLINE: '\r'?'\n';
WS: (' ' | '\t'|'\n'|'\r')+ {skip{};}; // 空行,一般执行跳过动作

// 2 tree 文件  Eval.g  执行命令后会生成Eval.tokens/Eval.java
tree grammar Eval;

options {
tokenVocab = Expr; // parser文件名
ASTLabelType = CommonTree;
language = Java;
}
// tokens 分词  构建AST需要
tokens {
PROG;
STAT;
NUM;
VAR;
// AND = 'and';
}

@header {import java.util.Random;}
//tree parser rule
prog: ^(PROG s=stat) {
// prog要执行的方法体
System.out.println("Computer result:" +  s.intValue());
};
stat returns [Integer value]: ^(STAT e=expr) {
$value = e.intValue();
};

expr  returns [Integer value]:  ^('+' e1=expr e2=expr) {$value = e1.intValue() + e2.intValue();}
| ^('-' e1=expr e2=expr) {$value = e1.intValue() - e2.intValue();}
| a = atom {$value = a.intValue();};
atom returns [Integer value]: ^(NUM i=INT) {$value = Integer.parseInt(i.getText());};

//备注: 1. 整个两个文件在执行org.antlr.Tool 的时候,格式为org.antlr.Tool *.g,确保Expr.tokens 和 Eval.tokens一致才行


4、个人总结:

1. 编写.g脚本的时候,里面的语言可以java/c++等

2. 编写tree的脚本的时候,需要根据AST树的情况来确定最终的结果。一般需要设计成迭代执行。

3. parser rule 和tree rule 冒号左边都是方法名。

5、 java代码调用

String rule= "111=222 AND 333=444";

ANTLRStringStream input = new ANTLRStringStream(rule);
// 生成的lexer类
FilterRuleLexer lexer = new FilterRuleLexer(input);
CommonTokenStream tokens = new CommonTokenStream(lexer);
// 生成的parser类
FilterRuleParser parser = new FilterRuleParser(tokens);

// parser中的主规则, parser中的任何规则都可以返回commontree, 一般默认调用主规则
CommonTree tree = (CommonTree)parser.rule().getTree();
CommonTreeNodeStream nodes = new CommonTreeNodeStream(tree);
nodes.setTokenStream(tokens);

//生成的treerule类
FilterTreeRule treeRule = new FilterTreeRule(nodes);
System.out.println(treeRule.rule());// tree rule类中的主规则
System.out.println(tree.token);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  脚本 antlr
相关文章推荐