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的布尔表达式语句解释器的实现的更多相关文章

  1. 初识NodeJS,一个基于GoogleV8引擎的Javascript运行环境

    思考 首先我们来思考一个问题:我们都知道几乎所有现代主流浏览器都全面支持了ECMAScript 5.1版标准,而JavaScript的标准是ECMAScript.那么我们就容易认为JavaScript ...

  2. 一个基于.NET平台的自动化/压力测试系统设计简述

    AutoTest系统设计概述 AutoTest是一个基于.NET平台实现的自动化/压力测试的系统,可独立运行于windows平台下,支持分布式部署,不需要其他配置或编译器的支持.(本质是一个基于协议的 ...

  3. 构建一个基于 Spring 的 RESTful Web Service

    本文详细介绍了基于Spring创建一个“hello world” RESTful web service工程的步骤. 目标 构建一个service,接收如下HTTP GET请求: http://loc ...

  4. JAVA WEB快速入门之从编写一个基于SpringBoot+Mybatis快速创建的REST API项目了解SpringBoot、SpringMVC REST API、Mybatis等相关知识

    JAVA WEB快速入门系列之前的相关文章如下:(文章全部本人[梦在旅途原创],文中内容可能部份图片.代码参照网上资源) 第一篇:JAVA WEB快速入门之环境搭建 第二篇:JAVA WEB快速入门之 ...

  5. 一个基于ASP.NET(C#)的ACCESS数据库操作类

    using System; using System.Collections; using System.Collections.Specialized; using System.Data; usi ...

  6. 一个基于NodeJS开发的APP管理CMS系统

    花了大概3周独立开发了一个基于NodeJS的CMS系统,用于公司APP的内容管理( **公司APP?广告放在最后 ^_^ ** ,管理员请理解~~~ )晚上看了部电影还不想睡,闲着也是闲着就作下小小总 ...

  7. Go/Python/Erlang编程语言对比分析及示例 基于RabbitMQ.Client组件实现RabbitMQ可复用的 ConnectionPool(连接池) 封装一个基于NLog+NLog.Mongo的日志记录工具类LogUtil 分享基于MemoryCache(内存缓存)的缓存工具类,C# B/S 、C/S项目均可以使用!

    Go/Python/Erlang编程语言对比分析及示例   本文主要是介绍Go,从语言对比分析的角度切入.之所以选择与Python.Erlang对比,是因为做为高级语言,它们语言特性上有较大的相似性, ...

  8. Stateless是一个基于C#创建状态机的简单库

    Stateless是一个基于C#创建状态机的简单库 .Net轻量状态机Stateless 很多业务系统开发中,不可避免的会出现状态变化,通常采用的情形可能是使用工作流去完成,但是对于简单场景下,用工作 ...

  9. SDKMAN一个基于命令行界面的SDK用户环境管理程序

    1.背景 使用过Python开发的朋友,应该了解到Python2和Python3语法的差异,有时候从网上下载了基于不同解释器的代码,要来回切换版本, 使用起来不是很方便,有时候甚至很麻烦.于是有人发明 ...

随机推荐

  1. SQL2008游标

    最近让写一个自动生成数据的存储过程,其中会遍历表中数据并做出相应处理,因为数据量不算太大所以使用到了游标,初识游标遇到几个小问题,所以来和大家一起分享一下: 使用游标的五个步骤: 1.声明游标 语法: ...

  2. C++用PostMessage模拟按钮点击

    有时我们可能会在某个程序中用到模拟按钮点击事件. 本文中的例子在MFC程序中调试通过,duilib的没试过,还需探索 不多说,上代码: #include "stdafx.h" #i ...

  3. yii学习笔记

    学而不思则罔,思而不学则殆,适度的总结有利于学习效果的提升. 以前就是埋头看书很少动手所以学习效果不好. 学习yii的原因是自己基本功差,但是yii的学习本身也需要成本

  4. Cryptopp iOS 使用 RSA加密解密和签名验证签名

    Cryptopp 是一个c++写的功能完善的密码学工具,类似于openssl 官网:https://www.cryptopp.com 以下主要演示Cryptopp 在iOS上的RSA加密解密签名与验证 ...

  5. Python之路 day2 初识字典

    #Author:ersa ''' key-value 键值对 字典是无序的,不需要下标,有key 字典的查找.修改.添加.判断.删除 ''' info = { 'stu1101': "Ten ...

  6. C#窗体 WinForm 进程,线程

    一.进程 进程是一个具有独立功能的程序关于某个数据集合的一次运行活动. 它可以申请和拥有系统资源,是一个动态的概念,是一个活动的实体. Process 类,用来操作进程. 命名空间:using Sys ...

  7. HDU 1106 排序 题解

    排序 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submissi ...

  8. sorttable

    http://rubaxa.github.io/Sortable/Sortable.js http://rubaxa.github.io/Sortable/Sortable.min.jshttp:// ...

  9. 我的qq邮箱的GPG公钥

    呵呵,赶一波潮流,我的邮箱 175420840@qq.com 的GPG公钥如下,也可以在这里直接下载.具体可参见阮一峰的<GPG入门教程>. -----BEGIN PGP PUBLIC K ...

  10. K2BPM怎么让金融数据更有意义?

    西南证券成立于1999年,是唯一一家注册地在重庆的全国综合性证券公司,也是中国第九家上市证券公司和重庆第一家上市金融机构.公司现有员工逾2000名,在全国27个省份获批设立109家证券营业部,拥有17 ...