• antlr安装


    安装java环境,环境变量设置如下:

    ANTLR 简介

    1. ANTLR—Another Tool for Language Recognition,Antlr 本身是使用 Java 开发的,它为包括Java,Python,C#在内的语言提供了一个通过语法描述来自动构造自定义语言的识别器(recognizer),编译器(parser)和解释器(translator)的框架。
    2. Antlr 使用上下文无关文法描述语言, 它允许我们定义识别字符流的词法规则和用于解释Token流的语法分析规则。然后,ANTLR将根据用户提供的语法文件自动生成相应的词法/语法分析器。用户可以利用他们将输入的文本进行编译,并转换成其他形式.

    ANTLR 安装

    安装有两种:一种手动使用命令行安装与执行,第二种则是借助强大的Eclipse的插件安装。 Eclipse插件安装,官网给出了很详细的教程
    连接如下:
    Eclipse+Antlr V4 这里就不说了。
    无论那种方式,执行的过程原理都没有变。
    首先说明下配置的环境:

    Ubuntu 14.04 32bit
    Antlr V4 
    jdk 1.7
    • 1
    • 2
    • 3

    安装jdk

    ANTLR是用Java编写的,所以在你开始之前需要先安装Java。ANTLR v4需要Java 1.6 以上版本。安装的具体过程可以参考网上教程,挺多的。这里我安装都是jdk 1.7 版本

    命令行安装

    1. 下载ANTLR v4,截止到2015.6,官网最新的为antlr-4.5-complete.jar ,可以使用如下的shell命令下载:
      curl -O http://www.antlr.org/download/antlr-4.5-complete.jar
      或者直接到[][http://www.antlr.org/download.html] 处下载,
      之后,拷贝到/usr/local/lib 目录下供使用。
    2. 添加环境变量
      修改环境变量如下:直接修改gedit ~/.bashrc:找到CLASSPATH 行,直接再后面追加下面的变量, 完成保存之后, 执行source ~/.bashrc 生效。
    :/usr/local/lib/antlr-4.5-complete.jar
    1. 修改快捷命令
      下面的两个命令也是最常用的,这里设定别名来方便使用。
      同样在直接修改gedit ~/.bashrc 找到alias 再后面加上下面两行就可。完成保存退出,执行source ~/。bashrc 即可
    $ alias antlr4='java -Xmx500M -cp "/usr/local/lib/antlr-4.5-complete.jar:$CLASSPATH" org.antlr.v4.Tool
    $ alias grun='java org.antlr.v4.runtime.misc.TestRig

    样例测试

    命令行测试

    在我们的工作目录比如说 ~/workspace 下建立一个Hello.g4 语法文件:
    内容如下: 注意文件名与 与 语法一致。

    // Define a grammar called Hello
    grammar Hello;
    r  : 'hello' ID ;         // match keyword ‘hello’ followed by an identifier
    ID : [a-z]+ ;             // match lower-case identifiers
    WS : [ 	
    ]+ -> skip ; // skip spaces, tabs, newlines

    这个语法很简单,只识别hello 后面接小写字母组成的字符串。
    然后开始编译:

    $ cd workspace
    $ antlr4 Hello.g4 #这一步会自动生成几个java文件,下一步编译java
    $ javac Hello*.java

    可以ls 一下该目录,会发现有这么几个文件

    HelloBaseListener.class  HelloLexer.java      HelloParser.class
    HelloBaseListener.java   HelloLexer.tokens    HelloParser.java
    Hello.g4                 HelloListener.class  HelloParser$RContext.class
    HelloLexer.class         HelloListener.java   Hello.tokens

    表示已经编译完成,可以使用前面重命名的命令grun 来测试,,命令格式: grun file.g4 -r [option] 其中常用的参数有这三个:

     - tokens #打印出token流
     - tree   #用LISP表单打印出解析树
     - gui    #在对话框中可视化地展示解析树

    测试如下:

    $ grun Hello r -tree
    hello world#输完执行命令之后, 在这里输入一个字符串
    ^D#由于程序会一直等待用户输入,所以这里使用 ctrl +D 结束输入
    (r hell world)#输出结果
    

    我们也可查看创建的tokens:

     grun  Hello r -tokens
     hello world
     ^D
     [@0,0:4='hello',<1>,1:0]
     [@1,6:10='world',<2>,1:6]
     [@2,12:11='<EOF>',<-1>,2:0]
    #-------------#
    [“1,6:10 = ‘world’,<2>,1:6]表明第二个token(索引从0开始),从字符位置6到10(从0开始),有文本world,是第二个标记(ID),位置是在第一行(行数从1开始),在第6个字符处(位置是从零开始计算,tabs也算作一个独立的字符)。

    最后可以测试语法规则的图示形式

    grun Hello r -gui
    hello world
    ^D
    • 1
    • 2
    • 3

    这时,会弹出一个窗口:
    这里写图片描述

    到现在可以修改.g4 文件来作其他的语法分析了。

    推荐参考antlr 4权威指南, 毕竟antlr 4 在3的基础上变化不小,尽量参考新的资料。

    编写简单计算器:

    Expr.g4:

    grammar Expr;

    /** The start rule; begin parsing here. */
    prog: stat+ ;

    stat: ID '=' expr NEWLINE  # assign
        | NEWLINE              # blank
        ;
        
    expr: leftNum op=('*'|'/') rigNum   # MulDiv
        | leftNum op=('+'|'-') rigNum   # AddSub
        | '(' expr ')'        # parens
        ;
        
    leftNum: INT;
    rigNum: INT;

    ID : [a-zA-Z]+ ; // match identifiers
    INT : [0-9]+ ; // match integers
    NEWLINE:' '? ' ' ; // return newlines to parser
    WS : [ ]+ -> skip ; // toss out whitespac

    接下来运行命令:

    antlr4  -no-listener -visitor Expr.g4  (antlr4 PA.g4)

    javac Expr*.java

    grun Expr prog -gui

    当前文件夹下有这个文件,通过继承该文件编写语义规则:

    语义规则文件 ExprComplier.java

     
    import java.util.HashMap;
    import java.util.Map;

    import org.antlr.v4.runtime.misc.NotNull;

    //import .ExprBaseVisitor;
    //import .ExprParser;

    public class ExprComplier extends ExprBaseVisitor<Object> {
        
        Map<String, Double> memory = new HashMap<String, Double>();

        public void getMemory() {
            for (Map.Entry<String, Double> entry : memory.entrySet()) {
                  System.out.println("ID = " + entry.getKey() + ", Value = " + entry.getValue());
            }
        }
        
        @Override
        public Double visitAssign(@NotNull ExprParser.AssignContext ctx) {
            String id = ctx.ID().getText();
            Double value = (Double) visit(ctx.expr());
            memory.put(id, value);
            //System.out.println("ID is: " + id + " Value: " + value);
            return value;
            
        }
        
        @Override
        public Integer visitRigNum(@NotNull ExprParser.RigNumContext ctx) {
            int rigNum = Integer.parseInt(ctx.getText());
            return rigNum;
            
        }
        
        @Override
        public Integer visitLeftNum(@NotNull ExprParser.LeftNumContext ctx) {
            int leftNum = Integer.parseInt(ctx.getText());
            return leftNum;
            
        }
        
        
        @Override
        public Double visitParens(@NotNull ExprParser.ParensContext ctx) {
            return (Double) visit(ctx.expr());
            
        }
        
        @Override
        public Double visitAddSub(@NotNull ExprParser.AddSubContext ctx) {
            int leftNum  = visitLeftNum(ctx.leftNum());
            String op = ctx.op.getText();
            int rigNum  = visitRigNum(ctx.rigNum());
            if (op.equals("+")) {
                return (double) (leftNum + rigNum);
            }else if (op.equals("-")) {
                return (double) (leftNum - rigNum);
            }
            return 0.0;
            
        }
        
        @Override
        public Double visitMulDiv(@NotNull ExprParser.MulDivContext ctx) {
            int leftNum  = visitLeftNum(ctx.leftNum());
            String op = ctx.op.getText();
            int rigNum  = visitRigNum(ctx.rigNum());
            if (op.equals("*")) {
                return (double) (leftNum * rigNum);
            }else if (op.equals("/") && rigNum != 0) {
                return (double) (leftNum / rigNum);
            }
            return 0.0;
        }


    编写测试文件  Test.java

    //import ExprLexer;
    //import ExprParser;

    import org.antlr.v4.runtime.ANTLRInputStream;
    import org.antlr.v4.runtime.CommonTokenStream;
    import org.antlr.v4.runtime.tree.ParseTree;

    public class Test{
        public static void main(String[] args){
            String expr="Q=2+4"+" "+"P=2*4"+" "+"R=6/2"+" ";
            ANTLRInputStream input=new ANTLRInputStream(expr);
            ExprLexer lexer=new ExprLexer(input);
            CommonTokenStream tokens=new CommonTokenStream(lexer);
            ExprParser parser =new ExprParser(tokens);
            ParseTree tree = parser.prog();

            ExprComplier complier = new ExprComplier();
            complier.visit(tree);
            complier.getMemory();
        }
    }

    编译该文件: javac Test.java

    运行该文件: java    Test

  • 相关阅读:
    python 装饰器
    git
    JS原生方法实现jQuery的ready()
    js获取css属性方法
    列表页调出点击量
    数组操作
    判断IE版本
    判断IE浏览器用IE条件表达式
    [jQuery] Cannot read property ‘msie’ of undefined错误的解决方法
    复选框字段数组拆分后循环选项值,if判断根据选项值,前端输出html
  • 原文地址:https://www.cnblogs.com/invisible2/p/9101791.html
Copyright © 2020-2023  润新知