一个基于ANTLR 4的布尔表达式语句解释器的实现
Reference
The Definitive ANTLR 4 Reference, 2nd Edition.
0 Features
labeled grammar definition, i.e. # eq;
Visitorpattern.
1 The Grammar
grammar RuleSet;
prog: stmt+ ;
stmt: expr '=' expr NEWLINE #eq
|expr '<' expr NEWLINE #lt
|expr '<=' expr NEWLINE # le
|expr '>' expr NEWLINE # gt
|expr '>=' expr NEWLINE # ge
;
expr: expr op=('*'|'/') expr # MulDiv
| expr op=('+'|'-') expr # AddSub
| INT # int
| '(' expr ')' # parens
;
MUL : '*' ; // assigns token name to '*' used above in grammar
DIV : '/' ;
ADD : '+' ;
SUB : '-' ;
NEWLINE : [\r\n]+ ;
INT : [0-9]+ ; // match integers
WS : [ \t]+ -> skip ; // toss out whitespace
2 Play around with ANTLR 4
export CLASSPATH=".:./antlr-4.5.1-complete.jar:$CLASSPATH"
# generate listner
#java -jar ./antlr-4.5.1-complete.jar RuleSet.g4
# generate visitor
java -jar ./antlr-4.5.1-complete.jar -no-listener -visitor RuleSet.g4
3 The Interpreter
Put the generate java files in pakage com.spike.antlr4.rs.
3.1 The Visitor
package com.spike.antlr4.rs;
import com.spike.antlr4.rs.RuleSetParser.ExprContext;
public class EvalVisitor extends RuleSetBaseVisitor<Integer> {
private boolean result = false;
public boolean getResult() {
return result;
}
public void setResult(boolean result) {
this.result = result;
}
/** = */
@Override
public Integer visitEq(RuleSetParser.EqContext ctx) {
// Integer result = visitChildren(ctx);
ExprContext left = ctx.expr(0);
ExprContext right = ctx.expr(1);
int result = visit(left) - visit(right);
if (result == 0) {
this.setResult(true);
} else {
this.setResult(false);
}
return result;
}
/** <= */
@Override
public Integer visitLe(RuleSetParser.LeContext ctx) {
// Integer result = visitChildren(ctx);
ExprContext left = ctx.expr(0);
ExprContext right = ctx.expr(1);
int result = visit(left) - visit(right);
if (result <= 0) {
this.setResult(true);
} else {
this.setResult(false);
}
return result;
}
/** < */
@Override
public Integer visitLt(RuleSetParser.LtContext ctx) {
ExprContext left = ctx.expr(0);
ExprContext right = ctx.expr(1);
int result = visit(left) - visit(right);
if (result < 0) {
this.setResult(true);
} else {
this.setResult(false);
}
return result;
}
/** >= */
@Override
public Integer visitGe(RuleSetParser.GeContext ctx) {
ExprContext left = ctx.expr(0);
ExprContext right = ctx.expr(1);
int result = visit(left) - visit(right);
if (result >= 0) {
this.setResult(true);
} else {
this.setResult(false);
}
return result;
}
/** > */
@Override
public Integer visitGt(RuleSetParser.GtContext ctx) {
ExprContext left = ctx.expr(0);
ExprContext right = ctx.expr(1);
int result = visit(left) - visit(right);
if (result > 0) {
this.setResult(true);
} else {
this.setResult(false);
}
return result;
}
/** INT */
@Override
public Integer visitInt(RuleSetParser.IntContext ctx) {
return Integer.valueOf(ctx.INT().getText());
}
/** expr op=('*'|'/') expr */
@Override
public Integer visitMulDiv(RuleSetParser.MulDivContext ctx) {
int left = visit(ctx.expr(0)); // get value of left subexpression
int right = visit(ctx.expr(1)); // get value of right subexpression
if (ctx.op.getType() == RuleSetParser.MUL)
return left * right;
return left / right; // must be DIV
}
/** expr op=('+'|'-') expr */
@Override
public Integer visitAddSub(RuleSetParser.AddSubContext ctx) {
int left = visit(ctx.expr(0)); // get value of left subexpression
int right = visit(ctx.expr(1)); // get value of right subexpression
if (ctx.op.getType() == RuleSetParser.ADD)
return left + right;
return left - right; // must be SUB
}
/** '(' expr ')' */
@Override
public Integer visitParens(RuleSetParser.ParensContext ctx) {
return visit(ctx.expr()); // return child expr's value
}
}
3.2 The Main Entrance
package com.spike.antlr4.rs;
import java.util.ArrayList;
import java.util.List;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;
/**
* The Interpreter
*
* @author zhoujiagen<br/>
* Aug 26, 2015 1:20:34 AM
*/
public class Calc {
static String NEWLINE = "\r\n";
public static void main(String[] args) {
System.out.println(eval("123=100+12+11" + NEWLINE, "124 + 125 = 123 + 126" + NEWLINE, "345 <= 346 + 347 + 348"
+ NEWLINE));
}
static List<Boolean> eval(String... stmts) {
if (stmts != null && stmts.length > 0) {
List<Boolean> result = new ArrayList<Boolean>();
for (String stmt : stmts) {
result.add(eval(stmt));
}
return result;
}
return null;
}
static boolean eval(String stmt) {
boolean result = false;
if (stmt != null && stmt.length() > 0) {
ANTLRInputStream input = new ANTLRInputStream(stmt);
RuleSetLexer lexer = new RuleSetLexer(input);
CommonTokenStream tokens = new CommonTokenStream(lexer);
RuleSetParser parser = new RuleSetParser(tokens);
ParseTree tree = parser.stmt(); // parse
EvalVisitor eval = new EvalVisitor();
System.out.println(eval.visit(tree));
// get the final result
result = eval.getResult();
}
return result;
}
}
一个基于ANTLR 4的布尔表达式语句解释器的实现的更多相关文章
- 初识NodeJS,一个基于GoogleV8引擎的Javascript运行环境
思考 首先我们来思考一个问题:我们都知道几乎所有现代主流浏览器都全面支持了ECMAScript 5.1版标准,而JavaScript的标准是ECMAScript.那么我们就容易认为JavaScript ...
- 一个基于.NET平台的自动化/压力测试系统设计简述
AutoTest系统设计概述 AutoTest是一个基于.NET平台实现的自动化/压力测试的系统,可独立运行于windows平台下,支持分布式部署,不需要其他配置或编译器的支持.(本质是一个基于协议的 ...
- 构建一个基于 Spring 的 RESTful Web Service
本文详细介绍了基于Spring创建一个“hello world” RESTful web service工程的步骤. 目标 构建一个service,接收如下HTTP GET请求: http://loc ...
- JAVA WEB快速入门之从编写一个基于SpringBoot+Mybatis快速创建的REST API项目了解SpringBoot、SpringMVC REST API、Mybatis等相关知识
JAVA WEB快速入门系列之前的相关文章如下:(文章全部本人[梦在旅途原创],文中内容可能部份图片.代码参照网上资源) 第一篇:JAVA WEB快速入门之环境搭建 第二篇:JAVA WEB快速入门之 ...
- 一个基于ASP.NET(C#)的ACCESS数据库操作类
using System; using System.Collections; using System.Collections.Specialized; using System.Data; usi ...
- 一个基于NodeJS开发的APP管理CMS系统
花了大概3周独立开发了一个基于NodeJS的CMS系统,用于公司APP的内容管理( **公司APP?广告放在最后 ^_^ ** ,管理员请理解~~~ )晚上看了部电影还不想睡,闲着也是闲着就作下小小总 ...
- Go/Python/Erlang编程语言对比分析及示例 基于RabbitMQ.Client组件实现RabbitMQ可复用的 ConnectionPool(连接池) 封装一个基于NLog+NLog.Mongo的日志记录工具类LogUtil 分享基于MemoryCache(内存缓存)的缓存工具类,C# B/S 、C/S项目均可以使用!
Go/Python/Erlang编程语言对比分析及示例 本文主要是介绍Go,从语言对比分析的角度切入.之所以选择与Python.Erlang对比,是因为做为高级语言,它们语言特性上有较大的相似性, ...
- Stateless是一个基于C#创建状态机的简单库
Stateless是一个基于C#创建状态机的简单库 .Net轻量状态机Stateless 很多业务系统开发中,不可避免的会出现状态变化,通常采用的情形可能是使用工作流去完成,但是对于简单场景下,用工作 ...
- SDKMAN一个基于命令行界面的SDK用户环境管理程序
1.背景 使用过Python开发的朋友,应该了解到Python2和Python3语法的差异,有时候从网上下载了基于不同解释器的代码,要来回切换版本, 使用起来不是很方便,有时候甚至很麻烦.于是有人发明 ...
随机推荐
- 单据BE构建
本节来构建单据BE1.新建单据BE实体项目,修改命名空间 2.引入单据基类如下图所示,在UFIDA.U9.Base.BaseBE.MetaData命名空间下将类Doc托至设计BE视图中 3.分别托2个 ...
- (九)errno和perror、标准IO
3.1.6.文件读写的一些细节3.1.6.1.errno和perror(1)errno就是error number,意思就是错误号码.linux系统中对各种常见错误做了个编号,当函数执行错误时,函数会 ...
- mybatis 模糊查询 like
1. 参数中直接加入%% param.setUsername("%CD%"); param.setPassword("%11%"); <sel ...
- Shell重定向文件描述符
#!/bin/bash 最近在看shell,各种困惑,不过解决困惑的感觉还是很不错的.废话少说,linux中使用文件描述符来标识每个文件对象.文件描述符为一个非负整数,可以唯一标识会话中打开 ...
- GUI 测试
图形用户界面( GUI )对软件测试提出了有趣的挑战,因为 GUI 开发环境有可复用的构件,开发用户界面更加省时而且更加精确.同时, GUI 的复杂性也增加了,从而加大了设计和执行测试用例的难度.因为 ...
- 带事物处理的DBHelp和sql语句
DBHelp语句 using System; using System.Collections.Generic; using System.Linq; using System.Text; using ...
- (41) Aeroo 模板设计基础教程
1. 理论基础 注:我采用libreoffice5.2设计讲解 1.1. 定义模板指令 模板指令的语法和Genshi 模板语言相兼容,可以用Libreoffice( Write, Ca ...
- vuex是啥
vuex是一个状态管理工具. vuex store与一个简单的全局变量的区别是: 1.vuex stores 是响应式的,当组件改变state时,它能响应并高效地更新state. 2.state不能被 ...
- Intellij快捷键
- Java:多线程<二> 同步
由于多线程的访问出现延迟和线程的随机性,在使用多线程时往往会伴随安全性的问题,这些问题一旦出现将会是非常严重的.为了解决这种安全性问题,synchronized出现了. synchronized用法一 ...