Use jflex and javacup

Source: Internet
Author: User

The complete code for using jflex and javacup to create a analyzer example for a calculator is provided, so that readers can fully understand the usage of javacup.
Although this article only provides the calculator code, as long as you write the translation mode of your language, you only need to copy this template and change the corresponding action.

Referenced materials:
By Scott E. hudsonaddress: javacup-11a.rar/CUP-develop.tar.gz/develop/manual.html,
There are detailed instructions and sample code, but there are many errors. This document is short for the manual.
"Use cup for syntax analysis", taken from the blog of Apollo, seems to be reproduced (not to mention [transfer] and the real source ?!, BS ~), The author is waiting for the exam. Have a detailed explanation,
But there is no sample code. This document is short for syntax analysis.

Detailed steps:
1. preparation.
Like jflex, javacup has a lot of folders and files in the compressed package. I don't know if the orthodox approach requires a bunch of paths like jflex,
Classpath, jflex_home, and other environment variables, but if you only want to use it several times like me, you only need to perform the following two simple steps, it does not need to be set
Any environment variables (assume that your working directory is work /):
1) decompress the java-cup-11a.jar in the javacup compressed package to work.
2) decompress the java_cup folder under cup-develop.tar.gz/develop/src in the javacupcompressed package to work.
Now you can use javacup.

2. Write a lexical analyzer for this calculator. Or use jflex to generate a lexical analyzer.

Both methods can generate a lexical analyzer. The code for Directly Writing the analyzer is as follows:

Logging. Java
// Simple example EXAMPLE Class
// Producer. Java
Import java_cup.runtime .*;
Import java. Io .*;
// Import sym;

Public class implements java_cup.runtime.htm {
/** // * 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;
Public Uploader (filereader fr ){
This. filereader = fr;
}
/** // * Advance input by one character */
Protected static void advance ()
Throws java. Io. ioexception
{Next_char = filereader. Read ();}

/** // * Initialize the parameter */
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 example we just ignore everything else */
Advance ();
Break;
}
}
};
 

The above Code comes from appendix B of the Manual, but has the following modifications:

 

Modify Overview
Comment out the import sym of 4th rows;
In the original article, change row 6th to public class calclex implements java_cup.runtime.htm {
Because the syntax analyzer requires its lexical analyzer to be derived from the parser class.
Delete the static data of the first row of the original article. Because the next_token () method of its superclass is not static.
Delete one of the 48th rows in the original article (boring syntax error !)
A new Constructor (filereader) and static attribute filereader fr are added. (Of course, import is required.
System. Io. *;) They will be used later.
Modified the definition of advance ().
At this time, runtime. Java has not been compiled, because the sym class to be referenced has not yet been generated, so you don't have to worry about it. continue to the next step.
If you use jflex to generate a lexical analyzer, you need to write a lexical. Flex file. The Code is as follows:

Connector. Flex
// Consumer. Flex
// User code segment
Import java_cup.runtime .*;
Import java. Io .*;

%
// Parameter settings and declaration segments
% Class Program
% Line
% Column
% Cup
% Unicode

% {
Public static void Init () {}/ ** // * just to be compatible with the handwritten version */
Private symbol (INT type ){
Return new symbol (type, yyline, yycolumn );
}
Private 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]
%
// Lexical rule segment
{
";" {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. Use javacup to generate a syntax analyzer.

In this step, you need to write a parser. Cup file. The Code is as follows:

Parser. Cup
// Cup specification for a simple expression evaluator (W/Actions)
// Parser. Cup
Import java_cup.runtime .*;

/** // * Preliminaries to set up and use the setting .*/
Init with {: Response. INIT ();:};
Scan with {: Return getken (). next_token ();:};

/** // * Terminals (tokens returned by the queue ).*/
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 ;:}
;

 

Now you need to use javacup to analyze your cup file. Enter

Java-jar java-cup-11a.jar (parser. Cup)

If the following output appears on the screen, it indicates that you have succeeded. At this time, javacup automatically generates two files: parser. Java and Sym. java.
Now your pipeline. Java can also be compiled successfully.

------- 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. Compile the main function.
Now that the syntax analyzer of your calculator is ready, you need to write a main function to call this analyzer. Please go to work/
Create a calc. Java file and enter the following code:

Calc. Java
// Calc. Java
Import java. Io .*;
Public class calc {
Public static void main (string argv []) throws exception {
Parser P = new Parser (new partition (New filereader (argv [0]);
P. parse ();
}
}
 

5. test cases.
You also need to design some test examples to check whether you have successfully completed this calculator. Create a new test.txt under work,
Enter some numeric expressions, such:

Test.txt
2*4 + 6;
7*(5 + 3 );
(5-3)/(2*4 + 3 );

Then input the following in the command line:

Java calc test.txt

If the screen output is:

= 14
= 56
= 0
This means that you have achieved success ~~

 

Add two points:
After I posted this blog post, many of my friends told me that the following output appeared when I input Java calc test.txt:
Exception in thread "Main" Java. Lang. noclassdeffounderror: calc or even
Exception in thread "Main" Java. Lang. nosuchmethoderror: calc, but all previous Code Generation and compilation tasks are successful.
After my analysis, this is because the. Java file and. Class file version do not match. Usually you use jflex or javacup to generate a new one. java file, but does not re-compile it, so. the class is old. java file content, so it will generate errors during running. The solution is to input del *. Class in the command line and re-compile it. At this time, Java will re-generate all. class files.
Do you think it is very troublesome to manually enter commands to generate code, compile and run code very slowly? Haha ~~ Of course, people like me are not so stupid ~~ You can write a BAT file to automatically help you complete all the work. Naturally, you can solve the ". noclassdeffounderror" problem above. Do not understand bat? Google the batch file. Here we will teach you another way to use branches in BAT:
Run. bat
Call jflex connector. Flex
If errorlevel 1 goto exit
Java-jar cup. Jar parser. Cup
If errorlevel 1 goto exit
Javac consumer. Java
If errorlevel 1 goto exit
Javac parser. Java
If errorlevel 1 goto exit
Javac Calc. Java
If errorlevel 1 goto exit
Java calc test.txt
: Exit
In this way, you only need to gently enter run and press enter to automatically call jflex and javacup to generate code, compile, and run. When one of the steps fails, all subsequent steps are not executed. Is it fun?

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.