如何使用JFlex、JavaCUP(详细代码模版)
openkk
13年前
编译原理的实验要求我们用JFlex和JavaCUP来对语言进行分析处理,JavaCUP有一个User's Manual教你怎样做,上面还有一个简单的计算器作为例子,但一试之下,却发现那个例子有不少错误,结果改了我n久才完成~当然马上就决定写一篇博客告诉大家怎样做才是正确的,以免像我那样白走许多弯路。我也不知是不是我找的那份不好,如果你有更好的manual,记得告诉我。 <br /> <br /> <strong><u>撰写本文的目的</u></strong>: <br /> 给出使用JFlex、JavaCUP来为一个计算器建立分析器的示例的完整代码,使读者能充分领会JavaCUP的使用方法。虽然本文仅仅给出了计算器的代码,但只要你会写你的语言的翻译模式,则只要照抄这个模版,并改改相应动作就可以了。 <br /> <br /> <strong><u>引用到的资料</u></strong>: <ul> <li>《CUP User's Manual》,作者:<a href="/misc/goto?guid=4959500124418784036"><u><span style="color:#0000ff;">Scott E. Hudson</span></u></a>地址为李老师那里下载下来的JavaCUP-11a.rar\CUP-develop.tar.gz\develop\manual.html,有详细的英文说明和示例代码,但有很多错。本文中简称为《手册》。 </li> <li><a href="/misc/goto?guid=4959500124507711725">《使用CUP进行语法分析》</a>,摘自Apollo的博客,貎似是转载的(竟然不注明[转]和真实出处?!,BS之~),作者待考。有详尽的解释,但缺乏示例代码。本文中简称为《语法分析》。 </li> </ul> <p><u><strong>详细步骤</strong></u>:<br /> 1、准备工作。<br /> JavaCUP和JFlex一样,压缩包里边有许多的文件夹和文件,我不知道正统的做法是否要求使用javaCUP也像Jflex一样要设置一堆path啊、classpath啊、jflex_home 之类的环境变量,但如果你像我一样只打算用它几次,你只要执行下述的两个简单步骤就可以了,它并不需要你设置任何的环境变量(以下假设你的工作目录是 work\):<br /> 1) 将JavaCUP压缩包里的java-cup-11a.jar解压到work\下。<br /> 2) 将JavaCUP压缩包里的CUP-develop.tar.gz\develop\src下的java_cup文件夹整个解压到work\下。<br /> 现在你可以使用JavaCUP了。<br /> <br /> 2、为这个计算器写一个词法分析器。或者用JFlex生成一个词法分析器</p> 两种方法都可以生成词法分析器,其中,直接写分析器的代码如下: <pre class="brush:java; toolbar: true; auto-links: false;">// 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; } } };</pre>