• 用Java写编译器(1)- 词法和语法分析


    词法和语法分析器构建

    ANTLR简介

    ANTLR全称ANother Tool for Languate Recognition,是基于LL(*)算法实现的语法分析器生成器和词法分析器生成器,由旧金山大学的Terence Parr博士等人创建。截止到目前,ANTLR已经支持生成适用于Ada95、C、C#、JavaScript、Objective-C、Perl、Python、Ruby、C++和Standard ML等多种编程语言的词法和语法分析器了。

    ANTLR安装

    $ cd /usr/local/lib
    $ wget https://www.antlr.org/download/antlr-4.7.1-complete.jar
    $ export CLASSPATH=".:/usr/local/lib/antlr-4.7.1-complete.jar:$CLASSPATH"
    $ alias antlr4='java -jar /usr/local/lib/antlr-4.7.1-complete.jar'
    $ alias grun='java org.antlr.v4.gui.TestRig'
    

    词法分析和Antlr词法定义

    词法分析就是讲字符序列转换为单词序列的过程。单词是构成源代码的最小单位,它由一个或多个连续字符组成。比如对代码int year=2018进行词法分析,源代码将被转换成由5个单词组成的序列:int,s(空格),year,=2018

    antlr的词法定义比较简单,大部分的词法都可以使用简单的正则表达式表示。我们来看一个简单的例子DemoLexer.g4

    lexer grammer Demo;
    PLUS:'+';
    MINUS:'-';
    MULTIPLE:'*';
    DIV:'/';
    LPAREN:'(';
    RPAREN:')';
    NUMBER:[0-9]+;
    

    第1行声明这是一个词法定义文件,第2-7定义4个运算符关键字和左右两个括号,第8行则是正整数的定义。

    语法分析和antlr语法定义

    语法分析就是根据特定的形式文法对由单词序列构成的输入进行分析并确定其语法结构的过程。比如int,s(空格),year,=2018这5个单词序列按顺序输入到语法分析器,语法分析器就能识别出这是一条变量声明和初始化的语句。

    antlr的语法定义和词法定义类似,列出所有可能的单词组合情况。我们还是从一个简单的四则运算语法定义作为例子。

    DemoParser.g4

    parser grammar DemoParser;
    options { tokenVocab=DemoLexer; }
    expr:
        '(' expr ')'
        | NUMBER ( MULTIPLE | DIV ) NUMBER
        | NUMBER ( PLUS | MINUS ) NUMBER
    ;
    

    第1行声明这是一个语法定义文件,第2行设置词法选项,说明使用哪个词法,第3-7行是运算表达式的文法定义。这里简单介绍一下,expr为我们为文法取的名称,此文法有三种情况:由括号包起来的表达式、乘除表达式和加减表达式。需要注意的是乘除表达式和加减表达式定义的顺序不能随便调换,不然会影响运算符的优先级,得到错误的语法解析树。高优先级的表达式需要先定义。

    生成词法分析器和语法分析器

    上面只是antlr词法和语法的定义,无法在java里直接使用,因为它不是合法的java源代码,我们需要将其转换成java代码,这个转换工作还是由antlr为我们完成。在终端运行如下命令:

    antlr4 DemoLexer.g4 -package demo.antlr
    antlr4 DemoParser.g4 -package demo.antlr -visitor
    

    命令执行后,将会自动生成如下文件:

    DemoLexer.java
    DemoLexer.tokens
    DemoParser.java
    DemoParser.tokens
    DemoParserBaseListener.java
    DemoParserBaseVisitor.java
    DemoParserListener.java
    DemoParserVisitor.java
    

    这些java文件就是我们能在程序里直接调用的词法分析器和语法分析器。

    词法分析器和语法分析器的使用

    生成的词法分析器和语法分析器拷贝到源码目录后就可以直接使用了,我们来看一下最常用的调用方法:

    String source = "1+2+3";//我们需要解析的表达式
    CharStream charStream = new ANTLRInputStream(source);
    DemoLexer lexer = new DemoLexer(charStrem);//词法分析器
    CommonTokenStream tokenStream = new CommonTokenStream(lexer);
    DemoParser parser = new DemoParser(tokenStream);//语法分析器
    ExprContext exprContext = parser.expr();//以expr规则为起始规矩开始解析,得到语法解析树
    

    通过以上步骤,表达式字符串最终被转换成了语法解析树,有了语法解析树,对表达式求值就变得很简单了。首先,我们先定义一个解析树访问(遍历)器MainDemoParserVisitor.java:

    public MainDemoParserVisitor extends DemoParserBaseVisitor {
        @override
        public Integer visitExpr(ExprContext ctx) {
            if (ctx.MULTIPLE()!=null) {//乘法
                return Integer.parseInt(ctx.NUMBER(0)) * Integer.parseInt(ctx.NUMBER(1));
            } else if (ctx.DIV()!=null) {//除法
                return Integer.parseInt(ctx.NUMBER(0)) / Integer.parseInt(ctx.NUMBER(1));
            } else if (ctx.PLUS()!=null) {//加法
                return Integer.parseInt(ctx.NUMBER(0)) + Integer.parseInt(ctx.NUMBER(1));
            } else if (ctx.MINUS()!=null) {//减法
                return Integer.parseInt(ctx.NUMBER(0)) - Integer.parseInt(ctx.NUMBER(1));
            } else {//对括号内表达式求值
                return visitExpr(ctx.expr());
            }
        }
    
    }
    

    使用访问器对解析树进行遍历并求值:

    MainDemoParserVisitor visitor = new MainDemoParserVisitor();//创建访问者
    Integer result = (Integer) vistor.visit(exprContext);//开始遍历语法解析树对表达式求值
    System.out.println(result);
    

    参考链接

    1. Antlr文档:https://github.com/antlr/antlr4/blob/master/doc/index.md
    2. Antlr词法语法示例:https://github.com/antlr/grammars-v4
    3. 使用Antlr构建的编程语言Kalang:https://github.com/kasonyang/kalang
  • 相关阅读:
    [ python ] 线程的操作
    [ python ] 进程的操作
    RabbitMQ 集群
    RabbitMQ 实践及使用
    RabbitMQ 基础知识
    [ python ] FTP作业进阶
    [ python ] 项目一:FTP程序
    [ python ] 网络编程(2)
    [ python ] 网络编程(1)
    Linux 日志系统及分析
  • 原文地址:https://www.cnblogs.com/kason/p/13601348.html
Copyright © 2020-2023  润新知