358 lines
15 KiB
HTML
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 < ycalc.cup
|
|
<BR>*/
|
|
<BR>
|
|
|
|
<P>/* ----------------------<B>Preliminary Declarations Section</B>--------------------*/
|
|
|
|
<P>/* Import the class java_cup.runtime.* */
|
|
<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> Lexer lexer;
|
|
|
|
<P> public parser(Lexer lexer) {
|
|
<BR> this.lexer = lexer;
|
|
<BR> }
|
|
|
|
<P> /* Change the method report_error so it will display the line
|
|
<BR> and column of where the error occurred in
|
|
the input as well as the reason
|
|
<BR> for the error which is passed into the method
|
|
in the String 'message'. */
|
|
<BR> public void report_error(String message, Object info) {
|
|
|
|
<P> /* Create a StringBuffer called 'm' with the string
|
|
'Error' in it. */
|
|
<BR> StringBuffer m = new StringBuffer("Error");
|
|
|
|
<P> /* Check if the information passed to the method
|
|
is the same type as the
|
|
<BR> type java_cup.runtime.Symbol.
|
|
*/
|
|
<BR> if (info instanceof java_cup.runtime.Symbol) {
|
|
|
|
<P> /* Declare a java_cup.runtime.Symbol
|
|
object 's' with the information in the
|
|
<BR> object info
|
|
that is being typecasted as a java_cup.runtime.Symbol object. */
|
|
<BR> java_cup.runtime.Symbol s = ((java_cup.runtime.Symbol)
|
|
info);
|
|
|
|
<P> /* Check if the line number in the input
|
|
is greater or equal to zero. */
|
|
<BR> if (s.left >= 0) {
|
|
|
|
<P> /* Add to the end of the
|
|
StringBuffer error message the line number of
|
|
<BR> the error
|
|
in the input. */
|
|
<BR> m.append(" in line "+(s.left+1));
|
|
|
|
<P> /* Check if the column number
|
|
in the input is greater or equal to
|
|
<BR> zero.
|
|
*/
|
|
<BR> if (s.right >= 0)
|
|
|
|
<P> /* Add to the
|
|
end of the StringBuffer error message the column number
|
|
<BR>
|
|
of the error in the input. */
|
|
<BR> m.append(",
|
|
column "+(s.right+1));
|
|
<BR> }
|
|
<BR> }
|
|
|
|
<P> /* Add to the end of the StringBuffer error message
|
|
created in this
|
|
<BR> method the message that was passed
|
|
into this method. */
|
|
<BR> m.append(" : "+message);
|
|
|
|
<P> /* Print the contents of the StringBuffer 'm', which
|
|
contains an error
|
|
<BR> message out on a line. */
|
|
<BR> System.err.println(m);
|
|
<BR> }
|
|
|
|
<P> /* Change the method report_fatal_error so when it reports a
|
|
fatal error it
|
|
<BR> will display the line and column number of
|
|
where the fatal error
|
|
<BR> occurred in the input as well as the reason
|
|
for the fatal error which is
|
|
<BR> passed into the method in the object 'message'
|
|
and then exit.*/
|
|
<BR> public void report_fatal_error(String message, Object info)
|
|
{
|
|
<BR> report_error(message, info);
|
|
<BR> System.exit(1);
|
|
<BR> }
|
|
<BR><B>:};</B>
|
|
|
|
<P><B>/* </B> <A HREF="lopes.html#prelim">Return to Using CUP</A>
|
|
*/
|
|
|
|
<P>/* Use the scanner created with JFlex */
|
|
<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> Terminals that have no value are listed first and then
|
|
terminals that do
|
|
<BR> have an value, in this case an integer value, are listed
|
|
on the next line
|
|
<BR> down. */
|
|
<BR><B>terminal</B>
|
|
SEMI, PLUS, MINUS, TIMES, DIVIDE, LPAREN, RPAREN;
|
|
<BR><B>terminal Integer</B> NUMBER, ID;
|
|
|
|
<P>/* Non Terminals used in the Grammar Section.
|
|
|
|
<P> Non Terminals that have an object value are listed first
|
|
and then Non Terminals
|
|
<BR> that have an integer value are listed. An object
|
|
value means that it can be
|
|
<BR> any type, it isn't set to a specific type. So it
|
|
could be an integer or a String or
|
|
<BR> whatever. */
|
|
<BR><B>non terminal Object</B> expr_list, expr_part;
|
|
<BR><B>non terminal Integer</B> expr, factor, term;
|
|
|
|
<P>/* -------------<B>Precedence and Associatively of Terminals Section</B>-----------
|
|
*/
|
|
|
|
<P>/*
|
|
<BR>Precedence of Non Terminals could be defined here. 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> expr_list ::=
|
|
expr_list expr_part
|
|
<BR>
|
|
| expr_part
|
|
<BR> expr_part ::=
|
|
expr SEMI
|
|
<BR> expr
|
|
::= factor PLUS expr
|
|
<BR>
|
|
| factor MINUS expr
|
|
<BR>
|
|
| factor
|
|
<BR> factor
|
|
::= factor TIMES term
|
|
<BR>
|
|
| factor DIVIDE term
|
|
<BR>
|
|
| term
|
|
<BR> primary ::=
|
|
LPAREN expr RPAREN
|
|
<BR>
|
|
| NUMBER
|
|
<BR>
|
|
| ID
|
|
|
|
<P> <A HREF="lopes.html#prec">Return to Using CUP</A>
|
|
|
|
<P>*/
|
|
|
|
<P>/* 'expr_list' is the start of our grammar. It can lead to another
|
|
'expr_list'
|
|
<BR>followed by an 'expr_part' or it can just lead an 'expr_part'.
|
|
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. 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. This process keeps
|
|
continuing
|
|
<BR>until only Terminals are found in the rhs of a production. 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>
|
|
|
|
|
<BR>
|
|
expr_part;
|
|
<BR>
|
|
|
|
<P>/* 'expr_part' is an 'expr' followed by the terminal 'SEMI'. 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. The action for the production
|
|
lies between
|
|
<BR>{: and :}. This action will print out the line " = + e" where
|
|
e is the value of
|
|
<BR>'expr'. Before the action takes places we need to go deeper into
|
|
the grammar
|
|
<BR>since 'expr' is a Non Terminal. 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. 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>
|
|
{: System.out.println(" = " + e); :}
|
|
<BR>
|
|
SEMI
|
|
<BR>
|
|
;
|
|
<BR>
|
|
|
|
<P>/* 'expr' can lead to 'factor PLUS expr', 'factor MINUS expr', or 'factor'.
|
|
<BR>The 'TIMES' and 'DIVIDE' productions are not at this level. 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'.
|
|
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'. 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'. The value of each is retrieved with
|
|
the same
|
|
<BR>function 'intValue'. The values will be added or subtracted and
|
|
then the new
|
|
<BR>integer will be stored in 'RESULT'.*/
|
|
|
|
<P>expr ::= factor:f PLUS expr:e
|
|
<BR>
|
|
{: RESULT = new Integer(f.intValue() + e.intValue()); :}
|
|
<BR>
|
|
|
|
|
<BR>
|
|
factor:f MINUS expr:e
|
|
<BR>
|
|
{: RESULT = new Integer(f.intValue() - e.intValue()); :}
|
|
<BR>
|
|
|
|
|
<BR>
|
|
factor:f
|
|
<BR>
|
|
{: RESULT = new Integer(f.intValue()); :}
|
|
<BR>
|
|
;
|
|
<BR>
|
|
|
|
<P>/* 'factor' can lead to 'factor TIMES term', 'factor DIVIDE term', or
|
|
<BR>'term'. Since the productions for TIMES and DIVIDE are lower
|
|
in the
|
|
<BR>grammar than 'PLUS' and 'MINUS' they will have higher precedence.
|
|
The same
|
|
<BR>sort of actions take place in the rhs of 'factor' as in 'expr'.
|
|
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 ::= factor:f TIMES term:t
|
|
<BR>
|
|
{: RESULT = new Integer(f.intValue() * t.intValue()); :}
|
|
<BR>
|
|
|
|
|
<BR>
|
|
factor:f DIVIDE term:t
|
|
<BR>
|
|
{: RESULT = new Integer(f.intValue() / t.intValue()); :}
|
|
<BR>
|
|
|
|
|
<BR>
|
|
term:t
|
|
<BR>
|
|
{: RESULT = new Integer(t.intValue()); :}
|
|
<BR>
|
|
;
|
|
<BR>
|
|
|
|
<P>/* 'term' can lead to 'LPAREN expr RPAREN', 'NUMBER', or 'ID'.
|
|
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. The next rhs has no Non
|
|
Terminals. So
|
|
<BR>the grammar ends here and can go back up. 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. The same action occurs for 'ID', except the 'i' is
|
|
used to refer
|
|
<BR>to 'ID'. 'ID' is also the only thing on the rhs of the production.
|
|
And since
|
|
<BR>'ID' is a Terminal the grammar will end here and go back up. */
|
|
|
|
<P>primary ::= LPAREN expr:e RPAREN
|
|
<BR>
|
|
{: RESULT = e; :}
|
|
<BR>
|
|
|
|
|
<BR>
|
|
NUMBER:n
|
|
<BR>
|
|
{: RESULT = n; :}
|
|
<BR>
|
|
|
|
|
<BR>
|
|
ID:i
|
|
<BR>
|
|
{: RESULT = i; :}
|
|
<BR>
|
|
;
|
|
|
|
<P>/* <A HREF="lopes.html#cupcode">Return to Using CUP</A>
|
|
*/
|
|
</BODY>
|
|
</HTML>
|