old-www/LDP/LG/issue41/lopes/ycalc.htm

358 lines
15 KiB
HTML

<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
<META NAME="GENERATOR" CONTENT="Mozilla/4.05 [en] (X11; I; Linux 2.0.34 i586) [Netscape]">
</HEAD>
<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#0000EE" VLINK="#551A8B" ALINK="#FF0000">
/*
<BR>Commented By: Christopher Lopes
<BR>File Name: ycalc.cup
<BR>To Create: > java java_cup.Main &lt; ycalc.cup
<BR>*/
<BR>&nbsp;
<P>/* ----------------------<B>Preliminary Declarations Section</B>--------------------*/
<P>/* Import the class java_cup.runtime.*&nbsp; */
<BR><B>import java_cup.runtime.*;</B>
<P><A NAME="parser_code"></A>
<BR>/* Parser code so that it can interface with the scanner created with
JFlex and change the way that it reports errors (include line and column
number of the error).*/
<BR><B>parser code {:</B>
<BR>&nbsp; Lexer lexer;
<P>&nbsp; public parser(Lexer lexer) {
<BR>&nbsp;&nbsp;&nbsp; this.lexer = lexer;
<BR>&nbsp; }
<P>&nbsp; /* Change the method report_error so it will display the line
<BR>&nbsp;&nbsp;&nbsp;&nbsp; and column of where the error occurred in
the input as well as the reason
<BR>&nbsp;&nbsp;&nbsp;&nbsp; for the error which is passed into the method
in the String 'message'.&nbsp; */
<BR>&nbsp; public void report_error(String message, Object info) {
<P>&nbsp;&nbsp;&nbsp; /* Create a StringBuffer called 'm' with the string
'Error' in it. */
<BR>&nbsp;&nbsp;&nbsp; StringBuffer m = new StringBuffer("Error");
<P>&nbsp;&nbsp;&nbsp; /* Check if the information passed to the method
is the same type as the
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; type java_cup.runtime.Symbol.
*/
<BR>&nbsp;&nbsp;&nbsp; if (info instanceof java_cup.runtime.Symbol) {
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Declare a java_cup.runtime.Symbol
object 's' with the information in the
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; object info
that is being typecasted as a java_cup.runtime.Symbol object. */
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; java_cup.runtime.Symbol s = ((java_cup.runtime.Symbol)
info);
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Check if the line number in the input
is greater or equal to zero. */
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (s.left >= 0) {
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Add to the end of the
StringBuffer error message the line number of
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; the error
in the input. */
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m.append(" in line "+(s.left+1));
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Check if the column number
in the input is greater or equal to
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; zero.
*/
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (s.right >= 0)
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Add to the
end of the StringBuffer error message the column number
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
of the error in the input. */
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m.append(",
column "+(s.right+1));
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }
<BR>&nbsp;&nbsp;&nbsp; }
<P>&nbsp;&nbsp;&nbsp; /* Add to the end of the StringBuffer error message
created in this
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; method the message that was passed
into this method. */
<BR>&nbsp;&nbsp;&nbsp; m.append(" : "+message);
<P>&nbsp;&nbsp;&nbsp; /* Print the contents of the StringBuffer 'm', which
contains an error
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; message out on a line. */
<BR>&nbsp;&nbsp;&nbsp; System.err.println(m);
<BR>&nbsp; }
<P>&nbsp; /* Change the method report_fatal_error so when it reports a
fatal error it
<BR>&nbsp;&nbsp;&nbsp;&nbsp; will display the line and column number of
where the fatal error
<BR>&nbsp;&nbsp;&nbsp;&nbsp; occurred in the input as well as the reason
for the fatal error which is
<BR>&nbsp;&nbsp;&nbsp;&nbsp; passed into the method in the object 'message'
and then exit.*/
<BR>&nbsp; public void report_fatal_error(String message, Object info)
{
<BR>&nbsp;&nbsp;&nbsp; report_error(message, info);
<BR>&nbsp;&nbsp;&nbsp; System.exit(1);
<BR>&nbsp;&nbsp;&nbsp; }
<BR><B>:};</B>
<P><B>/*&nbsp;</B> <A HREF="lopes.html#prelim">Return to Using CUP</A>&nbsp;
*/
<P>/* Use the scanner created with JFlex&nbsp; */
<BR><B>scan with {: return lexer.yylex(); :};</B>
<P>/* ------------<B>Declaration of Terminals and Non Terminals Section</B>-----------
*/
<P>/* Terminals (tokens returned by the scanner).
<P>&nbsp;&nbsp; Terminals that have no value are listed first and then
terminals that do
<BR>&nbsp;&nbsp; have an value, in this case an integer value, are listed
on the next line
<BR>&nbsp;&nbsp; down. */
<BR><B>terminal</B>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
SEMI, PLUS, MINUS, TIMES, DIVIDE, LPAREN, RPAREN;
<BR><B>terminal Integer</B>&nbsp;&nbsp; NUMBER, ID;
<P>/* Non Terminals used in the Grammar Section.
<P>&nbsp;&nbsp; Non Terminals that have an object value are listed first
and then Non Terminals
<BR>&nbsp;&nbsp; that have an integer value are listed.&nbsp; An object
value means that it can be
<BR>&nbsp;&nbsp; any type, it isn't set to a specific type.&nbsp; So it
could be an integer or a String or
<BR>&nbsp;&nbsp; whatever. */
<BR><B>non terminal Object</B>&nbsp;&nbsp;&nbsp;&nbsp; expr_list, expr_part;
<BR><B>non terminal Integer</B>&nbsp;&nbsp;&nbsp; expr, factor, term;
<P>/* -------------<B>Precedence and Associatively of Terminals Section</B>-----------
*/
<P>/*
<BR>Precedence of Non Terminals could be defined here.&nbsp; If you do
define precedence
<BR>here you won't need to worry about precedence in the Grammar Section.
<BR>i.e. that TIMES should have a higher precedence than PLUS.
<P>The precedence defined here would look something like this where the
lower
<BR>line always will have higher precedence than the line before it.
<P><B>precedence left</B> PLUS, MINUS;
<BR><B>precedence left </B>TIMES, DIVIDE;
<BR>*/
<BR><A NAME="grammar"></A>
<BR>/* ----------------------------<B>Grammar Section</B>--------------------
*/
<P>/* The grammar for our parser.
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; expr_list ::=&nbsp;&nbsp;
expr_list expr_part
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
| expr_part
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; expr_part ::=&nbsp;&nbsp;
expr SEMI
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; expr&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
::=&nbsp;&nbsp; factor PLUS expr
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
| factor MINUS expr
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
| factor
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; factor&nbsp;&nbsp;&nbsp;
::=&nbsp;&nbsp; factor TIMES term
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
| factor DIVIDE term
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
| term
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; primary&nbsp;&nbsp; ::=&nbsp;&nbsp;
LPAREN expr RPAREN
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
| NUMBER
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
| ID
<P>&nbsp;<A HREF="lopes.html#prec">Return to Using CUP</A>
<P>*/
<P>/* 'expr_list' is the start of our grammar.&nbsp; It can lead to another
'expr_list'
<BR>followed by an 'expr_part' or it can just lead an 'expr_part'.&nbsp;
The lhs of
<BR>the Non Terminals 'expr_list' and 'expr_part' that are in the rhs side
of the
<BR>production below need to be found.&nbsp; Then the rhs sides of those
Non Terminals
<BR>need to be followed in a similar manner, i.e. if there are any Non
Terminals
<BR>in the rhs of those productions then the productions with those Non
Terminals
<BR>need to be found and those rhs's followed.&nbsp; This process keeps
continuing
<BR>until only Terminals are found in the rhs of a production.&nbsp; Then
we can work
<BR>are way back up the grammar bringing any values that might have been
assigned
<BR>from a Terminal. */
<P>expr_list ::= expr_list expr_part
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
|
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
expr_part;
<BR>&nbsp;
<P>/* 'expr_part' is an 'expr' followed by the terminal 'SEMI'.&nbsp; The
':e'
<BR>after the Non Terminal 'expr' is a label an is used to access the value
of
<BR>'expr' which will be an integer.&nbsp; The action for the production
lies between
<BR>{: and :}.&nbsp; This action will print out the line " = + e" where
e is the value of
<BR>'expr'.&nbsp; Before the action takes places we need to go deeper into
the grammar
<BR>since 'expr' is a Non Terminal.&nbsp; Whenever a Non Terminal is encountered
on
<BR>the rhs of a production we need to find the rhs of that Non Terminal
until
<BR>there are no more Non Terminals in the rhs.&nbsp; So when we finish
going through
<BR>the grammar and don't encounter any more Non Terminals in the rhs productions
<BR>will return until we get back to 'expr' and at that point 'expr' will
contain
<BR>an integer value. */
<P>expr_part ::= expr:e
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
{: System.out.println(" = " + e); :}
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
SEMI
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
;
<BR>&nbsp;
<P>/* 'expr' can lead to 'factor PLUS expr', 'factor MINUS expr', or 'factor'.
<BR>The 'TIMES' and 'DIVIDE' productions are not at this level.&nbsp; They
are at a
<BR>lower level in the grammar which in affect makes them have higher precedence.
<BR>Actions for the rhs of the Non Terminal 'expr' return a value to 'expr'.&nbsp;
This
<BR>value that is created is an integer and gets stored in 'RESULT' in
the action.
<BR>RESULT is the label that is assigned automatically to the rhs, in this
case 'expr'.
<BR>If the rhs is just 'factor' then 'f' refers to the Non Terminal 'factor'.
<BR>The value of 'f' is retrieved with the function 'intValue()' and will
be
<BR>stored in 'RESULT'.&nbsp; In the other two cases 'f' and 'e' refers
to the Non
<BR>Terminals 'factor' and 'expr' respectively with a Terminal between
them,
<BR>either 'PLUS' or 'MINUS'.&nbsp; The value of each is retrieved with
the same
<BR>function 'intValue'.&nbsp; The values will be added or subtracted and
then the new
<BR>integer will be stored in 'RESULT'.*/
<P>expr&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ::= factor:f PLUS expr:e
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
{: RESULT = new Integer(f.intValue() + e.intValue()); :}
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
|
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
factor:f MINUS expr:e
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
{: RESULT = new Integer(f.intValue() - e.intValue()); :}
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
|
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
factor:f
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
{: RESULT = new Integer(f.intValue()); :}
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
;
<BR>&nbsp;
<P>/* 'factor' can lead to 'factor TIMES term', 'factor DIVIDE term', or
<BR>'term'.&nbsp; Since the productions for TIMES and DIVIDE are lower
in the
<BR>grammar than 'PLUS' and 'MINUS' they will have higher precedence.&nbsp;
The same
<BR>sort of actions take place in the rhs of 'factor' as in 'expr'.&nbsp;
The only
<BR>difference is the operations that takes place on the values retrieved
with
<BR>'intValue()', 'TIMES' and 'DIVIDE' here instead of 'PLUS' and 'MINUS'.
*/
<P>factor&nbsp;&nbsp;&nbsp; ::= factor:f TIMES term:t
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
{: RESULT = new Integer(f.intValue() * t.intValue()); :}
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
|
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
factor:f DIVIDE term:t
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
{: RESULT = new Integer(f.intValue() / t.intValue()); :}
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
|
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
term:t
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
{: RESULT = new Integer(t.intValue()); :}
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
;
<BR>&nbsp;
<P>/* 'term' can lead to 'LPAREN expr RPAREN', 'NUMBER', or 'ID'.&nbsp;
The first
<BR>production has the Non Terminal 'expr' in it so the production with
its lhs
<BR>side needs to be found and followed.&nbsp; The next rhs has no Non
Terminals.&nbsp; So
<BR>the grammar ends here and can go back up.&nbsp; When it goes back up
it will bring
<BR>the value that was retrieved when the scanner encounter the token 'NUMBER'.
<BR>'RESULT' is assigned 'n', which refers to 'NUMBER', as the action for
this
<BR>production.&nbsp; The same action occurs for 'ID', except the 'i' is
used to refer
<BR>to 'ID'.&nbsp; 'ID' is also the only thing on the rhs of the production.&nbsp;
And since
<BR>'ID' is a Terminal the grammar will end here and go back up. */
<P>primary&nbsp;&nbsp; ::= LPAREN expr:e RPAREN
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
{: RESULT = e; :}
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
|
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
NUMBER:n
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
{: RESULT = n; :}
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
|
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
ID:i
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
{: RESULT = i; :}
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
;
<P>/*&nbsp; <A HREF="lopes.html#cupcode">Return to Using CUP</A>&nbsp;
*/
</BODY>
</HTML>