给出使用JFlex、JavaCUP来为一个计算器建立分析器的示例的完整代码,使读者能充分领会JavaCUP的使用方法。

虽然本文仅仅给出了计算器的代码,但只要你会写你的语言的翻译模式,则只要照抄这个模版,并改改相应动作就可以了。

引用到的资料:

《CUP User's Manual》,作者:Scott E. Hudson地址为李老师那里下载下来的JavaCUP-11a.rar/CUP-develop.tar.gz/develop/manual.html,

有详细的英文说明和示例代码,但有很多错。本文中简称为《手册》。

《使用CUP进行语法分析》,摘自Apollo的博客,貎似是转载的(竟然不注明[转]和真实出处?!,BS之~),作者待考。有详尽的解释,

但缺乏示例代码。本文中简称为《语法分析》。

详细步骤:

1、准备工作。

JavaCUP和JFlex一样,压缩包里边有许多的文件夹和文件,我不知道正统的做法是否要求使用javaCUP也像Jflex一样要设置一堆path啊、

classpath啊、jflex_home之类的环境变量,但如果你像我一样只打算用它几次,你只要执行下述的两个简单步骤就可以了,它并不需要你设置

任何的环境变量(以下假设你的工作目录是work/):

1)   将JavaCUP压缩包里的java-cup-11a.jar解压到work/下。

2)   将JavaCUP压缩包里的CUP-develop.tar.gz/develop/src下的java_cup文件夹整个解压到work/下。

现在你可以使用JavaCUP了。

2、为这个计算器写一个词法分析器。或者用JFlex生成一个词法分析器

两种方法都可以生成词法分析器,其中,直接写分析器的代码如下:

scanner.java

// Simple Example Scanner Class

// scanner.java

import java_cup.runtime.*;

import java.io.*;

//import sym;

public class scanner implements java_cup.runtime.Scanner {

/**//* single lookahead character */

protected static int next_char;

// since cup v11 we use SymbolFactories rather than Symbols

private SymbolFactory sf = new DefaultSymbolFactory();

private static FileReader fileReader;

public scanner(FileReader fr){

this.fileReader=fr;

}

/**//* advance input by one character */

protected static void  advance()

throws java.io.IOException

{ next_char = fileReader.read(); }

/**//* initialize the scanner */

public static void init()

throws java.io.IOException

{ advance(); }

/**//* recognize and return the next complete token */

public Symbol next_token()

throws java.io.IOException

{

for (;;)

switch (next_char)

{

case '0': case '1': case '2': case '3': case '4':

case '5': case '6': case '7': case '8': case '9':

/**//* parse a decimal integer */

int i_val = 0;

do {

i_val = i_val * 10 + (next_char - '0');

advance();

} while (next_char >= '0' && next_char <= '9');

return sf.newSymbol("NUMBER",sym.NUMBER, new Integer(i_val));

case ';': advance(); return sf.newSymbol("SEMI",sym.SEMI);

case '+': advance(); return sf.newSymbol("PLUS",sym.PLUS);

case '-': advance(); return sf.newSymbol("MINUS",sym.MINUS);

case '*': advance(); return sf.newSymbol("TIMES",sym.TIMES);

case '/': advance(); return sf.newSymbol("DIVIDE",sym.DIVIDE);

case '%': advance(); return sf.newSymbol("MOD",sym.MOD);

case '(': advance(); return sf.newSymbol("LPAREN",sym.LPAREN);

case ')': advance(); return sf.newSymbol("RPAREN",sym.RPAREN);

case -1: return sf.newSymbol("EOF",sym.EOF);

default:

/**//* in this simple scanner we just ignore everything else */

advance();

break;

}

}

};

以上代码来自《手册》的附录B,但有以下修改:

修改概要

注释掉第4行的import sym;

