--- /dev/null
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+\f
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
--- /dev/null
+# Makefile to create simple test framework for the java parsers.
+# Copyright (C) 1998 C. Scott Ananian <cananian@alumni.princeton.edu>
+# Released under the terms of the GPL with NO WARRANTY. See COPYING.
+
+# java environment.
+JAVA=java
+JAVAC=javac
+JFLAGS=-g
+#CUPFLAGS=-dump_states
+
+# list the available java grammar versions
+JAVA_GRAMMARS=10 11 12 14 15
+
+all: $(foreach j,$(JAVA_GRAMMARS),Parse/Grm$(j).class) \
+ Lex/Lex.class Main/Main.class
+
+# Feed the appropriate CUP specification to javaCUP.
+Parse/Grm%.java Parse/Sym%.java: Parse/java%.cup
+ cd Parse && \
+ ${JAVA} java_cup.Main ${CUPFLAGS} -parser Grm$* -symbols Sym$* \
+ < java$*.cup 2>Grm$*.err && tail Grm$*.err
+
+# Compile the java source for the parser.
+Parse/Grm%.class: Parse/Lexer.java Parse/Grm%.java Parse/Sym%.java
+ ${JAVAC} ${JFLAGS} $^
+
+# Make the lexer symbols from the parser symbols.
+Lex/Sym.java: $(foreach j,$(JAVA_GRAMMARS),Parse/Sym$(j).java)
+# verify that these are all identical!
+ @if cat $^ | sed -e 's/Sym[0-9][0-9]/Sym/g' | sort | uniq -c | \
+ egrep -v '^[ ]*[0-9]*[05] ' | grep -v "^[ ]*[0-9]*[ ]*//"\
+ ; then \
+ echo $^ "are not identical;" ;\
+ echo "we won't be able to build a single lexer for all of these." ;\
+ exit 1;\
+ fi
+# now make a generic version.
+ sed -e "s/package Parse/package Lex/" -e "s/Sym10/Sym/g" \
+ < Parse/Sym10.java > $@
+
+# Compile the java source for the (unified) lexer.
+Lex/Lex.class: Lex/*.java Lex/Sym.java
+ ${JAVAC} ${JFLAGS} Lex/*.java
+
+# Compile the java source for the driver.
+Main/Main.class: Main/Main.java
+ ${JAVAC} ${JFLAGS} Main/*.java
+
+# run some quick tests.
+test: Parse/Lexer.java Parse/Grm14.java all phony
+ for n in 1 2 3 4 5; do \
+ ( ${JAVA} Main.Main Parse/Lexer.java $$n && \
+ ${JAVA} Main.Main Parse/Grm14.java $$n && \
+ ${JAVA} Main.Main tests/Escape.java) || exit 1; \
+ done
+ for n in 2 3 4 5; do \
+ ${JAVA} Main.Main tests/Eric.java $$n || exit 1; \
+ done
+ ${JAVA} Main.Main tests/TestJSR201.java 5
+ ${JAVA} Main.Main tests/Test15.java 5
+ ${JAVA} Main.Main tests/Eric15.java 5
+# always run the test.
+phony:
+
+# target to make the distributed files.
+dist:
+ -$(RM) -rf JavaGrammar javagrm.tar.gz javagrm.zip
+ cvs -d `cat CVS/Root` co -A -P JavaGrammar
+ find JavaGrammar -type d -name CVS | xargs $(RM) -rf
+ tar czvf javagrm.tar.gz JavaGrammar
+ zip -r javagrm.zip JavaGrammar
+ cp javagrm.tar.gz `date +javagrm-%d-%b-%Y.tar.gz`
+ cp README javagrm-README.txt
+ $(RM) -rf JavaGrammar
+upload: dist
+ chmod a+r javagrm*
+ scp javagrm* shades.cs.princeton.edu:/u/appel/public_html/modern/java/CUP
+
+# clean up after ourselves.
+clean:
+ $(RM) Lex/Sym.java \
+ $(foreach j,$(JAVA_GRAMMARS),Parse/Grm$(j).err) \
+ $(foreach j,$(JAVA_GRAMMARS),Parse/Grm$(j).java) \
+ $(foreach j,$(JAVA_GRAMMARS),Parse/Sym$(j).java) \
+ Parse/parser.java Parse/sym.java \
+ */*.class
+
+veryclean: clean
+ $(RM) *~ */*~ javagrm*
--- /dev/null
+This package contains CUP grammars for the Java programming language.
+
+Copyright (C) 2002 C. Scott Ananian
+This code is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2 of the License, or (at your
+option) any later version. See the file COPYING for more details.
+
+Directory structure:
+ Parse/ contains the Java grammars.
+ java10.cup contains a Java 1.0 grammar.
+ java11.cup contains a Java 1.1 grammar.
+ java12.cup contains a Java 1.2 grammar. [added 11-feb-1999]
+ java14.cup contains a Java 1.4 grammar. [added 10-apr-2002]
+ java15.cup contains a Java 1.5 Java grammar. [added 12-apr-2002]
+ [last updated 28-jul-2003; Java 1.5 spec not yet final.]
+ Lexer.java interface description for a lexer.
+
+ Lex/ contains a simple but complete Java lexer.
+ Lex.java main class
+ Sym.java a copy of Parse/Sym.java containing symbolic constants.
+
+ Main/
+ Main.java a simple testing skeleton for the parser/lexer.
+
+The grammar in Parse/ should be processed by CUP into Grm.java.
+There are much better ways to write lexers for java, but the
+implementation in Lex/ seemed to be the easiest at the time. The
+lexer implemented here may not be as efficient as a table-driven lexer,
+but adheres to the java specification exactly.
+
+ -- C. Scott Ananian <cananian@alumni.princeton.edu> 3-Apr-1998
+ [revised 12-apr-2002]
+ [revised 28-jul-2003]
+
+UPDATE: Fixed a lexer bug: '5.2' is a double, not a float. Thanks to
+Ben Walter <bwalter@mit.edu> for spotting this.
+
+ -- C. Scott Ananian <cananian@alumni.princeton.edu> 14-Jul-1998
+
+UPDATE: Fixed a couple of minor bugs.
+1) Lex.EscapedUnicodeReader wasn't actually parsing unicode escape sequences
+ properly because we didn't implement read(char[], int, int).
+2) Grammar fixes: int[].class, Object[].class and all array class
+ literals were not being parsed. Also special void.class literal
+ inadvertantly omitted from the grammar.
+Both these problems have been fixed.
+
+ -- C. Scott Ananian <cananian@alumni.princeton.edu> 11-Feb-1999
+
+UPDATE: Fixed another lexer bug: Large integer constants such as
+0xFFFF0000 were being incorrectly flagged as 'too large for an int'.
+Also, by the Java Language Specification, "\477" is a valid string
+literal (it is the same as "\0477": the character '\047' followed by
+the character '7'). The lexer handles this case correctly now.
+
+Created java12.cup with grammar updated to Java 1.2. Features
+added include the 'strictfp' keyword and the various new inner class
+features at http://java.sun.com/docs/books/jls/nested-class-clarify.html.
+
+Also added slightly better position/error reporting to all parsers.
+
+ -- C. Scott Ananian <cananian@alumni.princeton.edu> 11-Feb-1999
+
+UPDATE: fixed some buglets with symbol/error position reporting.
+
+ -- C. Scott Ananian <cananian@alumni.princeton.edu> 13-Sep-1999
+
+UPDATE: multi-line comments were causing incorrect character position
+reporting. If you were using the character-position-to-line-number
+code in Lexer, you would never have noticed this problem. Thanks to
+William Young <youngwr@rose-hulman.edu> for pointing this out.
+
+ -- C. Scott Ananian <cananian@alumni.princeton.edu> 27-Oct-1999
+
+UPDATE: extended grammar to handle the 'assert' statement added in
+Java 1.4. Also fixed an oversight: a single SEMICOLON is a valid
+ClassBodyDeclaration; this was added to allow trailing semicolons
+uniformly on class declarations. This wasn't part of the original
+JLS, but was revised in to conform with the actual behavior of the
+javac compiler. I've added this to all the grammars from 1.0-1.4
+to conform to javac behavior; let me know if you've got a good
+reason why this production shouldn't be in early grammars.
+
+Also futzed with the Makefile some to allow building a 'universal'
+driver which will switch between java 1.0/1.1/1.2/1.4 on demand.
+This helps me test the separate grammars; maybe you'll find a
+use for this behavior too.
+
+ -- C. Scott Ananian <cananian@alumni.princeton.edu> 10-Apr-2002
+
+NEW: added a grammar for the JSR-14 "Adding Generics to the Java
+Programming Language" Java variant. Calling this java15.cup, since
+this JSR currently seems to be destined for inclusion in Java 1.5.
+This grammar is very very tricky! I need to use a lexer trick to
+handle type casts to parameterized types, which otherwise do not
+seem to be LALR(1).
+ -- C. Scott Ananian <cananian@alumni.princeton.edu> 12-Apr-2002
+
+UPDATE: various bug fixes to all grammars, in reponse to bugs reported
+by Eric Blake <ebb9@email.byu.edu> and others.
+ a) TWEAK: added 'String' type to IDENTIFIER terminal to match Number types
+ given to numeric literals. (all grammars)
+ b) BUG FIX: added SEMICOLON production to interface_member_declaration to
+ allow optional trailing semicolons, in accordance with the JLS (for
+ java 1.2-and-later grammars) and Sun practice (for earlier grammars).
+ The 10-Apr-2002 release did not address this problem completely, due
+ to an oversight. (all grammars)
+ c) BUG FIX: '<primary>.this(...);' is not a legal production;
+ '<name>.super(...);' and '<name>.new <identifier>(...' ought to be.
+ In particular, plain identifiers ought to be able to qualify instance
+ creation and explicit constructor invocation.
+ (fix due to Eric Blake; java 1.2 grammar and following)
+ d) BUG FIX: parenthesized variables on the left-hand-side of an assignment
+ ought to be legal, according to JLS2. For example, this code is
+ legal:
+ class Foo { void m(int i) { (i) = 1; } }
+ (fix due to Eric Blake; java 1.2 grammar and following)
+ e) BUG FIX: array access of anonymous arrays ought to be legal, according
+ to JLS2. For example, this is legal code:
+ class Foo { int i = new int[]{0}[0]; }
+ (fix due to Eric Blake; java 1.2 grammar and following)
+ f) BUG FIX: nested parameterized types ought to be legal, for example:
+ class A<T> { class B<S> { } A<String>.B<String> c; }
+ (bug found by Eric Blake; jsr-14 grammar only)
+ g) TWEAK: test cases were added for these issues.
+
+In addition, it should be clarified that the 'java15.cup' grammar is
+really only for java 1.4 + jsr-14; recent developments at Sun indicate
+that "Java 1.5" is likely to include several additional language changes
+in addition to JSR-14 parameterized types; see JSR-201 for more details.
+I will endeavor to add these features to 'java15.cup' as soon as their
+syntax is nailed down.
+ -- C. Scott Ananian <cananian@alumni.princeton.edu> 13-Apr-2003
+
+UPDATE: Updated the 'java15.cup' grammar to match the latest specifications
+(and their corrections) for Java 1.5. This grammar matches the 2.2
+prototype of JSR-14 + JSR-201 capabilities, with some corrections for
+mistakes in the released specification and expected future features of
+Java 1.5 (in particular, arrays of parameterized types bounded by
+wildcards). Reimplemented java15.cup to use a refactoring originally
+due to Eric Blake which eliminates our previous need for "lexer lookahead"
+(see release notes for 12-April-2002). Added new 'enum' and '...' tokens
+to the lexer to accomodate Java 1.5. New test cases added for the
+additional language features.
+ -- C. Scott Ananian <cananian@alumni.princeton.edu> 28-Jul-2003
--- /dev/null
+package java_cup.runtime;
+
+/**
+ * Defines the Scanner interface, which CUP uses in the default
+ * implementation of <code>lr_parser.scan()</code>. Integration
+ * of scanners implementing <code>Scanner</code> is facilitated.
+ *
+ * @version last updated 23-Jul-1999
+ * @author David MacMahon <davidm@smartsc.com>
+ */
+
+/* *************************************************
+ Interface Scanner
+
+ Declares the next_token() method that should be
+ implemented by scanners. This method is typically
+ called by lr_parser.scan(). End-of-file can be
+ indicated either by returning
+ <code>new Symbol(lr_parser.EOF_sym())</code> or
+ <code>null</code>.
+ ***************************************************/
+public interface Scanner {
+ /** Return the next token, or <code>null</code> on end-of-file. */
+ public Symbol next_token() throws java.lang.Exception;
+}
--- /dev/null
+package java_cup.runtime;
+
+/**
+ * Defines the Symbol class, which is used to represent all terminals
+ * and nonterminals while parsing. The lexer should pass CUP Symbols
+ * and CUP returns a Symbol.
+ *
+ * @version last updated: 7/3/96
+ * @author Frank Flannery
+ */
+
+/* ****************************************************************
+ Class Symbol
+ what the parser expects to receive from the lexer.
+ the token is identified as follows:
+ sym: the symbol type
+ parse_state: the parse state.
+ value: is the lexical value of type Object
+ left : is the left position in the original input file
+ right: is the right position in the original input file
+******************************************************************/
+
+public class Symbol {
+
+/*******************************
+ Constructor for l,r values
+ *******************************/
+
+ public Symbol(int id, int l, int r, Object o) {
+ this(id);
+ left = l;
+ right = r;
+ value = o;
+ }
+
+/*******************************
+ Constructor for no l,r values
+********************************/
+
+ public Symbol(int id, Object o) {
+ this(id, -1, -1, o);
+ }
+
+/*****************************
+ Constructor for no value
+ ***************************/
+
+ public Symbol(int id, int l, int r) {
+ this(id, l, r, null);
+ }
+
+/***********************************
+ Constructor for no value or l,r
+***********************************/
+
+ public Symbol(int sym_num) {
+ this(sym_num, -1);
+ left = -1;
+ right = -1;
+ value = null;
+ }
+
+/***********************************
+ Constructor to give a start state
+***********************************/
+ Symbol(int sym_num, int state)
+ {
+ sym = sym_num;
+ parse_state = state;
+ }
+
+/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** The symbol number of the terminal or non terminal being represented */
+ public int sym;
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** The parse state to be recorded on the parse stack with this symbol.
+ * This field is for the convenience of the parser and shouldn't be
+ * modified except by the parser.
+ */
+ public int parse_state;
+ /** This allows us to catch some errors caused by scanners recycling
+ * symbols. For the use of the parser only. [CSA, 23-Jul-1999] */
+ boolean used_by_parser = false;
+
+/*******************************
+ The data passed to parser
+ *******************************/
+
+ public int left, right;
+ public Object value;
+
+ /*****************************
+ Printing this token out. (Override for pretty-print).
+ ****************************/
+ public String toString() { return "#"+sym; }
+}
+
+
+
+
+
+
--- /dev/null
+
+package java_cup.runtime;
+
+import java.util.Stack;
+
+/** This class implements a skeleton table driven LR parser. In general,
+ * LR parsers are a form of bottom up shift-reduce parsers. Shift-reduce
+ * parsers act by shifting input onto a parse stack until the Symbols
+ * matching the right hand side of a production appear on the top of the
+ * stack. Once this occurs, a reduce is performed. This involves removing
+ * the Symbols corresponding to the right hand side of the production
+ * (the so called "handle") and replacing them with the non-terminal from
+ * the left hand side of the production. <p>
+ *
+ * To control the decision of whether to shift or reduce at any given point,
+ * the parser uses a state machine (the "viable prefix recognition machine"
+ * built by the parser generator). The current state of the machine is placed
+ * on top of the parse stack (stored as part of a Symbol object representing
+ * a terminal or non terminal). The parse action table is consulted
+ * (using the current state and the current lookahead Symbol as indexes) to
+ * determine whether to shift or to reduce. When the parser shifts, it
+ * changes to a new state by pushing a new Symbol (containing a new state)
+ * onto the stack. When the parser reduces, it pops the handle (right hand
+ * side of a production) off the stack. This leaves the parser in the state
+ * it was in before any of those Symbols were matched. Next the reduce-goto
+ * table is consulted (using the new state and current lookahead Symbol as
+ * indexes) to determine a new state to go to. The parser then shifts to
+ * this goto state by pushing the left hand side Symbol of the production
+ * (also containing the new state) onto the stack.<p>
+ *
+ * This class actually provides four LR parsers. The methods parse() and
+ * debug_parse() provide two versions of the main parser (the only difference
+ * being that debug_parse() emits debugging trace messages as it parses).
+ * In addition to these main parsers, the error recovery mechanism uses two
+ * more. One of these is used to simulate "parsing ahead" in the input
+ * without carrying out actions (to verify that a potential error recovery
+ * has worked), and the other is used to parse through buffered "parse ahead"
+ * input in order to execute all actions and re-synchronize the actual parser
+ * configuration.<p>
+ *
+ * This is an abstract class which is normally filled out by a subclass
+ * generated by the JavaCup parser generator. In addition to supplying
+ * the actual parse tables, generated code also supplies methods which
+ * invoke various pieces of user supplied code, provide access to certain
+ * special Symbols (e.g., EOF and error), etc. Specifically, the following
+ * abstract methods are normally supplied by generated code:
+ * <dl compact>
+ * <dt> short[][] production_table()
+ * <dd> Provides a reference to the production table (indicating the index of
+ * the left hand side non terminal and the length of the right hand side
+ * for each production in the grammar).
+ * <dt> short[][] action_table()
+ * <dd> Provides a reference to the parse action table.
+ * <dt> short[][] reduce_table()
+ * <dd> Provides a reference to the reduce-goto table.
+ * <dt> int start_state()
+ * <dd> Indicates the index of the start state.
+ * <dt> int start_production()
+ * <dd> Indicates the index of the starting production.
+ * <dt> int EOF_sym()
+ * <dd> Indicates the index of the EOF Symbol.
+ * <dt> int error_sym()
+ * <dd> Indicates the index of the error Symbol.
+ * <dt> Symbol do_action()
+ * <dd> Executes a piece of user supplied action code. This always comes at
+ * the point of a reduce in the parse, so this code also allocates and
+ * fills in the left hand side non terminal Symbol object that is to be
+ * pushed onto the stack for the reduce.
+ * <dt> void init_actions()
+ * <dd> Code to initialize a special object that encapsulates user supplied
+ * actions (this object is used by do_action() to actually carry out the
+ * actions).
+ * </dl>
+ *
+ * In addition to these routines that <i>must</i> be supplied by the
+ * generated subclass there are also a series of routines that <i>may</i>
+ * be supplied. These include:
+ * <dl>
+ * <dt> Symbol scan()
+ * <dd> Used to get the next input Symbol from the scanner.
+ * <dt> Scanner getScanner()
+ * <dd> Used to provide a scanner for the default implementation of
+ * scan().
+ * <dt> int error_sync_size()
+ * <dd> This determines how many Symbols past the point of an error
+ * must be parsed without error in order to consider a recovery to
+ * be valid. This defaults to 3. Values less than 2 are not
+ * recommended.
+ * <dt> void report_error(String message, Object info)
+ * <dd> This method is called to report an error. The default implementation
+ * simply prints a message to System.err and where the error occurred.
+ * This method is often replaced in order to provide a more sophisticated
+ * error reporting mechanism.
+ * <dt> void report_fatal_error(String message, Object info)
+ * <dd> This method is called when a fatal error that cannot be recovered from
+ * is encountered. In the default implementation, it calls
+ * report_error() to emit a message, then throws an exception.
+ * <dt> void syntax_error(Symbol cur_token)
+ * <dd> This method is called as soon as syntax error is detected (but
+ * before recovery is attempted). In the default implementation it
+ * invokes: report_error("Syntax error", null);
+ * <dt> void unrecovered_syntax_error(Symbol cur_token)
+ * <dd> This method is called if syntax error recovery fails. In the default
+ * implementation it invokes:<br>
+ * report_fatal_error("Couldn't repair and continue parse", null);
+ * </dl>
+ *
+ * @see java_cup.runtime.Symbol
+ * @see java_cup.runtime.Symbol
+ * @see java_cup.runtime.virtual_parse_stack
+ * @version last updated: 7/3/96
+ * @author Frank Flannery
+ */
+
+public abstract class lr_parser {
+
+ /*-----------------------------------------------------------*/
+ /*--- Constructor(s) ----------------------------------------*/
+ /*-----------------------------------------------------------*/
+
+ /** Simple constructor. */
+ public lr_parser()
+ {
+ /* nothing to do here */
+ }
+
+ /** Constructor that sets the default scanner. [CSA/davidm] */
+ public lr_parser(Scanner s) {
+ this(); /* in case default constructor someday does something */
+ setScanner(s);
+ }
+
+ /*-----------------------------------------------------------*/
+ /*--- (Access to) Static (Class) Variables ------------------*/
+ /*-----------------------------------------------------------*/
+
+ /** The default number of Symbols after an error we much match to consider
+ * it recovered from.
+ */
+ protected final static int _error_sync_size = 3;
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** The number of Symbols after an error we much match to consider it
+ * recovered from.
+ */
+ protected int error_sync_size() {return _error_sync_size; }
+
+ /*-----------------------------------------------------------*/
+ /*--- (Access to) Instance Variables ------------------------*/
+ /*-----------------------------------------------------------*/
+
+ /** Table of production information (supplied by generated subclass).
+ * This table contains one entry per production and is indexed by
+ * the negative-encoded values (reduce actions) in the action_table.
+ * Each entry has two parts, the index of the non-terminal on the
+ * left hand side of the production, and the number of Symbols
+ * on the right hand side.
+ */
+ public abstract short[][] production_table();
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** The action table (supplied by generated subclass). This table is
+ * indexed by state and terminal number indicating what action is to
+ * be taken when the parser is in the given state (i.e., the given state
+ * is on top of the stack) and the given terminal is next on the input.
+ * States are indexed using the first dimension, however, the entries for
+ * a given state are compacted and stored in adjacent index, value pairs
+ * which are searched for rather than accessed directly (see get_action()).
+ * The actions stored in the table will be either shifts, reduces, or
+ * errors. Shifts are encoded as positive values (one greater than the
+ * state shifted to). Reduces are encoded as negative values (one less
+ * than the production reduced by). Error entries are denoted by zero.
+ *
+ * @see java_cup.runtime.lr_parser#get_action
+ */
+ public abstract short[][] action_table();
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** The reduce-goto table (supplied by generated subclass). This
+ * table is indexed by state and non-terminal number and contains
+ * state numbers. States are indexed using the first dimension, however,
+ * the entries for a given state are compacted and stored in adjacent
+ * index, value pairs which are searched for rather than accessed
+ * directly (see get_reduce()). When a reduce occurs, the handle
+ * (corresponding to the RHS of the matched production) is popped off
+ * the stack. The new top of stack indicates a state. This table is
+ * then indexed by that state and the LHS of the reducing production to
+ * indicate where to "shift" to.
+ *
+ * @see java_cup.runtime.lr_parser#get_reduce
+ */
+ public abstract short[][] reduce_table();
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** The index of the start state (supplied by generated subclass). */
+ public abstract int start_state();
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** The index of the start production (supplied by generated subclass). */
+ public abstract int start_production();
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** The index of the end of file terminal Symbol (supplied by generated
+ * subclass).
+ */
+ public abstract int EOF_sym();
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** The index of the special error Symbol (supplied by generated subclass). */
+ public abstract int error_sym();
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** Internal flag to indicate when parser should quit. */
+ protected boolean _done_parsing = false;
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** This method is called to indicate that the parser should quit. This is
+ * normally called by an accept action, but can be used to cancel parsing
+ * early in other circumstances if desired.
+ */
+ public void done_parsing()
+ {
+ _done_parsing = true;
+ }
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+ /* Global parse state shared by parse(), error recovery, and
+ * debugging routines */
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** Indication of the index for top of stack (for use by actions). */
+ protected int tos;
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** The current lookahead Symbol. */
+ protected Symbol cur_token;
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** The parse stack itself. */
+ protected Stack stack = new Stack();
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** Direct reference to the production table. */
+ protected short[][] production_tab;
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** Direct reference to the action table. */
+ protected short[][] action_tab;
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** Direct reference to the reduce-goto table. */
+ protected short[][] reduce_tab;
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** This is the scanner object used by the default implementation
+ * of scan() to get Symbols. To avoid name conflicts with existing
+ * code, this field is private. [CSA/davidm] */
+ private Scanner _scanner;
+
+ /**
+ * Simple accessor method to set the default scanner.
+ */
+ public void setScanner(Scanner s) { _scanner = s; }
+
+ /**
+ * Simple accessor method to get the default scanner.
+ */
+ public Scanner getScanner() { return _scanner; }
+
+ /*-----------------------------------------------------------*/
+ /*--- General Methods ---------------------------------------*/
+ /*-----------------------------------------------------------*/
+
+ /** Perform a bit of user supplied action code (supplied by generated
+ * subclass). Actions are indexed by an internal action number assigned
+ * at parser generation time.
+ *
+ * @param act_num the internal index of the action to be performed.
+ * @param parser the parser object we are acting for.
+ * @param stack the parse stack of that object.
+ * @param top the index of the top element of the parse stack.
+ */
+ public abstract Symbol do_action(
+ int act_num,
+ lr_parser parser,
+ Stack stack,
+ int top)
+ throws java.lang.Exception;
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** User code for initialization inside the parser. Typically this
+ * initializes the scanner. This is called before the parser requests
+ * the first Symbol. Here this is just a placeholder for subclasses that
+ * might need this and we perform no action. This method is normally
+ * overridden by the generated code using this contents of the "init with"
+ * clause as its body.
+ */
+ public void user_init() throws java.lang.Exception { }
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** Initialize the action object. This is called before the parser does
+ * any parse actions. This is filled in by generated code to create
+ * an object that encapsulates all action code.
+ */
+ protected abstract void init_actions() throws java.lang.Exception;
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** Get the next Symbol from the input (supplied by generated subclass).
+ * Once end of file has been reached, all subsequent calls to scan
+ * should return an EOF Symbol (which is Symbol number 0). By default
+ * this method returns getScanner().next_token(); this implementation
+ * can be overriden by the generated parser using the code declared in
+ * the "scan with" clause. Do not recycle objects; every call to
+ * scan() should return a fresh object.
+ */
+ public Symbol scan() throws java.lang.Exception {
+ Symbol sym = getScanner().next_token();
+ return (sym!=null) ? sym : new Symbol(EOF_sym());
+ }
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** Report a fatal error. This method takes a message string and an
+ * additional object (to be used by specializations implemented in
+ * subclasses). Here in the base class a very simple implementation
+ * is provided which reports the error then throws an exception.
+ *
+ * @param message an error message.
+ * @param info an extra object reserved for use by specialized subclasses.
+ */
+ public void report_fatal_error(
+ String message,
+ Object info)
+ throws java.lang.Exception
+ {
+ /* stop parsing (not really necessary since we throw an exception, but) */
+ done_parsing();
+
+ /* use the normal error message reporting to put out the message */
+ report_error(message, info);
+
+ /* throw an exception */
+ throw new Exception("Can't recover from previous error(s)");
+ }
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** Report a non fatal error (or warning). This method takes a message
+ * string and an additional object (to be used by specializations
+ * implemented in subclasses). Here in the base class a very simple
+ * implementation is provided which simply prints the message to
+ * System.err.
+ *
+ * @param message an error message.
+ * @param info an extra object reserved for use by specialized subclasses.
+ */
+ public void report_error(String message, Object info)
+ {
+ System.err.print(message);
+ if (info instanceof Symbol)
+ if (((Symbol)info).left != -1)
+ System.err.println(" at character " + ((Symbol)info).left +
+ " of input");
+ else System.err.println("");
+ else System.err.println("");
+ }
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** This method is called when a syntax error has been detected and recovery
+ * is about to be invoked. Here in the base class we just emit a
+ * "Syntax error" error message.
+ *
+ * @param cur_token the current lookahead Symbol.
+ */
+ public void syntax_error(Symbol cur_token)
+ {
+ report_error("Syntax error", cur_token);
+ }
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** This method is called if it is determined that syntax error recovery
+ * has been unsuccessful. Here in the base class we report a fatal error.
+ *
+ * @param cur_token the current lookahead Symbol.
+ */
+ public void unrecovered_syntax_error(Symbol cur_token)
+ throws java.lang.Exception
+ {
+ report_fatal_error("Couldn't repair and continue parse", cur_token);
+ }
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** Fetch an action from the action table. The table is broken up into
+ * rows, one per state (rows are indexed directly by state number).
+ * Within each row, a list of index, value pairs are given (as sequential
+ * entries in the table), and the list is terminated by a default entry
+ * (denoted with a Symbol index of -1). To find the proper entry in a row
+ * we do a linear or binary search (depending on the size of the row).
+ *
+ * @param state the state index of the action being accessed.
+ * @param sym the Symbol index of the action being accessed.
+ */
+ protected final short get_action(int state, int sym)
+ {
+ short tag;
+ int first, last, probe;
+ short[] row = action_tab[state];
+
+ /* linear search if we are < 10 entries */
+ if (row.length < 20)
+ for (probe = 0; probe < row.length; probe++)
+ {
+ /* is this entry labeled with our Symbol or the default? */
+ tag = row[probe++];
+ if (tag == sym || tag == -1)
+ {
+ /* return the next entry */
+ return row[probe];
+ }
+ }
+ /* otherwise binary search */
+ else
+ {
+ first = 0;
+ last = (row.length-1)/2 - 1; /* leave out trailing default entry */
+ while (first <= last)
+ {
+ probe = (first+last)/2;
+ if (sym == row[probe*2])
+ return row[probe*2+1];
+ else if (sym > row[probe*2])
+ first = probe+1;
+ else
+ last = probe-1;
+ }
+
+ /* not found, use the default at the end */
+ return row[row.length-1];
+ }
+
+ /* shouldn't happened, but if we run off the end we return the
+ default (error == 0) */
+ return 0;
+ }
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** Fetch a state from the reduce-goto table. The table is broken up into
+ * rows, one per state (rows are indexed directly by state number).
+ * Within each row, a list of index, value pairs are given (as sequential
+ * entries in the table), and the list is terminated by a default entry
+ * (denoted with a Symbol index of -1). To find the proper entry in a row
+ * we do a linear search.
+ *
+ * @param state the state index of the entry being accessed.
+ * @param sym the Symbol index of the entry being accessed.
+ */
+ protected final short get_reduce(int state, int sym)
+ {
+ short tag;
+ short[] row = reduce_tab[state];
+
+ /* if we have a null row we go with the default */
+ if (row == null)
+ return -1;
+
+ for (int probe = 0; probe < row.length; probe++)
+ {
+ /* is this entry labeled with our Symbol or the default? */
+ tag = row[probe++];
+ if (tag == sym || tag == -1)
+ {
+ /* return the next entry */
+ return row[probe];
+ }
+ }
+ /* if we run off the end we return the default (error == -1) */
+ return -1;
+ }
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** This method provides the main parsing routine. It returns only when
+ * done_parsing() has been called (typically because the parser has
+ * accepted, or a fatal error has been reported). See the header
+ * documentation for the class regarding how shift/reduce parsers operate
+ * and how the various tables are used.
+ */
+ public Symbol parse() throws java.lang.Exception
+ {
+ /* the current action code */
+ int act;
+
+ /* the Symbol/stack element returned by a reduce */
+ Symbol lhs_sym = null;
+
+ /* information about production being reduced with */
+ short handle_size, lhs_sym_num;
+
+ /* set up direct reference to tables to drive the parser */
+
+ production_tab = production_table();
+ action_tab = action_table();
+ reduce_tab = reduce_table();
+
+ /* initialize the action encapsulation object */
+ init_actions();
+
+ /* do user initialization */
+ user_init();
+
+ /* get the first token */
+ cur_token = scan();
+
+ /* push dummy Symbol with start state to get us underway */
+ stack.removeAllElements();
+ stack.push(new Symbol(0, start_state()));
+ tos = 0;
+
+ /* continue until we are told to stop */
+ for (_done_parsing = false; !_done_parsing; )
+ {
+ /* Check current token for freshness. */
+ if (cur_token.used_by_parser)
+ throw new Error("Symbol recycling detected (fix your scanner).");
+
+ /* current state is always on the top of the stack */
+
+ /* look up action out of the current state with the current input */
+ act = get_action(((Symbol)stack.peek()).parse_state, cur_token.sym);
+
+ /* decode the action -- > 0 encodes shift */
+ if (act > 0)
+ {
+ /* shift to the encoded state by pushing it on the stack */
+ cur_token.parse_state = act-1;
+ cur_token.used_by_parser = true;
+ stack.push(cur_token);
+ tos++;
+
+ /* advance to the next Symbol */
+ cur_token = scan();
+ }
+ /* if its less than zero, then it encodes a reduce action */
+ else if (act < 0)
+ {
+ /* perform the action for the reduce */
+ lhs_sym = do_action((-act)-1, this, stack, tos);
+
+ /* look up information about the production */
+ lhs_sym_num = production_tab[(-act)-1][0];
+ handle_size = production_tab[(-act)-1][1];
+
+ /* pop the handle off the stack */
+ for (int i = 0; i < handle_size; i++)
+ {
+ stack.pop();
+ tos--;
+ }
+
+ /* look up the state to go to from the one popped back to */
+ act = get_reduce(((Symbol)stack.peek()).parse_state, lhs_sym_num);
+
+ /* shift to that state */
+ lhs_sym.parse_state = act;
+ lhs_sym.used_by_parser = true;
+ stack.push(lhs_sym);
+ tos++;
+ }
+ /* finally if the entry is zero, we have an error */
+ else if (act == 0)
+ {
+ /* call user syntax error reporting routine */
+ syntax_error(cur_token);
+
+ /* try to error recover */
+ if (!error_recovery(false))
+ {
+ /* if that fails give up with a fatal syntax error */
+ unrecovered_syntax_error(cur_token);
+
+ /* just in case that wasn't fatal enough, end parse */
+ done_parsing();
+ } else {
+ lhs_sym = (Symbol)stack.peek();
+ }
+ }
+ }
+ return lhs_sym;
+ }
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** Write a debugging message to System.err for the debugging version
+ * of the parser.
+ *
+ * @param mess the text of the debugging message.
+ */
+ public void debug_message(String mess)
+ {
+ System.err.println(mess);
+ }
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** Dump the parse stack for debugging purposes. */
+ public void dump_stack()
+ {
+ if (stack == null)
+ {
+ debug_message("# Stack dump requested, but stack is null");
+ return;
+ }
+
+ debug_message("============ Parse Stack Dump ============");
+
+ /* dump the stack */
+ for (int i=0; i<stack.size(); i++)
+ {
+ debug_message("Symbol: " + ((Symbol)stack.elementAt(i)).sym +
+ " State: " + ((Symbol)stack.elementAt(i)).parse_state);
+ }
+ debug_message("==========================================");
+ }
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** Do debug output for a reduce.
+ *
+ * @param prod_num the production we are reducing with.
+ * @param nt_num the index of the LHS non terminal.
+ * @param rhs_size the size of the RHS.
+ */
+ public void debug_reduce(int prod_num, int nt_num, int rhs_size)
+ {
+ debug_message("# Reduce with prod #" + prod_num + " [NT=" + nt_num +
+ ", " + "SZ=" + rhs_size + "]");
+ }
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** Do debug output for shift.
+ *
+ * @param shift_tkn the Symbol being shifted onto the stack.
+ */
+ public void debug_shift(Symbol shift_tkn)
+ {
+ debug_message("# Shift under term #" + shift_tkn.sym +
+ " to state #" + shift_tkn.parse_state);
+ }
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** Do debug output for stack state. [CSA]
+ */
+ public void debug_stack() {
+ StringBuffer sb=new StringBuffer("## STACK:");
+ for (int i=0; i<stack.size(); i++) {
+ Symbol s = (Symbol) stack.elementAt(i);
+ sb.append(" <state "+s.parse_state+", sym "+s.sym+">");
+ if ((i%3)==2 || (i==(stack.size()-1))) {
+ debug_message(sb.toString());
+ sb = new StringBuffer(" ");
+ }
+ }
+ }
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** Perform a parse with debugging output. This does exactly the
+ * same things as parse(), except that it calls debug_shift() and
+ * debug_reduce() when shift and reduce moves are taken by the parser
+ * and produces various other debugging messages.
+ */
+ public Symbol debug_parse()
+ throws java.lang.Exception
+ {
+ /* the current action code */
+ int act;
+
+ /* the Symbol/stack element returned by a reduce */
+ Symbol lhs_sym = null;
+
+ /* information about production being reduced with */
+ short handle_size, lhs_sym_num;
+
+ /* set up direct reference to tables to drive the parser */
+ production_tab = production_table();
+ action_tab = action_table();
+ reduce_tab = reduce_table();
+
+ debug_message("# Initializing parser");
+
+ /* initialize the action encapsulation object */
+ init_actions();
+
+ /* do user initialization */
+ user_init();
+
+ /* the current Symbol */
+ cur_token = scan();
+
+ debug_message("# Current Symbol is #" + cur_token.sym);
+
+ /* push dummy Symbol with start state to get us underway */
+ stack.removeAllElements();
+ stack.push(new Symbol(0, start_state()));
+ tos = 0;
+
+ /* continue until we are told to stop */
+ for (_done_parsing = false; !_done_parsing; )
+ {
+ /* Check current token for freshness. */
+ if (cur_token.used_by_parser)
+ throw new Error("Symbol recycling detected (fix your scanner).");
+
+ /* current state is always on the top of the stack */
+ //debug_stack();
+
+ /* look up action out of the current state with the current input */
+ act = get_action(((Symbol)stack.peek()).parse_state, cur_token.sym);
+
+ /* decode the action -- > 0 encodes shift */
+ if (act > 0)
+ {
+ /* shift to the encoded state by pushing it on the stack */
+ cur_token.parse_state = act-1;
+ cur_token.used_by_parser = true;
+ debug_shift(cur_token);
+ stack.push(cur_token);
+ tos++;
+
+ /* advance to the next Symbol */
+ cur_token = scan();
+ debug_message("# Current token is " + cur_token);
+ }
+ /* if its less than zero, then it encodes a reduce action */
+ else if (act < 0)
+ {
+ /* perform the action for the reduce */
+ lhs_sym = do_action((-act)-1, this, stack, tos);
+
+ /* look up information about the production */
+ lhs_sym_num = production_tab[(-act)-1][0];
+ handle_size = production_tab[(-act)-1][1];
+
+ debug_reduce((-act)-1, lhs_sym_num, handle_size);
+
+ /* pop the handle off the stack */
+ for (int i = 0; i < handle_size; i++)
+ {
+ stack.pop();
+ tos--;
+ }
+
+ /* look up the state to go to from the one popped back to */
+ act = get_reduce(((Symbol)stack.peek()).parse_state, lhs_sym_num);
+ debug_message("# Reduce rule: top state " +
+ ((Symbol)stack.peek()).parse_state +
+ ", lhs sym " + lhs_sym_num + " -> state " + act);
+
+ /* shift to that state */
+ lhs_sym.parse_state = act;
+ lhs_sym.used_by_parser = true;
+ stack.push(lhs_sym);
+ tos++;
+
+ debug_message("# Goto state #" + act);
+ }
+ /* finally if the entry is zero, we have an error */
+ else if (act == 0)
+ {
+ /* call user syntax error reporting routine */
+ syntax_error(cur_token);
+
+ /* try to error recover */
+ if (!error_recovery(true))
+ {
+ /* if that fails give up with a fatal syntax error */
+ unrecovered_syntax_error(cur_token);
+
+ /* just in case that wasn't fatal enough, end parse */
+ done_parsing();
+ } else {
+ lhs_sym = (Symbol)stack.peek();
+ }
+ }
+ }
+ return lhs_sym;
+ }
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+ /* Error recovery code */
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** Attempt to recover from a syntax error. This returns false if recovery
+ * fails, true if it succeeds. Recovery happens in 4 steps. First we
+ * pop the parse stack down to a point at which we have a shift out
+ * of the top-most state on the error Symbol. This represents the
+ * initial error recovery configuration. If no such configuration is
+ * found, then we fail. Next a small number of "lookahead" or "parse
+ * ahead" Symbols are read into a buffer. The size of this buffer is
+ * determined by error_sync_size() and determines how many Symbols beyond
+ * the error must be matched to consider the recovery a success. Next,
+ * we begin to discard Symbols in attempt to get past the point of error
+ * to a point where we can continue parsing. After each Symbol, we attempt
+ * to "parse ahead" though the buffered lookahead Symbols. The "parse ahead"
+ * process simulates that actual parse, but does not modify the real
+ * parser's configuration, nor execute any actions. If we can parse all
+ * the stored Symbols without error, then the recovery is considered a
+ * success. Once a successful recovery point is determined, we do an
+ * actual parse over the stored input -- modifying the real parse
+ * configuration and executing all actions. Finally, we return the the
+ * normal parser to continue with the overall parse.
+ *
+ * @param debug should we produce debugging messages as we parse.
+ */
+ protected boolean error_recovery(boolean debug)
+ throws java.lang.Exception
+ {
+ if (debug) debug_message("# Attempting error recovery");
+
+ /* first pop the stack back into a state that can shift on error and
+ do that shift (if that fails, we fail) */
+ if (!find_recovery_config(debug))
+ {
+ if (debug) debug_message("# Error recovery fails");
+ return false;
+ }
+
+ /* read ahead to create lookahead we can parse multiple times */
+ read_lookahead();
+
+ /* repeatedly try to parse forward until we make it the required dist */
+ for (;;)
+ {
+ /* try to parse forward, if it makes it, bail out of loop */
+ if (debug) debug_message("# Trying to parse ahead");
+ if (try_parse_ahead(debug))
+ {
+ break;
+ }
+
+ /* if we are now at EOF, we have failed */
+ if (lookahead[0].sym == EOF_sym())
+ {
+ if (debug) debug_message("# Error recovery fails at EOF");
+ return false;
+ }
+
+ /* otherwise, we consume another Symbol and try again */
+ // BUG FIX by Bruce Hutton
+ // Computer Science Department, University of Auckland,
+ // Auckland, New Zealand.
+ // It is the first token that is being consumed, not the one
+ // we were up to parsing
+ if (debug)
+ debug_message("# Consuming Symbol #" + lookahead[ 0 ].sym);
+ restart_lookahead();
+ }
+
+ /* we have consumed to a point where we can parse forward */
+ if (debug) debug_message("# Parse-ahead ok, going back to normal parse");
+
+ /* do the real parse (including actions) across the lookahead */
+ parse_lookahead(debug);
+
+ /* we have success */
+ return true;
+ }
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** Determine if we can shift under the special error Symbol out of the
+ * state currently on the top of the (real) parse stack.
+ */
+ protected boolean shift_under_error()
+ {
+ /* is there a shift under error Symbol */
+ return get_action(((Symbol)stack.peek()).parse_state, error_sym()) > 0;
+ }
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** Put the (real) parse stack into error recovery configuration by
+ * popping the stack down to a state that can shift on the special
+ * error Symbol, then doing the shift. If no suitable state exists on
+ * the stack we return false
+ *
+ * @param debug should we produce debugging messages as we parse.
+ */
+ protected boolean find_recovery_config(boolean debug)
+ {
+ Symbol error_token;
+ int act;
+
+ if (debug) debug_message("# Finding recovery state on stack");
+
+ /* Remember the right-position of the top symbol on the stack */
+ int right_pos = ((Symbol)stack.peek()).right;
+ int left_pos = ((Symbol)stack.peek()).left;
+
+ /* pop down until we can shift under error Symbol */
+ while (!shift_under_error())
+ {
+ /* pop the stack */
+ if (debug)
+ debug_message("# Pop stack by one, state was # " +
+ ((Symbol)stack.peek()).parse_state);
+ left_pos = ((Symbol)stack.pop()).left;
+ tos--;
+
+ /* if we have hit bottom, we fail */
+ if (stack.empty())
+ {
+ if (debug) debug_message("# No recovery state found on stack");
+ return false;
+ }
+ }
+
+ /* state on top of the stack can shift under error, find the shift */
+ act = get_action(((Symbol)stack.peek()).parse_state, error_sym());
+ if (debug)
+ {
+ debug_message("# Recover state found (#" +
+ ((Symbol)stack.peek()).parse_state + ")");
+ debug_message("# Shifting on error to state #" + (act-1));
+ }
+
+ /* build and shift a special error Symbol */
+ error_token = new Symbol(error_sym(), left_pos, right_pos);
+ error_token.parse_state = act-1;
+ error_token.used_by_parser = true;
+ stack.push(error_token);
+ tos++;
+
+ return true;
+ }
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** Lookahead Symbols used for attempting error recovery "parse aheads". */
+ protected Symbol lookahead[];
+
+ /** Position in lookahead input buffer used for "parse ahead". */
+ protected int lookahead_pos;
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** Read from input to establish our buffer of "parse ahead" lookahead
+ * Symbols.
+ */
+ protected void read_lookahead() throws java.lang.Exception
+ {
+ /* create the lookahead array */
+ lookahead = new Symbol[error_sync_size()];
+
+ /* fill in the array */
+ for (int i = 0; i < error_sync_size(); i++)
+ {
+ lookahead[i] = cur_token;
+ cur_token = scan();
+ }
+
+ /* start at the beginning */
+ lookahead_pos = 0;
+ }
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** Return the current lookahead in our error "parse ahead" buffer. */
+ protected Symbol cur_err_token() { return lookahead[lookahead_pos]; }
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** Advance to next "parse ahead" input Symbol. Return true if we have
+ * input to advance to, false otherwise.
+ */
+ protected boolean advance_lookahead()
+ {
+ /* advance the input location */
+ lookahead_pos++;
+
+ /* return true if we didn't go off the end */
+ return lookahead_pos < error_sync_size();
+ }
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** Reset the parse ahead input to one Symbol past where we started error
+ * recovery (this consumes one new Symbol from the real input).
+ */
+ protected void restart_lookahead() throws java.lang.Exception
+ {
+ /* move all the existing input over */
+ for (int i = 1; i < error_sync_size(); i++)
+ lookahead[i-1] = lookahead[i];
+
+ /* read a new Symbol into the last spot */
+ // BUG Fix by Bruce Hutton
+ // Computer Science Department, University of Auckland,
+ // Auckland, New Zealand. [applied 5-sep-1999 by csa]
+ // The following two lines were out of order!!
+ lookahead[error_sync_size()-1] = cur_token;
+ cur_token = scan();
+
+ /* reset our internal position marker */
+ lookahead_pos = 0;
+ }
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** Do a simulated parse forward (a "parse ahead") from the current
+ * stack configuration using stored lookahead input and a virtual parse
+ * stack. Return true if we make it all the way through the stored
+ * lookahead input without error. This basically simulates the action of
+ * parse() using only our saved "parse ahead" input, and not executing any
+ * actions.
+ *
+ * @param debug should we produce debugging messages as we parse.
+ */
+ protected boolean try_parse_ahead(boolean debug)
+ throws java.lang.Exception
+ {
+ int act;
+ short lhs, rhs_size;
+
+ /* create a virtual stack from the real parse stack */
+ virtual_parse_stack vstack = new virtual_parse_stack(stack);
+
+ /* parse until we fail or get past the lookahead input */
+ for (;;)
+ {
+ /* look up the action from the current state (on top of stack) */
+ act = get_action(vstack.top(), cur_err_token().sym);
+
+ /* if its an error, we fail */
+ if (act == 0) return false;
+
+ /* > 0 encodes a shift */
+ if (act > 0)
+ {
+ /* push the new state on the stack */
+ vstack.push(act-1);
+
+ if (debug) debug_message("# Parse-ahead shifts Symbol #" +
+ cur_err_token().sym + " into state #" + (act-1));
+
+ /* advance simulated input, if we run off the end, we are done */
+ if (!advance_lookahead()) return true;
+ }
+ /* < 0 encodes a reduce */
+ else
+ {
+ /* if this is a reduce with the start production we are done */
+ if ((-act)-1 == start_production())
+ {
+ if (debug) debug_message("# Parse-ahead accepts");
+ return true;
+ }
+
+ /* get the lhs Symbol and the rhs size */
+ lhs = production_tab[(-act)-1][0];
+ rhs_size = production_tab[(-act)-1][1];
+
+ /* pop handle off the stack */
+ for (int i = 0; i < rhs_size; i++)
+ vstack.pop();
+
+ if (debug)
+ debug_message("# Parse-ahead reduces: handle size = " +
+ rhs_size + " lhs = #" + lhs + " from state #" + vstack.top());
+
+ /* look up goto and push it onto the stack */
+ vstack.push(get_reduce(vstack.top(), lhs));
+ if (debug)
+ debug_message("# Goto state #" + vstack.top());
+ }
+ }
+ }
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** Parse forward using stored lookahead Symbols. In this case we have
+ * already verified that parsing will make it through the stored lookahead
+ * Symbols and we are now getting back to the point at which we can hand
+ * control back to the normal parser. Consequently, this version of the
+ * parser performs all actions and modifies the real parse configuration.
+ * This returns once we have consumed all the stored input or we accept.
+ *
+ * @param debug should we produce debugging messages as we parse.
+ */
+ protected void parse_lookahead(boolean debug)
+ throws java.lang.Exception
+ {
+ /* the current action code */
+ int act;
+
+ /* the Symbol/stack element returned by a reduce */
+ Symbol lhs_sym = null;
+
+ /* information about production being reduced with */
+ short handle_size, lhs_sym_num;
+
+ /* restart the saved input at the beginning */
+ lookahead_pos = 0;
+
+ if (debug)
+ {
+ debug_message("# Reparsing saved input with actions");
+ debug_message("# Current Symbol is #" + cur_err_token().sym);
+ debug_message("# Current state is #" +
+ ((Symbol)stack.peek()).parse_state);
+ }
+
+ /* continue until we accept or have read all lookahead input */
+ while(!_done_parsing)
+ {
+ /* current state is always on the top of the stack */
+
+ /* look up action out of the current state with the current input */
+ act =
+ get_action(((Symbol)stack.peek()).parse_state, cur_err_token().sym);
+
+ /* decode the action -- > 0 encodes shift */
+ if (act > 0)
+ {
+ /* shift to the encoded state by pushing it on the stack */
+ cur_err_token().parse_state = act-1;
+ cur_err_token().used_by_parser = true;
+ if (debug) debug_shift(cur_err_token());
+ stack.push(cur_err_token());
+ tos++;
+
+ /* advance to the next Symbol, if there is none, we are done */
+ if (!advance_lookahead())
+ {
+ if (debug) debug_message("# Completed reparse");
+
+ /* scan next Symbol so we can continue parse */
+ // BUGFIX by Chris Harris <ckharris@ucsd.edu>:
+ // correct a one-off error by commenting out
+ // this next line.
+ /*cur_token = scan();*/
+
+ /* go back to normal parser */
+ return;
+ }
+
+ if (debug)
+ debug_message("# Current Symbol is #" + cur_err_token().sym);
+ }
+ /* if its less than zero, then it encodes a reduce action */
+ else if (act < 0)
+ {
+ /* perform the action for the reduce */
+ lhs_sym = do_action((-act)-1, this, stack, tos);
+
+ /* look up information about the production */
+ lhs_sym_num = production_tab[(-act)-1][0];
+ handle_size = production_tab[(-act)-1][1];
+
+ if (debug) debug_reduce((-act)-1, lhs_sym_num, handle_size);
+
+ /* pop the handle off the stack */
+ for (int i = 0; i < handle_size; i++)
+ {
+ stack.pop();
+ tos--;
+ }
+
+ /* look up the state to go to from the one popped back to */
+ act = get_reduce(((Symbol)stack.peek()).parse_state, lhs_sym_num);
+
+ /* shift to that state */
+ lhs_sym.parse_state = act;
+ lhs_sym.used_by_parser = true;
+ stack.push(lhs_sym);
+ tos++;
+
+ if (debug) debug_message("# Goto state #" + act);
+
+ }
+ /* finally if the entry is zero, we have an error
+ (shouldn't happen here, but...)*/
+ else if (act == 0)
+ {
+ report_fatal_error("Syntax error", lhs_sym);
+ return;
+ }
+ }
+
+
+ }
+
+ /*-----------------------------------------------------------*/
+
+ /** Utility function: unpacks parse tables from strings */
+ protected static short[][] unpackFromStrings(String[] sa)
+ {
+ // Concatanate initialization strings.
+ StringBuffer sb = new StringBuffer(sa[0]);
+ for (int i=1; i<sa.length; i++)
+ sb.append(sa[i]);
+ int n=0; // location in initialization string
+ int size1 = (((int)sb.charAt(n))<<16) | ((int)sb.charAt(n+1)); n+=2;
+ short[][] result = new short[size1][];
+ for (int i=0; i<size1; i++) {
+ int size2 = (((int)sb.charAt(n))<<16) | ((int)sb.charAt(n+1)); n+=2;
+ result[i] = new short[size2];
+ for (int j=0; j<size2; j++)
+ result[i][j] = (short) (sb.charAt(n++)-2);
+ }
+ return result;
+ }
+}
+
--- /dev/null
+
+package java_cup.runtime;
+
+import java.util.Stack;
+
+/** This class implements a temporary or "virtual" parse stack that
+ * replaces the top portion of the actual parse stack (the part that
+ * has been changed by some set of operations) while maintaining its
+ * original contents. This data structure is used when the parse needs
+ * to "parse ahead" to determine if a given error recovery attempt will
+ * allow the parse to continue far enough to consider it successful. Once
+ * success or failure of parse ahead is determined the system then
+ * reverts to the original parse stack (which has not actually been
+ * modified). Since parse ahead does not execute actions, only parse
+ * state is maintained on the virtual stack, not full Symbol objects.
+ *
+ * @see java_cup.runtime.lr_parser
+ * @version last updated: 7/3/96
+ * @author Frank Flannery
+ */
+
+public class virtual_parse_stack {
+ /*-----------------------------------------------------------*/
+ /*--- Constructor(s) ----------------------------------------*/
+ /*-----------------------------------------------------------*/
+
+ /** Constructor to build a virtual stack out of a real stack. */
+ public virtual_parse_stack(Stack shadowing_stack) throws java.lang.Exception
+ {
+ /* sanity check */
+ if (shadowing_stack == null)
+ throw new Exception(
+ "Internal parser error: attempt to create null virtual stack");
+
+ /* set up our internals */
+ real_stack = shadowing_stack;
+ vstack = new Stack();
+ real_next = 0;
+
+ /* get one element onto the virtual portion of the stack */
+ get_from_real();
+ }
+
+ /*-----------------------------------------------------------*/
+ /*--- (Access to) Instance Variables ------------------------*/
+ /*-----------------------------------------------------------*/
+
+ /** The real stack that we shadow. This is accessed when we move off
+ * the bottom of the virtual portion of the stack, but is always left
+ * unmodified.
+ */
+ protected Stack real_stack;
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** Top of stack indicator for where we leave off in the real stack.
+ * This is measured from top of stack, so 0 would indicate that no
+ * elements have been "moved" from the real to virtual stack.
+ */
+ protected int real_next;
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** The virtual top portion of the stack. This stack contains Integer
+ * objects with state numbers. This stack shadows the top portion
+ * of the real stack within the area that has been modified (via operations
+ * on the virtual stack). When this portion of the stack becomes empty we
+ * transfer elements from the underlying stack onto this stack.
+ */
+ protected Stack vstack;
+
+ /*-----------------------------------------------------------*/
+ /*--- General Methods ---------------------------------------*/
+ /*-----------------------------------------------------------*/
+
+ /** Transfer an element from the real to the virtual stack. This assumes
+ * that the virtual stack is currently empty.
+ */
+ protected void get_from_real()
+ {
+ Symbol stack_sym;
+
+ /* don't transfer if the real stack is empty */
+ if (real_next >= real_stack.size()) return;
+
+ /* get a copy of the first Symbol we have not transfered */
+ stack_sym = (Symbol)real_stack.elementAt(real_stack.size()-1-real_next);
+
+ /* record the transfer */
+ real_next++;
+
+ /* put the state number from the Symbol onto the virtual stack */
+ vstack.push(new Integer(stack_sym.parse_state));
+ }
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** Indicate whether the stack is empty. */
+ public boolean empty()
+ {
+ /* if vstack is empty then we were unable to transfer onto it and
+ the whole thing is empty. */
+ return vstack.empty();
+ }
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** Return value on the top of the stack (without popping it). */
+ public int top() throws java.lang.Exception
+ {
+ if (vstack.empty())
+ throw new Exception(
+ "Internal parser error: top() called on empty virtual stack");
+
+ return ((Integer)vstack.peek()).intValue();
+ }
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** Pop the stack. */
+ public void pop() throws java.lang.Exception
+ {
+ if (vstack.empty())
+ throw new Exception(
+ "Internal parser error: pop from empty virtual stack");
+
+ /* pop it */
+ vstack.pop();
+
+ /* if we are now empty transfer an element (if there is one) */
+ if (vstack.empty())
+ get_from_real();
+ }
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** Push a state number onto the stack. */
+ public void push(int state_num)
+ {
+ vstack.push(new Integer(state_num));
+ }
+
+ /*-----------------------------------------------------------*/
+
+}
--- /dev/null
+// Driver for parser
+
+package java_cup.simple_calc;
+
+import java_cup.simple_calc.parser;
+import java_cup.runtime.Symbol;
+
+class Main {
+
+ static boolean do_debug_parse = false;
+
+ static public void main(String[] args) throws java.io.IOException {
+
+ /* create a parsing object */
+ parser parser_obj = new parser(new scanner());
+
+ /* open input files, etc. here */
+ Symbol parse_tree = null;
+
+ try {
+ if (do_debug_parse)
+ parse_tree = parser_obj.debug_parse();
+ else
+ parse_tree = parser_obj.parse();
+ } catch (Exception e) {
+ /* do cleanup here -- possibly rethrow e */
+ } finally {
+ /* do close out here */
+ }
+ }
+}
+
--- /dev/null
+// JavaCup specification for a simple expression evaluator (w/ actions)
+
+package java_cup.simple_calc;
+
+import java_cup.runtime.*;
+
+/* Terminals (tokens returned by the scanner). */
+terminal SEMI, PLUS, MINUS, TIMES, DIVIDE, MOD;
+terminal UMINUS, LPAREN, RPAREN;
+terminal Integer NUMBER;
+
+/* Non terminals */
+non terminal Object expr_list, expr_part;
+non terminal Integer expr;
+
+/* Precedences */
+precedence left PLUS, MINUS;
+precedence left TIMES, DIVIDE, MOD;
+precedence left UMINUS, LPAREN;
+
+/* 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; :}
+ ;
--- /dev/null
+
+//----------------------------------------------------
+// The following code was generated by CUP v0.10k
+// Sun Jul 25 13:36:02 EDT 1999
+//----------------------------------------------------
+
+package java_cup.simple_calc;
+
+import java_cup.runtime.*;
+
+/** CUP v0.10k generated parser.
+ * @version Sun Jul 25 13:36:02 EDT 1999
+ */
+public class parser extends java_cup.runtime.lr_parser {
+
+ /** Default constructor. */
+ public parser() {super();}
+
+ /** Constructor which sets the default scanner. */
+ public parser(java_cup.runtime.Scanner s) {super(s);}
+
+ /** Production table. */
+ protected static final short _production_table[][] =
+ unpackFromStrings(new String[] {
+ "\000\015\000\002\003\004\000\002\002\004\000\002\003" +
+ "\003\000\002\006\002\000\002\004\005\000\002\005\005" +
+ "\000\002\005\005\000\002\005\005\000\002\005\005\000" +
+ "\002\005\005\000\002\005\003\000\002\005\004\000\002" +
+ "\005\005" });
+
+ /** Access to production table. */
+ public short[][] production_table() {return _production_table;}
+
+ /** Parse-action table. */
+ protected static final short[][] _action_table =
+ unpackFromStrings(new String[] {
+ "\000\030\000\010\006\004\013\011\015\005\001\002\000" +
+ "\010\006\004\013\011\015\005\001\002\000\020\004\ufff7" +
+ "\005\ufff7\006\ufff7\007\ufff7\010\ufff7\011\ufff7\014\ufff7\001" +
+ "\002\000\012\002\uffff\006\uffff\013\uffff\015\uffff\001\002" +
+ "\000\016\004\ufffe\005\016\006\014\007\020\010\017\011" +
+ "\013\001\002\000\012\002\027\006\004\013\011\015\005" +
+ "\001\002\000\010\006\004\013\011\015\005\001\002\000" +
+ "\016\005\016\006\014\007\020\010\017\011\013\014\015" +
+ "\001\002\000\010\006\004\013\011\015\005\001\002\000" +
+ "\010\006\004\013\011\015\005\001\002\000\020\004\ufff5" +
+ "\005\ufff5\006\ufff5\007\ufff5\010\ufff5\011\ufff5\014\ufff5\001" +
+ "\002\000\010\006\004\013\011\015\005\001\002\000\010" +
+ "\006\004\013\011\015\005\001\002\000\010\006\004\013" +
+ "\011\015\005\001\002\000\020\004\ufffa\005\ufffa\006\ufffa" +
+ "\007\ufffa\010\ufffa\011\ufffa\014\ufffa\001\002\000\020\004" +
+ "\ufff9\005\ufff9\006\ufff9\007\ufff9\010\ufff9\011\ufff9\014\ufff9" +
+ "\001\002\000\020\004\ufffc\005\ufffc\006\ufffc\007\020\010" +
+ "\017\011\013\014\ufffc\001\002\000\020\004\ufffb\005\ufffb" +
+ "\006\ufffb\007\020\010\017\011\013\014\ufffb\001\002\000" +
+ "\020\004\ufff8\005\ufff8\006\ufff8\007\ufff8\010\ufff8\011\ufff8" +
+ "\014\ufff8\001\002\000\012\002\001\006\001\013\001\015" +
+ "\001\001\002\000\004\002\000\001\002\000\004\004\031" +
+ "\001\002\000\012\002\ufffd\006\ufffd\013\ufffd\015\ufffd\001" +
+ "\002\000\020\004\ufff6\005\ufff6\006\ufff6\007\ufff6\010\ufff6" +
+ "\011\ufff6\014\ufff6\001\002" });
+
+ /** Access to parse-action table. */
+ public short[][] action_table() {return _action_table;}
+
+ /** <code>reduce_goto</code> table. */
+ protected static final short[][] _reduce_table =
+ unpackFromStrings(new String[] {
+ "\000\030\000\010\003\007\004\005\005\006\001\001\000" +
+ "\004\005\031\001\001\000\002\001\001\000\002\001\001" +
+ "\000\004\006\027\001\001\000\006\004\025\005\006\001" +
+ "\001\000\004\005\011\001\001\000\002\001\001\000\004" +
+ "\005\024\001\001\000\004\005\023\001\001\000\002\001" +
+ "\001\000\004\005\022\001\001\000\004\005\021\001\001" +
+ "\000\004\005\020\001\001\000\002\001\001\000\002\001" +
+ "\001\000\002\001\001\000\002\001\001\000\002\001\001" +
+ "\000\002\001\001\000\002\001\001\000\002\001\001\000" +
+ "\002\001\001\000\002\001\001" });
+
+ /** Access to <code>reduce_goto</code> table. */
+ public short[][] reduce_table() {return _reduce_table;}
+
+ /** Instance of action encapsulation class. */
+ protected CUP$parser$actions action_obj;
+
+ /** Action encapsulation object initializer. */
+ protected void init_actions()
+ {
+ action_obj = new CUP$parser$actions(this);
+ }
+
+ /** Invoke a user supplied parse action. */
+ public java_cup.runtime.Symbol do_action(
+ int act_num,
+ java_cup.runtime.lr_parser parser,
+ java.util.Stack stack,
+ int top)
+ throws java.lang.Exception
+ {
+ /* call code in generated class */
+ return action_obj.CUP$parser$do_action(act_num, parser, stack, top);
+ }
+
+ /** Indicates start state. */
+ public int start_state() {return 0;}
+ /** Indicates start production. */
+ public int start_production() {return 1;}
+
+ /** <code>EOF</code> Symbol index. */
+ public int EOF_sym() {return 0;}
+
+ /** <code>error</code> Symbol index. */
+ public int error_sym() {return 1;}
+
+}
+
+/** Cup generated class to encapsulate user supplied action code.*/
+class CUP$parser$actions {
+ private final parser parser;
+
+ /** Constructor */
+ CUP$parser$actions(parser parser) {
+ this.parser = parser;
+ }
+
+ /** Method with the actual generated action code. */
+ public final java_cup.runtime.Symbol CUP$parser$do_action(
+ int CUP$parser$act_num,
+ java_cup.runtime.lr_parser CUP$parser$parser,
+ java.util.Stack CUP$parser$stack,
+ int CUP$parser$top)
+ throws java.lang.Exception
+ {
+ /* Symbol object for return from actions */
+ java_cup.runtime.Symbol CUP$parser$result;
+
+ /* select the action based on the action number */
+ switch (CUP$parser$act_num)
+ {
+ /*. . . . . . . . . . . . . . . . . . . .*/
+ case 12: // expr ::= LPAREN expr RPAREN
+ {
+ Integer RESULT = null;
+ int eleft = ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-1)).left;
+ int eright = ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-1)).right;
+ Integer e = (Integer)((java_cup.runtime.Symbol) CUP$parser$stack.elementAt(CUP$parser$top-1)).value;
+ RESULT = e;
+ CUP$parser$result = new java_cup.runtime.Symbol(3/*expr*/, ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-2)).left, ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-0)).right, RESULT);
+ }
+ return CUP$parser$result;
+
+ /*. . . . . . . . . . . . . . . . . . . .*/
+ case 11: // expr ::= MINUS expr
+ {
+ Integer RESULT = null;
+ int eleft = ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-0)).left;
+ int eright = ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-0)).right;
+ Integer e = (Integer)((java_cup.runtime.Symbol) CUP$parser$stack.elementAt(CUP$parser$top-0)).value;
+ RESULT = new Integer(0 - e.intValue());
+ CUP$parser$result = new java_cup.runtime.Symbol(3/*expr*/, ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-1)).left, ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-0)).right, RESULT);
+ }
+ return CUP$parser$result;
+
+ /*. . . . . . . . . . . . . . . . . . . .*/
+ case 10: // expr ::= NUMBER
+ {
+ Integer RESULT = null;
+ int nleft = ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-0)).left;
+ int nright = ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-0)).right;
+ Integer n = (Integer)((java_cup.runtime.Symbol) CUP$parser$stack.elementAt(CUP$parser$top-0)).value;
+ RESULT = n;
+ CUP$parser$result = new java_cup.runtime.Symbol(3/*expr*/, ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-0)).left, ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-0)).right, RESULT);
+ }
+ return CUP$parser$result;
+
+ /*. . . . . . . . . . . . . . . . . . . .*/
+ case 9: // expr ::= expr MOD expr
+ {
+ Integer RESULT = null;
+ int e1left = ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-2)).left;
+ int e1right = ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-2)).right;
+ Integer e1 = (Integer)((java_cup.runtime.Symbol) CUP$parser$stack.elementAt(CUP$parser$top-2)).value;
+ int e2left = ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-0)).left;
+ int e2right = ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-0)).right;
+ Integer e2 = (Integer)((java_cup.runtime.Symbol) CUP$parser$stack.elementAt(CUP$parser$top-0)).value;
+ RESULT = new Integer(e1.intValue() % e2.intValue());
+ CUP$parser$result = new java_cup.runtime.Symbol(3/*expr*/, ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-2)).left, ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-0)).right, RESULT);
+ }
+ return CUP$parser$result;
+
+ /*. . . . . . . . . . . . . . . . . . . .*/
+ case 8: // expr ::= expr DIVIDE expr
+ {
+ Integer RESULT = null;
+ int e1left = ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-2)).left;
+ int e1right = ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-2)).right;
+ Integer e1 = (Integer)((java_cup.runtime.Symbol) CUP$parser$stack.elementAt(CUP$parser$top-2)).value;
+ int e2left = ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-0)).left;
+ int e2right = ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-0)).right;
+ Integer e2 = (Integer)((java_cup.runtime.Symbol) CUP$parser$stack.elementAt(CUP$parser$top-0)).value;
+ RESULT = new Integer(e1.intValue() / e2.intValue());
+ CUP$parser$result = new java_cup.runtime.Symbol(3/*expr*/, ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-2)).left, ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-0)).right, RESULT);
+ }
+ return CUP$parser$result;
+
+ /*. . . . . . . . . . . . . . . . . . . .*/
+ case 7: // expr ::= expr TIMES expr
+ {
+ Integer RESULT = null;
+ int e1left = ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-2)).left;
+ int e1right = ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-2)).right;
+ Integer e1 = (Integer)((java_cup.runtime.Symbol) CUP$parser$stack.elementAt(CUP$parser$top-2)).value;
+ int e2left = ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-0)).left;
+ int e2right = ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-0)).right;
+ Integer e2 = (Integer)((java_cup.runtime.Symbol) CUP$parser$stack.elementAt(CUP$parser$top-0)).value;
+ RESULT = new Integer(e1.intValue() * e2.intValue());
+ CUP$parser$result = new java_cup.runtime.Symbol(3/*expr*/, ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-2)).left, ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-0)).right, RESULT);
+ }
+ return CUP$parser$result;
+
+ /*. . . . . . . . . . . . . . . . . . . .*/
+ case 6: // expr ::= expr MINUS expr
+ {
+ Integer RESULT = null;
+ int e1left = ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-2)).left;
+ int e1right = ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-2)).right;
+ Integer e1 = (Integer)((java_cup.runtime.Symbol) CUP$parser$stack.elementAt(CUP$parser$top-2)).value;
+ int e2left = ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-0)).left;
+ int e2right = ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-0)).right;
+ Integer e2 = (Integer)((java_cup.runtime.Symbol) CUP$parser$stack.elementAt(CUP$parser$top-0)).value;
+ RESULT = new Integer(e1.intValue() - e2.intValue());
+ CUP$parser$result = new java_cup.runtime.Symbol(3/*expr*/, ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-2)).left, ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-0)).right, RESULT);
+ }
+ return CUP$parser$result;
+
+ /*. . . . . . . . . . . . . . . . . . . .*/
+ case 5: // expr ::= expr PLUS expr
+ {
+ Integer RESULT = null;
+ int e1left = ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-2)).left;
+ int e1right = ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-2)).right;
+ Integer e1 = (Integer)((java_cup.runtime.Symbol) CUP$parser$stack.elementAt(CUP$parser$top-2)).value;
+ int e2left = ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-0)).left;
+ int e2right = ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-0)).right;
+ Integer e2 = (Integer)((java_cup.runtime.Symbol) CUP$parser$stack.elementAt(CUP$parser$top-0)).value;
+ RESULT = new Integer(e1.intValue() + e2.intValue());
+ CUP$parser$result = new java_cup.runtime.Symbol(3/*expr*/, ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-2)).left, ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-0)).right, RESULT);
+ }
+ return CUP$parser$result;
+
+ /*. . . . . . . . . . . . . . . . . . . .*/
+ case 4: // expr_part ::= expr NT$0 SEMI
+ {
+ Object RESULT = null;
+ // propagate RESULT from NT$0
+ if ( ((java_cup.runtime.Symbol) CUP$parser$stack.elementAt(CUP$parser$top-1)).value != null )
+ RESULT = (Object) ((java_cup.runtime.Symbol) CUP$parser$stack.elementAt(CUP$parser$top-1)).value;
+ int eleft = ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-2)).left;
+ int eright = ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-2)).right;
+ Integer e = (Integer)((java_cup.runtime.Symbol) CUP$parser$stack.elementAt(CUP$parser$top-2)).value;
+
+ CUP$parser$result = new java_cup.runtime.Symbol(2/*expr_part*/, ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-2)).left, ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-0)).right, RESULT);
+ }
+ return CUP$parser$result;
+
+ /*. . . . . . . . . . . . . . . . . . . .*/
+ case 3: // NT$0 ::=
+ {
+ Object RESULT = null;
+ int eleft = ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-0)).left;
+ int eright = ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-0)).right;
+ Integer e = (Integer)((java_cup.runtime.Symbol) CUP$parser$stack.elementAt(CUP$parser$top-0)).value;
+ System.out.println("= " + e);
+ CUP$parser$result = new java_cup.runtime.Symbol(4/*NT$0*/, ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-0)).right, ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-0)).right, RESULT);
+ }
+ return CUP$parser$result;
+
+ /*. . . . . . . . . . . . . . . . . . . .*/
+ case 2: // expr_list ::= expr_part
+ {
+ Object RESULT = null;
+
+ CUP$parser$result = new java_cup.runtime.Symbol(1/*expr_list*/, ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-0)).left, ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-0)).right, RESULT);
+ }
+ return CUP$parser$result;
+
+ /*. . . . . . . . . . . . . . . . . . . .*/
+ case 1: // $START ::= expr_list EOF
+ {
+ Object RESULT = null;
+ int start_valleft = ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-1)).left;
+ int start_valright = ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-1)).right;
+ Object start_val = (Object)((java_cup.runtime.Symbol) CUP$parser$stack.elementAt(CUP$parser$top-1)).value;
+ RESULT = start_val;
+ CUP$parser$result = new java_cup.runtime.Symbol(0/*$START*/, ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-1)).left, ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-0)).right, RESULT);
+ }
+ /* ACCEPT */
+ CUP$parser$parser.done_parsing();
+ return CUP$parser$result;
+
+ /*. . . . . . . . . . . . . . . . . . . .*/
+ case 0: // expr_list ::= expr_list expr_part
+ {
+ Object RESULT = null;
+
+ CUP$parser$result = new java_cup.runtime.Symbol(1/*expr_list*/, ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-1)).left, ((java_cup.runtime.Symbol)CUP$parser$stack.elementAt(CUP$parser$top-0)).right, RESULT);
+ }
+ return CUP$parser$result;
+
+ /* . . . . . .*/
+ default:
+ throw new Exception(
+ "Invalid action number found in internal parse table");
+
+ }
+ }
+}
+
--- /dev/null
+// Simple Example Scanner Class
+
+package java_cup.simple_calc;
+
+import java_cup.runtime.Symbol;
+
+public class scanner implements java_cup.runtime.Scanner {
+ final java.io.InputStream instream;
+
+ public scanner(java.io.InputStream is) throws java.io.IOException {
+ instream = is;
+ }
+ public scanner() throws java.io.IOException { this(System.in); }
+
+ /* single lookahead character */
+ protected int next_char = -2;
+
+ /* advance input by one character */
+ protected void advance()
+ throws java.io.IOException
+ { next_char = instream.read(); }
+
+ /* initialize the scanner */
+ private void init()
+ throws java.io.IOException
+ { advance(); }
+
+ /* recognize and return the next complete token */
+ public Symbol next_token()
+ throws java.io.IOException
+ {
+ if (next_char==-2) init(); // set stuff up first time we are called.
+ 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 new Symbol(sym.NUMBER, new Integer(i_val));
+
+ case ';': advance(); return new Symbol(sym.SEMI);
+ case '+': advance(); return new Symbol(sym.PLUS);
+ case '-': advance(); return new Symbol(sym.MINUS);
+ case '*': advance(); return new Symbol(sym.TIMES);
+ case '/': advance(); return new Symbol(sym.DIVIDE);
+ case '%': advance(); return new Symbol(sym.MOD);
+ case '(': advance(); return new Symbol(sym.LPAREN);
+ case ')': advance(); return new Symbol(sym.RPAREN);
+
+ case -1: return new Symbol(sym.EOF);
+
+ default:
+ /* in this simple scanner we just ignore everything else */
+ advance();
+ break;
+ }
+ }
+};
--- /dev/null
+
+//----------------------------------------------------
+// The following code was generated by CUP v0.10k
+// Sun Jul 25 13:36:02 EDT 1999
+//----------------------------------------------------
+
+package java_cup.simple_calc;
+
+/** CUP generated class containing symbol constants. */
+public class sym {
+ /* terminals */
+ public static final int SEMI = 2;
+ public static final int EOF = 0;
+ public static final int DIVIDE = 6;
+ public static final int NUMBER = 11;
+ public static final int error = 1;
+ public static final int UMINUS = 8;
+ public static final int MINUS = 4;
+ public static final int TIMES = 5;
+ public static final int LPAREN = 9;
+ public static final int RPAREN = 10;
+ public static final int MOD = 7;
+ public static final int PLUS = 3;
+}
+