zoukankan      html  css  js  c++  java
  • 7.JavaCC官方入门指南-例2

    例2:整数加法运算--改良版(增强语法分析器)

    1.修改

      上一个例子中,JavaCC为BNF生产式所生成的方法,比如Start(),这些方法默认只简单的检查输入是否匹配BNF生产式指定的规范。但是我们也可以用java代码来扩充BNF生产式,使得由生产式生成的方法中也包含java代码。
      我们加下来会对上面例一中的adder.jj代码做一些修改。对于其中的Start这个BNF生产式,我们加入一些声明和java代码,如下所示:

    int Start() throws NumberFormatException :
    {
        Token t ;
        int i ;
        int value ;
    }
    {
        t = <NUMBER>
        { i = Integer.parseInt( t.image ) ; }
        { value = i ; }
        (
            <PLUS>
            t = <NUMBER>
            { i = Integer.parseInt( t.image ) ; }
            { value += i ; }
        )*
        <EOF>
        { return value ; }
    }
    

      首先第一个改动是BNF生产式的返回类型,这就使得由该BNF生产式生成的方法的返回值类型由void变成了int。另外的改动是,我们声明了一个可能抛出的异常NumberFormatException。在方法内,声明了3个变量,其中变量t是Token类型的,Token类是我们编译.jj文件文件之后生成的类,而Token类中的image属性则表示匹配到的token的值。在声明完变量之后,当一个token被BNF生产式匹配到,我们就可以通过t = 的方式,将token赋值给t从而记录下来。在BNF生产式中,我们可以加上任何的合法的Java代码,这些Java代码在javacc编译生成语法分析器类时,将会被原封不动的复制到语法分析器类的相应方法中。
      现在生成的Start方法将有一个返回值,因此我们对main方法做如下修改:

    Public static void main( String[] args ) throws ParseException, TokenMgrError, NumberFormatException {
        Adder parser = new Adder( System.in );
        int val = parser.Start() ;
        System.out.println(val);
    }
    

      除此之外,我们还要做如下的一点小改进,我们看到,下面的代码出现了两次:

    { i = Integer.parseInt( t.image ) ; }
    { value = i ; }
    

      虽然在这个例子中影响并不大,但是像这种重复出现的代码还是可能会导致代码维护的问题。因此我们对这两行代码进行重构,将它重构成另外一个BNF生产式,并把这个生产式命名为Primary。

    int Start() throws NumberFormatException :
    {
        int i ;
        int value ;
    }
    {
        value = Primary()
        (
            <PLUS>
            i = Primary()
            { value += i ; }
        )*
        <EOF>
        { return value ; }
    }
    
    int Primary() throws NumberFormatException :
    {
        Token t ;
    }
    {
        t=<NUMBER>
        { return Integer.parseInt( t.image ) ; }
    }
    

      下面是生成的代码,从中我们可以看出javacc如何吧java的变量声明和逻辑代码跟生产式融合起来的。

    final public int Start() throws ParseException, NumberFormatException {
        int i ;
        int value ;
        value = Primary();
        label 1:
        while (true) {
            switch ((jj ntk==-1)?jj ntk():jj ntk) {
                case PLUS:
                    ;
                    break;
                default:
                    jj la1[0] = jj gen;
                    break label 1;
            }
            jj consume token(PLUS);
            i = Primary();
            value += i ;
        }
        jj consume token(0);
        {if (true)
            return value ;}
        throw new Error(”Missing return statement in function”);
    }
    
    final public int Primary() throws ParseException, NumberFormatException {
        Token t ;
        t = jj consume token(NUMBER);
        {if (true)
            return Integer.parseInt( t.image ) ;}
        throw new Error(”Missing return statement in function”);
    }
    

    2.运行

    2.1 adder2.jj

      经过上面的修改,最终得到.jj描述文件内容如下,我们将其保存命名为adder2.jj:

    /* adder.jj Adding up numbers */
    options {
        STATIC = false ;
        }
    
    PARSER_BEGIN(Adder)
        class Adder {
            public static void main( String[] args ) throws ParseException, TokenMgrError, NumberFormatException {
                Adder parser = new Adder( System.in );
                int val = parser.Start();
                System.out.println(val);
            }
        }
    PARSER_END(Adder)
    
    SKIP : { " "}
    SKIP : { "
    " | "
    " | "
    " }
    TOKEN : { < PLUS : "+" > }
    TOKEN : { < NUMBER : (["0"-"9"])+ > }
    
    int Start() throws NumberFormatException :
    {
        int i ;
        int value ;
    }
    {
        value = Primary()
        (
            <PLUS>
            i = Primary()
            { value += i ; }
        )*
        <EOF>
        { return value ; }
    }
    
    int Primary() throws NumberFormatException :
    {
        Token t ;
    }
    {
        t=<NUMBER>
        { return Integer.parseInt( t.image ) ; }
    }
    

    2.2 运行javacc命令

    2.3 编译生成的java文件

    2.4 运行程序

      可以看到,input.txt输入文件中的内容是1+2,运行完程序之后,即可计算出结果:3。
      同样的,如果input.txt文件中的内容是1-2,则会报 词法异常 ,如下图所示:

    如果input.txt文件中的内容是1++2,则会报 语法异常 ,如下图所示:

  • 相关阅读:
    测测你是男是女
    密集恐惧症候群测试图
    弱智的我
    你还单纯么
    压力测试
    理性人与感性人
    [家里蹲大学数学杂志]第248期东北师范大学2013年数学分析考研试题
    [家里蹲大学数学杂志]第254期第五届[2013年]全国大学生数学竞赛[数学类]试题
    PostgreSQL中,如何查表属于哪个数据库
    对PostgreSQL中tablespace 与 database, table的理解
  • 原文地址:https://www.cnblogs.com/suhaha/p/11733565.html
Copyright © 2011-2022 走看看