原文第6行改成public class CalcLex implements java_cup.runtime.Scanner {

因为语法分析器要求其词法分析器必须派生自Scanner类。

删去原文第23行的static。因为其超类Scanner的next_token()方法不是静态的。

删掉原文第48行其中一个return(无聊的语法错误!)

新增加了一个构造函数scanner(FileReader)和静态属性FileReader fr,(当然要import

System.io.*;)它们之后将会用到。

修改了advance()的定义

这时scanner.java还未能通过编译的,因为其需要引用到的sym类还未生成,不用管它,继续下一步。

如果用JFlex来生成一个词法分析器,则要先写一个scanner.flex,代码如下:

scanner.flex

//scanner.flex

//用户代码段

import java_cup.runtime.*;

import java.io.*;

%%

//参数设置和声明段

%class scanner

%line

%column

%cup

%unicode

%{

public static void init(){}/**//* Just为了兼容手写版*/

private Symbol symbol(int type){

return new Symbol(type,yyline,yycolumn);

}

private Symbol symbol(int type,Object value){

return new Symbol(type,yyline,yycolumn,value);

}

%}

digit=[0-9]

number={digit}+

LineTerminator=/r|/n|/r/n

WhiteSpace={LineTerminator}|[ /t/f]

%%

//词法规则段

{

";" { return symbol(sym.SEMI); /**//*case ";"*/}

"+" { return symbol(sym.PLUS); /**//*case "+"*/}

"-" { return symbol(sym.MINUS); /**//*case "-"*/}

"*" { return symbol(sym.TIMES); /**//*case "*"*/}

"/" { return symbol(sym.DIVIDE); /**//*case "/"*/}

"%" { return symbol(sym.MOD); /**//*case "%"*/}

"(" { return symbol(sym.LPAREN); /**//*case "("*/}

")" { return symbol(sym.RPAREN); /**//*case ")"*/}

{number} { return symbol(sym.NUMBER,new Integer(yytext())); /**//*case {number}*/}

{WhiteSpace} {/**//*case {WhiteSpace}:  do nothing*/}

}

. {

System.out.println("Error:"+yytext()+" is illegal!");

}

3、使用javaCUP生成一个语法分析器。

在这一步里,你需要写一个parser.cup文件,代码如下:

parser.cup

// CUP specification for a simple expression evaluator (w/ actions)

//parser.cup

import java_cup.runtime.*;

/**//* Preliminaries to set up and use the scanner.  */

init with {: scanner.init();              :};

scan with {: return getScanner().next_token(); :};

/**//* Terminals (tokens returned by the scanner). */

terminal           SEMI, PLUS, MINUS, TIMES, DIVIDE, MOD;

terminal           UMINUS, LPAREN, RPAREN;

terminal Integer   NUMBER;

/**//* Non-terminals */

non terminal            expr_list, expr_part;

non terminal Integer    expr;

/**//* Precedences */

precedence left PLUS, MINUS;

precedence left TIMES, DIVIDE, MOD;

precedence left UMINUS;

/**//* The grammar */

expr_list ::= expr_list expr_part

|

expr_part;

expr_part ::= expr:e

{: System.out.println("= " + e); :}

SEMI

;

expr      ::= expr:e1 PLUS expr:e2

{: RESULT = new Integer(e1.intValue() + e2.intValue()); :}

|

expr:e1 MINUS expr:e2

{: RESULT = new Integer(e1.intValue() - e2.intValue()); :}

|

expr:e1 TIMES expr:e2

{: RESULT = new Integer(e1.intValue() * e2.intValue()); :}

|

expr:e1 DIVIDE expr:e2

{: RESULT = new Integer(e1.intValue() / e2.intValue()); :}

|

expr:e1 MOD expr:e2

{: RESULT = new Integer(e1.intValue() % e2.intValue()); :}

|

NUMBER:n

{: RESULT = n; :}

|

MINUS expr:e

{: RESULT = new Integer(0 - e.intValue()); :}

%prec UMINUS

|

LPAREN expr:e RPAREN

{: RESULT = e; :}

;

现在你需要用JavaCUP来分析你的cup文件,请在命令行下输入

java -jar java-cup-11a.jar parser.cup

如果屏幕出现以下输出,就说明你已经成功了,这时javaCUP自动生成了parser.java和sym.java两个文件。

现在你的scanner.java也可以成功通过编译了。

------- CUP v0.11a beta 20060608 Parser Generation Summary -------

0 errors and 0 warnings

12 terminals, 4 non-terminals, and 13 productions declared,

producing 24 unique parse states.

0 terminals declared but not used.

0 non-terminals declared but not used.

0 productions never reduced.

0 conflicts detected (0 expected).

Code written to "parser.java", and "sym.java".

---------------------------------------------------- (v0.11a beta 20060608)

4、编写主函数。

现在你的计算器的语法分析器已经做好,你还要做的就是编写一个主函数来调用这个分析器。请在work/

下新建一个Calc.java,然后输入以下代码:

Calc.java

//Calc.java

import java.io.*;

public class Calc{

public static void main(String argv[])throws Exception{

parser p=new parser(new scanner(new FileReader(argv[0])));

p.parse();

}

}

5、测试用例。

你还需要设计一些测试例子来检查你是否已经成功完成了这个计算器。在work/下新建一个test.txt,

输入一些数值表达式,例如:

test.txt

2 * 4 + 6;

7 * (5+3);

(5-3) / (2 * 4 +3);

然后在命令行输入:

java Calc test.txt

如果屏幕输出:

= 14

= 56

= 0

这就表示你已经大功告成了~~

补充两点:自我贴出这篇博文后,有很多朋友跟我说在输入java Calc test.txt时出现以下输出:Exception in thread "main" java.lang.NoClassDefFoundError: calc甚至Exception in thread "main" java.lang.NoSuchMethodError: calc但此前所有的代码生成、编译工作都是成功的。  经过我的分析,这是因为.java文件和.class文件版本不匹配造成的。通常是你用jflex或javaCUP生成了新的.java文件,却没有对它重新编译,因此.class里边的是旧的.java文件的内容,因此在运行的时候就会产生错误。解决方法是在命令行输入del *.class并重新编译,这时java会重新生成所有.class文件。  觉得每次都要手工输入命令去生成代码、编译、运行很慢很麻烦?呵呵~~像我这么懒的人当然不会这么笨啦~~你可以写一个bat文件去自动帮你完成所有的工作,自然也可以解决上面那个“.NoClassDefFoundError”问题。不懂bat?去google一下“批处理文件”吧。这里再教你一个技巧,就是如何在bat中使用分支:run.batcall jflex scanner.flexif errorlevel 1 goto EXITjava -jar cup.jar parser.cupif errorlevel 1 goto EXITjavac scanner.javaif errorlevel 1 goto EXITjavac parser.javaif errorlevel 1 goto EXITjavac Calc.javaif errorlevel 1 goto EXITjava Calc test.txt:EXIT这样你只要轻轻的输入run,然后回车,就可以自动调用Jflex、JavaCUP生成代码、编译、运行了,并且当其中一步出错时,其后所有的步骤都不会被执行。是不是很好玩?

java cup_使用JFlex、JavaCUP相关推荐

  1. Index of Java

    JNLP(Java Network Launching Protocol) JAWS(Java Web Start) JNI(Java Native Interface) JFlex&Java ...

  2. 初识python之画图神器篇

    前言 前面我们写了一篇关于python实例的汇率转换的文章,有的小伙伴说它虽然可以解决我们生活中的实际问题,但是好像缺少点什么. 我仔细想了想,想起了一句话,"生活不止眼前的苟且,还有诗和远 ...

  3. 开源指南|如何从零开始参与 Apache 顶级开源项目?(二)

    作者:苏奕嘉|SelectDB 生态研发工程师 写在开头 上一篇文章 如何从零开始参与 Apache 顶级开源项目?我们介绍了 Apache Doris 社区的工作机制.如何参与社区贡献以及如何完成第 ...

  4. Windows10下配置JavaCup、JFlex及运行JavaCup测试用例

      本文主要是介绍如何在Windows10下下载.配置JavaCup.JFlex及运行JavaCup测试用例.其他博客介绍一种配置JavaCup的方法是:将java-cup-11a.jar的路径添加到 ...

  5. linux下安装java编译器,编译器构造工具:安装 JFlex 和 CUP - 具 - 精华区 - 优秀的Free OS(Linux)版 - 北大未名BBS...

    发信人: chenhao (阅读文献), 信区: Linux 标  题: 编译器构造工具:安装 JFlex 和 CUP - 具体化的指南 发信站: 北大未名站 (2000年12月06日00:27:52 ...

  6. java weka包_在Eclipse中调用weka包实现分类

    1.如题. 最近写了一个FCM的聚类算法,希望能够可视化结果,因此一个想法是调用weka中的包,使自己的程序可以可视化.这里参考了网络上的方法,首先实现在Eclipse中调用weka包实现分类的功能. ...

  7. java语法分析生成器,语法词法生成器

    一.语法词法生成器 Flex 语法扫描器生成器 flex (fast lexical analyser generator) 是Lex的另一个替代品.它经常和自由软件Bison语法分析器生成器 一起使 ...

  8. spark需要maven管理吗_Spark-Maven全新安装:如何同时编译Java和Scala类

    我有一个Spark项目,其中同时包含.scala和.java文件.我正在尝试通过Maven构建来编译这两种类型的类.但是,当我运行" mvn clean install"时,它只会 ...

  9. 用Java解析:您可以使用的所有工具和库

    如果需要从Java解析语言或文档,则从根本上讲有三种方法可以解决问题: 使用支持该特定语言的现有库:例如用于解析XML的库 手动构建自己的自定义解析器 生成解析器的工具或库:例如ANTLR,可用于构建 ...

最新文章

  1. 用 Redis 实现分布式锁(分析)
  2. python测试开发django-1.开始hello world!
  3. jenkins 项目启动日志_jenkins 修改启动文件即jdk路径、log路径和切换jenkins用户
  4. python中的文件I/O
  5. CentOS下Redis 2.2.14安装配置详解
  6. 微软想通了?Windows 11恢复一键改变默认浏览器功能
  7. OA打造企业“最强大脑”
  8. 安全需求可划分为物理安全、网络安全、系统安全和应用安全,下面的安全需求中属于系统安全的是(67),属于应用安全的是(68)。...
  9. POJ-3376 Finding Palindromes
  10. 雷达原理 知识点汇总
  11. H3C交换机WEB管理时间_H3C 交换机之VLAN配置与VLAN间访问
  12. dede服务器建站_织梦建站之本地服务器怎么装,怎么部署
  13. rti matlab,dSPACE-RTI知识介绍.pdf
  14. 数据库入门day06之联接查询(脑图+详解)
  15. 分析一下前段很火的玩客云(区块链相关产品)
  16. 中规中矩的CentOS7安装Python3.5
  17. 入行10年后,我总结了这份FPGA学习路线
  18. openCV学习-day02--如何计算图像色彩种类
  19. PowerPC简介及编程
  20. php 去除中英文空格,php去除字符串首尾中英文空格程序

热门文章

  1. 干货|数据分析之落地sop流程(一)
  2. 2013-9-7中文幽默演讲比赛-我的演讲之路
  3. 树莓派魔镜项目——笔记二 Docker软件安装
  4. [loj#539][LibreOJ NOIP Round #1]旅游路线_倍增_dp
  5. 虚拟地址和物理地址之间的映射关系
  6. 电子与通信工程专硕考分_2021年华北电力大学电子与通信工程专硕考研必看成功上岸前辈复习经验分享...
  7. oracle数据库led显示屏,LED大屏幕设置软件
  8. 接口自动化集成TestNG框架
  9. matlab cg steihaug,信赖域(一):Cauchy Point与Dogleg
  10. PHP长方体体积,长方体的体积课件|小学数学,北师大版,五年级下册,数学课件下载_21课件_21世纪教育网...