mirror of
https://github.com/marcin-szczepanski/jFuzzyLogic.git
synced 2024-12-18 16:35:27 +01:00
Moving code to GitHub
This commit is contained in:
parent
6657143f71
commit
5588192716
165
LICENSE
Normal file
165
LICENSE
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
|
||||||
|
This version of the GNU Lesser General Public License incorporates
|
||||||
|
the terms and conditions of version 3 of the GNU General Public
|
||||||
|
License, supplemented by the additional permissions listed below.
|
||||||
|
|
||||||
|
0. Additional Definitions.
|
||||||
|
|
||||||
|
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||||
|
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||||
|
General Public License.
|
||||||
|
|
||||||
|
"The Library" refers to a covered work governed by this License,
|
||||||
|
other than an Application or a Combined Work as defined below.
|
||||||
|
|
||||||
|
An "Application" is any work that makes use of an interface provided
|
||||||
|
by the Library, but which is not otherwise based on the Library.
|
||||||
|
Defining a subclass of a class defined by the Library is deemed a mode
|
||||||
|
of using an interface provided by the Library.
|
||||||
|
|
||||||
|
A "Combined Work" is a work produced by combining or linking an
|
||||||
|
Application with the Library. The particular version of the Library
|
||||||
|
with which the Combined Work was made is also called the "Linked
|
||||||
|
Version".
|
||||||
|
|
||||||
|
The "Minimal Corresponding Source" for a Combined Work means the
|
||||||
|
Corresponding Source for the Combined Work, excluding any source code
|
||||||
|
for portions of the Combined Work that, considered in isolation, are
|
||||||
|
based on the Application, and not on the Linked Version.
|
||||||
|
|
||||||
|
The "Corresponding Application Code" for a Combined Work means the
|
||||||
|
object code and/or source code for the Application, including any data
|
||||||
|
and utility programs needed for reproducing the Combined Work from the
|
||||||
|
Application, but excluding the System Libraries of the Combined Work.
|
||||||
|
|
||||||
|
1. Exception to Section 3 of the GNU GPL.
|
||||||
|
|
||||||
|
You may convey a covered work under sections 3 and 4 of this License
|
||||||
|
without being bound by section 3 of the GNU GPL.
|
||||||
|
|
||||||
|
2. Conveying Modified Versions.
|
||||||
|
|
||||||
|
If you modify a copy of the Library, and, in your modifications, a
|
||||||
|
facility refers to a function or data to be supplied by an Application
|
||||||
|
that uses the facility (other than as an argument passed when the
|
||||||
|
facility is invoked), then you may convey a copy of the modified
|
||||||
|
version:
|
||||||
|
|
||||||
|
a) under this License, provided that you make a good faith effort to
|
||||||
|
ensure that, in the event an Application does not supply the
|
||||||
|
function or data, the facility still operates, and performs
|
||||||
|
whatever part of its purpose remains meaningful, or
|
||||||
|
|
||||||
|
b) under the GNU GPL, with none of the additional permissions of
|
||||||
|
this License applicable to that copy.
|
||||||
|
|
||||||
|
3. Object Code Incorporating Material from Library Header Files.
|
||||||
|
|
||||||
|
The object code form of an Application may incorporate material from
|
||||||
|
a header file that is part of the Library. You may convey such object
|
||||||
|
code under terms of your choice, provided that, if the incorporated
|
||||||
|
material is not limited to numerical parameters, data structure
|
||||||
|
layouts and accessors, or small macros, inline functions and templates
|
||||||
|
(ten or fewer lines in length), you do both of the following:
|
||||||
|
|
||||||
|
a) Give prominent notice with each copy of the object code that the
|
||||||
|
Library is used in it and that the Library and its use are
|
||||||
|
covered by this License.
|
||||||
|
|
||||||
|
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||||
|
document.
|
||||||
|
|
||||||
|
4. Combined Works.
|
||||||
|
|
||||||
|
You may convey a Combined Work under terms of your choice that,
|
||||||
|
taken together, effectively do not restrict modification of the
|
||||||
|
portions of the Library contained in the Combined Work and reverse
|
||||||
|
engineering for debugging such modifications, if you also do each of
|
||||||
|
the following:
|
||||||
|
|
||||||
|
a) Give prominent notice with each copy of the Combined Work that
|
||||||
|
the Library is used in it and that the Library and its use are
|
||||||
|
covered by this License.
|
||||||
|
|
||||||
|
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||||
|
document.
|
||||||
|
|
||||||
|
c) For a Combined Work that displays copyright notices during
|
||||||
|
execution, include the copyright notice for the Library among
|
||||||
|
these notices, as well as a reference directing the user to the
|
||||||
|
copies of the GNU GPL and this license document.
|
||||||
|
|
||||||
|
d) Do one of the following:
|
||||||
|
|
||||||
|
0) Convey the Minimal Corresponding Source under the terms of this
|
||||||
|
License, and the Corresponding Application Code in a form
|
||||||
|
suitable for, and under terms that permit, the user to
|
||||||
|
recombine or relink the Application with a modified version of
|
||||||
|
the Linked Version to produce a modified Combined Work, in the
|
||||||
|
manner specified by section 6 of the GNU GPL for conveying
|
||||||
|
Corresponding Source.
|
||||||
|
|
||||||
|
1) Use a suitable shared library mechanism for linking with the
|
||||||
|
Library. A suitable mechanism is one that (a) uses at run time
|
||||||
|
a copy of the Library already present on the user's computer
|
||||||
|
system, and (b) will operate properly with a modified version
|
||||||
|
of the Library that is interface-compatible with the Linked
|
||||||
|
Version.
|
||||||
|
|
||||||
|
e) Provide Installation Information, but only if you would otherwise
|
||||||
|
be required to provide such information under section 6 of the
|
||||||
|
GNU GPL, and only to the extent that such information is
|
||||||
|
necessary to install and execute a modified version of the
|
||||||
|
Combined Work produced by recombining or relinking the
|
||||||
|
Application with a modified version of the Linked Version. (If
|
||||||
|
you use option 4d0, the Installation Information must accompany
|
||||||
|
the Minimal Corresponding Source and Corresponding Application
|
||||||
|
Code. If you use option 4d1, you must provide the Installation
|
||||||
|
Information in the manner specified by section 6 of the GNU GPL
|
||||||
|
for conveying Corresponding Source.)
|
||||||
|
|
||||||
|
5. Combined Libraries.
|
||||||
|
|
||||||
|
You may place library facilities that are a work based on the
|
||||||
|
Library side by side in a single library together with other library
|
||||||
|
facilities that are not Applications and are not covered by this
|
||||||
|
License, and convey such a combined library under terms of your
|
||||||
|
choice, if you do both of the following:
|
||||||
|
|
||||||
|
a) Accompany the combined library with a copy of the same work based
|
||||||
|
on the Library, uncombined with any other library facilities,
|
||||||
|
conveyed under the terms of this License.
|
||||||
|
|
||||||
|
b) Give prominent notice with the combined library that part of it
|
||||||
|
is a work based on the Library, and explaining where to find the
|
||||||
|
accompanying uncombined form of the same work.
|
||||||
|
|
||||||
|
6. Revised Versions of the GNU Lesser General Public License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the GNU Lesser 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
|
||||||
|
Library as you received it specifies that a certain numbered version
|
||||||
|
of the GNU Lesser General Public License "or any later version"
|
||||||
|
applies to it, you have the option of following the terms and
|
||||||
|
conditions either of that published version or of any later version
|
||||||
|
published by the Free Software Foundation. If the Library as you
|
||||||
|
received it does not specify a version number of the GNU Lesser
|
||||||
|
General Public License, you may choose any version of the GNU Lesser
|
||||||
|
General Public License ever published by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Library as you received it specifies that a proxy can decide
|
||||||
|
whether future versions of the GNU Lesser General Public License shall
|
||||||
|
apply, that proxy's public statement of acceptance of any version is
|
||||||
|
permanent authorization for you to choose that version for the
|
||||||
|
Library.
|
3
MANIFEST.MF
Normal file
3
MANIFEST.MF
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Manifest-Version: 1.0
|
||||||
|
Main-Class: net.sourceforge.jFuzzyLogic.JFuzzyLogic
|
||||||
|
|
4
README.txt
Normal file
4
README.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
Documentation
|
||||||
|
|
||||||
|
http://jfuzzylogic.sourceforge.net
|
73
README_release.txt
Normal file
73
README_release.txt
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
|
||||||
|
|
||||||
|
Release instructions
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
|
||||||
|
Main JAR file
|
||||||
|
-------------
|
||||||
|
|
||||||
|
1) Create jFuzzyLogic.jar file
|
||||||
|
|
||||||
|
Eclipse -> Package explorer -> jFuzzyLogic -> Select file jFuzzyLogic.jardesc -> Right click "Create JAR"
|
||||||
|
|
||||||
|
2) Upload JAR file SourceForge (use sf.net menu)
|
||||||
|
|
||||||
|
|
||||||
|
HTML pages
|
||||||
|
----------
|
||||||
|
|
||||||
|
1) Upload HTML pages to SourceForge
|
||||||
|
|
||||||
|
cd ~/workspace/jFuzzyLogic
|
||||||
|
scp index.html pcingola,jfuzzylogic@frs.sourceforge.net:htdocs/
|
||||||
|
|
||||||
|
cd ~/workspace/jFuzzyLogic/html
|
||||||
|
scp *.{html,css} pcingola,jfuzzylogic@frs.sourceforge.net:htdocs/html
|
||||||
|
scp images/*.png pcingola,jfuzzylogic@frs.sourceforge.net:htdocs/html/images/
|
||||||
|
scp videos/*.swf pcingola,jfuzzylogic@frs.sourceforge.net:htdocs/html/videos/
|
||||||
|
scp -R assets dist fcl pdf pcingola,jfuzzylogic@frs.sourceforge.net:htdocs/html/
|
||||||
|
|
||||||
|
Eclipse plugin
|
||||||
|
--------------
|
||||||
|
|
||||||
|
1) Create small jFuzzyLogic.jar file (it's better to use a small file and not the big JAR file that has all source files)
|
||||||
|
|
||||||
|
cd ~/workspace/jFuzzyLogic/
|
||||||
|
ant
|
||||||
|
|
||||||
|
# Check the JAR file
|
||||||
|
cd
|
||||||
|
java -jar jFuzzyLogic.jar
|
||||||
|
|
||||||
|
|
||||||
|
2) Copy jFuzzyLogic.jar file to UI project
|
||||||
|
|
||||||
|
cp jFuzzyLogic.jar net.sourceforge.jFuzzyLogic.Fcl.ui/lib/jFuzzyLogic.jar
|
||||||
|
|
||||||
|
3) Build eclipse update site
|
||||||
|
|
||||||
|
In Eclipse:
|
||||||
|
- In package explorer, refresh all net.sourceforge.jFuzzyLogic.Fcl.* projects
|
||||||
|
|
||||||
|
- Open the net.sourceforge.jFuzzyLogic.Fcl.updateSite project
|
||||||
|
- Delete the contents of the 'plugins' 'features' and dir
|
||||||
|
|
||||||
|
cd ~/workspace/net.sourceforge.jFuzzyLogic.Fcl.updateSite
|
||||||
|
rm -vf *.jar plugins/*.jar features/*.jar
|
||||||
|
|
||||||
|
- Open site.xml file
|
||||||
|
- Go to "Site Map" tab
|
||||||
|
|
||||||
|
- Open jFuzzyLogic category and remove the 'feature' (called something like "net.sourceforge.jFuzzyLogic.Fcl.sdk_1.1.0.201212101535.jar"
|
||||||
|
and add it again (just to be sure)
|
||||||
|
|
||||||
|
- Click the "Buid All" button
|
||||||
|
|
||||||
|
- Refresh the project (you should see the JAR files in the plugin folders now).
|
||||||
|
|
||||||
|
4) Upload Eclipse plugin files to SourceForge (Eclipse update site)
|
||||||
|
|
||||||
|
cd ~/workspace/net.sourceforge.jFuzzyLogic.Fcl.updateSite
|
||||||
|
scp -r . pcingola,jfuzzylogic@frs.sourceforge.net:htdocs/eclipse/
|
||||||
|
|
659
antlr_3_1_source/Tool.java
Normal file
659
antlr_3_1_source/Tool.java
Normal file
@ -0,0 +1,659 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2008 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.antlr;
|
||||||
|
|
||||||
|
import org.antlr.analysis.*;
|
||||||
|
import org.antlr.codegen.CodeGenerator;
|
||||||
|
import org.antlr.runtime.misc.Stats;
|
||||||
|
import org.antlr.tool.*;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/** The main ANTLR entry point. Read a grammar and generate a parser. */
|
||||||
|
public class Tool {
|
||||||
|
public static final String VERSION = "3.1";
|
||||||
|
|
||||||
|
public static final String UNINITIALIZED_DIR = "<unset-dir>";
|
||||||
|
|
||||||
|
// Input parameters / option
|
||||||
|
|
||||||
|
protected List grammarFileNames = new ArrayList();
|
||||||
|
protected boolean generate_NFA_dot = false;
|
||||||
|
protected boolean generate_DFA_dot = false;
|
||||||
|
protected String outputDirectory = UNINITIALIZED_DIR;
|
||||||
|
protected String libDirectory = ".";
|
||||||
|
protected boolean debug = false;
|
||||||
|
protected boolean trace = false;
|
||||||
|
protected boolean profile = false;
|
||||||
|
protected boolean report = false;
|
||||||
|
protected boolean printGrammar = false;
|
||||||
|
protected boolean depend = false;
|
||||||
|
protected boolean forceAllFilesToOutputDir = false;
|
||||||
|
protected boolean deleteTempLexer = true;
|
||||||
|
|
||||||
|
// the internal options are for my use on the command line during dev
|
||||||
|
|
||||||
|
public static boolean internalOption_PrintGrammarTree = false;
|
||||||
|
public static boolean internalOption_PrintDFA = false;
|
||||||
|
public static boolean internalOption_ShowNFAConfigsInDFA = false;
|
||||||
|
public static boolean internalOption_watchNFAConversion = false;
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
ErrorManager.info("ANTLR Parser Generator Version " +
|
||||||
|
VERSION + " (August 12, 2008) 1989-2008");
|
||||||
|
Tool antlr = new Tool(args);
|
||||||
|
antlr.process();
|
||||||
|
if ( ErrorManager.getNumErrors() > 0 ) {
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Tool() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Tool(String[] args) {
|
||||||
|
processArgs(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void processArgs(String[] args) {
|
||||||
|
if ( args==null || args.length==0 ) {
|
||||||
|
help();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < args.length; i++) {
|
||||||
|
if (args[i].equals("-o") || args[i].equals("-fo")) {
|
||||||
|
if (i + 1 >= args.length) {
|
||||||
|
System.err.println("missing output directory with -fo/-o option; ignoring");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if ( args[i].equals("-fo") ) { // force output into dir
|
||||||
|
forceAllFilesToOutputDir = true;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
outputDirectory = args[i];
|
||||||
|
if ( outputDirectory.endsWith("/") ||
|
||||||
|
outputDirectory.endsWith("\\") )
|
||||||
|
{
|
||||||
|
outputDirectory =
|
||||||
|
outputDirectory.substring(0,outputDirectory.length()-1);
|
||||||
|
}
|
||||||
|
File outDir = new File(outputDirectory);
|
||||||
|
if( outDir.exists() && !outDir.isDirectory() ) {
|
||||||
|
ErrorManager.error(ErrorManager.MSG_OUTPUT_DIR_IS_FILE,outputDirectory);
|
||||||
|
libDirectory = ".";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (args[i].equals("-lib")) {
|
||||||
|
if (i + 1 >= args.length) {
|
||||||
|
System.err.println("missing library directory with -lib option; ignoring");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
i++;
|
||||||
|
libDirectory = args[i];
|
||||||
|
if ( libDirectory.endsWith("/") ||
|
||||||
|
libDirectory.endsWith("\\") )
|
||||||
|
{
|
||||||
|
libDirectory =
|
||||||
|
libDirectory.substring(0,libDirectory.length()-1);
|
||||||
|
}
|
||||||
|
File outDir = new File(libDirectory);
|
||||||
|
if( !outDir.exists() ) {
|
||||||
|
ErrorManager.error(ErrorManager.MSG_DIR_NOT_FOUND,libDirectory);
|
||||||
|
libDirectory = ".";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (args[i].equals("-nfa")) {
|
||||||
|
generate_NFA_dot=true;
|
||||||
|
}
|
||||||
|
else if (args[i].equals("-dfa")) {
|
||||||
|
generate_DFA_dot=true;
|
||||||
|
}
|
||||||
|
else if (args[i].equals("-debug")) {
|
||||||
|
debug=true;
|
||||||
|
}
|
||||||
|
else if (args[i].equals("-trace")) {
|
||||||
|
trace=true;
|
||||||
|
}
|
||||||
|
else if (args[i].equals("-report")) {
|
||||||
|
report=true;
|
||||||
|
}
|
||||||
|
else if (args[i].equals("-profile")) {
|
||||||
|
profile=true;
|
||||||
|
}
|
||||||
|
else if (args[i].equals("-print")) {
|
||||||
|
printGrammar = true;
|
||||||
|
}
|
||||||
|
else if (args[i].equals("-depend")) {
|
||||||
|
depend=true;
|
||||||
|
}
|
||||||
|
else if (args[i].equals("-message-format")) {
|
||||||
|
if (i + 1 >= args.length) {
|
||||||
|
System.err.println("missing output format with -message-format option; using default");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
i++;
|
||||||
|
ErrorManager.setFormat(args[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (args[i].equals("-Xgrtree")) {
|
||||||
|
internalOption_PrintGrammarTree=true; // print grammar tree
|
||||||
|
}
|
||||||
|
else if (args[i].equals("-Xdfa")) {
|
||||||
|
internalOption_PrintDFA=true;
|
||||||
|
}
|
||||||
|
else if (args[i].equals("-Xnoprune")) {
|
||||||
|
DFAOptimizer.PRUNE_EBNF_EXIT_BRANCHES=false;
|
||||||
|
}
|
||||||
|
else if (args[i].equals("-Xnocollapse")) {
|
||||||
|
DFAOptimizer.COLLAPSE_ALL_PARALLEL_EDGES=false;
|
||||||
|
}
|
||||||
|
else if (args[i].equals("-Xdbgconversion")) {
|
||||||
|
NFAToDFAConverter.debug = true;
|
||||||
|
}
|
||||||
|
else if (args[i].equals("-Xmultithreaded")) {
|
||||||
|
NFAToDFAConverter.SINGLE_THREADED_NFA_CONVERSION = false;
|
||||||
|
}
|
||||||
|
else if (args[i].equals("-Xnomergestopstates")) {
|
||||||
|
DFAOptimizer.MERGE_STOP_STATES = false;
|
||||||
|
}
|
||||||
|
else if (args[i].equals("-Xdfaverbose")) {
|
||||||
|
internalOption_ShowNFAConfigsInDFA = true;
|
||||||
|
}
|
||||||
|
else if (args[i].equals("-Xwatchconversion")) {
|
||||||
|
internalOption_watchNFAConversion = true;
|
||||||
|
}
|
||||||
|
else if (args[i].equals("-XdbgST")) {
|
||||||
|
CodeGenerator.EMIT_TEMPLATE_DELIMITERS = true;
|
||||||
|
}
|
||||||
|
else if (args[i].equals("-Xmaxinlinedfastates")) {
|
||||||
|
if (i + 1 >= args.length) {
|
||||||
|
System.err.println("missing max inline dfa states -Xmaxinlinedfastates option; ignoring");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
i++;
|
||||||
|
CodeGenerator.MAX_ACYCLIC_DFA_STATES_INLINE = Integer.parseInt(args[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (args[i].equals("-Xm")) {
|
||||||
|
if (i + 1 >= args.length) {
|
||||||
|
System.err.println("missing max recursion with -Xm option; ignoring");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
i++;
|
||||||
|
NFAContext.MAX_SAME_RULE_INVOCATIONS_PER_NFA_CONFIG_STACK = Integer.parseInt(args[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (args[i].equals("-Xmaxdfaedges")) {
|
||||||
|
if (i + 1 >= args.length) {
|
||||||
|
System.err.println("missing max number of edges with -Xmaxdfaedges option; ignoring");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
i++;
|
||||||
|
DFA.MAX_STATE_TRANSITIONS_FOR_TABLE = Integer.parseInt(args[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (args[i].equals("-Xconversiontimeout")) {
|
||||||
|
if (i + 1 >= args.length) {
|
||||||
|
System.err.println("missing max time in ms -Xconversiontimeout option; ignoring");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
i++;
|
||||||
|
DFA.MAX_TIME_PER_DFA_CREATION = Integer.parseInt(args[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (args[i].equals("-Xnfastates")) {
|
||||||
|
DecisionProbe.verbose=true;
|
||||||
|
}
|
||||||
|
else if (args[i].equals("-X")) {
|
||||||
|
Xhelp();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (args[i].charAt(0) != '-') {
|
||||||
|
// Must be the grammar file
|
||||||
|
grammarFileNames.add(args[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
protected void checkForInvalidArguments(String[] args, BitSet cmdLineArgValid) {
|
||||||
|
// check for invalid command line args
|
||||||
|
for (int a = 0; a < args.length; a++) {
|
||||||
|
if (!cmdLineArgValid.member(a)) {
|
||||||
|
System.err.println("invalid command-line argument: " + args[a] + "; ignored");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
public void process() {
|
||||||
|
int numFiles = grammarFileNames.size();
|
||||||
|
boolean exceptionWhenWritingLexerFile = false;
|
||||||
|
String lexerGrammarFileName = null; // necessary at this scope to have access in the catch below
|
||||||
|
for (int i = 0; i < numFiles; i++) {
|
||||||
|
String grammarFileName = (String) grammarFileNames.get(i);
|
||||||
|
if ( numFiles > 1 && !depend ) {
|
||||||
|
System.out.println(grammarFileName);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if ( depend ) {
|
||||||
|
BuildDependencyGenerator dep =
|
||||||
|
new BuildDependencyGenerator(this, grammarFileName);
|
||||||
|
List outputFiles = dep.getGeneratedFileList();
|
||||||
|
List dependents = dep.getDependenciesFileList();
|
||||||
|
//System.out.println("output: "+outputFiles);
|
||||||
|
//System.out.println("dependents: "+dependents);
|
||||||
|
System.out.println(dep.getDependencies());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Grammar grammar = getRootGrammar(grammarFileName);
|
||||||
|
// we now have all grammars read in as ASTs
|
||||||
|
// (i.e., root and all delegates)
|
||||||
|
grammar.composite.assignTokenTypes();
|
||||||
|
grammar.composite.defineGrammarSymbols();
|
||||||
|
grammar.composite.createNFAs();
|
||||||
|
|
||||||
|
generateRecognizer(grammar);
|
||||||
|
|
||||||
|
if ( printGrammar ) {
|
||||||
|
grammar.printGrammar(System.out);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( report ) {
|
||||||
|
GrammarReport report = new GrammarReport(grammar);
|
||||||
|
System.out.println(report.toString());
|
||||||
|
// print out a backtracking report too (that is not encoded into log)
|
||||||
|
System.out.println(report.getBacktrackingReport());
|
||||||
|
// same for aborted NFA->DFA conversions
|
||||||
|
System.out.println(report.getAnalysisTimeoutReport());
|
||||||
|
}
|
||||||
|
if ( profile ) {
|
||||||
|
GrammarReport report = new GrammarReport(grammar);
|
||||||
|
Stats.writeReport(GrammarReport.GRAMMAR_STATS_FILENAME,
|
||||||
|
report.toNotifyString());
|
||||||
|
}
|
||||||
|
|
||||||
|
// now handle the lexer if one was created for a merged spec
|
||||||
|
String lexerGrammarStr = grammar.getLexerGrammar();
|
||||||
|
//System.out.println("lexer grammar:\n"+lexerGrammarStr);
|
||||||
|
if ( grammar.type==Grammar.COMBINED && lexerGrammarStr!=null ) {
|
||||||
|
lexerGrammarFileName = grammar.getImplicitlyGeneratedLexerFileName();
|
||||||
|
try {
|
||||||
|
Writer w = getOutputFile(grammar,lexerGrammarFileName);
|
||||||
|
w.write(lexerGrammarStr);
|
||||||
|
w.close();
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
// emit different error message when creating the implicit lexer fails
|
||||||
|
// due to write permission error
|
||||||
|
exceptionWhenWritingLexerFile = true;
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
StringReader sr = new StringReader(lexerGrammarStr);
|
||||||
|
Grammar lexerGrammar = new Grammar();
|
||||||
|
lexerGrammar.composite.watchNFAConversion = internalOption_watchNFAConversion;
|
||||||
|
lexerGrammar.implicitLexer = true;
|
||||||
|
lexerGrammar.setTool(this);
|
||||||
|
File lexerGrammarFullFile =
|
||||||
|
new File(getFileDirectory(lexerGrammarFileName),lexerGrammarFileName);
|
||||||
|
lexerGrammar.setFileName(lexerGrammarFullFile.toString());
|
||||||
|
|
||||||
|
lexerGrammar.importTokenVocabulary(grammar);
|
||||||
|
lexerGrammar.parseAndBuildAST(sr);
|
||||||
|
|
||||||
|
sr.close();
|
||||||
|
|
||||||
|
lexerGrammar.composite.assignTokenTypes();
|
||||||
|
lexerGrammar.composite.defineGrammarSymbols();
|
||||||
|
lexerGrammar.composite.createNFAs();
|
||||||
|
|
||||||
|
generateRecognizer(lexerGrammar);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
// make sure we clean up
|
||||||
|
if ( deleteTempLexer ) {
|
||||||
|
File outputDir = getOutputDirectory(lexerGrammarFileName);
|
||||||
|
File outputFile = new File(outputDir, lexerGrammarFileName);
|
||||||
|
outputFile.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
if (exceptionWhenWritingLexerFile) {
|
||||||
|
ErrorManager.error(ErrorManager.MSG_CANNOT_WRITE_FILE,
|
||||||
|
lexerGrammarFileName, e);
|
||||||
|
} else {
|
||||||
|
ErrorManager.error(ErrorManager.MSG_CANNOT_OPEN_FILE,
|
||||||
|
grammarFileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
ErrorManager.error(ErrorManager.MSG_INTERNAL_ERROR, grammarFileName, e);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
finally {
|
||||||
|
System.out.println("creates="+ Interval.creates);
|
||||||
|
System.out.println("hits="+ Interval.hits);
|
||||||
|
System.out.println("misses="+ Interval.misses);
|
||||||
|
System.out.println("outOfRange="+ Interval.outOfRange);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get a grammar mentioned on the command-line and any delegates */
|
||||||
|
public Grammar getRootGrammar(String grammarFileName)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
//StringTemplate.setLintMode(true);
|
||||||
|
// grammars mentioned on command line are either roots or single grammars.
|
||||||
|
// create the necessary composite in case it's got delegates; even
|
||||||
|
// single grammar needs it to get token types.
|
||||||
|
CompositeGrammar composite = new CompositeGrammar();
|
||||||
|
Grammar grammar = new Grammar(this,grammarFileName,composite);
|
||||||
|
composite.setDelegationRoot(grammar);
|
||||||
|
FileReader fr = null;
|
||||||
|
fr = new FileReader(grammarFileName);
|
||||||
|
BufferedReader br = new BufferedReader(fr);
|
||||||
|
grammar.parseAndBuildAST(br);
|
||||||
|
composite.watchNFAConversion = internalOption_watchNFAConversion;
|
||||||
|
br.close();
|
||||||
|
fr.close();
|
||||||
|
return grammar;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Create NFA, DFA and generate code for grammar.
|
||||||
|
* Create NFA for any delegates first. Once all NFA are created,
|
||||||
|
* it's ok to create DFA, which must check for left-recursion. That check
|
||||||
|
* is done by walking the full NFA, which therefore must be complete.
|
||||||
|
* After all NFA, comes DFA conversion for root grammar then code gen for
|
||||||
|
* root grammar. DFA and code gen for delegates comes next.
|
||||||
|
*/
|
||||||
|
protected void generateRecognizer(Grammar grammar) {
|
||||||
|
String language = (String)grammar.getOption("language");
|
||||||
|
if ( language!=null ) {
|
||||||
|
CodeGenerator generator = new CodeGenerator(this, grammar, language);
|
||||||
|
grammar.setCodeGenerator(generator);
|
||||||
|
generator.setDebug(debug);
|
||||||
|
generator.setProfile(profile);
|
||||||
|
generator.setTrace(trace);
|
||||||
|
|
||||||
|
// generate NFA early in case of crash later (for debugging)
|
||||||
|
if ( generate_NFA_dot ) {
|
||||||
|
generateNFAs(grammar);
|
||||||
|
}
|
||||||
|
|
||||||
|
// GENERATE CODE
|
||||||
|
generator.genRecognizer();
|
||||||
|
|
||||||
|
if ( generate_DFA_dot ) {
|
||||||
|
generateDFAs(grammar);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Grammar> delegates = grammar.getDirectDelegates();
|
||||||
|
for (int i = 0; delegates!=null && i < delegates.size(); i++) {
|
||||||
|
Grammar delegate = (Grammar)delegates.get(i);
|
||||||
|
if ( delegate!=grammar ) { // already processing this one
|
||||||
|
generateRecognizer(delegate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void generateDFAs(Grammar g) {
|
||||||
|
for (int d=1; d<=g.getNumberOfDecisions(); d++) {
|
||||||
|
DFA dfa = g.getLookaheadDFA(d);
|
||||||
|
if ( dfa==null ) {
|
||||||
|
continue; // not there for some reason, ignore
|
||||||
|
}
|
||||||
|
DOTGenerator dotGenerator = new DOTGenerator(g);
|
||||||
|
String dot = dotGenerator.getDOT( dfa.startState );
|
||||||
|
String dotFileName = g.name+"."+"dec-"+d;
|
||||||
|
if ( g.implicitLexer ) {
|
||||||
|
dotFileName = g.name+Grammar.grammarTypeToFileNameSuffix[g.type]+"."+"dec-"+d;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
writeDOTFile(g, dotFileName, dot);
|
||||||
|
}
|
||||||
|
catch(IOException ioe) {
|
||||||
|
ErrorManager.error(ErrorManager.MSG_CANNOT_GEN_DOT_FILE,
|
||||||
|
dotFileName,
|
||||||
|
ioe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void generateNFAs(Grammar g) {
|
||||||
|
DOTGenerator dotGenerator = new DOTGenerator(g);
|
||||||
|
Collection rules = g.getAllImportedRules();
|
||||||
|
rules.addAll(g.getRules());
|
||||||
|
|
||||||
|
for (Iterator itr = rules.iterator(); itr.hasNext();) {
|
||||||
|
Rule r = (Rule) itr.next();
|
||||||
|
try {
|
||||||
|
String dot = dotGenerator.getDOT(r.startState);
|
||||||
|
if ( dot!=null ) {
|
||||||
|
writeDOTFile(g, r, dot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException ioe) {
|
||||||
|
ErrorManager.error(ErrorManager.MSG_CANNOT_WRITE_FILE, ioe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void writeDOTFile(Grammar g, Rule r, String dot) throws IOException {
|
||||||
|
writeDOTFile(g, r.grammar.name+"."+r.name, dot);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void writeDOTFile(Grammar g, String name, String dot) throws IOException {
|
||||||
|
Writer fw = getOutputFile(g, name+".dot");
|
||||||
|
fw.write(dot);
|
||||||
|
fw.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void help() {
|
||||||
|
System.err.println("usage: java org.antlr.Tool [args] file.g [file2.g file3.g ...]");
|
||||||
|
System.err.println(" -o outputDir specify output directory where all output is generated");
|
||||||
|
System.err.println(" -fo outputDir same as -o but force even files with relative paths to dir");
|
||||||
|
System.err.println(" -lib dir specify location of token files");
|
||||||
|
System.err.println(" -depend generate file dependencies");
|
||||||
|
System.err.println(" -report print out a report about the grammar(s) processed");
|
||||||
|
System.err.println(" -print print out the grammar without actions");
|
||||||
|
System.err.println(" -debug generate a parser that emits debugging events");
|
||||||
|
System.err.println(" -profile generate a parser that computes profiling information");
|
||||||
|
System.err.println(" -nfa generate an NFA for each rule");
|
||||||
|
System.err.println(" -dfa generate a DFA for each decision point");
|
||||||
|
System.err.println(" -message-format name specify output style for messages");
|
||||||
|
System.err.println(" -X display extended argument list");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Xhelp() {
|
||||||
|
System.err.println(" -Xgrtree print the grammar AST");
|
||||||
|
System.err.println(" -Xdfa print DFA as text ");
|
||||||
|
System.err.println(" -Xnoprune test lookahead against EBNF block exit branches");
|
||||||
|
System.err.println(" -Xnocollapse collapse incident edges into DFA states");
|
||||||
|
System.err.println(" -Xdbgconversion dump lots of info during NFA conversion");
|
||||||
|
System.err.println(" -Xmultithreaded run the analysis in 2 threads");
|
||||||
|
System.err.println(" -Xnomergestopstates do not merge stop states");
|
||||||
|
System.err.println(" -Xdfaverbose generate DFA states in DOT with NFA configs");
|
||||||
|
System.err.println(" -Xwatchconversion print a message for each NFA before converting");
|
||||||
|
System.err.println(" -XdbgST put tags at start/stop of all templates in output");
|
||||||
|
System.err.println(" -Xm m max number of rule invocations during conversion");
|
||||||
|
System.err.println(" -Xmaxdfaedges m max \"comfortable\" number of edges for single DFA state");
|
||||||
|
System.err.println(" -Xconversiontimeout t set NFA conversion timeout for each decision");
|
||||||
|
System.err.println(" -Xmaxinlinedfastates m max DFA states before table used rather than inlining");
|
||||||
|
System.err.println(" -Xnfastates for nondeterminisms, list NFA states for each path");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOutputDirectory(String outputDirectory) {
|
||||||
|
this.outputDirectory = outputDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** This method is used by all code generators to create new output
|
||||||
|
* files. If the outputDir set by -o is not present it will be created.
|
||||||
|
* The final filename is sensitive to the output directory and
|
||||||
|
* the directory where the grammar file was found. If -o is /tmp
|
||||||
|
* and the original grammar file was foo/t.g then output files
|
||||||
|
* go in /tmp/foo.
|
||||||
|
*
|
||||||
|
* The output dir -o spec takes precedence if it's absolute.
|
||||||
|
* E.g., if the grammar file dir is absolute the output dir is given
|
||||||
|
* precendence. "-o /tmp /usr/lib/t.g" results in "/tmp/T.java" as
|
||||||
|
* output (assuming t.g holds T.java).
|
||||||
|
*
|
||||||
|
* If no -o is specified, then just write to the directory where the
|
||||||
|
* grammar file was found.
|
||||||
|
*
|
||||||
|
* If outputDirectory==null then write a String.
|
||||||
|
*/
|
||||||
|
public Writer getOutputFile(Grammar g, String fileName) throws IOException {
|
||||||
|
if ( outputDirectory==null ) {
|
||||||
|
return new StringWriter();
|
||||||
|
}
|
||||||
|
// output directory is a function of where the grammar file lives
|
||||||
|
// for subdir/T.g, you get subdir here. Well, depends on -o etc...
|
||||||
|
File outputDir = getOutputDirectory(g.getFileName());
|
||||||
|
File outputFile = new File(outputDir, fileName);
|
||||||
|
|
||||||
|
if( !outputDir.exists() ) {
|
||||||
|
outputDir.mkdirs();
|
||||||
|
}
|
||||||
|
FileWriter fw = new FileWriter(outputFile);
|
||||||
|
return new BufferedWriter(fw);
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getOutputDirectory(String fileNameWithPath) {
|
||||||
|
File outputDir = new File(outputDirectory);
|
||||||
|
String fileDirectory = getFileDirectory(fileNameWithPath);
|
||||||
|
if ( outputDirectory!=UNINITIALIZED_DIR ) {
|
||||||
|
// -o /tmp /var/lib/t.g => /tmp/T.java
|
||||||
|
// -o subdir/output /usr/lib/t.g => subdir/output/T.java
|
||||||
|
// -o . /usr/lib/t.g => ./T.java
|
||||||
|
if ( fileDirectory!=null &&
|
||||||
|
(new File(fileDirectory).isAbsolute() ||
|
||||||
|
fileDirectory.startsWith("~")) || // isAbsolute doesn't count this :(
|
||||||
|
forceAllFilesToOutputDir
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// somebody set the dir, it takes precendence; write new file there
|
||||||
|
outputDir = new File(outputDirectory);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// -o /tmp subdir/t.g => /tmp/subdir/t.g
|
||||||
|
if ( fileDirectory!=null ) {
|
||||||
|
outputDir = new File(outputDirectory, fileDirectory);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
outputDir = new File(outputDirectory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// they didn't specify a -o dir so just write to location
|
||||||
|
// where grammar is, absolute or relative
|
||||||
|
String dir = ".";
|
||||||
|
if ( fileDirectory!=null ) {
|
||||||
|
dir = fileDirectory;
|
||||||
|
}
|
||||||
|
outputDir = new File(dir);
|
||||||
|
}
|
||||||
|
return outputDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Name a file in the -lib dir. Imported grammars and .tokens files */
|
||||||
|
public String getLibraryFile(String fileName) throws IOException {
|
||||||
|
return libDirectory+File.separator+fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLibraryDirectory() {
|
||||||
|
return libDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return the directory containing the grammar file for this grammar.
|
||||||
|
* normally this is a relative path from current directory. People will
|
||||||
|
* often do "java org.antlr.Tool grammars/*.g3" So the file will be
|
||||||
|
* "grammars/foo.g3" etc... This method returns "grammars".
|
||||||
|
*/
|
||||||
|
public String getFileDirectory(String fileName) {
|
||||||
|
File f = new File(fileName);
|
||||||
|
return f.getParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return a File descriptor for vocab file. Look in library or
|
||||||
|
* in -o output path. antlr -o foo T.g U.g where U needs T.tokens
|
||||||
|
* won't work unless we look in foo too.
|
||||||
|
*/
|
||||||
|
public File getImportedVocabFile(String vocabName) {
|
||||||
|
File f = new File(getLibraryDirectory(),
|
||||||
|
File.separator+
|
||||||
|
vocabName+
|
||||||
|
CodeGenerator.VOCAB_FILE_EXTENSION);
|
||||||
|
if ( f.exists() ) {
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new File(outputDirectory+
|
||||||
|
File.separator+
|
||||||
|
vocabName+
|
||||||
|
CodeGenerator.VOCAB_FILE_EXTENSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** If the tool needs to panic/exit, how do we do that? */
|
||||||
|
public void panic() {
|
||||||
|
throw new Error("ANTLR panic");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return a time stamp string accurate to sec: yyyy-mm-dd hh:mm:ss */
|
||||||
|
public static String getCurrentTimeStamp() {
|
||||||
|
GregorianCalendar calendar = new java.util.GregorianCalendar();
|
||||||
|
int y = calendar.get(Calendar.YEAR);
|
||||||
|
int m = calendar.get(Calendar.MONTH)+1; // zero-based for months
|
||||||
|
int d = calendar.get(Calendar.DAY_OF_MONTH);
|
||||||
|
int h = calendar.get(Calendar.HOUR_OF_DAY);
|
||||||
|
int min = calendar.get(Calendar.MINUTE);
|
||||||
|
int sec = calendar.get(Calendar.SECOND);
|
||||||
|
String sy = String.valueOf(y);
|
||||||
|
String sm = m<10?"0"+m:String.valueOf(m);
|
||||||
|
String sd = d<10?"0"+d:String.valueOf(d);
|
||||||
|
String sh = h<10?"0"+h:String.valueOf(h);
|
||||||
|
String smin = min<10?"0"+min:String.valueOf(min);
|
||||||
|
String ssec = sec<10?"0"+sec:String.valueOf(sec);
|
||||||
|
return new StringBuffer().append(sy).append("-").append(sm).append("-")
|
||||||
|
.append(sd).append(" ").append(sh).append(":").append(smin)
|
||||||
|
.append(":").append(ssec).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
56
antlr_3_1_source/analysis/ActionLabel.java
Normal file
56
antlr_3_1_source/analysis/ActionLabel.java
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2008 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.antlr.analysis;
|
||||||
|
|
||||||
|
import org.antlr.tool.GrammarAST;
|
||||||
|
import org.antlr.tool.Grammar;
|
||||||
|
|
||||||
|
public class ActionLabel extends Label {
|
||||||
|
public GrammarAST actionAST;
|
||||||
|
|
||||||
|
public ActionLabel(GrammarAST actionAST) {
|
||||||
|
super(ACTION);
|
||||||
|
this.actionAST = actionAST;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEpsilon() {
|
||||||
|
return true; // we are to be ignored by analysis 'cept for predicates
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAction() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "{"+actionAST+"}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString(Grammar g) {
|
||||||
|
return toString();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2008 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.antlr.analysis;
|
||||||
|
|
||||||
|
/** An NFA configuration context stack overflowed. */
|
||||||
|
public class AnalysisRecursionOverflowException extends RuntimeException {
|
||||||
|
public DFAState ovfState;
|
||||||
|
public NFAConfiguration proposedNFAConfiguration;
|
||||||
|
public AnalysisRecursionOverflowException(DFAState ovfState,
|
||||||
|
NFAConfiguration proposedNFAConfiguration)
|
||||||
|
{
|
||||||
|
this.ovfState = ovfState;
|
||||||
|
this.proposedNFAConfiguration = proposedNFAConfiguration;
|
||||||
|
}
|
||||||
|
}
|
36
antlr_3_1_source/analysis/AnalysisTimeoutException.java
Normal file
36
antlr_3_1_source/analysis/AnalysisTimeoutException.java
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2008 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.antlr.analysis;
|
||||||
|
|
||||||
|
/** Analysis took too long; bail out of entire DFA construction. */
|
||||||
|
public class AnalysisTimeoutException extends RuntimeException {
|
||||||
|
public DFA abortedDFA;
|
||||||
|
public AnalysisTimeoutException(DFA abortedDFA) {
|
||||||
|
this.abortedDFA = abortedDFA;
|
||||||
|
}
|
||||||
|
}
|
1061
antlr_3_1_source/analysis/DFA.java
Normal file
1061
antlr_3_1_source/analysis/DFA.java
Normal file
File diff suppressed because it is too large
Load Diff
265
antlr_3_1_source/analysis/DFAOptimizer.java
Normal file
265
antlr_3_1_source/analysis/DFAOptimizer.java
Normal file
@ -0,0 +1,265 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.antlr.analysis;
|
||||||
|
|
||||||
|
import org.antlr.tool.Grammar;
|
||||||
|
import org.antlr.misc.Utils;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/** A module to perform optimizations on DFAs.
|
||||||
|
*
|
||||||
|
* I could more easily (and more quickly) do some optimizations (such as
|
||||||
|
* PRUNE_EBNF_EXIT_BRANCHES) during DFA construction, but then it
|
||||||
|
* messes up the determinism checking. For example, it looks like
|
||||||
|
* loop exit branches are unreachable if you prune exit branches
|
||||||
|
* during DFA construction and before determinism checks.
|
||||||
|
*
|
||||||
|
* In general, ANTLR's NFA->DFA->codegen pipeline seems very robust
|
||||||
|
* to me which I attribute to a uniform and consistent set of data
|
||||||
|
* structures. Regardless of what I want to "say"/implement, I do so
|
||||||
|
* within the confines of, for example, a DFA. The code generator
|
||||||
|
* can then just generate code--it doesn't have to do much thinking.
|
||||||
|
* Putting optimizations in the code gen code really starts to make
|
||||||
|
* it a spagetti factory (uh oh, now I'm hungry!). The pipeline is
|
||||||
|
* very testable; each stage has well defined input/output pairs.
|
||||||
|
*
|
||||||
|
* ### Optimization: PRUNE_EBNF_EXIT_BRANCHES
|
||||||
|
*
|
||||||
|
* There is no need to test EBNF block exit branches. Not only is it
|
||||||
|
* an unneeded computation, but counter-intuitively, you actually get
|
||||||
|
* better errors. You can report an error at the missing or extra
|
||||||
|
* token rather than as soon as you've figured out you will fail.
|
||||||
|
*
|
||||||
|
* Imagine optional block "( DOT CLASS )? SEMI". ANTLR generates:
|
||||||
|
*
|
||||||
|
* int alt=0;
|
||||||
|
* if ( input.LA(1)==DOT ) {
|
||||||
|
* alt=1;
|
||||||
|
* }
|
||||||
|
* else if ( input.LA(1)==SEMI ) {
|
||||||
|
* alt=2;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* Clearly, since Parser.match() will ultimately find the error, we
|
||||||
|
* do not want to report an error nor do we want to bother testing
|
||||||
|
* lookahead against what follows the (...)? We want to generate
|
||||||
|
* simply "should I enter the subrule?":
|
||||||
|
*
|
||||||
|
* int alt=2;
|
||||||
|
* if ( input.LA(1)==DOT ) {
|
||||||
|
* alt=1;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* NOTE 1. Greedy loops cannot be optimized in this way. For example,
|
||||||
|
* "(greedy=false:'x'|.)* '\n'". You specifically need the exit branch
|
||||||
|
* to tell you when to terminate the loop as the same input actually
|
||||||
|
* predicts one of the alts (i.e., staying in the loop).
|
||||||
|
*
|
||||||
|
* NOTE 2. I do not optimize cyclic DFAs at the moment as it doesn't
|
||||||
|
* seem to work. ;) I'll have to investigate later to see what work I
|
||||||
|
* can do on cyclic DFAs to make them have fewer edges. Might have
|
||||||
|
* something to do with the EOT token.
|
||||||
|
*
|
||||||
|
* ### PRUNE_SUPERFLUOUS_EOT_EDGES
|
||||||
|
*
|
||||||
|
* When a token is a subset of another such as the following rules, ANTLR
|
||||||
|
* quietly assumes the first token to resolve the ambiguity.
|
||||||
|
*
|
||||||
|
* EQ : '=' ;
|
||||||
|
* ASSIGNOP : '=' | '+=' ;
|
||||||
|
*
|
||||||
|
* It can yield states that have only a single edge on EOT to an accept
|
||||||
|
* state. This is a waste and messes up my code generation. ;) If
|
||||||
|
* Tokens rule DFA goes
|
||||||
|
*
|
||||||
|
* s0 -'='-> s3 -EOT-> s5 (accept)
|
||||||
|
*
|
||||||
|
* then s5 should be pruned and s3 should be made an accept. Do NOT do this
|
||||||
|
* for keyword versus ID as the state with EOT edge emanating from it will
|
||||||
|
* also have another edge.
|
||||||
|
*
|
||||||
|
* ### Optimization: COLLAPSE_ALL_INCIDENT_EDGES
|
||||||
|
*
|
||||||
|
* Done during DFA construction. See method addTransition() in
|
||||||
|
* NFAToDFAConverter.
|
||||||
|
*
|
||||||
|
* ### Optimization: MERGE_STOP_STATES
|
||||||
|
*
|
||||||
|
* Done during DFA construction. See addDFAState() in NFAToDFAConverter.
|
||||||
|
*/
|
||||||
|
public class DFAOptimizer {
|
||||||
|
public static boolean PRUNE_EBNF_EXIT_BRANCHES = true;
|
||||||
|
public static boolean PRUNE_TOKENS_RULE_SUPERFLUOUS_EOT_EDGES = true;
|
||||||
|
public static boolean COLLAPSE_ALL_PARALLEL_EDGES = true;
|
||||||
|
public static boolean MERGE_STOP_STATES = true;
|
||||||
|
|
||||||
|
/** Used by DFA state machine generator to avoid infinite recursion
|
||||||
|
* resulting from cycles int the DFA. This is a set of int state #s.
|
||||||
|
* This is a side-effect of calling optimize; can't clear after use
|
||||||
|
* because code gen needs it.
|
||||||
|
*/
|
||||||
|
protected Set visited = new HashSet();
|
||||||
|
|
||||||
|
protected Grammar grammar;
|
||||||
|
|
||||||
|
public DFAOptimizer(Grammar grammar) {
|
||||||
|
this.grammar = grammar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void optimize() {
|
||||||
|
// optimize each DFA in this grammar
|
||||||
|
for (int decisionNumber=1;
|
||||||
|
decisionNumber<=grammar.getNumberOfDecisions();
|
||||||
|
decisionNumber++)
|
||||||
|
{
|
||||||
|
DFA dfa = grammar.getLookaheadDFA(decisionNumber);
|
||||||
|
optimize(dfa);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void optimize(DFA dfa) {
|
||||||
|
if ( dfa==null ) {
|
||||||
|
return; // nothing to do
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
System.out.println("Optimize DFA "+dfa.decisionNFAStartState.decisionNumber+
|
||||||
|
" num states="+dfa.getNumberOfStates());
|
||||||
|
*/
|
||||||
|
//long start = System.currentTimeMillis();
|
||||||
|
if ( PRUNE_EBNF_EXIT_BRANCHES && dfa.canInlineDecision() ) {
|
||||||
|
visited.clear();
|
||||||
|
int decisionType =
|
||||||
|
dfa.getNFADecisionStartState().decisionStateType;
|
||||||
|
if ( dfa.isGreedy() &&
|
||||||
|
(decisionType==NFAState.OPTIONAL_BLOCK_START ||
|
||||||
|
decisionType==NFAState.LOOPBACK) )
|
||||||
|
{
|
||||||
|
optimizeExitBranches(dfa.startState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If the Tokens rule has syntactically ambiguous rules, try to prune
|
||||||
|
if ( PRUNE_TOKENS_RULE_SUPERFLUOUS_EOT_EDGES &&
|
||||||
|
dfa.isTokensRuleDecision() &&
|
||||||
|
dfa.probe.stateToSyntacticallyAmbiguousTokensRuleAltsMap.size()>0 )
|
||||||
|
{
|
||||||
|
visited.clear();
|
||||||
|
optimizeEOTBranches(dfa.startState);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ack...code gen needs this, cannot optimize
|
||||||
|
visited.clear();
|
||||||
|
unlinkUnneededStateData(dfa.startState);
|
||||||
|
*/
|
||||||
|
//long stop = System.currentTimeMillis();
|
||||||
|
//System.out.println("minimized in "+(int)(stop-start)+" ms");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void optimizeExitBranches(DFAState d) {
|
||||||
|
Integer sI = Utils.integer(d.stateNumber);
|
||||||
|
if ( visited.contains(sI) ) {
|
||||||
|
return; // already visited
|
||||||
|
}
|
||||||
|
visited.add(sI);
|
||||||
|
int nAlts = d.dfa.getNumberOfAlts();
|
||||||
|
for (int i = 0; i < d.getNumberOfTransitions(); i++) {
|
||||||
|
Transition edge = (Transition) d.transition(i);
|
||||||
|
DFAState edgeTarget = ((DFAState)edge.target);
|
||||||
|
/*
|
||||||
|
System.out.println(d.stateNumber+"-"+
|
||||||
|
edge.label.toString(d.dfa.nfa.grammar)+"->"+
|
||||||
|
edgeTarget.stateNumber);
|
||||||
|
*/
|
||||||
|
// if target is an accept state and that alt is the exit alt
|
||||||
|
if ( edgeTarget.isAcceptState() &&
|
||||||
|
edgeTarget.getUniquelyPredictedAlt()==nAlts)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
System.out.println("ignoring transition "+i+" to max alt "+
|
||||||
|
d.dfa.getNumberOfAlts());
|
||||||
|
*/
|
||||||
|
d.removeTransition(i);
|
||||||
|
i--; // back up one so that i++ of loop iteration stays within bounds
|
||||||
|
}
|
||||||
|
optimizeExitBranches(edgeTarget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void optimizeEOTBranches(DFAState d) {
|
||||||
|
Integer sI = Utils.integer(d.stateNumber);
|
||||||
|
if ( visited.contains(sI) ) {
|
||||||
|
return; // already visited
|
||||||
|
}
|
||||||
|
visited.add(sI);
|
||||||
|
for (int i = 0; i < d.getNumberOfTransitions(); i++) {
|
||||||
|
Transition edge = (Transition) d.transition(i);
|
||||||
|
DFAState edgeTarget = ((DFAState)edge.target);
|
||||||
|
/*
|
||||||
|
System.out.println(d.stateNumber+"-"+
|
||||||
|
edge.label.toString(d.dfa.nfa.grammar)+"->"+
|
||||||
|
edgeTarget.stateNumber);
|
||||||
|
*/
|
||||||
|
// if only one edge coming out, it is EOT, and target is accept prune
|
||||||
|
if ( PRUNE_TOKENS_RULE_SUPERFLUOUS_EOT_EDGES &&
|
||||||
|
edgeTarget.isAcceptState() &&
|
||||||
|
d.getNumberOfTransitions()==1 &&
|
||||||
|
edge.label.isAtom() &&
|
||||||
|
edge.label.getAtom()==Label.EOT )
|
||||||
|
{
|
||||||
|
//System.out.println("state "+d+" can be pruned");
|
||||||
|
// remove the superfluous EOT edge
|
||||||
|
d.removeTransition(i);
|
||||||
|
d.setAcceptState(true); // make it an accept state
|
||||||
|
// force it to uniquely predict the originally predicted state
|
||||||
|
d.cachedUniquelyPredicatedAlt =
|
||||||
|
edgeTarget.getUniquelyPredictedAlt();
|
||||||
|
i--; // back up one so that i++ of loop iteration stays within bounds
|
||||||
|
}
|
||||||
|
optimizeEOTBranches(edgeTarget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Walk DFA states, unlinking the nfa configs and whatever else I
|
||||||
|
* can to reduce memory footprint.
|
||||||
|
protected void unlinkUnneededStateData(DFAState d) {
|
||||||
|
Integer sI = Utils.integer(d.stateNumber);
|
||||||
|
if ( visited.contains(sI) ) {
|
||||||
|
return; // already visited
|
||||||
|
}
|
||||||
|
visited.add(sI);
|
||||||
|
d.nfaConfigurations = null;
|
||||||
|
for (int i = 0; i < d.getNumberOfTransitions(); i++) {
|
||||||
|
Transition edge = (Transition) d.transition(i);
|
||||||
|
DFAState edgeTarget = ((DFAState)edge.target);
|
||||||
|
unlinkUnneededStateData(edgeTarget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
}
|
776
antlr_3_1_source/analysis/DFAState.java
Normal file
776
antlr_3_1_source/analysis/DFAState.java
Normal file
@ -0,0 +1,776 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.antlr.analysis;
|
||||||
|
|
||||||
|
import org.antlr.misc.IntSet;
|
||||||
|
import org.antlr.misc.MultiMap;
|
||||||
|
import org.antlr.misc.OrderedHashSet;
|
||||||
|
import org.antlr.misc.Utils;
|
||||||
|
import org.antlr.tool.Grammar;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/** A DFA state represents a set of possible NFA configurations.
|
||||||
|
* As Aho, Sethi, Ullman p. 117 says "The DFA uses its state
|
||||||
|
* to keep track of all possible states the NFA can be in after
|
||||||
|
* reading each input symbol. That is to say, after reading
|
||||||
|
* input a1a2..an, the DFA is in a state that represents the
|
||||||
|
* subset T of the states of the NFA that are reachable from the
|
||||||
|
* NFA's start state along some path labeled a1a2..an."
|
||||||
|
* In conventional NFA->DFA conversion, therefore, the subset T
|
||||||
|
* would be a bitset representing the set of states the
|
||||||
|
* NFA could be in. We need to track the alt predicted by each
|
||||||
|
* state as well, however. More importantly, we need to maintain
|
||||||
|
* a stack of states, tracking the closure operations as they
|
||||||
|
* jump from rule to rule, emulating rule invocations (method calls).
|
||||||
|
* Recall that NFAs do not normally have a stack like a pushdown-machine
|
||||||
|
* so I have to add one to simulate the proper lookahead sequences for
|
||||||
|
* the underlying LL grammar from which the NFA was derived.
|
||||||
|
*
|
||||||
|
* I use a list of NFAConfiguration objects. An NFAConfiguration
|
||||||
|
* is both a state (ala normal conversion) and an NFAContext describing
|
||||||
|
* the chain of rules (if any) followed to arrive at that state. There
|
||||||
|
* is also the semantic context, which is the "set" of predicates found
|
||||||
|
* on the path to this configuration.
|
||||||
|
*
|
||||||
|
* A DFA state may have multiple references to a particular state,
|
||||||
|
* but with different NFAContexts (with same or different alts)
|
||||||
|
* meaning that state was reached via a different set of rule invocations.
|
||||||
|
*/
|
||||||
|
public class DFAState extends State {
|
||||||
|
public static final int INITIAL_NUM_TRANSITIONS = 4;
|
||||||
|
public static final int PREDICTED_ALT_UNSET = NFA.INVALID_ALT_NUMBER-1;
|
||||||
|
|
||||||
|
/** We are part of what DFA? Use this ref to get access to the
|
||||||
|
* context trees for an alt.
|
||||||
|
*/
|
||||||
|
public DFA dfa;
|
||||||
|
|
||||||
|
/** Track the transitions emanating from this DFA state. The List
|
||||||
|
* elements are Transition objects.
|
||||||
|
*/
|
||||||
|
protected List<Transition> transitions =
|
||||||
|
new ArrayList<Transition>(INITIAL_NUM_TRANSITIONS);
|
||||||
|
|
||||||
|
/** When doing an acyclic DFA, this is the number of lookahead symbols
|
||||||
|
* consumed to reach this state. This value may be nonzero for most
|
||||||
|
* dfa states, but it is only a valid value if the user has specified
|
||||||
|
* a max fixed lookahead.
|
||||||
|
*/
|
||||||
|
protected int k;
|
||||||
|
|
||||||
|
/** The NFA->DFA algorithm may terminate leaving some states
|
||||||
|
* without a path to an accept state, implying that upon certain
|
||||||
|
* input, the decision is not deterministic--no decision about
|
||||||
|
* predicting a unique alternative can be made. Recall that an
|
||||||
|
* accept state is one in which a unique alternative is predicted.
|
||||||
|
*/
|
||||||
|
protected int acceptStateReachable = DFA.REACHABLE_UNKNOWN;
|
||||||
|
|
||||||
|
/** Rather than recheck every NFA configuration in a DFA state (after
|
||||||
|
* resolving) in findNewDFAStatesAndAddDFATransitions just check
|
||||||
|
* this boolean. Saves a linear walk perhaps DFA state creation.
|
||||||
|
* Every little bit helps.
|
||||||
|
*/
|
||||||
|
protected boolean resolvedWithPredicates = false;
|
||||||
|
|
||||||
|
/** If a closure operation finds that we tried to invoke the same
|
||||||
|
* rule too many times (stack would grow beyond a threshold), it
|
||||||
|
* marks the state has aborted and notifies the DecisionProbe.
|
||||||
|
*/
|
||||||
|
public boolean abortedDueToRecursionOverflow = false;
|
||||||
|
|
||||||
|
/** If we detect recursion on more than one alt, decision is non-LL(*),
|
||||||
|
* but try to isolate it to only those states whose closure operations
|
||||||
|
* detect recursion. There may be other alts that are cool:
|
||||||
|
*
|
||||||
|
* a : recur '.'
|
||||||
|
* | recur ';'
|
||||||
|
* | X Y // LL(2) decision; don't abort and use k=1 plus backtracking
|
||||||
|
* | X Z
|
||||||
|
* ;
|
||||||
|
*
|
||||||
|
* 12/13/2007: Actually this has caused problems. If k=*, must terminate
|
||||||
|
* and throw out entire DFA; retry with k=1. Since recursive, do not
|
||||||
|
* attempt more closure ops as it may take forever. Exception thrown
|
||||||
|
* now and we simply report the problem. If synpreds exist, I'll retry
|
||||||
|
* with k=1.
|
||||||
|
*/
|
||||||
|
protected boolean abortedDueToMultipleRecursiveAlts = false;
|
||||||
|
|
||||||
|
/** Build up the hash code for this state as NFA configurations
|
||||||
|
* are added as it's monotonically increasing list of configurations.
|
||||||
|
*/
|
||||||
|
protected int cachedHashCode;
|
||||||
|
|
||||||
|
protected int cachedUniquelyPredicatedAlt = PREDICTED_ALT_UNSET;
|
||||||
|
|
||||||
|
public int minAltInConfigurations=Integer.MAX_VALUE;
|
||||||
|
|
||||||
|
public boolean atLeastOneConfigurationHasAPredicate = false;
|
||||||
|
|
||||||
|
/** The set of NFA configurations (state,alt,context) for this DFA state */
|
||||||
|
public OrderedHashSet<NFAConfiguration> nfaConfigurations =
|
||||||
|
new OrderedHashSet<NFAConfiguration>();
|
||||||
|
|
||||||
|
public List<NFAConfiguration> configurationsWithLabeledEdges =
|
||||||
|
new ArrayList<NFAConfiguration>();
|
||||||
|
|
||||||
|
/** Used to prevent the closure operation from looping to itself and
|
||||||
|
* hence looping forever. Sensitive to the NFA state, the alt, and
|
||||||
|
* the stack context. This just the nfa config set because we want to
|
||||||
|
* prevent closures only on states contributed by closure not reach
|
||||||
|
* operations.
|
||||||
|
*
|
||||||
|
* Two configurations identical including semantic context are
|
||||||
|
* considered the same closure computation. @see NFAToDFAConverter.closureBusy().
|
||||||
|
*/
|
||||||
|
protected Set<NFAConfiguration> closureBusy = new HashSet<NFAConfiguration>();
|
||||||
|
|
||||||
|
/** As this state is constructed (i.e., as NFA states are added), we
|
||||||
|
* can easily check for non-epsilon transitions because the only
|
||||||
|
* transition that could be a valid label is transition(0). When we
|
||||||
|
* process this node eventually, we'll have to walk all states looking
|
||||||
|
* for all possible transitions. That is of the order: size(label space)
|
||||||
|
* times size(nfa states), which can be pretty damn big. It's better
|
||||||
|
* to simply track possible labels.
|
||||||
|
*/
|
||||||
|
protected OrderedHashSet<Label> reachableLabels;
|
||||||
|
|
||||||
|
public DFAState(DFA dfa) {
|
||||||
|
this.dfa = dfa;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
//nfaConfigurations = null; // getGatedPredicatesInNFAConfigurations needs
|
||||||
|
configurationsWithLabeledEdges = null;
|
||||||
|
closureBusy = null;
|
||||||
|
reachableLabels = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Transition transition(int i) {
|
||||||
|
return (Transition)transitions.get(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumberOfTransitions() {
|
||||||
|
return transitions.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addTransition(Transition t) {
|
||||||
|
transitions.add(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Add a transition from this state to target with label. Return
|
||||||
|
* the transition number from 0..n-1.
|
||||||
|
*/
|
||||||
|
public int addTransition(DFAState target, Label label) {
|
||||||
|
transitions.add( new Transition(label, target) );
|
||||||
|
return transitions.size()-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Transition getTransition(int trans) {
|
||||||
|
return transitions.get(trans);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeTransition(int trans) {
|
||||||
|
transitions.remove(trans);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Add an NFA configuration to this DFA node. Add uniquely
|
||||||
|
* an NFA state/alt/syntactic&semantic context (chain of invoking state(s)
|
||||||
|
* and semantic predicate contexts).
|
||||||
|
*
|
||||||
|
* I don't see how there could be two configurations with same
|
||||||
|
* state|alt|synCtx and different semantic contexts because the
|
||||||
|
* semantic contexts are computed along the path to a particular state
|
||||||
|
* so those two configurations would have to have the same predicate.
|
||||||
|
* Nonetheless, the addition of configurations is unique on all
|
||||||
|
* configuration info. I guess I'm saying that syntactic context
|
||||||
|
* implies semantic context as the latter is computed according to the
|
||||||
|
* former.
|
||||||
|
*
|
||||||
|
* As we add configurations to this DFA state, track the set of all possible
|
||||||
|
* transition labels so we can simply walk it later rather than doing a
|
||||||
|
* loop over all possible labels in the NFA.
|
||||||
|
*/
|
||||||
|
public void addNFAConfiguration(NFAState state, NFAConfiguration c) {
|
||||||
|
if ( nfaConfigurations.contains(c) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nfaConfigurations.add(c);
|
||||||
|
|
||||||
|
// track min alt rather than compute later
|
||||||
|
if ( c.alt < minAltInConfigurations ) {
|
||||||
|
minAltInConfigurations = c.alt;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( c.semanticContext!=SemanticContext.EMPTY_SEMANTIC_CONTEXT ) {
|
||||||
|
atLeastOneConfigurationHasAPredicate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update hashCode; for some reason using context.hashCode() also
|
||||||
|
// makes the GC take like 70% of the CPU and is slow!
|
||||||
|
cachedHashCode += c.state + c.alt;
|
||||||
|
|
||||||
|
// update reachableLabels
|
||||||
|
// We're adding an NFA state; check to see if it has a non-epsilon edge
|
||||||
|
if ( state.transition[0] != null ) {
|
||||||
|
Label label = state.transition[0].label;
|
||||||
|
if ( !(label.isEpsilon()||label.isSemanticPredicate()) ) {
|
||||||
|
// this NFA state has a non-epsilon edge, track for fast
|
||||||
|
// walking later when we do reach on this DFA state we're
|
||||||
|
// building.
|
||||||
|
configurationsWithLabeledEdges.add(c);
|
||||||
|
if ( state.transition[1] ==null ) {
|
||||||
|
// later we can check this to ignore o-A->o states in closure
|
||||||
|
c.singleAtomTransitionEmanating = true;
|
||||||
|
}
|
||||||
|
addReachableLabel(label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public NFAConfiguration addNFAConfiguration(NFAState state,
|
||||||
|
int alt,
|
||||||
|
NFAContext context,
|
||||||
|
SemanticContext semanticContext)
|
||||||
|
{
|
||||||
|
NFAConfiguration c = new NFAConfiguration(state.stateNumber,
|
||||||
|
alt,
|
||||||
|
context,
|
||||||
|
semanticContext);
|
||||||
|
addNFAConfiguration(state, c);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Add label uniquely and disjointly; intersection with
|
||||||
|
* another set or int/char forces breaking up the set(s).
|
||||||
|
*
|
||||||
|
* Example, if reachable list of labels is [a..z, {k,9}, 0..9],
|
||||||
|
* the disjoint list will be [{a..j,l..z}, k, 9, 0..8].
|
||||||
|
*
|
||||||
|
* As we add NFA configurations to a DFA state, we might as well track
|
||||||
|
* the set of all possible transition labels to make the DFA conversion
|
||||||
|
* more efficient. W/o the reachable labels, we'd need to check the
|
||||||
|
* whole vocabulary space (could be 0..\uFFFF)! The problem is that
|
||||||
|
* labels can be sets, which may overlap with int labels or other sets.
|
||||||
|
* As we need a deterministic set of transitions from any
|
||||||
|
* state in the DFA, we must make the reachable labels set disjoint.
|
||||||
|
* This operation amounts to finding the character classes for this
|
||||||
|
* DFA state whereas with tools like flex, that need to generate a
|
||||||
|
* homogeneous DFA, must compute char classes across all states.
|
||||||
|
* We are going to generate DFAs with heterogeneous states so we
|
||||||
|
* only care that the set of transitions out of a single state are
|
||||||
|
* unique. :)
|
||||||
|
*
|
||||||
|
* The idea for adding a new set, t, is to look for overlap with the
|
||||||
|
* elements of existing list s. Upon overlap, replace
|
||||||
|
* existing set s[i] with two new disjoint sets, s[i]-t and s[i]&t.
|
||||||
|
* (if s[i]-t is nil, don't add). The remainder is t-s[i], which is
|
||||||
|
* what you want to add to the set minus what was already there. The
|
||||||
|
* remainder must then be compared against the i+1..n elements in s
|
||||||
|
* looking for another collision. Each collision results in a smaller
|
||||||
|
* and smaller remainder. Stop when you run out of s elements or
|
||||||
|
* remainder goes to nil. If remainder is non nil when you run out of
|
||||||
|
* s elements, then add remainder to the end.
|
||||||
|
*
|
||||||
|
* Single element labels are treated as sets to make the code uniform.
|
||||||
|
*/
|
||||||
|
protected void addReachableLabel(Label label) {
|
||||||
|
if ( reachableLabels==null ) {
|
||||||
|
reachableLabels = new OrderedHashSet<Label>();
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
System.out.println("addReachableLabel to state "+dfa.decisionNumber+"."+stateNumber+": "+label.getSet().toString(dfa.nfa.grammar));
|
||||||
|
System.out.println("start of add to state "+dfa.decisionNumber+"."+stateNumber+": " +
|
||||||
|
"reachableLabels="+reachableLabels.toString());
|
||||||
|
*/
|
||||||
|
if ( reachableLabels.contains(label) ) { // exact label present
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
IntSet t = label.getSet();
|
||||||
|
IntSet remainder = t; // remainder starts out as whole set to add
|
||||||
|
int n = reachableLabels.size(); // only look at initial elements
|
||||||
|
// walk the existing list looking for the collision
|
||||||
|
for (int i=0; i<n; i++) {
|
||||||
|
Label rl = reachableLabels.get(i);
|
||||||
|
/*
|
||||||
|
System.out.println("comparing ["+i+"]: "+label.toString(dfa.nfa.grammar)+" & "+
|
||||||
|
rl.toString(dfa.nfa.grammar)+"="+
|
||||||
|
intersection.toString(dfa.nfa.grammar));
|
||||||
|
*/
|
||||||
|
if ( !Label.intersect(label, rl) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//System.out.println(label+" collides with "+rl);
|
||||||
|
|
||||||
|
// For any (s_i, t) with s_i&t!=nil replace with (s_i-t, s_i&t)
|
||||||
|
// (ignoring s_i-t if nil; don't put in list)
|
||||||
|
|
||||||
|
// Replace existing s_i with intersection since we
|
||||||
|
// know that will always be a non nil character class
|
||||||
|
IntSet s_i = rl.getSet();
|
||||||
|
IntSet intersection = s_i.and(t);
|
||||||
|
reachableLabels.set(i, new Label(intersection));
|
||||||
|
|
||||||
|
// Compute s_i-t to see what is in current set and not in incoming
|
||||||
|
IntSet existingMinusNewElements = s_i.subtract(t);
|
||||||
|
//System.out.println(s_i+"-"+t+"="+existingMinusNewElements);
|
||||||
|
if ( !existingMinusNewElements.isNil() ) {
|
||||||
|
// found a new character class, add to the end (doesn't affect
|
||||||
|
// outer loop duration due to n computation a priori.
|
||||||
|
Label newLabel = new Label(existingMinusNewElements);
|
||||||
|
reachableLabels.add(newLabel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
System.out.println("after collision, " +
|
||||||
|
"reachableLabels="+reachableLabels.toString());
|
||||||
|
*/
|
||||||
|
|
||||||
|
// anything left to add to the reachableLabels?
|
||||||
|
remainder = t.subtract(s_i);
|
||||||
|
if ( remainder.isNil() ) {
|
||||||
|
break; // nothing left to add to set. done!
|
||||||
|
}
|
||||||
|
|
||||||
|
t = remainder;
|
||||||
|
}
|
||||||
|
if ( !remainder.isNil() ) {
|
||||||
|
/*
|
||||||
|
System.out.println("before add remainder to state "+dfa.decisionNumber+"."+stateNumber+": " +
|
||||||
|
"reachableLabels="+reachableLabels.toString());
|
||||||
|
System.out.println("remainder state "+dfa.decisionNumber+"."+stateNumber+": "+remainder.toString(dfa.nfa.grammar));
|
||||||
|
*/
|
||||||
|
Label newLabel = new Label(remainder);
|
||||||
|
reachableLabels.add(newLabel);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
System.out.println("#END of add to state "+dfa.decisionNumber+"."+stateNumber+": " +
|
||||||
|
"reachableLabels="+reachableLabels.toString());
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
public OrderedHashSet getReachableLabels() {
|
||||||
|
return reachableLabels;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNFAConfigurations(OrderedHashSet<NFAConfiguration> configs) {
|
||||||
|
this.nfaConfigurations = configs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A decent hash for a DFA state is the sum of the NFA state/alt pairs.
|
||||||
|
* This is used when we add DFAState objects to the DFA.states Map and
|
||||||
|
* when we compare DFA states. Computed in addNFAConfiguration()
|
||||||
|
*/
|
||||||
|
public int hashCode() {
|
||||||
|
if ( cachedHashCode==0 ) {
|
||||||
|
// LL(1) algorithm doesn't use NFA configurations, which
|
||||||
|
// dynamically compute hashcode; must have something; use super
|
||||||
|
return super.hashCode();
|
||||||
|
}
|
||||||
|
return cachedHashCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Two DFAStates are equal if their NFA configuration sets are the
|
||||||
|
* same. This method is used to see if a DFA state already exists.
|
||||||
|
*
|
||||||
|
* Because the number of alternatives and number of NFA configurations are
|
||||||
|
* finite, there is a finite number of DFA states that can be processed.
|
||||||
|
* This is necessary to show that the algorithm terminates.
|
||||||
|
*
|
||||||
|
* Cannot test the DFA state numbers here because in DFA.addState we need
|
||||||
|
* to know if any other state exists that has this exact set of NFA
|
||||||
|
* configurations. The DFAState state number is irrelevant.
|
||||||
|
*/
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
// compare set of NFA configurations in this set with other
|
||||||
|
DFAState other = (DFAState)o;
|
||||||
|
return this.nfaConfigurations.equals(other.nfaConfigurations);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Walk each configuration and if they are all the same alt, return
|
||||||
|
* that alt else return NFA.INVALID_ALT_NUMBER. Ignore resolved
|
||||||
|
* configurations, but don't ignore resolveWithPredicate configs
|
||||||
|
* because this state should not be an accept state. We need to add
|
||||||
|
* this to the work list and then have semantic predicate edges
|
||||||
|
* emanating from it.
|
||||||
|
*/
|
||||||
|
public int getUniquelyPredictedAlt() {
|
||||||
|
if ( cachedUniquelyPredicatedAlt!=PREDICTED_ALT_UNSET ) {
|
||||||
|
return cachedUniquelyPredicatedAlt;
|
||||||
|
}
|
||||||
|
int alt = NFA.INVALID_ALT_NUMBER;
|
||||||
|
int numConfigs = nfaConfigurations.size();
|
||||||
|
for (int i = 0; i < numConfigs; i++) {
|
||||||
|
NFAConfiguration configuration = (NFAConfiguration) nfaConfigurations.get(i);
|
||||||
|
// ignore anything we resolved; predicates will still result
|
||||||
|
// in transitions out of this state, so must count those
|
||||||
|
// configurations; i.e., don't ignore resolveWithPredicate configs
|
||||||
|
if ( configuration.resolved ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ( alt==NFA.INVALID_ALT_NUMBER ) {
|
||||||
|
alt = configuration.alt; // found first nonresolved alt
|
||||||
|
}
|
||||||
|
else if ( configuration.alt!=alt ) {
|
||||||
|
return NFA.INVALID_ALT_NUMBER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.cachedUniquelyPredicatedAlt = alt;
|
||||||
|
return alt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return the uniquely mentioned alt from the NFA configurations;
|
||||||
|
* Ignore the resolved bit etc... Return INVALID_ALT_NUMBER
|
||||||
|
* if there is more than one alt mentioned.
|
||||||
|
*/
|
||||||
|
public int getUniqueAlt() {
|
||||||
|
int alt = NFA.INVALID_ALT_NUMBER;
|
||||||
|
int numConfigs = nfaConfigurations.size();
|
||||||
|
for (int i = 0; i < numConfigs; i++) {
|
||||||
|
NFAConfiguration configuration = (NFAConfiguration) nfaConfigurations.get(i);
|
||||||
|
if ( alt==NFA.INVALID_ALT_NUMBER ) {
|
||||||
|
alt = configuration.alt; // found first alt
|
||||||
|
}
|
||||||
|
else if ( configuration.alt!=alt ) {
|
||||||
|
return NFA.INVALID_ALT_NUMBER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return alt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** When more than one alternative can match the same input, the first
|
||||||
|
* alternative is chosen to resolve the conflict. The other alts
|
||||||
|
* are "turned off" by setting the "resolved" flag in the NFA
|
||||||
|
* configurations. Return the set of disabled alternatives. For
|
||||||
|
*
|
||||||
|
* a : A | A | A ;
|
||||||
|
*
|
||||||
|
* this method returns {2,3} as disabled. This does not mean that
|
||||||
|
* the alternative is totally unreachable, it just means that for this
|
||||||
|
* DFA state, that alt is disabled. There may be other accept states
|
||||||
|
* for that alt.
|
||||||
|
*/
|
||||||
|
public Set getDisabledAlternatives() {
|
||||||
|
Set disabled = new LinkedHashSet();
|
||||||
|
int numConfigs = nfaConfigurations.size();
|
||||||
|
for (int i = 0; i < numConfigs; i++) {
|
||||||
|
NFAConfiguration configuration = (NFAConfiguration) nfaConfigurations.get(i);
|
||||||
|
if ( configuration.resolved ) {
|
||||||
|
disabled.add(Utils.integer(configuration.alt));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return disabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Set getNonDeterministicAlts() {
|
||||||
|
int user_k = dfa.getUserMaxLookahead();
|
||||||
|
if ( user_k>0 && user_k==k ) {
|
||||||
|
// if fixed lookahead, then more than 1 alt is a nondeterminism
|
||||||
|
// if we have hit the max lookahead
|
||||||
|
return getAltSet();
|
||||||
|
}
|
||||||
|
else if ( abortedDueToMultipleRecursiveAlts || abortedDueToRecursionOverflow ) {
|
||||||
|
// if we had to abort for non-LL(*) state assume all alts are a problem
|
||||||
|
return getAltSet();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return getConflictingAlts();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Walk each NFA configuration in this DFA state looking for a conflict
|
||||||
|
* where (s|i|ctx) and (s|j|ctx) exist, indicating that state s with
|
||||||
|
* context conflicting ctx predicts alts i and j. Return an Integer set
|
||||||
|
* of the alternative numbers that conflict. Two contexts conflict if
|
||||||
|
* they are equal or one is a stack suffix of the other or one is
|
||||||
|
* the empty context.
|
||||||
|
*
|
||||||
|
* Use a hash table to record the lists of configs for each state
|
||||||
|
* as they are encountered. We need only consider states for which
|
||||||
|
* there is more than one configuration. The configurations' predicted
|
||||||
|
* alt must be different or must have different contexts to avoid a
|
||||||
|
* conflict.
|
||||||
|
*
|
||||||
|
* Don't report conflicts for DFA states that have conflicting Tokens
|
||||||
|
* rule NFA states; they will be resolved in favor of the first rule.
|
||||||
|
*/
|
||||||
|
protected Set<Integer> getConflictingAlts() {
|
||||||
|
// TODO this is called multiple times: cache result?
|
||||||
|
//System.out.println("getNondetAlts for DFA state "+stateNumber);
|
||||||
|
Set<Integer> nondeterministicAlts = new HashSet<Integer>();
|
||||||
|
|
||||||
|
// If only 1 NFA conf then no way it can be nondeterministic;
|
||||||
|
// save the overhead. There are many o-a->o NFA transitions
|
||||||
|
// and so we save a hash map and iterator creation for each
|
||||||
|
// state.
|
||||||
|
int numConfigs = nfaConfigurations.size();
|
||||||
|
if ( numConfigs <=1 ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// First get a list of configurations for each state.
|
||||||
|
// Most of the time, each state will have one associated configuration.
|
||||||
|
MultiMap<Integer, NFAConfiguration> stateToConfigListMap =
|
||||||
|
new MultiMap<Integer, NFAConfiguration>();
|
||||||
|
for (int i = 0; i < numConfigs; i++) {
|
||||||
|
NFAConfiguration configuration = (NFAConfiguration) nfaConfigurations.get(i);
|
||||||
|
Integer stateI = Utils.integer(configuration.state);
|
||||||
|
stateToConfigListMap.map(stateI, configuration);
|
||||||
|
}
|
||||||
|
// potential conflicts are states with > 1 configuration and diff alts
|
||||||
|
Set states = stateToConfigListMap.keySet();
|
||||||
|
int numPotentialConflicts = 0;
|
||||||
|
for (Iterator it = states.iterator(); it.hasNext();) {
|
||||||
|
Integer stateI = (Integer) it.next();
|
||||||
|
boolean thisStateHasPotentialProblem = false;
|
||||||
|
List configsForState = (List)stateToConfigListMap.get(stateI);
|
||||||
|
int alt=0;
|
||||||
|
int numConfigsForState = configsForState.size();
|
||||||
|
for (int i = 0; i < numConfigsForState && numConfigsForState>1 ; i++) {
|
||||||
|
NFAConfiguration c = (NFAConfiguration) configsForState.get(i);
|
||||||
|
if ( alt==0 ) {
|
||||||
|
alt = c.alt;
|
||||||
|
}
|
||||||
|
else if ( c.alt!=alt ) {
|
||||||
|
/*
|
||||||
|
System.out.println("potential conflict in state "+stateI+
|
||||||
|
" configs: "+configsForState);
|
||||||
|
*/
|
||||||
|
// 11/28/2005: don't report closures that pinch back
|
||||||
|
// together in Tokens rule. We want to silently resolve
|
||||||
|
// to the first token definition ala lex/flex by ignoring
|
||||||
|
// these conflicts.
|
||||||
|
// Also this ensures that lexers look for more and more
|
||||||
|
// characters (longest match) before resorting to predicates.
|
||||||
|
// TestSemanticPredicates.testLexerMatchesLongestThenTestPred()
|
||||||
|
// for example would terminate at state s1 and test predicate
|
||||||
|
// meaning input "ab" would test preds to decide what to
|
||||||
|
// do but it should match rule C w/o testing preds.
|
||||||
|
if ( dfa.nfa.grammar.type!=Grammar.LEXER ||
|
||||||
|
!dfa.decisionNFAStartState.enclosingRule.name.equals(Grammar.ARTIFICIAL_TOKENS_RULENAME) )
|
||||||
|
{
|
||||||
|
numPotentialConflicts++;
|
||||||
|
thisStateHasPotentialProblem = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( !thisStateHasPotentialProblem ) {
|
||||||
|
// remove NFA state's configurations from
|
||||||
|
// further checking; no issues with it
|
||||||
|
// (can't remove as it's concurrent modification; set to null)
|
||||||
|
stateToConfigListMap.put(stateI, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// a fast check for potential issues; most states have none
|
||||||
|
if ( numPotentialConflicts==0 ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we have a potential problem, so now go through config lists again
|
||||||
|
// looking for different alts (only states with potential issues
|
||||||
|
// are left in the states set). Now we will check context.
|
||||||
|
// For example, the list of configs for NFA state 3 in some DFA
|
||||||
|
// state might be:
|
||||||
|
// [3|2|[28 18 $], 3|1|[28 $], 3|1, 3|2]
|
||||||
|
// I want to create a map from context to alts looking for overlap:
|
||||||
|
// [28 18 $] -> 2
|
||||||
|
// [28 $] -> 1
|
||||||
|
// [$] -> 1,2
|
||||||
|
// Indeed a conflict exists as same state 3, same context [$], predicts
|
||||||
|
// alts 1 and 2.
|
||||||
|
// walk each state with potential conflicting configurations
|
||||||
|
for (Iterator it = states.iterator(); it.hasNext();) {
|
||||||
|
Integer stateI = (Integer) it.next();
|
||||||
|
List configsForState = (List)stateToConfigListMap.get(stateI);
|
||||||
|
// compare each configuration pair s, t to ensure:
|
||||||
|
// s.ctx different than t.ctx if s.alt != t.alt
|
||||||
|
int numConfigsForState = 0;
|
||||||
|
if ( configsForState!=null ) {
|
||||||
|
numConfigsForState = configsForState.size();
|
||||||
|
}
|
||||||
|
for (int i = 0; i < numConfigsForState; i++) {
|
||||||
|
NFAConfiguration s = (NFAConfiguration) configsForState.get(i);
|
||||||
|
for (int j = i+1; j < numConfigsForState; j++) {
|
||||||
|
NFAConfiguration t = (NFAConfiguration)configsForState.get(j);
|
||||||
|
// conflicts means s.ctx==t.ctx or s.ctx is a stack
|
||||||
|
// suffix of t.ctx or vice versa (if alts differ).
|
||||||
|
// Also a conflict if s.ctx or t.ctx is empty
|
||||||
|
if ( s.alt != t.alt && s.context.conflictsWith(t.context) ) {
|
||||||
|
nondeterministicAlts.add(Utils.integer(s.alt));
|
||||||
|
nondeterministicAlts.add(Utils.integer(t.alt));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( nondeterministicAlts.size()==0 ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return nondeterministicAlts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get the set of all alts mentioned by all NFA configurations in this
|
||||||
|
* DFA state.
|
||||||
|
*/
|
||||||
|
public Set getAltSet() {
|
||||||
|
int numConfigs = nfaConfigurations.size();
|
||||||
|
Set alts = new HashSet();
|
||||||
|
for (int i = 0; i < numConfigs; i++) {
|
||||||
|
NFAConfiguration configuration = (NFAConfiguration) nfaConfigurations.get(i);
|
||||||
|
alts.add(Utils.integer(configuration.alt));
|
||||||
|
}
|
||||||
|
if ( alts.size()==0 ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return alts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set getGatedSyntacticPredicatesInNFAConfigurations() {
|
||||||
|
int numConfigs = nfaConfigurations.size();
|
||||||
|
Set<SemanticContext> synpreds = new HashSet<SemanticContext>();
|
||||||
|
for (int i = 0; i < numConfigs; i++) {
|
||||||
|
NFAConfiguration configuration = (NFAConfiguration) nfaConfigurations.get(i);
|
||||||
|
SemanticContext gatedPredExpr =
|
||||||
|
configuration.semanticContext.getGatedPredicateContext();
|
||||||
|
// if this is a manual syn pred (gated and syn pred), add
|
||||||
|
if ( gatedPredExpr!=null &&
|
||||||
|
configuration.semanticContext.isSyntacticPredicate() )
|
||||||
|
{
|
||||||
|
synpreds.add(configuration.semanticContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( synpreds.size()==0 ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return synpreds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** For gated productions, we need an OR'd list of all predicates for the
|
||||||
|
* target of an edge so we can gate the edge based upon the predicates
|
||||||
|
* associated with taking that path (if any).
|
||||||
|
*
|
||||||
|
* For syntactic predicates, we only want to generate predicate
|
||||||
|
* evaluations as it transitions to an accept state; waste to
|
||||||
|
* do it earlier. So, only add gated preds derived from manually-
|
||||||
|
* specified syntactic predicates if this is an accept state.
|
||||||
|
*
|
||||||
|
* Also, since configurations w/o gated predicates are like true
|
||||||
|
* gated predicates, finding a configuration whose alt has no gated
|
||||||
|
* predicate implies we should evaluate the predicate to true. This
|
||||||
|
* means the whole edge has to be ungated. Consider:
|
||||||
|
*
|
||||||
|
* X : ('a' | {p}?=> 'a')
|
||||||
|
* | 'a' 'b'
|
||||||
|
* ;
|
||||||
|
*
|
||||||
|
* Here, you 'a' gets you from s0 to s1 but you can't test p because
|
||||||
|
* plain 'a' is ok. It's also ok for starting alt 2. Hence, you can't
|
||||||
|
* test p. Even on the edge going to accept state for alt 1 of X, you
|
||||||
|
* can't test p. You can get to the same place with and w/o the context.
|
||||||
|
* Therefore, it is never ok to test p in this situation.
|
||||||
|
*
|
||||||
|
* TODO: cache this as it's called a lot; or at least set bit if >1 present in state
|
||||||
|
*/
|
||||||
|
public SemanticContext getGatedPredicatesInNFAConfigurations() {
|
||||||
|
SemanticContext unionOfPredicatesFromAllAlts = null;
|
||||||
|
int numConfigs = nfaConfigurations.size();
|
||||||
|
for (int i = 0; i < numConfigs; i++) {
|
||||||
|
NFAConfiguration configuration = (NFAConfiguration) nfaConfigurations.get(i);
|
||||||
|
SemanticContext gatedPredExpr =
|
||||||
|
configuration.semanticContext.getGatedPredicateContext();
|
||||||
|
if ( gatedPredExpr==null ) {
|
||||||
|
// if we ever find a configuration w/o a gated predicate
|
||||||
|
// (even if it's a nongated predicate), we cannot gate
|
||||||
|
// the indident edges.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else if ( acceptState || !configuration.semanticContext.isSyntacticPredicate() ) {
|
||||||
|
// at this point we have a gated predicate and, due to elseif,
|
||||||
|
// we know it's an accept and not a syn pred. In this case,
|
||||||
|
// it's safe to add the gated predicate to the union. We
|
||||||
|
// only want to add syn preds if it's an accept state. Other
|
||||||
|
// gated preds can be used with edges leading to accept states.
|
||||||
|
if ( unionOfPredicatesFromAllAlts==null ) {
|
||||||
|
unionOfPredicatesFromAllAlts = gatedPredExpr;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
unionOfPredicatesFromAllAlts =
|
||||||
|
SemanticContext.or(unionOfPredicatesFromAllAlts,gatedPredExpr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( unionOfPredicatesFromAllAlts instanceof SemanticContext.TruePredicate ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return unionOfPredicatesFromAllAlts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Is an accept state reachable from this state? */
|
||||||
|
public int getAcceptStateReachable() {
|
||||||
|
return acceptStateReachable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAcceptStateReachable(int acceptStateReachable) {
|
||||||
|
this.acceptStateReachable = acceptStateReachable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isResolvedWithPredicates() {
|
||||||
|
return resolvedWithPredicates;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Print all NFA states plus what alts they predict */
|
||||||
|
public String toString() {
|
||||||
|
StringBuffer buf = new StringBuffer();
|
||||||
|
buf.append(stateNumber+":{");
|
||||||
|
for (int i = 0; i < nfaConfigurations.size(); i++) {
|
||||||
|
NFAConfiguration configuration = (NFAConfiguration) nfaConfigurations.get(i);
|
||||||
|
if ( i>0 ) {
|
||||||
|
buf.append(", ");
|
||||||
|
}
|
||||||
|
buf.append(configuration);
|
||||||
|
}
|
||||||
|
buf.append("}");
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getLookaheadDepth() {
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLookaheadDepth(int k) {
|
||||||
|
this.k = k;
|
||||||
|
if ( k > dfa.max_k ) { // track max k for entire DFA
|
||||||
|
dfa.max_k = k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
915
antlr_3_1_source/analysis/DecisionProbe.java
Normal file
915
antlr_3_1_source/analysis/DecisionProbe.java
Normal file
@ -0,0 +1,915 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.antlr.analysis;
|
||||||
|
|
||||||
|
import org.antlr.tool.ErrorManager;
|
||||||
|
import org.antlr.tool.Grammar;
|
||||||
|
import org.antlr.tool.GrammarAST;
|
||||||
|
import org.antlr.tool.ANTLRParser;
|
||||||
|
import org.antlr.misc.Utils;
|
||||||
|
import org.antlr.misc.MultiMap;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import antlr.Token;
|
||||||
|
|
||||||
|
/** Collection of information about what is wrong with a decision as
|
||||||
|
* discovered while building the DFA predictor.
|
||||||
|
*
|
||||||
|
* The information is collected during NFA->DFA conversion and, while
|
||||||
|
* some of this is available elsewhere, it is nice to have it all tracked
|
||||||
|
* in one spot so a great error message can be easily had. I also like
|
||||||
|
* the fact that this object tracks it all for later perusing to make an
|
||||||
|
* excellent error message instead of lots of imprecise on-the-fly warnings
|
||||||
|
* (during conversion).
|
||||||
|
*
|
||||||
|
* A decision normally only has one problem; e.g., some input sequence
|
||||||
|
* can be matched by multiple alternatives. Unfortunately, some decisions
|
||||||
|
* such as
|
||||||
|
*
|
||||||
|
* a : ( A | B ) | ( A | B ) | A ;
|
||||||
|
*
|
||||||
|
* have multiple problems. So in general, you should approach a decision
|
||||||
|
* as having multiple flaws each one uniquely identified by a DFAState.
|
||||||
|
* For example, statesWithSyntacticallyAmbiguousAltsSet tracks the set of
|
||||||
|
* all DFAStates where ANTLR has discovered a problem. Recall that a decision
|
||||||
|
* is represented internall with a DFA comprised of multiple states, each of
|
||||||
|
* which could potentially have problems.
|
||||||
|
*
|
||||||
|
* Because of this, you need to iterate over this list of DFA states. You'll
|
||||||
|
* note that most of the informational methods like
|
||||||
|
* getSampleNonDeterministicInputSequence() require a DFAState. This state
|
||||||
|
* will be one of the iterated states from stateToSyntacticallyAmbiguousAltsSet.
|
||||||
|
*
|
||||||
|
* This class is not thread safe due to shared use of visited maps etc...
|
||||||
|
* Only one thread should really need to access one DecisionProbe anyway.
|
||||||
|
*/
|
||||||
|
public class DecisionProbe {
|
||||||
|
public DFA dfa;
|
||||||
|
|
||||||
|
/** Track all DFA states with nondeterministic alternatives.
|
||||||
|
* By reaching the same DFA state, a path through the NFA for some input
|
||||||
|
* is able to reach the same NFA state by starting at more than one
|
||||||
|
* alternative's left edge. Though, later, we may find that predicates
|
||||||
|
* resolve the issue, but track info anyway.
|
||||||
|
* Note that from the DFA state, you can ask for
|
||||||
|
* which alts are nondeterministic.
|
||||||
|
*/
|
||||||
|
protected Set<DFAState> statesWithSyntacticallyAmbiguousAltsSet = new HashSet<DFAState>();
|
||||||
|
|
||||||
|
/** Track just like stateToSyntacticallyAmbiguousAltsMap, but only
|
||||||
|
* for nondeterminisms that arise in the Tokens rule such as keyword vs
|
||||||
|
* ID rule. The state maps to the list of Tokens rule alts that are
|
||||||
|
* in conflict.
|
||||||
|
*/
|
||||||
|
protected Map<DFAState, Set<Integer>> stateToSyntacticallyAmbiguousTokensRuleAltsMap =
|
||||||
|
new HashMap<DFAState, Set<Integer>>();
|
||||||
|
|
||||||
|
/** Was a syntactic ambiguity resolved with predicates? Any DFA
|
||||||
|
* state that predicts more than one alternative, must be resolved
|
||||||
|
* with predicates or it should be reported to the user.
|
||||||
|
*/
|
||||||
|
protected Set<DFAState> statesResolvedWithSemanticPredicatesSet = new HashSet<DFAState>();
|
||||||
|
|
||||||
|
/** Track the predicates for each alt per DFA state;
|
||||||
|
* more than one DFA state might have syntactically ambig alt prediction.
|
||||||
|
* Maps DFA state to another map, mapping alt number to a
|
||||||
|
* SemanticContext (pred(s) to execute to resolve syntactic ambiguity).
|
||||||
|
*/
|
||||||
|
protected Map<DFAState, Map<Integer,SemanticContext>> stateToAltSetWithSemanticPredicatesMap =
|
||||||
|
new HashMap<DFAState, Map<Integer,SemanticContext>>();
|
||||||
|
|
||||||
|
/** Tracks alts insufficiently covered.
|
||||||
|
* For example, p1||true gets reduced to true and so leaves
|
||||||
|
* whole alt uncovered. This maps DFA state to the set of alts
|
||||||
|
*/
|
||||||
|
protected Map<DFAState,Map<Integer, Set<Token>>> stateToIncompletelyCoveredAltsMap =
|
||||||
|
new HashMap<DFAState,Map<Integer, Set<Token>>>();
|
||||||
|
|
||||||
|
/** The set of states w/o emanating edges and w/o resolving sem preds. */
|
||||||
|
protected Set<DFAState> danglingStates = new HashSet<DFAState>();
|
||||||
|
|
||||||
|
/** The overall list of alts within the decision that have at least one
|
||||||
|
* conflicting input sequence.
|
||||||
|
*/
|
||||||
|
protected Set<Integer> altsWithProblem = new HashSet<Integer>();
|
||||||
|
|
||||||
|
/** If decision with > 1 alt has recursion in > 1 alt, it's nonregular
|
||||||
|
* lookahead. The decision cannot be made with a DFA.
|
||||||
|
* the alts are stored in altsWithProblem.
|
||||||
|
*/
|
||||||
|
protected boolean nonLLStarDecision = false;
|
||||||
|
|
||||||
|
/** Recursion is limited to a particular depth. If that limit is exceeded
|
||||||
|
* the proposed new NFAConfiguration is recorded for the associated DFA state.
|
||||||
|
*/
|
||||||
|
protected MultiMap<Integer, NFAConfiguration> stateToRecursionOverflowConfigurationsMap =
|
||||||
|
new MultiMap<Integer, NFAConfiguration>();
|
||||||
|
/*
|
||||||
|
protected Map<Integer, List<NFAConfiguration>> stateToRecursionOverflowConfigurationsMap =
|
||||||
|
new HashMap<Integer, List<NFAConfiguration>>();
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Left recursion discovered. The proposed new NFAConfiguration
|
||||||
|
* is recorded for the associated DFA state.
|
||||||
|
protected Map<Integer,List<NFAConfiguration>> stateToLeftRecursiveConfigurationsMap =
|
||||||
|
new HashMap<Integer,List<NFAConfiguration>>();
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Did ANTLR have to terminate early on the analysis of this decision? */
|
||||||
|
protected boolean timedOut = false;
|
||||||
|
|
||||||
|
/** Used to find paths through syntactically ambiguous DFA. If we've
|
||||||
|
* seen statement number before, what did we learn?
|
||||||
|
*/
|
||||||
|
protected Map<Integer, Integer> stateReachable;
|
||||||
|
|
||||||
|
public static final Integer REACHABLE_BUSY = Utils.integer(-1);
|
||||||
|
public static final Integer REACHABLE_NO = Utils.integer(0);
|
||||||
|
public static final Integer REACHABLE_YES = Utils.integer(1);
|
||||||
|
|
||||||
|
/** Used while finding a path through an NFA whose edge labels match
|
||||||
|
* an input sequence. Tracks the input position
|
||||||
|
* we were at the last time at this node. If same input position, then
|
||||||
|
* we'd have reached same state without consuming input...probably an
|
||||||
|
* infinite loop. Stop. Set<String>. The strings look like
|
||||||
|
* stateNumber_labelIndex.
|
||||||
|
*/
|
||||||
|
protected Set<String> statesVisitedAtInputDepth;
|
||||||
|
|
||||||
|
protected Set<Integer> statesVisitedDuringSampleSequence;
|
||||||
|
|
||||||
|
public static boolean verbose = false;
|
||||||
|
|
||||||
|
public DecisionProbe(DFA dfa) {
|
||||||
|
this.dfa = dfa;
|
||||||
|
}
|
||||||
|
|
||||||
|
// I N F O R M A T I O N A B O U T D E C I S I O N
|
||||||
|
|
||||||
|
/** Return a string like "3:22: ( A {;} | B )" that describes this
|
||||||
|
* decision.
|
||||||
|
*/
|
||||||
|
public String getDescription() {
|
||||||
|
return dfa.getNFADecisionStartState().getDescription();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isReduced() {
|
||||||
|
return dfa.isReduced();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCyclic() {
|
||||||
|
return dfa.isCyclic();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** If no states are dead-ends, no alts are unreachable, there are
|
||||||
|
* no nondeterminisms unresolved by syn preds, all is ok with decision.
|
||||||
|
*/
|
||||||
|
public boolean isDeterministic() {
|
||||||
|
if ( danglingStates.size()==0 &&
|
||||||
|
statesWithSyntacticallyAmbiguousAltsSet.size()==0 &&
|
||||||
|
dfa.getUnreachableAlts().size()==0 )
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( statesWithSyntacticallyAmbiguousAltsSet.size()>0 ) {
|
||||||
|
Iterator it =
|
||||||
|
statesWithSyntacticallyAmbiguousAltsSet.iterator();
|
||||||
|
while ( it.hasNext() ) {
|
||||||
|
DFAState d = (DFAState) it.next();
|
||||||
|
if ( !statesResolvedWithSemanticPredicatesSet.contains(d) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// no syntactically ambig alts were left unresolved by predicates
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Did the analysis complete it's work? */
|
||||||
|
public boolean analysisTimedOut() {
|
||||||
|
return timedOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Took too long to analyze a DFA */
|
||||||
|
public boolean analysisOverflowed() {
|
||||||
|
return stateToRecursionOverflowConfigurationsMap.size()>0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Found recursion in > 1 alt */
|
||||||
|
public boolean isNonLLStarDecision() {
|
||||||
|
return nonLLStarDecision;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** How many states does the DFA predictor have? */
|
||||||
|
public int getNumberOfStates() {
|
||||||
|
return dfa.getNumberOfStates();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get a list of all unreachable alternatives for this decision. There
|
||||||
|
* may be multiple alternatives with ambiguous input sequences, but this
|
||||||
|
* is the overall list of unreachable alternatives (either due to
|
||||||
|
* conflict resolution or alts w/o accept states).
|
||||||
|
*/
|
||||||
|
public List<Integer> getUnreachableAlts() {
|
||||||
|
return dfa.getUnreachableAlts();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** return set of states w/o emanating edges and w/o resolving sem preds.
|
||||||
|
* These states come about because the analysis algorithm had to
|
||||||
|
* terminate early to avoid infinite recursion for example (due to
|
||||||
|
* left recursion perhaps).
|
||||||
|
*/
|
||||||
|
public Set getDanglingStates() {
|
||||||
|
return danglingStates;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set getNonDeterministicAlts() {
|
||||||
|
return altsWithProblem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return the sorted list of alts that conflict within a single state.
|
||||||
|
* Note that predicates may resolve the conflict.
|
||||||
|
*/
|
||||||
|
public List getNonDeterministicAltsForState(DFAState targetState) {
|
||||||
|
Set nondetAlts = targetState.getNonDeterministicAlts();
|
||||||
|
if ( nondetAlts==null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
List sorted = new LinkedList();
|
||||||
|
sorted.addAll(nondetAlts);
|
||||||
|
Collections.sort(sorted); // make sure it's 1, 2, ...
|
||||||
|
return sorted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return all DFA states in this DFA that have NFA configurations that
|
||||||
|
* conflict. You must report a problem for each state in this set
|
||||||
|
* because each state represents a different input sequence.
|
||||||
|
*/
|
||||||
|
public Set getDFAStatesWithSyntacticallyAmbiguousAlts() {
|
||||||
|
return statesWithSyntacticallyAmbiguousAltsSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Which alts were specifically turned off to resolve nondeterminisms?
|
||||||
|
* This is different than the unreachable alts. Disabled doesn't mean that
|
||||||
|
* the alternative is totally unreachable necessarily, it just means
|
||||||
|
* that for this DFA state, that alt is disabled. There may be other
|
||||||
|
* accept states for that alt that make an alt reachable.
|
||||||
|
*/
|
||||||
|
public Set getDisabledAlternatives(DFAState d) {
|
||||||
|
return d.getDisabledAlternatives();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** If a recursion overflow is resolve with predicates, then we need
|
||||||
|
* to shut off the warning that would be generated.
|
||||||
|
*/
|
||||||
|
public void removeRecursiveOverflowState(DFAState d) {
|
||||||
|
Integer stateI = Utils.integer(d.stateNumber);
|
||||||
|
stateToRecursionOverflowConfigurationsMap.remove(stateI);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return a List<Label> indicating an input sequence that can be matched
|
||||||
|
* from the start state of the DFA to the targetState (which is known
|
||||||
|
* to have a problem).
|
||||||
|
*/
|
||||||
|
public List<Label> getSampleNonDeterministicInputSequence(DFAState targetState) {
|
||||||
|
Set dfaStates = getDFAPathStatesToTarget(targetState);
|
||||||
|
statesVisitedDuringSampleSequence = new HashSet<Integer>();
|
||||||
|
List<Label> labels = new ArrayList<Label>(); // may access ith element; use array
|
||||||
|
if ( dfa==null || dfa.startState==null ) {
|
||||||
|
return labels;
|
||||||
|
}
|
||||||
|
getSampleInputSequenceUsingStateSet(dfa.startState,
|
||||||
|
targetState,
|
||||||
|
dfaStates,
|
||||||
|
labels);
|
||||||
|
return labels;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Given List<Label>, return a String with a useful representation
|
||||||
|
* of the associated input string. One could show something different
|
||||||
|
* for lexers and parsers, for example.
|
||||||
|
*/
|
||||||
|
public String getInputSequenceDisplay(List labels) {
|
||||||
|
Grammar g = dfa.nfa.grammar;
|
||||||
|
StringBuffer buf = new StringBuffer();
|
||||||
|
for (Iterator it = labels.iterator(); it.hasNext();) {
|
||||||
|
Label label = (Label) it.next();
|
||||||
|
buf.append(label.toString(g));
|
||||||
|
if ( it.hasNext() && g.type!=Grammar.LEXER ) {
|
||||||
|
buf.append(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Given an alternative associated with a nondeterministic DFA state,
|
||||||
|
* find the path of NFA states associated with the labels sequence.
|
||||||
|
* Useful tracing where in the NFA, a single input sequence can be
|
||||||
|
* matched. For different alts, you should get different NFA paths.
|
||||||
|
*
|
||||||
|
* The first NFA state for all NFA paths will be the same: the starting
|
||||||
|
* NFA state of the first nondeterministic alt. Imagine (A|B|A|A):
|
||||||
|
*
|
||||||
|
* 5->9-A->o
|
||||||
|
* |
|
||||||
|
* 6->10-B->o
|
||||||
|
* |
|
||||||
|
* 7->11-A->o
|
||||||
|
* |
|
||||||
|
* 8->12-A->o
|
||||||
|
*
|
||||||
|
* There are 3 nondeterministic alts. The paths should be:
|
||||||
|
* 5 9 ...
|
||||||
|
* 5 6 7 11 ...
|
||||||
|
* 5 6 7 8 12 ...
|
||||||
|
*
|
||||||
|
* The NFA path matching the sample input sequence (labels) is computed
|
||||||
|
* using states 9, 11, and 12 rather than 5, 7, 8 because state 5, for
|
||||||
|
* example can get to all ambig paths. Must isolate for each alt (hence,
|
||||||
|
* the extra state beginning each alt in my NFA structures). Here,
|
||||||
|
* firstAlt=1.
|
||||||
|
*/
|
||||||
|
public List getNFAPathStatesForAlt(int firstAlt,
|
||||||
|
int alt,
|
||||||
|
List labels)
|
||||||
|
{
|
||||||
|
NFAState nfaStart = dfa.getNFADecisionStartState();
|
||||||
|
List path = new LinkedList();
|
||||||
|
// first add all NFA states leading up to altStart state
|
||||||
|
for (int a=firstAlt; a<=alt; a++) {
|
||||||
|
NFAState s =
|
||||||
|
dfa.nfa.grammar.getNFAStateForAltOfDecision(nfaStart,a);
|
||||||
|
path.add(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
// add first state of actual alt
|
||||||
|
NFAState altStart = dfa.nfa.grammar.getNFAStateForAltOfDecision(nfaStart,alt);
|
||||||
|
NFAState isolatedAltStart = (NFAState)altStart.transition[0].target;
|
||||||
|
path.add(isolatedAltStart);
|
||||||
|
|
||||||
|
// add the actual path now
|
||||||
|
statesVisitedAtInputDepth = new HashSet();
|
||||||
|
getNFAPath(isolatedAltStart,
|
||||||
|
0,
|
||||||
|
labels,
|
||||||
|
path);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Each state in the DFA represents a different input sequence for an
|
||||||
|
* alt of the decision. Given a DFA state, what is the semantic
|
||||||
|
* predicate context for a particular alt.
|
||||||
|
*/
|
||||||
|
public SemanticContext getSemanticContextForAlt(DFAState d, int alt) {
|
||||||
|
Map altToPredMap = (Map)stateToAltSetWithSemanticPredicatesMap.get(d);
|
||||||
|
if ( altToPredMap==null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (SemanticContext)altToPredMap.get(Utils.integer(alt));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** At least one alt refs a sem or syn pred */
|
||||||
|
public boolean hasPredicate() {
|
||||||
|
return stateToAltSetWithSemanticPredicatesMap.size()>0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set getNondeterministicStatesResolvedWithSemanticPredicate() {
|
||||||
|
return statesResolvedWithSemanticPredicatesSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return a list of alts whose predicate context was insufficient to
|
||||||
|
* resolve a nondeterminism for state d.
|
||||||
|
*/
|
||||||
|
public Map<Integer, Set<Token>> getIncompletelyCoveredAlts(DFAState d) {
|
||||||
|
return stateToIncompletelyCoveredAltsMap.get(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void issueWarnings() {
|
||||||
|
// NONREGULAR DUE TO RECURSION > 1 ALTS
|
||||||
|
// Issue this before aborted analysis, which might also occur
|
||||||
|
// if we take too long to terminate
|
||||||
|
if ( nonLLStarDecision && !dfa.getAutoBacktrackMode() ) {
|
||||||
|
ErrorManager.nonLLStarDecision(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( analysisTimedOut() ) {
|
||||||
|
// only report early termination errors if !backtracking
|
||||||
|
if ( !dfa.getAutoBacktrackMode() ) {
|
||||||
|
ErrorManager.analysisAborted(this);
|
||||||
|
}
|
||||||
|
// now just return...if we bailed out, don't spew other messages
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
issueRecursionWarnings();
|
||||||
|
|
||||||
|
// generate a separate message for each problem state in DFA
|
||||||
|
Set resolvedStates = getNondeterministicStatesResolvedWithSemanticPredicate();
|
||||||
|
Set problemStates = getDFAStatesWithSyntacticallyAmbiguousAlts();
|
||||||
|
if ( problemStates.size()>0 ) {
|
||||||
|
Iterator it =
|
||||||
|
problemStates.iterator();
|
||||||
|
while ( it.hasNext() && !dfa.nfa.grammar.NFAToDFAConversionExternallyAborted() ) {
|
||||||
|
DFAState d = (DFAState) it.next();
|
||||||
|
Map<Integer, Set<Token>> insufficientAltToLocations = getIncompletelyCoveredAlts(d);
|
||||||
|
if ( insufficientAltToLocations!=null && insufficientAltToLocations.size()>0 ) {
|
||||||
|
ErrorManager.insufficientPredicates(this,d,insufficientAltToLocations);
|
||||||
|
}
|
||||||
|
// don't report problem if resolved
|
||||||
|
if ( resolvedStates==null || !resolvedStates.contains(d) ) {
|
||||||
|
// first strip last alt from disableAlts if it's wildcard
|
||||||
|
// then don't print error if no more disable alts
|
||||||
|
Set disabledAlts = getDisabledAlternatives(d);
|
||||||
|
stripWildCardAlts(disabledAlts);
|
||||||
|
if ( disabledAlts.size()>0 ) {
|
||||||
|
ErrorManager.nondeterminism(this,d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Set danglingStates = getDanglingStates();
|
||||||
|
if ( danglingStates.size()>0 ) {
|
||||||
|
//System.err.println("no emanating edges for states: "+danglingStates);
|
||||||
|
for (Iterator it = danglingStates.iterator(); it.hasNext();) {
|
||||||
|
DFAState d = (DFAState) it.next();
|
||||||
|
ErrorManager.danglingState(this,d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !nonLLStarDecision ) {
|
||||||
|
List<Integer> unreachableAlts = dfa.getUnreachableAlts();
|
||||||
|
if ( unreachableAlts!=null && unreachableAlts.size()>0 ) {
|
||||||
|
// give different msg if it's an empty Tokens rule from delegate
|
||||||
|
boolean isInheritedTokensRule = false;
|
||||||
|
if ( dfa.isTokensRuleDecision() ) {
|
||||||
|
for (Integer altI : unreachableAlts) {
|
||||||
|
GrammarAST decAST = dfa.getDecisionASTNode();
|
||||||
|
GrammarAST altAST = decAST.getChild(altI-1);
|
||||||
|
GrammarAST delegatedTokensAlt =
|
||||||
|
altAST.getFirstChildWithType(ANTLRParser.DOT);
|
||||||
|
if ( delegatedTokensAlt !=null ) {
|
||||||
|
isInheritedTokensRule = true;
|
||||||
|
ErrorManager.grammarWarning(ErrorManager.MSG_IMPORTED_TOKENS_RULE_EMPTY,
|
||||||
|
dfa.nfa.grammar,
|
||||||
|
null,
|
||||||
|
dfa.nfa.grammar.name,
|
||||||
|
delegatedTokensAlt.getFirstChild().getText());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( isInheritedTokensRule ) {
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ErrorManager.unreachableAlts(this,unreachableAlts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get the last disabled alt number and check in the grammar to see
|
||||||
|
* if that alt is a simple wildcard. If so, treat like an else clause
|
||||||
|
* and don't emit the error. Strip out the last alt if it's wildcard.
|
||||||
|
*/
|
||||||
|
protected void stripWildCardAlts(Set disabledAlts) {
|
||||||
|
List sortedDisableAlts = new ArrayList(disabledAlts);
|
||||||
|
Collections.sort(sortedDisableAlts);
|
||||||
|
Integer lastAlt =
|
||||||
|
(Integer)sortedDisableAlts.get(sortedDisableAlts.size()-1);
|
||||||
|
GrammarAST blockAST =
|
||||||
|
dfa.nfa.grammar.getDecisionBlockAST(dfa.decisionNumber);
|
||||||
|
//System.out.println("block with error = "+blockAST.toStringTree());
|
||||||
|
GrammarAST lastAltAST = null;
|
||||||
|
if ( blockAST.getChild(0).getType()==ANTLRParser.OPTIONS ) {
|
||||||
|
// if options, skip first child: ( options { ( = greedy false ) )
|
||||||
|
lastAltAST = blockAST.getChild(lastAlt.intValue());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lastAltAST = blockAST.getChild(lastAlt.intValue()-1);
|
||||||
|
}
|
||||||
|
//System.out.println("last alt is "+lastAltAST.toStringTree());
|
||||||
|
// if last alt looks like ( ALT . <end-of-alt> ) then wildcard
|
||||||
|
// Avoid looking at optional blocks etc... that have last alt
|
||||||
|
// as the EOB:
|
||||||
|
// ( BLOCK ( ALT 'else' statement <end-of-alt> ) <end-of-block> )
|
||||||
|
if ( lastAltAST.getType()!=ANTLRParser.EOB &&
|
||||||
|
lastAltAST.getChild(0).getType()== ANTLRParser.WILDCARD &&
|
||||||
|
lastAltAST.getChild(1).getType()== ANTLRParser.EOA )
|
||||||
|
{
|
||||||
|
//System.out.println("wildcard");
|
||||||
|
disabledAlts.remove(lastAlt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void issueRecursionWarnings() {
|
||||||
|
// RECURSION OVERFLOW
|
||||||
|
Set dfaStatesWithRecursionProblems =
|
||||||
|
stateToRecursionOverflowConfigurationsMap.keySet();
|
||||||
|
// now walk truly unique (unaliased) list of dfa states with inf recur
|
||||||
|
// Goal: create a map from alt to map<target,List<callsites>>
|
||||||
|
// Map<Map<String target, List<NFAState call sites>>
|
||||||
|
Map altToTargetToCallSitesMap = new HashMap();
|
||||||
|
// track a single problem DFA state for each alt
|
||||||
|
Map altToDFAState = new HashMap();
|
||||||
|
computeAltToProblemMaps(dfaStatesWithRecursionProblems,
|
||||||
|
stateToRecursionOverflowConfigurationsMap,
|
||||||
|
altToTargetToCallSitesMap, // output param
|
||||||
|
altToDFAState); // output param
|
||||||
|
|
||||||
|
// walk each alt with recursion overflow problems and generate error
|
||||||
|
Set alts = altToTargetToCallSitesMap.keySet();
|
||||||
|
List sortedAlts = new ArrayList(alts);
|
||||||
|
Collections.sort(sortedAlts);
|
||||||
|
for (Iterator altsIt = sortedAlts.iterator(); altsIt.hasNext();) {
|
||||||
|
Integer altI = (Integer) altsIt.next();
|
||||||
|
Map targetToCallSiteMap =
|
||||||
|
(Map)altToTargetToCallSitesMap.get(altI);
|
||||||
|
Set targetRules = targetToCallSiteMap.keySet();
|
||||||
|
Collection callSiteStates = targetToCallSiteMap.values();
|
||||||
|
DFAState sampleBadState = (DFAState)altToDFAState.get(altI);
|
||||||
|
ErrorManager.recursionOverflow(this,
|
||||||
|
sampleBadState,
|
||||||
|
altI.intValue(),
|
||||||
|
targetRules,
|
||||||
|
callSiteStates);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void computeAltToProblemMaps(Set dfaStatesUnaliased,
|
||||||
|
Map configurationsMap,
|
||||||
|
Map altToTargetToCallSitesMap,
|
||||||
|
Map altToDFAState)
|
||||||
|
{
|
||||||
|
for (Iterator it = dfaStatesUnaliased.iterator(); it.hasNext();) {
|
||||||
|
Integer stateI = (Integer) it.next();
|
||||||
|
// walk this DFA's config list
|
||||||
|
List configs = (List)configurationsMap.get(stateI);
|
||||||
|
for (int i = 0; i < configs.size(); i++) {
|
||||||
|
NFAConfiguration c = (NFAConfiguration) configs.get(i);
|
||||||
|
NFAState ruleInvocationState = dfa.nfa.getState(c.state);
|
||||||
|
Transition transition0 = ruleInvocationState.transition[0];
|
||||||
|
RuleClosureTransition ref = (RuleClosureTransition)transition0;
|
||||||
|
String targetRule = ((NFAState) ref.target).enclosingRule.name;
|
||||||
|
Integer altI = Utils.integer(c.alt);
|
||||||
|
Map targetToCallSiteMap =
|
||||||
|
(Map)altToTargetToCallSitesMap.get(altI);
|
||||||
|
if ( targetToCallSiteMap==null ) {
|
||||||
|
targetToCallSiteMap = new HashMap();
|
||||||
|
altToTargetToCallSitesMap.put(altI, targetToCallSiteMap);
|
||||||
|
}
|
||||||
|
Set callSites =
|
||||||
|
(HashSet)targetToCallSiteMap.get(targetRule);
|
||||||
|
if ( callSites==null ) {
|
||||||
|
callSites = new HashSet();
|
||||||
|
targetToCallSiteMap.put(targetRule, callSites);
|
||||||
|
}
|
||||||
|
callSites.add(ruleInvocationState);
|
||||||
|
// track one problem DFA state per alt
|
||||||
|
if ( altToDFAState.get(altI)==null ) {
|
||||||
|
DFAState sampleBadState = dfa.getState(stateI.intValue());
|
||||||
|
altToDFAState.put(altI, sampleBadState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set getUnaliasedDFAStateSet(Set dfaStatesWithRecursionProblems) {
|
||||||
|
Set dfaStatesUnaliased = new HashSet();
|
||||||
|
for (Iterator it = dfaStatesWithRecursionProblems.iterator(); it.hasNext();) {
|
||||||
|
Integer stateI = (Integer) it.next();
|
||||||
|
DFAState d = dfa.getState(stateI.intValue());
|
||||||
|
dfaStatesUnaliased.add(Utils.integer(d.stateNumber));
|
||||||
|
}
|
||||||
|
return dfaStatesUnaliased;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// T R A C K I N G M E T H O D S
|
||||||
|
|
||||||
|
/** Report the fact that DFA state d is not a state resolved with
|
||||||
|
* predicates and yet it has no emanating edges. Usually this
|
||||||
|
* is a result of the closure/reach operations being unable to proceed
|
||||||
|
*/
|
||||||
|
public void reportDanglingState(DFAState d) {
|
||||||
|
danglingStates.add(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reportAnalysisTimeout() {
|
||||||
|
timedOut = true;
|
||||||
|
dfa.nfa.grammar.setOfDFAWhoseAnalysisTimedOut.add(dfa);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Report that at least 2 alts have recursive constructs. There is
|
||||||
|
* no way to build a DFA so we terminated.
|
||||||
|
*/
|
||||||
|
public void reportNonLLStarDecision(DFA dfa) {
|
||||||
|
/*
|
||||||
|
System.out.println("non-LL(*) DFA "+dfa.decisionNumber+", alts: "+
|
||||||
|
dfa.recursiveAltSet.toList());
|
||||||
|
*/
|
||||||
|
nonLLStarDecision = true;
|
||||||
|
altsWithProblem.addAll(dfa.recursiveAltSet.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reportRecursionOverflow(DFAState d,
|
||||||
|
NFAConfiguration recursionNFAConfiguration)
|
||||||
|
{
|
||||||
|
// track the state number rather than the state as d will change
|
||||||
|
// out from underneath us; hash wouldn't return any value
|
||||||
|
|
||||||
|
// left-recursion is detected in start state. Since we can't
|
||||||
|
// call resolveNondeterminism() on the start state (it would
|
||||||
|
// not look k=1 to get min single token lookahead), we must
|
||||||
|
// prevent errors derived from this state. Avoid start state
|
||||||
|
if ( d.stateNumber > 0 ) {
|
||||||
|
Integer stateI = Utils.integer(d.stateNumber);
|
||||||
|
stateToRecursionOverflowConfigurationsMap.map(stateI, recursionNFAConfiguration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reportNondeterminism(DFAState d, Set<Integer> nondeterministicAlts) {
|
||||||
|
altsWithProblem.addAll(nondeterministicAlts); // track overall list
|
||||||
|
statesWithSyntacticallyAmbiguousAltsSet.add(d);
|
||||||
|
dfa.nfa.grammar.setOfNondeterministicDecisionNumbers.add(
|
||||||
|
Utils.integer(dfa.getDecisionNumber())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Currently the analysis reports issues between token definitions, but
|
||||||
|
* we don't print out warnings in favor of just picking the first token
|
||||||
|
* definition found in the grammar ala lex/flex.
|
||||||
|
*/
|
||||||
|
public void reportLexerRuleNondeterminism(DFAState d, Set<Integer> nondeterministicAlts) {
|
||||||
|
stateToSyntacticallyAmbiguousTokensRuleAltsMap.put(d,nondeterministicAlts);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reportNondeterminismResolvedWithSemanticPredicate(DFAState d) {
|
||||||
|
// First, prevent a recursion warning on this state due to
|
||||||
|
// pred resolution
|
||||||
|
if ( d.abortedDueToRecursionOverflow ) {
|
||||||
|
d.dfa.probe.removeRecursiveOverflowState(d);
|
||||||
|
}
|
||||||
|
statesResolvedWithSemanticPredicatesSet.add(d);
|
||||||
|
//System.out.println("resolved with pred: "+d);
|
||||||
|
dfa.nfa.grammar.setOfNondeterministicDecisionNumbersResolvedWithPredicates.add(
|
||||||
|
Utils.integer(dfa.getDecisionNumber())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Report the list of predicates found for each alternative; copy
|
||||||
|
* the list because this set gets altered later by the method
|
||||||
|
* tryToResolveWithSemanticPredicates() while flagging NFA configurations
|
||||||
|
* in d as resolved.
|
||||||
|
*/
|
||||||
|
public void reportAltPredicateContext(DFAState d, Map altPredicateContext) {
|
||||||
|
Map copy = new HashMap();
|
||||||
|
copy.putAll(altPredicateContext);
|
||||||
|
stateToAltSetWithSemanticPredicatesMap.put(d,copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reportIncompletelyCoveredAlts(DFAState d,
|
||||||
|
Map<Integer, Set<Token>> altToLocationsReachableWithoutPredicate)
|
||||||
|
{
|
||||||
|
stateToIncompletelyCoveredAltsMap.put(d, altToLocationsReachableWithoutPredicate);
|
||||||
|
}
|
||||||
|
|
||||||
|
// S U P P O R T
|
||||||
|
|
||||||
|
/** Given a start state and a target state, return true if start can reach
|
||||||
|
* target state. Also, compute the set of DFA states
|
||||||
|
* that are on a path from start to target; return in states parameter.
|
||||||
|
*/
|
||||||
|
protected boolean reachesState(DFAState startState,
|
||||||
|
DFAState targetState,
|
||||||
|
Set states) {
|
||||||
|
if ( startState==targetState ) {
|
||||||
|
states.add(targetState);
|
||||||
|
//System.out.println("found target DFA state "+targetState.getStateNumber());
|
||||||
|
stateReachable.put(startState.stateNumber, REACHABLE_YES);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
DFAState s = startState;
|
||||||
|
// avoid infinite loops
|
||||||
|
stateReachable.put(s.stateNumber, REACHABLE_BUSY);
|
||||||
|
|
||||||
|
// look for a path to targetState among transitions for this state
|
||||||
|
// stop when you find the first one; I'm pretty sure there is
|
||||||
|
// at most one path to any DFA state with conflicting predictions
|
||||||
|
for (int i=0; i<s.getNumberOfTransitions(); i++) {
|
||||||
|
Transition t = s.transition(i);
|
||||||
|
DFAState edgeTarget = (DFAState)t.target;
|
||||||
|
Integer targetStatus = stateReachable.get(edgeTarget.stateNumber);
|
||||||
|
if ( targetStatus==REACHABLE_BUSY ) { // avoid cycles; they say nothing
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ( targetStatus==REACHABLE_YES ) { // return success!
|
||||||
|
stateReachable.put(s.stateNumber, REACHABLE_YES);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ( targetStatus==REACHABLE_NO ) { // try another transition
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// if null, target must be REACHABLE_UNKNOWN (i.e., unvisited)
|
||||||
|
if ( reachesState(edgeTarget, targetState, states) ) {
|
||||||
|
states.add(s);
|
||||||
|
stateReachable.put(s.stateNumber, REACHABLE_YES);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stateReachable.put(s.stateNumber, REACHABLE_NO);
|
||||||
|
return false; // no path to targetState found.
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Set getDFAPathStatesToTarget(DFAState targetState) {
|
||||||
|
Set dfaStates = new HashSet();
|
||||||
|
stateReachable = new HashMap();
|
||||||
|
if ( dfa==null || dfa.startState==null ) {
|
||||||
|
return dfaStates;
|
||||||
|
}
|
||||||
|
boolean reaches = reachesState(dfa.startState, targetState, dfaStates);
|
||||||
|
return dfaStates;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Given a start state and a final state, find a list of edge labels
|
||||||
|
* between the two ignoring epsilon. Limit your scan to a set of states
|
||||||
|
* passed in. This is used to show a sample input sequence that is
|
||||||
|
* nondeterministic with respect to this decision. Return List<Label> as
|
||||||
|
* a parameter. The incoming states set must be all states that lead
|
||||||
|
* from startState to targetState and no others so this algorithm doesn't
|
||||||
|
* take a path that eventually leads to a state other than targetState.
|
||||||
|
* Don't follow loops, leading to short (possibly shortest) path.
|
||||||
|
*/
|
||||||
|
protected void getSampleInputSequenceUsingStateSet(State startState,
|
||||||
|
State targetState,
|
||||||
|
Set states,
|
||||||
|
List<Label> labels)
|
||||||
|
{
|
||||||
|
statesVisitedDuringSampleSequence.add(startState.stateNumber);
|
||||||
|
|
||||||
|
// pick the first edge in states as the one to traverse
|
||||||
|
for (int i=0; i<startState.getNumberOfTransitions(); i++) {
|
||||||
|
Transition t = startState.transition(i);
|
||||||
|
DFAState edgeTarget = (DFAState)t.target;
|
||||||
|
if ( states.contains(edgeTarget) &&
|
||||||
|
!statesVisitedDuringSampleSequence.contains(edgeTarget.stateNumber) )
|
||||||
|
{
|
||||||
|
labels.add(t.label); // traverse edge and track label
|
||||||
|
if ( edgeTarget!=targetState ) {
|
||||||
|
// get more labels if not at target
|
||||||
|
getSampleInputSequenceUsingStateSet(edgeTarget,
|
||||||
|
targetState,
|
||||||
|
states,
|
||||||
|
labels);
|
||||||
|
}
|
||||||
|
// done with this DFA state as we've found a good path to target
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
labels.add(new Label(Label.EPSILON)); // indicate no input found
|
||||||
|
// this happens on a : {p1}? a | A ;
|
||||||
|
//ErrorManager.error(ErrorManager.MSG_CANNOT_COMPUTE_SAMPLE_INPUT_SEQ);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Given a sample input sequence, you usually would like to know the
|
||||||
|
* path taken through the NFA. Return the list of NFA states visited
|
||||||
|
* while matching a list of labels. This cannot use the usual
|
||||||
|
* interpreter, which does a deterministic walk. We need to be able to
|
||||||
|
* take paths that are turned off during nondeterminism resolution. So,
|
||||||
|
* just do a depth-first walk traversing edges labeled with the current
|
||||||
|
* label. Return true if a path was found emanating from state s.
|
||||||
|
*/
|
||||||
|
protected boolean getNFAPath(NFAState s, // starting where?
|
||||||
|
int labelIndex, // 0..labels.size()-1
|
||||||
|
List labels, // input sequence
|
||||||
|
List path) // output list of NFA states
|
||||||
|
{
|
||||||
|
// track a visit to state s at input index labelIndex if not seen
|
||||||
|
String thisStateKey = getStateLabelIndexKey(s.stateNumber,labelIndex);
|
||||||
|
if ( statesVisitedAtInputDepth.contains(thisStateKey) ) {
|
||||||
|
/*
|
||||||
|
System.out.println("### already visited "+s.stateNumber+" previously at index "+
|
||||||
|
labelIndex);
|
||||||
|
*/
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
statesVisitedAtInputDepth.add(thisStateKey);
|
||||||
|
|
||||||
|
/*
|
||||||
|
System.out.println("enter state "+s.stateNumber+" visited states: "+
|
||||||
|
statesVisitedAtInputDepth);
|
||||||
|
*/
|
||||||
|
|
||||||
|
// pick the first edge whose target is in states and whose
|
||||||
|
// label is labels[labelIndex]
|
||||||
|
for (int i=0; i<s.getNumberOfTransitions(); i++) {
|
||||||
|
Transition t = s.transition[i];
|
||||||
|
NFAState edgeTarget = (NFAState)t.target;
|
||||||
|
Label label = (Label)labels.get(labelIndex);
|
||||||
|
/*
|
||||||
|
System.out.println(s.stateNumber+"-"+
|
||||||
|
t.label.toString(dfa.nfa.grammar)+"->"+
|
||||||
|
edgeTarget.stateNumber+" =="+
|
||||||
|
label.toString(dfa.nfa.grammar)+"?");
|
||||||
|
*/
|
||||||
|
if ( t.label.isEpsilon() || t.label.isSemanticPredicate() ) {
|
||||||
|
// nondeterministically backtrack down epsilon edges
|
||||||
|
path.add(edgeTarget);
|
||||||
|
boolean found =
|
||||||
|
getNFAPath(edgeTarget, labelIndex, labels, path);
|
||||||
|
if ( found ) {
|
||||||
|
statesVisitedAtInputDepth.remove(thisStateKey);
|
||||||
|
return true; // return to "calling" state
|
||||||
|
}
|
||||||
|
path.remove(path.size()-1); // remove; didn't work out
|
||||||
|
continue; // look at the next edge
|
||||||
|
}
|
||||||
|
if ( t.label.matches(label) ) {
|
||||||
|
path.add(edgeTarget);
|
||||||
|
/*
|
||||||
|
System.out.println("found label "+
|
||||||
|
t.label.toString(dfa.nfa.grammar)+
|
||||||
|
" at state "+s.stateNumber+"; labelIndex="+labelIndex);
|
||||||
|
*/
|
||||||
|
if ( labelIndex==labels.size()-1 ) {
|
||||||
|
// found last label; done!
|
||||||
|
statesVisitedAtInputDepth.remove(thisStateKey);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// otherwise try to match remaining input
|
||||||
|
boolean found =
|
||||||
|
getNFAPath(edgeTarget, labelIndex+1, labels, path);
|
||||||
|
if ( found ) {
|
||||||
|
statesVisitedAtInputDepth.remove(thisStateKey);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
System.out.println("backtrack; path from "+s.stateNumber+"->"+
|
||||||
|
t.label.toString(dfa.nfa.grammar)+" didn't work");
|
||||||
|
*/
|
||||||
|
path.remove(path.size()-1); // remove; didn't work out
|
||||||
|
continue; // keep looking for a path for labels
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//System.out.println("no epsilon or matching edge; removing "+thisStateKey);
|
||||||
|
// no edge was found matching label; is ok, some state will have it
|
||||||
|
statesVisitedAtInputDepth.remove(thisStateKey);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getStateLabelIndexKey(int s, int i) {
|
||||||
|
StringBuffer buf = new StringBuffer();
|
||||||
|
buf.append(s);
|
||||||
|
buf.append('_');
|
||||||
|
buf.append(i);
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** From an alt number associated with artificial Tokens rule, return
|
||||||
|
* the name of the token that is associated with that alt.
|
||||||
|
*/
|
||||||
|
public String getTokenNameForTokensRuleAlt(int alt) {
|
||||||
|
NFAState decisionState = dfa.getNFADecisionStartState();
|
||||||
|
NFAState altState =
|
||||||
|
dfa.nfa.grammar.getNFAStateForAltOfDecision(decisionState,alt);
|
||||||
|
NFAState decisionLeft = (NFAState)altState.transition[0].target;
|
||||||
|
RuleClosureTransition ruleCallEdge =
|
||||||
|
(RuleClosureTransition)decisionLeft.transition[0];
|
||||||
|
NFAState ruleStartState = (NFAState)ruleCallEdge.target;
|
||||||
|
//System.out.println("alt = "+decisionLeft.getEnclosingRule());
|
||||||
|
return ruleStartState.enclosingRule.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
stateToRecursionOverflowConfigurationsMap.clear();
|
||||||
|
}
|
||||||
|
}
|
444
antlr_3_1_source/analysis/LL1Analyzer.java
Normal file
444
antlr_3_1_source/analysis/LL1Analyzer.java
Normal file
@ -0,0 +1,444 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2008 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.antlr.analysis;
|
||||||
|
|
||||||
|
import org.antlr.tool.Rule;
|
||||||
|
import org.antlr.tool.ANTLRParser;
|
||||||
|
import org.antlr.tool.Grammar;
|
||||||
|
import org.antlr.misc.IntervalSet;
|
||||||
|
import org.antlr.misc.IntSet;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by IntelliJ IDEA.
|
||||||
|
* User: parrt
|
||||||
|
* Date: Dec 31, 2007
|
||||||
|
* Time: 1:31:16 PM
|
||||||
|
* To change this template use File | Settings | File Templates.
|
||||||
|
*/
|
||||||
|
public class LL1Analyzer {
|
||||||
|
/** 0 if we hit end of rule and invoker should keep going (epsilon) */
|
||||||
|
public static final int DETECT_PRED_EOR = 0;
|
||||||
|
/** 1 if we found a nonautobacktracking pred */
|
||||||
|
public static final int DETECT_PRED_FOUND = 1;
|
||||||
|
/** 2 if we didn't find such a pred */
|
||||||
|
public static final int DETECT_PRED_NOT_FOUND = 2;
|
||||||
|
|
||||||
|
public Grammar grammar;
|
||||||
|
|
||||||
|
/** Used during LOOK to detect computation cycles */
|
||||||
|
protected Set<NFAState> lookBusy = new HashSet<NFAState>();
|
||||||
|
|
||||||
|
public Map<NFAState, LookaheadSet> FIRSTCache = new HashMap<NFAState, LookaheadSet>();
|
||||||
|
public Map<Rule, LookaheadSet> FOLLOWCache = new HashMap<Rule, LookaheadSet>();
|
||||||
|
|
||||||
|
public LL1Analyzer(Grammar grammar) {
|
||||||
|
this.grammar = grammar;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
public void computeRuleFIRSTSets() {
|
||||||
|
if ( getNumberOfDecisions()==0 ) {
|
||||||
|
createNFAs();
|
||||||
|
}
|
||||||
|
for (Iterator it = getRules().iterator(); it.hasNext();) {
|
||||||
|
Rule r = (Rule)it.next();
|
||||||
|
if ( r.isSynPred ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
LookaheadSet s = FIRST(r);
|
||||||
|
System.out.println("FIRST("+r.name+")="+s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
public Set<String> getOverriddenRulesWithDifferentFIRST() {
|
||||||
|
// walk every rule in this grammar and compare FIRST set with
|
||||||
|
// those in imported grammars.
|
||||||
|
Set<String> rules = new HashSet();
|
||||||
|
for (Iterator it = getRules().iterator(); it.hasNext();) {
|
||||||
|
Rule r = (Rule)it.next();
|
||||||
|
//System.out.println(r.name+" FIRST="+r.FIRST);
|
||||||
|
for (int i = 0; i < delegates.size(); i++) {
|
||||||
|
Grammar g = delegates.get(i);
|
||||||
|
Rule importedRule = g.getRule(r.name);
|
||||||
|
if ( importedRule != null ) { // exists in imported grammar
|
||||||
|
// System.out.println(r.name+" exists in imported grammar: FIRST="+importedRule.FIRST);
|
||||||
|
if ( !r.FIRST.equals(importedRule.FIRST) ) {
|
||||||
|
rules.add(r.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rules;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Rule> getImportedRulesSensitiveToOverriddenRulesDueToLOOK() {
|
||||||
|
Set<String> diffFIRSTs = getOverriddenRulesWithDifferentFIRST();
|
||||||
|
Set<Rule> rules = new HashSet();
|
||||||
|
for (Iterator it = diffFIRSTs.iterator(); it.hasNext();) {
|
||||||
|
String r = (String) it.next();
|
||||||
|
for (int i = 0; i < delegates.size(); i++) {
|
||||||
|
Grammar g = delegates.get(i);
|
||||||
|
Set<Rule> callers = g.ruleSensitivity.get(r);
|
||||||
|
// somebody invokes rule whose FIRST changed in subgrammar?
|
||||||
|
if ( callers!=null ) {
|
||||||
|
rules.addAll(callers);
|
||||||
|
//System.out.println(g.name+" rules "+callers+" sensitive to "+r+"; dup 'em");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rules;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
public LookaheadSet LOOK(Rule r) {
|
||||||
|
if ( r.FIRST==null ) {
|
||||||
|
r.FIRST = FIRST(r.startState);
|
||||||
|
}
|
||||||
|
return r.FIRST;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** From an NFA state, s, find the set of all labels reachable from s.
|
||||||
|
* Used to compute follow sets for error recovery. Never computes
|
||||||
|
* a FOLLOW operation. FIRST stops at end of rules, returning EOR, unless
|
||||||
|
* invoked from another rule. I.e., routine properly handles
|
||||||
|
*
|
||||||
|
* a : b A ;
|
||||||
|
*
|
||||||
|
* where b is nullable.
|
||||||
|
*
|
||||||
|
* We record with EOR_TOKEN_TYPE if we hit the end of a rule so we can
|
||||||
|
* know at runtime (when these sets are used) to start walking up the
|
||||||
|
* follow chain to compute the real, correct follow set (as opposed to
|
||||||
|
* the FOLLOW, which is a superset).
|
||||||
|
*
|
||||||
|
* This routine will only be used on parser and tree parser grammars.
|
||||||
|
*/
|
||||||
|
public LookaheadSet FIRST(NFAState s) {
|
||||||
|
//System.out.println("> FIRST("+s+") in rule "+s.enclosingRule);
|
||||||
|
lookBusy.clear();
|
||||||
|
LookaheadSet look = _FIRST(s, false);
|
||||||
|
//System.out.println("< FIRST("+s+") in rule "+s.enclosingRule+"="+look.toString(this));
|
||||||
|
return look;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LookaheadSet FOLLOW(Rule r) {
|
||||||
|
LookaheadSet f = FOLLOWCache.get(r);
|
||||||
|
if ( f!=null ) {
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
f = _FIRST(r.stopState, true);
|
||||||
|
FOLLOWCache.put(r, f);
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LookaheadSet LOOK(NFAState s) {
|
||||||
|
if ( NFAToDFAConverter.debug ) {
|
||||||
|
System.out.println("> LOOK("+s+")");
|
||||||
|
}
|
||||||
|
lookBusy.clear();
|
||||||
|
LookaheadSet look = _FIRST(s, true);
|
||||||
|
// FOLLOW makes no sense (at the moment!) for lexical rules.
|
||||||
|
if ( grammar.type!=Grammar.LEXER && look.member(Label.EOR_TOKEN_TYPE) ) {
|
||||||
|
// avoid altering FIRST reset as it is cached
|
||||||
|
LookaheadSet f = FOLLOW(s.enclosingRule);
|
||||||
|
f.orInPlace(look);
|
||||||
|
f.remove(Label.EOR_TOKEN_TYPE);
|
||||||
|
look = f;
|
||||||
|
//look.orInPlace(FOLLOW(s.enclosingRule));
|
||||||
|
}
|
||||||
|
else if ( grammar.type==Grammar.LEXER && look.member(Label.EOT) ) {
|
||||||
|
// if this has EOT, lookahead is all char (all char can follow rule)
|
||||||
|
//look = new LookaheadSet(Label.EOT);
|
||||||
|
look = new LookaheadSet(IntervalSet.COMPLETE_SET);
|
||||||
|
}
|
||||||
|
if ( NFAToDFAConverter.debug ) {
|
||||||
|
System.out.println("< LOOK("+s+")="+look.toString(grammar));
|
||||||
|
}
|
||||||
|
return look;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected LookaheadSet _FIRST(NFAState s, boolean chaseFollowTransitions) {
|
||||||
|
//System.out.println("_LOOK("+s+") in rule "+s.enclosingRule);
|
||||||
|
/*
|
||||||
|
if ( s.transition[0] instanceof RuleClosureTransition ) {
|
||||||
|
System.out.println("go to rule "+((NFAState)s.transition[0].target).enclosingRule);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
if ( !chaseFollowTransitions && s.isAcceptState() ) {
|
||||||
|
if ( grammar.type==Grammar.LEXER ) {
|
||||||
|
// FOLLOW makes no sense (at the moment!) for lexical rules.
|
||||||
|
// assume all char can follow
|
||||||
|
return new LookaheadSet(IntervalSet.COMPLETE_SET);
|
||||||
|
}
|
||||||
|
return new LookaheadSet(Label.EOR_TOKEN_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( lookBusy.contains(s) ) {
|
||||||
|
// return a copy of an empty set; we may modify set inline
|
||||||
|
return new LookaheadSet();
|
||||||
|
}
|
||||||
|
lookBusy.add(s);
|
||||||
|
|
||||||
|
Transition transition0 = s.transition[0];
|
||||||
|
if ( transition0==null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( transition0.label.isAtom() ) {
|
||||||
|
int atom = transition0.label.getAtom();
|
||||||
|
return new LookaheadSet(atom);
|
||||||
|
}
|
||||||
|
if ( transition0.label.isSet() ) {
|
||||||
|
IntSet sl = transition0.label.getSet();
|
||||||
|
return new LookaheadSet(sl);
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute FIRST of transition 0
|
||||||
|
LookaheadSet tset = null;
|
||||||
|
// if transition 0 is a rule call and we don't want FOLLOW, check cache
|
||||||
|
if ( !chaseFollowTransitions && transition0 instanceof RuleClosureTransition ) {
|
||||||
|
LookaheadSet prev = FIRSTCache.get((NFAState)transition0.target);
|
||||||
|
if ( prev!=null ) {
|
||||||
|
tset = prev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if not in cache, must compute
|
||||||
|
if ( tset==null ) {
|
||||||
|
tset = _FIRST((NFAState)transition0.target, chaseFollowTransitions);
|
||||||
|
// save FIRST cache for transition 0 if rule call
|
||||||
|
if ( !chaseFollowTransitions && transition0 instanceof RuleClosureTransition ) {
|
||||||
|
FIRSTCache.put((NFAState)transition0.target, tset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// did we fall off the end?
|
||||||
|
if ( grammar.type!=Grammar.LEXER && tset.member(Label.EOR_TOKEN_TYPE) ) {
|
||||||
|
if ( transition0 instanceof RuleClosureTransition ) {
|
||||||
|
// we called a rule that found the end of the rule.
|
||||||
|
// That means the rule is nullable and we need to
|
||||||
|
// keep looking at what follows the rule ref. E.g.,
|
||||||
|
// a : b A ; where b is nullable means that LOOK(a)
|
||||||
|
// should include A.
|
||||||
|
RuleClosureTransition ruleInvocationTrans =
|
||||||
|
(RuleClosureTransition)transition0;
|
||||||
|
// remove the EOR and get what follows
|
||||||
|
//tset.remove(Label.EOR_TOKEN_TYPE);
|
||||||
|
NFAState following = (NFAState) ruleInvocationTrans.followState;
|
||||||
|
LookaheadSet fset = _FIRST(following, chaseFollowTransitions);
|
||||||
|
fset.orInPlace(tset); // tset cached; or into new set
|
||||||
|
fset.remove(Label.EOR_TOKEN_TYPE);
|
||||||
|
tset = fset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Transition transition1 = s.transition[1];
|
||||||
|
if ( transition1!=null ) {
|
||||||
|
LookaheadSet tset1 =
|
||||||
|
_FIRST((NFAState)transition1.target, chaseFollowTransitions);
|
||||||
|
tset1.orInPlace(tset); // tset cached; or into new set
|
||||||
|
tset = tset1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Is there a non-syn-pred predicate visible from s that is not in
|
||||||
|
* the rule enclosing s? This accounts for most predicate situations
|
||||||
|
* and lets ANTLR do a simple LL(1)+pred computation.
|
||||||
|
*
|
||||||
|
* TODO: what about gated vs regular preds?
|
||||||
|
*/
|
||||||
|
public boolean detectConfoundingPredicates(NFAState s) {
|
||||||
|
lookBusy.clear();
|
||||||
|
Rule r = s.enclosingRule;
|
||||||
|
return _detectConfoundingPredicates(s, r, false) == DETECT_PRED_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int _detectConfoundingPredicates(NFAState s,
|
||||||
|
Rule enclosingRule,
|
||||||
|
boolean chaseFollowTransitions)
|
||||||
|
{
|
||||||
|
//System.out.println("_detectNonAutobacktrackPredicates("+s+")");
|
||||||
|
if ( !chaseFollowTransitions && s.isAcceptState() ) {
|
||||||
|
if ( grammar.type==Grammar.LEXER ) {
|
||||||
|
// FOLLOW makes no sense (at the moment!) for lexical rules.
|
||||||
|
// assume all char can follow
|
||||||
|
return DETECT_PRED_NOT_FOUND;
|
||||||
|
}
|
||||||
|
return DETECT_PRED_EOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( lookBusy.contains(s) ) {
|
||||||
|
// return a copy of an empty set; we may modify set inline
|
||||||
|
return DETECT_PRED_NOT_FOUND;
|
||||||
|
}
|
||||||
|
lookBusy.add(s);
|
||||||
|
|
||||||
|
Transition transition0 = s.transition[0];
|
||||||
|
if ( transition0==null ) {
|
||||||
|
return DETECT_PRED_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !(transition0.label.isSemanticPredicate()||
|
||||||
|
transition0.label.isEpsilon()) ) {
|
||||||
|
return DETECT_PRED_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( transition0.label.isSemanticPredicate() ) {
|
||||||
|
//System.out.println("pred "+transition0.label);
|
||||||
|
SemanticContext ctx = transition0.label.getSemanticContext();
|
||||||
|
SemanticContext.Predicate p = (SemanticContext.Predicate)ctx;
|
||||||
|
if ( p.predicateAST.getType() != ANTLRParser.BACKTRACK_SEMPRED ) {
|
||||||
|
return DETECT_PRED_FOUND;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
if ( transition0.label.isSemanticPredicate() ) {
|
||||||
|
System.out.println("pred "+transition0.label);
|
||||||
|
SemanticContext ctx = transition0.label.getSemanticContext();
|
||||||
|
SemanticContext.Predicate p = (SemanticContext.Predicate)ctx;
|
||||||
|
// if a non-syn-pred found not in enclosingRule, say we found one
|
||||||
|
if ( p.predicateAST.getType() != ANTLRParser.BACKTRACK_SEMPRED &&
|
||||||
|
!p.predicateAST.enclosingRuleName.equals(enclosingRule.name) )
|
||||||
|
{
|
||||||
|
System.out.println("found pred "+p+" not in "+enclosingRule.name);
|
||||||
|
return DETECT_PRED_FOUND;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
int result = _detectConfoundingPredicates((NFAState)transition0.target,
|
||||||
|
enclosingRule,
|
||||||
|
chaseFollowTransitions);
|
||||||
|
if ( result == DETECT_PRED_FOUND ) {
|
||||||
|
return DETECT_PRED_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( result == DETECT_PRED_EOR ) {
|
||||||
|
if ( transition0 instanceof RuleClosureTransition ) {
|
||||||
|
// we called a rule that found the end of the rule.
|
||||||
|
// That means the rule is nullable and we need to
|
||||||
|
// keep looking at what follows the rule ref. E.g.,
|
||||||
|
// a : b A ; where b is nullable means that LOOK(a)
|
||||||
|
// should include A.
|
||||||
|
RuleClosureTransition ruleInvocationTrans =
|
||||||
|
(RuleClosureTransition)transition0;
|
||||||
|
NFAState following = (NFAState) ruleInvocationTrans.followState;
|
||||||
|
int afterRuleResult =
|
||||||
|
_detectConfoundingPredicates(following,
|
||||||
|
enclosingRule,
|
||||||
|
chaseFollowTransitions);
|
||||||
|
if ( afterRuleResult == DETECT_PRED_FOUND ) {
|
||||||
|
return DETECT_PRED_FOUND;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Transition transition1 = s.transition[1];
|
||||||
|
if ( transition1!=null ) {
|
||||||
|
int t1Result =
|
||||||
|
_detectConfoundingPredicates((NFAState)transition1.target,
|
||||||
|
enclosingRule,
|
||||||
|
chaseFollowTransitions);
|
||||||
|
if ( t1Result == DETECT_PRED_FOUND ) {
|
||||||
|
return DETECT_PRED_FOUND;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return DETECT_PRED_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return predicate expression found via epsilon edges from s. Do
|
||||||
|
* not look into other rules for now. Do something simple. Include
|
||||||
|
* backtracking synpreds.
|
||||||
|
*/
|
||||||
|
public SemanticContext getPredicates(NFAState altStartState) {
|
||||||
|
lookBusy.clear();
|
||||||
|
return _getPredicates(altStartState, altStartState);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected SemanticContext _getPredicates(NFAState s, NFAState altStartState) {
|
||||||
|
//System.out.println("_getPredicates("+s+")");
|
||||||
|
if ( s.isAcceptState() ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// avoid infinite loops from (..)* etc...
|
||||||
|
if ( lookBusy.contains(s) ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
lookBusy.add(s);
|
||||||
|
|
||||||
|
Transition transition0 = s.transition[0];
|
||||||
|
// no transitions
|
||||||
|
if ( transition0==null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// not a predicate and not even an epsilon
|
||||||
|
if ( !(transition0.label.isSemanticPredicate()||
|
||||||
|
transition0.label.isEpsilon()) ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
SemanticContext p = null;
|
||||||
|
SemanticContext p0 = null;
|
||||||
|
SemanticContext p1 = null;
|
||||||
|
if ( transition0.label.isSemanticPredicate() ) {
|
||||||
|
//System.out.println("pred "+transition0.label);
|
||||||
|
p = transition0.label.getSemanticContext();
|
||||||
|
// ignore backtracking preds not on left edge for this decision
|
||||||
|
if ( ((SemanticContext.Predicate)p).predicateAST.getType() ==
|
||||||
|
ANTLRParser.BACKTRACK_SEMPRED &&
|
||||||
|
s == altStartState.transition[0].target )
|
||||||
|
{
|
||||||
|
p = null; // don't count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get preds from beyond this state
|
||||||
|
p0 = _getPredicates((NFAState)transition0.target, altStartState);
|
||||||
|
|
||||||
|
// get preds from other transition
|
||||||
|
Transition transition1 = s.transition[1];
|
||||||
|
if ( transition1!=null ) {
|
||||||
|
p1 = _getPredicates((NFAState)transition1.target, altStartState);
|
||||||
|
}
|
||||||
|
|
||||||
|
// join this&following-right|following-down
|
||||||
|
return SemanticContext.and(p,SemanticContext.or(p0,p1));
|
||||||
|
}
|
||||||
|
}
|
179
antlr_3_1_source/analysis/LL1DFA.java
Normal file
179
antlr_3_1_source/analysis/LL1DFA.java
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2008 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.antlr.analysis;
|
||||||
|
|
||||||
|
import org.antlr.misc.IntervalSet;
|
||||||
|
import org.antlr.misc.MultiMap;
|
||||||
|
import org.antlr.tool.ANTLRParser;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
/** A special DFA that is exactly LL(1) or LL(1) with backtracking mode
|
||||||
|
* predicates to resolve edge set collisions.
|
||||||
|
*/
|
||||||
|
public class LL1DFA extends DFA {
|
||||||
|
/** From list of lookahead sets (one per alt in decision), create
|
||||||
|
* an LL(1) DFA. One edge per set.
|
||||||
|
*
|
||||||
|
* s0-{alt1}->:o=>1
|
||||||
|
* | \
|
||||||
|
* | -{alt2}->:o=>2
|
||||||
|
* |
|
||||||
|
* ...
|
||||||
|
*/
|
||||||
|
public LL1DFA(int decisionNumber, NFAState decisionStartState, LookaheadSet[] altLook) {
|
||||||
|
DFAState s0 = newState();
|
||||||
|
startState = s0;
|
||||||
|
nfa = decisionStartState.nfa;
|
||||||
|
nAlts = nfa.grammar.getNumberOfAltsForDecisionNFA(decisionStartState);
|
||||||
|
this.decisionNumber = decisionNumber;
|
||||||
|
this.decisionNFAStartState = decisionStartState;
|
||||||
|
initAltRelatedInfo();
|
||||||
|
unreachableAlts = null;
|
||||||
|
for (int alt=1; alt<altLook.length; alt++) {
|
||||||
|
DFAState acceptAltState = newState();
|
||||||
|
acceptAltState.acceptState = true;
|
||||||
|
setAcceptState(alt, acceptAltState);
|
||||||
|
acceptAltState.k = 1;
|
||||||
|
acceptAltState.cachedUniquelyPredicatedAlt = alt;
|
||||||
|
Label e = getLabelForSet(altLook[alt].tokenTypeSet);
|
||||||
|
s0.addTransition(acceptAltState, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** From a set of edgeset->list-of-alts mappings, create a DFA
|
||||||
|
* that uses syn preds for all |list-of-alts|>1.
|
||||||
|
*/
|
||||||
|
public LL1DFA(int decisionNumber,
|
||||||
|
NFAState decisionStartState,
|
||||||
|
MultiMap<IntervalSet, Integer> edgeMap)
|
||||||
|
{
|
||||||
|
DFAState s0 = newState();
|
||||||
|
startState = s0;
|
||||||
|
nfa = decisionStartState.nfa;
|
||||||
|
nAlts = nfa.grammar.getNumberOfAltsForDecisionNFA(decisionStartState);
|
||||||
|
this.decisionNumber = decisionNumber;
|
||||||
|
this.decisionNFAStartState = decisionStartState;
|
||||||
|
initAltRelatedInfo();
|
||||||
|
unreachableAlts = null;
|
||||||
|
for (Iterator it = edgeMap.keySet().iterator(); it.hasNext();) {
|
||||||
|
IntervalSet edge = (IntervalSet)it.next();
|
||||||
|
List<Integer> alts = edgeMap.get(edge);
|
||||||
|
Collections.sort(alts); // make sure alts are attempted in order
|
||||||
|
//System.out.println(edge+" -> "+alts);
|
||||||
|
DFAState s = newState();
|
||||||
|
s.k = 1;
|
||||||
|
Label e = getLabelForSet(edge);
|
||||||
|
s0.addTransition(s, e);
|
||||||
|
if ( alts.size()==1 ) {
|
||||||
|
s.acceptState = true;
|
||||||
|
int alt = alts.get(0);
|
||||||
|
setAcceptState(alt, s);
|
||||||
|
s.cachedUniquelyPredicatedAlt = alt;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// resolve with syntactic predicates. Add edges from
|
||||||
|
// state s that test predicates.
|
||||||
|
s.resolvedWithPredicates = true;
|
||||||
|
for (int i = 0; i < alts.size(); i++) {
|
||||||
|
int alt = (int)alts.get(i);
|
||||||
|
s.cachedUniquelyPredicatedAlt = NFA.INVALID_ALT_NUMBER;
|
||||||
|
DFAState predDFATarget = getAcceptState(alt);
|
||||||
|
if ( predDFATarget==null ) {
|
||||||
|
predDFATarget = newState(); // create if not there.
|
||||||
|
predDFATarget.acceptState = true;
|
||||||
|
predDFATarget.cachedUniquelyPredicatedAlt = alt;
|
||||||
|
setAcceptState(alt, predDFATarget);
|
||||||
|
}
|
||||||
|
// add a transition to pred target from d
|
||||||
|
/*
|
||||||
|
int walkAlt =
|
||||||
|
decisionStartState.translateDisplayAltToWalkAlt(alt);
|
||||||
|
NFAState altLeftEdge = nfa.grammar.getNFAStateForAltOfDecision(decisionStartState, walkAlt);
|
||||||
|
NFAState altStartState = (NFAState)altLeftEdge.transition[0].target;
|
||||||
|
SemanticContext ctx = nfa.grammar.ll1Analyzer.getPredicates(altStartState);
|
||||||
|
System.out.println("sem ctx = "+ctx);
|
||||||
|
if ( ctx == null ) {
|
||||||
|
ctx = new SemanticContext.TruePredicate();
|
||||||
|
}
|
||||||
|
s.addTransition(predDFATarget, new Label(ctx));
|
||||||
|
*/
|
||||||
|
SemanticContext.Predicate synpred =
|
||||||
|
getSynPredForAlt(decisionStartState, alt);
|
||||||
|
if ( synpred == null ) {
|
||||||
|
synpred = new SemanticContext.TruePredicate();
|
||||||
|
}
|
||||||
|
s.addTransition(predDFATarget, new PredicateLabel(synpred));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//System.out.println("dfa for preds=\n"+this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Label getLabelForSet(IntervalSet edgeSet) {
|
||||||
|
Label e = null;
|
||||||
|
int atom = edgeSet.getSingleElement();
|
||||||
|
if ( atom != Label.INVALID ) {
|
||||||
|
e = new Label(atom);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
e = new Label(edgeSet);
|
||||||
|
}
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected SemanticContext.Predicate getSynPredForAlt(NFAState decisionStartState,
|
||||||
|
int alt)
|
||||||
|
{
|
||||||
|
int walkAlt =
|
||||||
|
decisionStartState.translateDisplayAltToWalkAlt(alt);
|
||||||
|
NFAState altLeftEdge =
|
||||||
|
nfa.grammar.getNFAStateForAltOfDecision(decisionStartState, walkAlt);
|
||||||
|
NFAState altStartState = (NFAState)altLeftEdge.transition[0].target;
|
||||||
|
//System.out.println("alt "+alt+" start state = "+altStartState.stateNumber);
|
||||||
|
if ( altStartState.transition[0].isSemanticPredicate() ) {
|
||||||
|
SemanticContext ctx = altStartState.transition[0].label.getSemanticContext();
|
||||||
|
if ( ctx.isSyntacticPredicate() ) {
|
||||||
|
SemanticContext.Predicate p = (SemanticContext.Predicate)ctx;
|
||||||
|
if ( p.predicateAST.getType() == ANTLRParser.BACKTRACK_SEMPRED ) {
|
||||||
|
/*
|
||||||
|
System.out.println("syn pred for alt "+walkAlt+" "+
|
||||||
|
((SemanticContext.Predicate)altStartState.transition[0].label.getSemanticContext()).predicateAST);
|
||||||
|
*/
|
||||||
|
if ( ctx.isSyntacticPredicate() ) {
|
||||||
|
nfa.grammar.synPredUsedInDFA(this, ctx);
|
||||||
|
}
|
||||||
|
return (SemanticContext.Predicate)altStartState.transition[0].label.getSemanticContext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
382
antlr_3_1_source/analysis/Label.java
Normal file
382
antlr_3_1_source/analysis/Label.java
Normal file
@ -0,0 +1,382 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.antlr.analysis;
|
||||||
|
|
||||||
|
import org.antlr.tool.Grammar;
|
||||||
|
import org.antlr.tool.GrammarAST;
|
||||||
|
import org.antlr.misc.IntervalSet;
|
||||||
|
import org.antlr.misc.IntSet;
|
||||||
|
|
||||||
|
/** A state machine transition label. A label can be either a simple
|
||||||
|
* label such as a token or character. A label can be a set of char or
|
||||||
|
* tokens. It can be an epsilon transition. It can be a semantic predicate
|
||||||
|
* (which assumes an epsilon transition) or a tree of predicates (in a DFA).
|
||||||
|
*/
|
||||||
|
public class Label implements Comparable, Cloneable {
|
||||||
|
public static final int INVALID = -7;
|
||||||
|
|
||||||
|
public static final int ACTION = -6;
|
||||||
|
|
||||||
|
public static final int EPSILON = -5;
|
||||||
|
|
||||||
|
public static final String EPSILON_STR = "<EPSILON>";
|
||||||
|
|
||||||
|
/** label is a semantic predicate; implies label is epsilon also */
|
||||||
|
public static final int SEMPRED = -4;
|
||||||
|
|
||||||
|
/** label is a set of tokens or char */
|
||||||
|
public static final int SET = -3;
|
||||||
|
|
||||||
|
/** End of Token is like EOF for lexer rules. It implies that no more
|
||||||
|
* characters are available and that NFA conversion should terminate
|
||||||
|
* for this path. For example
|
||||||
|
*
|
||||||
|
* A : 'a' 'b' | 'a' ;
|
||||||
|
*
|
||||||
|
* yields a DFA predictor:
|
||||||
|
*
|
||||||
|
* o-a->o-b->1 predict alt 1
|
||||||
|
* |
|
||||||
|
* |-EOT->o predict alt 2
|
||||||
|
*
|
||||||
|
* To generate code for EOT, treat it as the "default" path, which
|
||||||
|
* implies there is no way to mismatch a char for the state from
|
||||||
|
* which the EOT emanates.
|
||||||
|
*/
|
||||||
|
public static final int EOT = -2;
|
||||||
|
|
||||||
|
public static final int EOF = -1;
|
||||||
|
|
||||||
|
/** We have labels like EPSILON that are below 0; it's hard to
|
||||||
|
* store them in an array with negative index so use this
|
||||||
|
* constant as an index shift when accessing arrays based upon
|
||||||
|
* token type. If real token type is i, then array index would be
|
||||||
|
* NUM_FAUX_LABELS + i.
|
||||||
|
*/
|
||||||
|
public static final int NUM_FAUX_LABELS = -INVALID;
|
||||||
|
|
||||||
|
/** Anything at this value or larger can be considered a simple atom int
|
||||||
|
* for easy comparison during analysis only; faux labels are not used
|
||||||
|
* during parse time for real token types or char values.
|
||||||
|
*/
|
||||||
|
public static final int MIN_ATOM_VALUE = EOT;
|
||||||
|
|
||||||
|
// TODO: is 0 a valid unicode char? max is FFFF -1, right?
|
||||||
|
public static final int MIN_CHAR_VALUE = '\u0000';
|
||||||
|
public static final int MAX_CHAR_VALUE = '\uFFFE';
|
||||||
|
|
||||||
|
/** End of rule token type; imaginary token type used only for
|
||||||
|
* local, partial FOLLOW sets to indicate that the local FOLLOW
|
||||||
|
* hit the end of rule. During error recovery, the local FOLLOW
|
||||||
|
* of a token reference may go beyond the end of the rule and have
|
||||||
|
* to use FOLLOW(rule). I have to just shift the token types to 2..n
|
||||||
|
* rather than 1..n to accommodate this imaginary token in my bitsets.
|
||||||
|
* If I didn't use a bitset implementation for runtime sets, I wouldn't
|
||||||
|
* need this. EOF is another candidate for a run time token type for
|
||||||
|
* parsers. Follow sets are not computed for lexers so we do not have
|
||||||
|
* this issue.
|
||||||
|
*/
|
||||||
|
public static final int EOR_TOKEN_TYPE =
|
||||||
|
org.antlr.runtime.Token.EOR_TOKEN_TYPE;
|
||||||
|
|
||||||
|
public static final int DOWN = org.antlr.runtime.Token.DOWN;
|
||||||
|
public static final int UP = org.antlr.runtime.Token.UP;
|
||||||
|
|
||||||
|
/** tokens and char range overlap; tokens are MIN_TOKEN_TYPE..n */
|
||||||
|
public static final int MIN_TOKEN_TYPE =
|
||||||
|
org.antlr.runtime.Token.MIN_TOKEN_TYPE;
|
||||||
|
|
||||||
|
/** The wildcard '.' char atom implies all valid characters==UNICODE */
|
||||||
|
//public static final IntSet ALLCHAR = IntervalSet.of(MIN_CHAR_VALUE,MAX_CHAR_VALUE);
|
||||||
|
|
||||||
|
/** The token type or character value; or, signifies special label. */
|
||||||
|
protected int label;
|
||||||
|
|
||||||
|
/** A set of token types or character codes if label==SET */
|
||||||
|
// TODO: try IntervalSet for everything
|
||||||
|
protected IntSet labelSet;
|
||||||
|
|
||||||
|
public Label(int label) {
|
||||||
|
this.label = label;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Make a set label */
|
||||||
|
public Label(IntSet labelSet) {
|
||||||
|
if ( labelSet==null ) {
|
||||||
|
this.label = SET;
|
||||||
|
this.labelSet = IntervalSet.of(INVALID);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int singleAtom = labelSet.getSingleElement();
|
||||||
|
if ( singleAtom!=INVALID ) {
|
||||||
|
// convert back to a single atomic element if |labelSet|==1
|
||||||
|
label = singleAtom;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.label = SET;
|
||||||
|
this.labelSet = labelSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object clone() {
|
||||||
|
Label l;
|
||||||
|
try {
|
||||||
|
l = (Label)super.clone();
|
||||||
|
l.label = this.label;
|
||||||
|
l.labelSet = new IntervalSet();
|
||||||
|
l.labelSet.addAll(this.labelSet);
|
||||||
|
}
|
||||||
|
catch (CloneNotSupportedException e) {
|
||||||
|
throw new InternalError();
|
||||||
|
}
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(Label a) {
|
||||||
|
if ( isAtom() ) {
|
||||||
|
labelSet = IntervalSet.of(label);
|
||||||
|
label=SET;
|
||||||
|
if ( a.isAtom() ) {
|
||||||
|
labelSet.add(a.getAtom());
|
||||||
|
}
|
||||||
|
else if ( a.isSet() ) {
|
||||||
|
labelSet.addAll(a.getSet());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new IllegalStateException("can't add element to Label of type "+label);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( isSet() ) {
|
||||||
|
if ( a.isAtom() ) {
|
||||||
|
labelSet.add(a.getAtom());
|
||||||
|
}
|
||||||
|
else if ( a.isSet() ) {
|
||||||
|
labelSet.addAll(a.getSet());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new IllegalStateException("can't add element to Label of type "+label);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("can't add element to Label of type "+label);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAtom() {
|
||||||
|
return label>=MIN_ATOM_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEpsilon() {
|
||||||
|
return label==EPSILON;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSemanticPredicate() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAction() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSet() {
|
||||||
|
return label==SET;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** return the single atom label or INVALID if not a single atom */
|
||||||
|
public int getAtom() {
|
||||||
|
if ( isAtom() ) {
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
return INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntSet getSet() {
|
||||||
|
if ( label!=SET ) {
|
||||||
|
// convert single element to a set if they ask for it.
|
||||||
|
return IntervalSet.of(label);
|
||||||
|
}
|
||||||
|
return labelSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSet(IntSet set) {
|
||||||
|
label=SET;
|
||||||
|
labelSet = set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SemanticContext getSemanticContext() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean matches(int atom) {
|
||||||
|
if ( label==atom ) {
|
||||||
|
return true; // handle the single atom case efficiently
|
||||||
|
}
|
||||||
|
if ( isSet() ) {
|
||||||
|
return labelSet.member(atom);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean matches(IntSet set) {
|
||||||
|
if ( isAtom() ) {
|
||||||
|
return set.member(getAtom());
|
||||||
|
}
|
||||||
|
if ( isSet() ) {
|
||||||
|
// matches if intersection non-nil
|
||||||
|
return !getSet().and(set).isNil();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public boolean matches(Label other) {
|
||||||
|
if ( other.isSet() ) {
|
||||||
|
return matches(other.getSet());
|
||||||
|
}
|
||||||
|
if ( other.isAtom() ) {
|
||||||
|
return matches(other.getAtom());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
if (label==SET) {
|
||||||
|
return labelSet.hashCode();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: do we care about comparing set {A} with atom A? Doesn't now.
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if ( o==null ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ( this == o ) {
|
||||||
|
return true; // equals if same object
|
||||||
|
}
|
||||||
|
// labels must be the same even if epsilon or set or sempred etc...
|
||||||
|
if ( label!=((Label)o).label ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ( label==SET ) {
|
||||||
|
return this.labelSet.equals(((Label)o).labelSet);
|
||||||
|
}
|
||||||
|
return true; // label values are same, so true
|
||||||
|
}
|
||||||
|
|
||||||
|
public int compareTo(Object o) {
|
||||||
|
return this.label-((Label)o).label;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Predicates are lists of AST nodes from the NFA created from the
|
||||||
|
* grammar, but the same predicate could be cut/paste into multiple
|
||||||
|
* places in the grammar. I must compare the text of all the
|
||||||
|
* predicates to truly answer whether {p1,p2} .equals {p1,p2}.
|
||||||
|
* Unfortunately, I cannot rely on the AST.equals() to work properly
|
||||||
|
* so I must do a brute force O(n^2) nested traversal of the Set
|
||||||
|
* doing a String compare.
|
||||||
|
*
|
||||||
|
* At this point, Labels are not compared for equals when they are
|
||||||
|
* predicates, but here's the code for future use.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
protected boolean predicatesEquals(Set others) {
|
||||||
|
Iterator iter = semanticContext.iterator();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
AST predAST = (AST) iter.next();
|
||||||
|
Iterator inner = semanticContext.iterator();
|
||||||
|
while (inner.hasNext()) {
|
||||||
|
AST otherPredAST = (AST) inner.next();
|
||||||
|
if ( !predAST.getText().equals(otherPredAST.getText()) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
switch (label) {
|
||||||
|
case SET :
|
||||||
|
return labelSet.toString();
|
||||||
|
default :
|
||||||
|
return String.valueOf(label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString(Grammar g) {
|
||||||
|
switch (label) {
|
||||||
|
case SET :
|
||||||
|
return labelSet.toString(g);
|
||||||
|
default :
|
||||||
|
return g.getTokenDisplayName(label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
public String predicatesToString() {
|
||||||
|
if ( semanticContext==NFAConfiguration.DEFAULT_CLAUSE_SEMANTIC_CONTEXT ) {
|
||||||
|
return "!other preds";
|
||||||
|
}
|
||||||
|
StringBuffer buf = new StringBuffer();
|
||||||
|
Iterator iter = semanticContext.iterator();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
AST predAST = (AST) iter.next();
|
||||||
|
buf.append(predAST.getText());
|
||||||
|
if ( iter.hasNext() ) {
|
||||||
|
buf.append("&");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static boolean intersect(Label label, Label edgeLabel) {
|
||||||
|
boolean hasIntersection = false;
|
||||||
|
boolean labelIsSet = label.isSet();
|
||||||
|
boolean edgeIsSet = edgeLabel.isSet();
|
||||||
|
if ( !labelIsSet && !edgeIsSet && edgeLabel.label==label.label ) {
|
||||||
|
hasIntersection = true;
|
||||||
|
}
|
||||||
|
else if ( labelIsSet && edgeIsSet &&
|
||||||
|
!edgeLabel.getSet().and(label.getSet()).isNil() ) {
|
||||||
|
hasIntersection = true;
|
||||||
|
}
|
||||||
|
else if ( labelIsSet && !edgeIsSet &&
|
||||||
|
label.getSet().member(edgeLabel.label) ) {
|
||||||
|
hasIntersection = true;
|
||||||
|
}
|
||||||
|
else if ( !labelIsSet && edgeIsSet &&
|
||||||
|
edgeLabel.getSet().member(label.label) ) {
|
||||||
|
hasIntersection = true;
|
||||||
|
}
|
||||||
|
return hasIntersection;
|
||||||
|
}
|
||||||
|
}
|
104
antlr_3_1_source/analysis/LookaheadSet.java
Normal file
104
antlr_3_1_source/analysis/LookaheadSet.java
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.antlr.analysis;
|
||||||
|
|
||||||
|
import org.antlr.misc.IntervalSet;
|
||||||
|
import org.antlr.misc.IntSet;
|
||||||
|
import org.antlr.tool.Grammar;
|
||||||
|
|
||||||
|
/** An LL(1) lookahead set; contains a set of token types and a "hasEOF"
|
||||||
|
* condition when the set contains EOF. Since EOF is -1 everywhere and -1
|
||||||
|
* cannot be stored in my BitSet, I set a condition here. There may be other
|
||||||
|
* reasons in the future to abstract a LookaheadSet over a raw BitSet.
|
||||||
|
*/
|
||||||
|
public class LookaheadSet {
|
||||||
|
public IntervalSet tokenTypeSet;
|
||||||
|
|
||||||
|
public LookaheadSet() {
|
||||||
|
tokenTypeSet = new IntervalSet();
|
||||||
|
}
|
||||||
|
|
||||||
|
public LookaheadSet(IntSet s) {
|
||||||
|
this();
|
||||||
|
tokenTypeSet.addAll(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LookaheadSet(int atom) {
|
||||||
|
tokenTypeSet = IntervalSet.of(atom);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void orInPlace(LookaheadSet other) {
|
||||||
|
this.tokenTypeSet.addAll(other.tokenTypeSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LookaheadSet or(LookaheadSet other) {
|
||||||
|
return new LookaheadSet(tokenTypeSet.or(other.tokenTypeSet));
|
||||||
|
}
|
||||||
|
|
||||||
|
public LookaheadSet subtract(LookaheadSet other) {
|
||||||
|
return new LookaheadSet(this.tokenTypeSet.subtract(other.tokenTypeSet));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean member(int a) {
|
||||||
|
return tokenTypeSet.member(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LookaheadSet intersection(LookaheadSet s) {
|
||||||
|
IntSet i = this.tokenTypeSet.and(s.tokenTypeSet);
|
||||||
|
LookaheadSet intersection = new LookaheadSet(i);
|
||||||
|
return intersection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isNil() {
|
||||||
|
return tokenTypeSet.isNil();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove(int a) {
|
||||||
|
tokenTypeSet = (IntervalSet)tokenTypeSet.subtract(IntervalSet.of(a));
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
return tokenTypeSet.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object other) {
|
||||||
|
return tokenTypeSet.equals(((LookaheadSet)other).tokenTypeSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString(Grammar g) {
|
||||||
|
if ( tokenTypeSet==null ) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
String r = tokenTypeSet.toString(g);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return toString(null);
|
||||||
|
}
|
||||||
|
}
|
73
antlr_3_1_source/analysis/NFA.java
Normal file
73
antlr_3_1_source/analysis/NFA.java
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.antlr.analysis;
|
||||||
|
|
||||||
|
import org.antlr.tool.Grammar;
|
||||||
|
import org.antlr.tool.NFAFactory;
|
||||||
|
|
||||||
|
/** An NFA (collection of NFAStates) constructed from a grammar. This
|
||||||
|
* NFA is one big machine for entire grammar. Decision points are recorded
|
||||||
|
* by the Grammar object so we can, for example, convert to DFA or simulate
|
||||||
|
* the NFA (interpret a decision).
|
||||||
|
*/
|
||||||
|
public class NFA {
|
||||||
|
public static final int INVALID_ALT_NUMBER = -1;
|
||||||
|
|
||||||
|
/** This NFA represents which grammar? */
|
||||||
|
public Grammar grammar;
|
||||||
|
|
||||||
|
/** Which factory created this NFA? */
|
||||||
|
protected NFAFactory factory = null;
|
||||||
|
|
||||||
|
public boolean complete;
|
||||||
|
|
||||||
|
public NFA(Grammar g) {
|
||||||
|
this.grammar = g;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNewNFAStateNumber() {
|
||||||
|
return grammar.composite.getNewNFAStateNumber();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addState(NFAState state) {
|
||||||
|
grammar.composite.addState(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
public NFAState getState(int s) {
|
||||||
|
return grammar.composite.getState(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
public NFAFactory getFactory() {
|
||||||
|
return factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFactory(NFAFactory factory) {
|
||||||
|
this.factory = factory;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
152
antlr_3_1_source/analysis/NFAConfiguration.java
Normal file
152
antlr_3_1_source/analysis/NFAConfiguration.java
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.antlr.analysis;
|
||||||
|
|
||||||
|
import org.antlr.misc.Utils;
|
||||||
|
|
||||||
|
/** An NFA state, predicted alt, and syntactic/semantic context.
|
||||||
|
* The syntactic context is a pointer into the rule invocation
|
||||||
|
* chain used to arrive at the state. The semantic context is
|
||||||
|
* the unordered set semantic predicates encountered before reaching
|
||||||
|
* an NFA state.
|
||||||
|
*/
|
||||||
|
public class NFAConfiguration {
|
||||||
|
/** The NFA state associated with this configuration */
|
||||||
|
public int state;
|
||||||
|
|
||||||
|
/** What alt is predicted by this configuration */
|
||||||
|
public int alt;
|
||||||
|
|
||||||
|
/** What is the stack of rule invocations that got us to state? */
|
||||||
|
public NFAContext context;
|
||||||
|
|
||||||
|
/** The set of semantic predicates associated with this NFA
|
||||||
|
* configuration. The predicates were found on the way to
|
||||||
|
* the associated NFA state in this syntactic context.
|
||||||
|
* Set<AST>: track nodes in grammar containing the predicate
|
||||||
|
* for error messages and such (nice to know where the predicate
|
||||||
|
* came from in case of duplicates etc...). By using a set,
|
||||||
|
* the equals() method will correctly show {pred1,pred2} as equals()
|
||||||
|
* to {pred2,pred1}.
|
||||||
|
*/
|
||||||
|
public SemanticContext semanticContext = SemanticContext.EMPTY_SEMANTIC_CONTEXT;
|
||||||
|
|
||||||
|
/** Indicate that this configuration has been resolved and no further
|
||||||
|
* DFA processing should occur with it. Essentially, this is used
|
||||||
|
* as an "ignore" bit so that upon a set of nondeterministic configurations
|
||||||
|
* such as (s|2) and (s|3), I can set (s|3) to resolved=true (and any
|
||||||
|
* other configuration associated with alt 3).
|
||||||
|
*/
|
||||||
|
protected boolean resolved;
|
||||||
|
|
||||||
|
/** This bit is used to indicate a semantic predicate will be
|
||||||
|
* used to resolve the conflict. Method
|
||||||
|
* DFA.findNewDFAStatesAndAddDFATransitions will add edges for
|
||||||
|
* the predicates after it performs the reach operation. The
|
||||||
|
* nondeterminism resolver sets this when it finds a set of
|
||||||
|
* nondeterministic configurations (as it does for "resolved" field)
|
||||||
|
* that have enough predicates to resolve the conflit.
|
||||||
|
*/
|
||||||
|
protected boolean resolveWithPredicate;
|
||||||
|
|
||||||
|
/** Lots of NFA states have only epsilon edges (1 or 2). We can
|
||||||
|
* safely consider only n>0 during closure.
|
||||||
|
*/
|
||||||
|
protected int numberEpsilonTransitionsEmanatingFromState;
|
||||||
|
|
||||||
|
/** Indicates that the NFA state associated with this configuration
|
||||||
|
* has exactly one transition and it's an atom (not epsilon etc...).
|
||||||
|
*/
|
||||||
|
protected boolean singleAtomTransitionEmanating;
|
||||||
|
|
||||||
|
//protected boolean addedDuringClosure = true;
|
||||||
|
|
||||||
|
public NFAConfiguration(int state,
|
||||||
|
int alt,
|
||||||
|
NFAContext context,
|
||||||
|
SemanticContext semanticContext)
|
||||||
|
{
|
||||||
|
this.state = state;
|
||||||
|
this.alt = alt;
|
||||||
|
this.context = context;
|
||||||
|
this.semanticContext = semanticContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** An NFA configuration is equal to another if both have
|
||||||
|
* the same state, the predict the same alternative, and
|
||||||
|
* syntactic/semantic contexts are the same. I don't think
|
||||||
|
* the state|alt|ctx could be the same and have two different
|
||||||
|
* semantic contexts, but might as well define equals to be
|
||||||
|
* everything.
|
||||||
|
*/
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if ( o==null ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
NFAConfiguration other = (NFAConfiguration)o;
|
||||||
|
return this.state==other.state &&
|
||||||
|
this.alt==other.alt &&
|
||||||
|
this.context.equals(other.context)&&
|
||||||
|
this.semanticContext.equals(other.semanticContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
int h = state + alt + context.hashCode();
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return toString(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString(boolean showAlt) {
|
||||||
|
StringBuffer buf = new StringBuffer();
|
||||||
|
buf.append(state);
|
||||||
|
if ( showAlt ) {
|
||||||
|
buf.append("|");
|
||||||
|
buf.append(alt);
|
||||||
|
}
|
||||||
|
if ( context.parent!=null ) {
|
||||||
|
buf.append("|");
|
||||||
|
buf.append(context);
|
||||||
|
}
|
||||||
|
if ( semanticContext!=null &&
|
||||||
|
semanticContext!=SemanticContext.EMPTY_SEMANTIC_CONTEXT ) {
|
||||||
|
buf.append("|");
|
||||||
|
String escQuote = Utils.replace(semanticContext.toString(), "\"", "\\\"");
|
||||||
|
buf.append(escQuote);
|
||||||
|
}
|
||||||
|
if ( resolved ) {
|
||||||
|
buf.append("|resolved");
|
||||||
|
}
|
||||||
|
if ( resolveWithPredicate ) {
|
||||||
|
buf.append("|resolveWithPredicate");
|
||||||
|
}
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
}
|
294
antlr_3_1_source/analysis/NFAContext.java
Normal file
294
antlr_3_1_source/analysis/NFAContext.java
Normal file
@ -0,0 +1,294 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.antlr.analysis;
|
||||||
|
|
||||||
|
/** A tree node for tracking the call chains for NFAs that invoke
|
||||||
|
* other NFAs. These trees only have to point upwards to their parents
|
||||||
|
* so we can walk back up the tree (i.e., pop stuff off the stack). We
|
||||||
|
* never walk from stack down down through the children.
|
||||||
|
*
|
||||||
|
* Each alt predicted in a decision has its own context tree,
|
||||||
|
* representing all possible return nodes. The initial stack has
|
||||||
|
* EOF ("$") in it. So, for m alternative productions, the lookahead
|
||||||
|
* DFA will have m NFAContext trees.
|
||||||
|
*
|
||||||
|
* To "push" a new context, just do "new NFAContext(context-parent, state)"
|
||||||
|
* which will add itself to the parent. The root is NFAContext(null, null).
|
||||||
|
*
|
||||||
|
* The complete context for an NFA configuration is the set of invoking states
|
||||||
|
* on the path from this node thru the parent pointers to the root.
|
||||||
|
*/
|
||||||
|
public class NFAContext {
|
||||||
|
/** This is similar to Bermudez's m constant in his LAR(m) where
|
||||||
|
* you bound the stack so your states don't explode. The main difference
|
||||||
|
* is that I bound only recursion on the stack, not the simple stack size.
|
||||||
|
* This looser constraint will let the conversion roam further to find
|
||||||
|
* lookahead to resolve a decision.
|
||||||
|
*
|
||||||
|
* Bermudez's m operates differently as it is his LR stack depth
|
||||||
|
* I'm pretty sure it therefore includes all stack symbols. Here I
|
||||||
|
* restrict the size of an NFA configuration to be finite because a
|
||||||
|
* stack component may mention the same NFA invocation state at
|
||||||
|
* most m times. Hence, the number of DFA states will not grow forever.
|
||||||
|
* With recursive rules like
|
||||||
|
*
|
||||||
|
* e : '(' e ')' | INT ;
|
||||||
|
*
|
||||||
|
* you could chase your tail forever if somebody said "s : e '.' | e ';' ;"
|
||||||
|
* This constant prevents new states from being created after a stack gets
|
||||||
|
* "too big". Actually (12/14/2007) I realize that this example is
|
||||||
|
* trapped by the non-LL(*) detector for recursion in > 1 alt. Here is
|
||||||
|
* an example that trips stack overflow:
|
||||||
|
*
|
||||||
|
* s : a Y | A A A A A X ; // force recursion past m=4
|
||||||
|
* a : A a | Q;
|
||||||
|
*
|
||||||
|
* If that were:
|
||||||
|
*
|
||||||
|
* s : a Y | A+ X ;
|
||||||
|
*
|
||||||
|
* it could loop forever.
|
||||||
|
*
|
||||||
|
* Imagine doing a depth-first search on the e DFA...as you chase an input
|
||||||
|
* sequence you can recurse to same rule such as e above. You'd have a
|
||||||
|
* chain of ((((. When you get do some point, you have to give up. The
|
||||||
|
* states in the chain will have longer and longer NFA config stacks.
|
||||||
|
* Must limit size.
|
||||||
|
*
|
||||||
|
* max=0 implies you cannot ever jump to another rule during closure.
|
||||||
|
* max=1 implies you can make as many calls as you want--you just
|
||||||
|
* can't ever visit a state that is on your rule invocation stack.
|
||||||
|
* I.e., you cannot ever recurse.
|
||||||
|
* max=2 implies you are able to recurse once (i.e., call a rule twice
|
||||||
|
* from the same place).
|
||||||
|
*
|
||||||
|
* This tracks recursion to a rule specific to an invocation site!
|
||||||
|
* It does not detect multiple calls to a rule from different rule
|
||||||
|
* invocation states. We are guaranteed to terminate because the
|
||||||
|
* stack can only grow as big as the number of NFA states * max.
|
||||||
|
*
|
||||||
|
* I noticed that the Java grammar didn't work with max=1, but did with
|
||||||
|
* max=4. Let's set to 4. Recursion is sometimes needed to resolve some
|
||||||
|
* fixed lookahead decisions.
|
||||||
|
*/
|
||||||
|
public static int MAX_SAME_RULE_INVOCATIONS_PER_NFA_CONFIG_STACK = 4;
|
||||||
|
|
||||||
|
public NFAContext parent;
|
||||||
|
|
||||||
|
/** The NFA state that invoked another rule's start state is recorded
|
||||||
|
* on the rule invocation context stack.
|
||||||
|
*/
|
||||||
|
public NFAState invokingState;
|
||||||
|
|
||||||
|
/** Computing the hashCode is very expensive and closureBusy()
|
||||||
|
* uses it to track when it's seen a state|ctx before to avoid
|
||||||
|
* infinite loops. As we add new contexts, record the hash code
|
||||||
|
* as this.invokingState + parent.cachedHashCode. Avoids walking
|
||||||
|
* up the tree for every hashCode(). Note that this caching works
|
||||||
|
* because a context is a monotonically growing tree of context nodes
|
||||||
|
* and nothing on the stack is ever modified...ctx just grows
|
||||||
|
* or shrinks.
|
||||||
|
*/
|
||||||
|
protected int cachedHashCode;
|
||||||
|
|
||||||
|
public NFAContext(NFAContext parent, NFAState invokingState) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.invokingState = invokingState;
|
||||||
|
if ( invokingState!=null ) {
|
||||||
|
this.cachedHashCode = invokingState.stateNumber;
|
||||||
|
}
|
||||||
|
if ( parent!=null ) {
|
||||||
|
this.cachedHashCode += parent.cachedHashCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Two contexts are equals() if both have
|
||||||
|
* same call stack; walk upwards to the root.
|
||||||
|
* Recall that the root sentinel node has no invokingStates and no parent.
|
||||||
|
* Note that you may be comparing contexts in different alt trees.
|
||||||
|
*
|
||||||
|
* The hashCode is now cheap as it's computed once upon each context
|
||||||
|
* push on the stack. Use it to make equals() more efficient.
|
||||||
|
*/
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
NFAContext other = ((NFAContext)o);
|
||||||
|
if ( this.cachedHashCode != other.cachedHashCode ) {
|
||||||
|
return false; // can't be same if hash is different
|
||||||
|
}
|
||||||
|
if ( this==other ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// System.out.println("comparing "+this+" with "+other);
|
||||||
|
NFAContext sp = this;
|
||||||
|
while ( sp.parent!=null && other.parent!=null ) {
|
||||||
|
if ( sp.invokingState != other.invokingState ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
sp = sp.parent;
|
||||||
|
other = other.parent;
|
||||||
|
}
|
||||||
|
if ( !(sp.parent==null && other.parent==null) ) {
|
||||||
|
return false; // both pointers must be at their roots after walk
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Two contexts conflict() if they are equals() or one is a stack suffix
|
||||||
|
* of the other. For example, contexts [21 12 $] and [21 9 $] do not
|
||||||
|
* conflict, but [21 $] and [21 12 $] do conflict. Note that I should
|
||||||
|
* probably not show the $ in this case. There is a dummy node for each
|
||||||
|
* stack that just means empty; $ is a marker that's all.
|
||||||
|
*
|
||||||
|
* This is used in relation to checking conflicts associated with a
|
||||||
|
* single NFA state's configurations within a single DFA state.
|
||||||
|
* If there are configurations s and t within a DFA state such that
|
||||||
|
* s.state=t.state && s.alt != t.alt && s.ctx conflicts t.ctx then
|
||||||
|
* the DFA state predicts more than a single alt--it's nondeterministic.
|
||||||
|
* Two contexts conflict if they are the same or if one is a suffix
|
||||||
|
* of the other.
|
||||||
|
*
|
||||||
|
* When comparing contexts, if one context has a stack and the other
|
||||||
|
* does not then they should be considered the same context. The only
|
||||||
|
* way for an NFA state p to have an empty context and a nonempty context
|
||||||
|
* is the case when closure falls off end of rule without a call stack
|
||||||
|
* and re-enters the rule with a context. This resolves the issue I
|
||||||
|
* discussed with Sriram Srinivasan Feb 28, 2005 about not terminating
|
||||||
|
* fast enough upon nondeterminism.
|
||||||
|
*/
|
||||||
|
public boolean conflictsWith(NFAContext other) {
|
||||||
|
return this.suffix(other); // || this.equals(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** [$] suffix any context
|
||||||
|
* [21 $] suffix [21 12 $]
|
||||||
|
* [21 12 $] suffix [21 $]
|
||||||
|
* [21 18 $] suffix [21 18 12 9 $]
|
||||||
|
* [21 18 12 9 $] suffix [21 18 $]
|
||||||
|
* [21 12 $] not suffix [21 9 $]
|
||||||
|
*
|
||||||
|
* Example "[21 $] suffix [21 12 $]" means: rule r invoked current rule
|
||||||
|
* from state 21. Rule s invoked rule r from state 12 which then invoked
|
||||||
|
* current rule also via state 21. While the context prior to state 21
|
||||||
|
* is different, the fact that both contexts emanate from state 21 implies
|
||||||
|
* that they are now going to track perfectly together. Once they
|
||||||
|
* converged on state 21, there is no way they can separate. In other
|
||||||
|
* words, the prior stack state is not consulted when computing where to
|
||||||
|
* go in the closure operation. ?$ and ??$ are considered the same stack.
|
||||||
|
* If ? is popped off then $ and ?$ remain; they are now an empty and
|
||||||
|
* nonempty context comparison. So, if one stack is a suffix of
|
||||||
|
* another, then it will still degenerate to the simple empty stack
|
||||||
|
* comparison case.
|
||||||
|
*/
|
||||||
|
protected boolean suffix(NFAContext other) {
|
||||||
|
NFAContext sp = this;
|
||||||
|
// if one of the contexts is empty, it never enters loop and returns true
|
||||||
|
while ( sp.parent!=null && other.parent!=null ) {
|
||||||
|
if ( sp.invokingState != other.invokingState ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
sp = sp.parent;
|
||||||
|
other = other.parent;
|
||||||
|
}
|
||||||
|
//System.out.println("suffix");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Walk upwards to the root of the call stack context looking
|
||||||
|
* for a particular invoking state.
|
||||||
|
public boolean contains(int state) {
|
||||||
|
NFAContext sp = this;
|
||||||
|
int n = 0; // track recursive invocations of state
|
||||||
|
System.out.println("this.context is "+sp);
|
||||||
|
while ( sp.parent!=null ) {
|
||||||
|
if ( sp.invokingState.stateNumber == state ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
sp = sp.parent;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Given an NFA state number, how many times has the NFA-to-DFA
|
||||||
|
* conversion pushed that state on the stack? In other words,
|
||||||
|
* the NFA state must be a rule invocation state and this method
|
||||||
|
* tells you how many times you've been to this state. If none,
|
||||||
|
* then you have not called the target rule from this state before
|
||||||
|
* (though another NFA state could have called that target rule).
|
||||||
|
* If n=1, then you've been to this state before during this
|
||||||
|
* DFA construction and are going to invoke that rule again.
|
||||||
|
*
|
||||||
|
* Note that many NFA states can invoke rule r, but we ignore recursion
|
||||||
|
* unless you hit the same rule invocation state again.
|
||||||
|
*/
|
||||||
|
public int recursionDepthEmanatingFromState(int state) {
|
||||||
|
NFAContext sp = this;
|
||||||
|
int n = 0; // track recursive invocations of target from this state
|
||||||
|
//System.out.println("this.context is "+sp);
|
||||||
|
while ( sp.parent!=null ) {
|
||||||
|
if ( sp.invokingState.stateNumber == state ) {
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
sp = sp.parent;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
return cachedHashCode;
|
||||||
|
/*
|
||||||
|
int h = 0;
|
||||||
|
NFAContext sp = this;
|
||||||
|
while ( sp.parent!=null ) {
|
||||||
|
h += sp.invokingState.getStateNumber();
|
||||||
|
sp = sp.parent;
|
||||||
|
}
|
||||||
|
return h;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A context is empty if there is no parent; meaning nobody pushed
|
||||||
|
* anything on the call stack.
|
||||||
|
*/
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return parent==null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
StringBuffer buf = new StringBuffer();
|
||||||
|
NFAContext sp = this;
|
||||||
|
buf.append("[");
|
||||||
|
while ( sp.parent!=null ) {
|
||||||
|
buf.append(sp.invokingState.stateNumber);
|
||||||
|
buf.append(" ");
|
||||||
|
sp = sp.parent;
|
||||||
|
}
|
||||||
|
buf.append("$]");
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
}
|
65
antlr_3_1_source/analysis/NFAConversionThread.java
Normal file
65
antlr_3_1_source/analysis/NFAConversionThread.java
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2008 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.antlr.analysis;
|
||||||
|
|
||||||
|
import org.antlr.misc.Barrier;
|
||||||
|
import org.antlr.tool.Grammar;
|
||||||
|
import org.antlr.tool.ErrorManager;
|
||||||
|
|
||||||
|
/** Convert all decisions i..j inclusive in a thread */
|
||||||
|
public class NFAConversionThread implements Runnable {
|
||||||
|
Grammar grammar;
|
||||||
|
int i, j;
|
||||||
|
Barrier barrier;
|
||||||
|
public NFAConversionThread(Grammar grammar,
|
||||||
|
Barrier barrier,
|
||||||
|
int i,
|
||||||
|
int j)
|
||||||
|
{
|
||||||
|
this.grammar = grammar;
|
||||||
|
this.barrier = barrier;
|
||||||
|
this.i = i;
|
||||||
|
this.j = j;
|
||||||
|
}
|
||||||
|
public void run() {
|
||||||
|
for (int decision=i; decision<=j; decision++) {
|
||||||
|
NFAState decisionStartState = grammar.getDecisionNFAStartState(decision);
|
||||||
|
if ( decisionStartState.getNumberOfTransitions()>1 ) {
|
||||||
|
grammar.createLookaheadDFA(decision,true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// now wait for others to finish
|
||||||
|
try {
|
||||||
|
barrier.waitForRelease();
|
||||||
|
}
|
||||||
|
catch(InterruptedException e) {
|
||||||
|
ErrorManager.internalError("what the hell? DFA interruptus", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
259
antlr_3_1_source/analysis/NFAState.java
Normal file
259
antlr_3_1_source/analysis/NFAState.java
Normal file
@ -0,0 +1,259 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.antlr.analysis;
|
||||||
|
|
||||||
|
import org.antlr.tool.GrammarAST;
|
||||||
|
import org.antlr.tool.Rule;
|
||||||
|
import org.antlr.tool.ErrorManager;
|
||||||
|
|
||||||
|
/** A state within an NFA. At most 2 transitions emanate from any NFA state. */
|
||||||
|
public class NFAState extends State {
|
||||||
|
// I need to distinguish between NFA decision states for (...)* and (...)+
|
||||||
|
// during NFA interpretation.
|
||||||
|
public static final int LOOPBACK = 1;
|
||||||
|
public static final int BLOCK_START = 2;
|
||||||
|
public static final int OPTIONAL_BLOCK_START = 3;
|
||||||
|
public static final int BYPASS = 4;
|
||||||
|
public static final int RIGHT_EDGE_OF_BLOCK = 5;
|
||||||
|
|
||||||
|
public static final int MAX_TRANSITIONS = 2;
|
||||||
|
|
||||||
|
/** How many transitions; 0, 1, or 2 transitions */
|
||||||
|
int numTransitions = 0;
|
||||||
|
public Transition[] transition = new Transition[MAX_TRANSITIONS];
|
||||||
|
|
||||||
|
/** For o-A->o type NFA tranitions, record the label that leads to this
|
||||||
|
* state. Useful for creating rich error messages when we find
|
||||||
|
* insufficiently (with preds) covered states.
|
||||||
|
*/
|
||||||
|
public Label incidentEdgeLabel;
|
||||||
|
|
||||||
|
/** Which NFA are we in? */
|
||||||
|
public NFA nfa = null;
|
||||||
|
|
||||||
|
/** What's its decision number from 1..n? */
|
||||||
|
protected int decisionNumber = 0;
|
||||||
|
|
||||||
|
/** Subrules (...)* and (...)+ have more than one decision point in
|
||||||
|
* the NFA created for them. They both have a loop-exit-or-stay-in
|
||||||
|
* decision node (the loop back node). They both have a normal
|
||||||
|
* alternative block decision node at the left edge. The (...)* is
|
||||||
|
* worse as it even has a bypass decision (2 alts: stay in or bypass)
|
||||||
|
* node at the extreme left edge. This is not how they get generated
|
||||||
|
* in code as a while-loop or whatever deals nicely with either. For
|
||||||
|
* error messages (where I need to print the nondeterministic alts)
|
||||||
|
* and for interpretation, I need to use the single DFA that is created
|
||||||
|
* (for efficiency) but interpret the results differently depending
|
||||||
|
* on which of the 2 or 3 decision states uses the DFA. For example,
|
||||||
|
* the DFA will always report alt n+1 as the exit branch for n real
|
||||||
|
* alts, so I need to translate that depending on the decision state.
|
||||||
|
*
|
||||||
|
* If decisionNumber>0 then this var tells you what kind of decision
|
||||||
|
* state it is.
|
||||||
|
*/
|
||||||
|
public int decisionStateType;
|
||||||
|
|
||||||
|
/** What rule do we live in? */
|
||||||
|
public Rule enclosingRule;
|
||||||
|
|
||||||
|
/** During debugging and for nondeterminism warnings, it's useful
|
||||||
|
* to know what relationship this node has to the original grammar.
|
||||||
|
* For example, "start of alt 1 of rule a".
|
||||||
|
*/
|
||||||
|
protected String description;
|
||||||
|
|
||||||
|
/** Associate this NFAState with the corresponding GrammarAST node
|
||||||
|
* from which this node was created. This is useful not only for
|
||||||
|
* associating the eventual lookahead DFA with the associated
|
||||||
|
* Grammar position, but also for providing users with
|
||||||
|
* nondeterminism warnings. Mainly used by decision states to
|
||||||
|
* report line:col info. Could also be used to track line:col
|
||||||
|
* for elements such as token refs.
|
||||||
|
*/
|
||||||
|
public GrammarAST associatedASTNode;
|
||||||
|
|
||||||
|
/** Is this state the sole target of an EOT transition? */
|
||||||
|
protected boolean EOTTargetState = false;
|
||||||
|
|
||||||
|
/** Jean Bovet needs in the GUI to know which state pairs correspond
|
||||||
|
* to the start/stop of a block.
|
||||||
|
*/
|
||||||
|
public int endOfBlockStateNumber = State.INVALID_STATE_NUMBER;
|
||||||
|
|
||||||
|
public NFAState(NFA nfa) {
|
||||||
|
this.nfa = nfa;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumberOfTransitions() {
|
||||||
|
return numTransitions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addTransition(Transition e) {
|
||||||
|
if ( e==null ) {
|
||||||
|
throw new IllegalArgumentException("You can't add a null transition");
|
||||||
|
}
|
||||||
|
if ( numTransitions>transition.length ) {
|
||||||
|
throw new IllegalArgumentException("You can only have "+transition.length+" transitions");
|
||||||
|
}
|
||||||
|
if ( e!=null ) {
|
||||||
|
transition[numTransitions] = e;
|
||||||
|
numTransitions++;
|
||||||
|
// Set the "back pointer" of the target state so that it
|
||||||
|
// knows about the label of the incoming edge.
|
||||||
|
Label label = e.label;
|
||||||
|
if ( label.isAtom() || label.isSet() ) {
|
||||||
|
if ( ((NFAState)e.target).incidentEdgeLabel!=null ) {
|
||||||
|
ErrorManager.internalError("Clobbered incident edge");
|
||||||
|
}
|
||||||
|
((NFAState)e.target).incidentEdgeLabel = e.label;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Used during optimization to reset a state to have the (single)
|
||||||
|
* transition another state has.
|
||||||
|
*/
|
||||||
|
public void setTransition0(Transition e) {
|
||||||
|
if ( e==null ) {
|
||||||
|
throw new IllegalArgumentException("You can't use a solitary null transition");
|
||||||
|
}
|
||||||
|
transition[0] = e;
|
||||||
|
transition[1] = null;
|
||||||
|
numTransitions = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Transition transition(int i) {
|
||||||
|
return transition[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The DFA decision for this NFA decision state always has
|
||||||
|
* an exit path for loops as n+1 for n alts in the loop.
|
||||||
|
* That is really useful for displaying nondeterministic alts
|
||||||
|
* and so on, but for walking the NFA to get a sequence of edge
|
||||||
|
* labels or for actually parsing, we need to get the real alt
|
||||||
|
* number. The real alt number for exiting a loop is always 1
|
||||||
|
* as transition 0 points at the exit branch (we compute DFAs
|
||||||
|
* always for loops at the loopback state).
|
||||||
|
*
|
||||||
|
* For walking/parsing the loopback state:
|
||||||
|
* 1 2 3 display alt (for human consumption)
|
||||||
|
* 2 3 1 walk alt
|
||||||
|
*
|
||||||
|
* For walking the block start:
|
||||||
|
* 1 2 3 display alt
|
||||||
|
* 1 2 3
|
||||||
|
*
|
||||||
|
* For walking the bypass state of a (...)* loop:
|
||||||
|
* 1 2 3 display alt
|
||||||
|
* 1 1 2 all block alts map to entering loop exit means take bypass
|
||||||
|
*
|
||||||
|
* Non loop EBNF do not need to be translated; they are ignored by
|
||||||
|
* this method as decisionStateType==0.
|
||||||
|
*
|
||||||
|
* Return same alt if we can't translate.
|
||||||
|
*/
|
||||||
|
public int translateDisplayAltToWalkAlt(int displayAlt) {
|
||||||
|
NFAState nfaStart = this;
|
||||||
|
if ( decisionNumber==0 || decisionStateType==0 ) {
|
||||||
|
return displayAlt;
|
||||||
|
}
|
||||||
|
int walkAlt = 0;
|
||||||
|
// find the NFA loopback state associated with this DFA
|
||||||
|
// and count number of alts (all alt numbers are computed
|
||||||
|
// based upon the loopback's NFA state.
|
||||||
|
/*
|
||||||
|
DFA dfa = nfa.grammar.getLookaheadDFA(decisionNumber);
|
||||||
|
if ( dfa==null ) {
|
||||||
|
ErrorManager.internalError("can't get DFA for decision "+decisionNumber);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
int nAlts = nfa.grammar.getNumberOfAltsForDecisionNFA(nfaStart);
|
||||||
|
switch ( nfaStart.decisionStateType ) {
|
||||||
|
case LOOPBACK :
|
||||||
|
walkAlt = displayAlt % nAlts + 1; // rotate right mod 1..3
|
||||||
|
break;
|
||||||
|
case BLOCK_START :
|
||||||
|
case OPTIONAL_BLOCK_START :
|
||||||
|
walkAlt = displayAlt; // identity transformation
|
||||||
|
break;
|
||||||
|
case BYPASS :
|
||||||
|
if ( displayAlt == nAlts ) {
|
||||||
|
walkAlt = 2; // bypass
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
walkAlt = 1; // any non exit branch alt predicts entering
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return walkAlt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setter/Getters
|
||||||
|
|
||||||
|
/** What AST node is associated with this NFAState? When you
|
||||||
|
* set the AST node, I set the node to point back to this NFA state.
|
||||||
|
*/
|
||||||
|
public void setDecisionASTNode(GrammarAST decisionASTNode) {
|
||||||
|
decisionASTNode.setNFAStartState(this);
|
||||||
|
this.associatedASTNode = decisionASTNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDecisionNumber() {
|
||||||
|
return decisionNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDecisionNumber(int decisionNumber) {
|
||||||
|
this.decisionNumber = decisionNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEOTTargetState() {
|
||||||
|
return EOTTargetState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEOTTargetState(boolean eot) {
|
||||||
|
EOTTargetState = eot;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDecisionState() {
|
||||||
|
return decisionStateType>0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return String.valueOf(stateNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
1733
antlr_3_1_source/analysis/NFAToDFAConverter.java
Normal file
1733
antlr_3_1_source/analysis/NFAToDFAConverter.java
Normal file
File diff suppressed because it is too large
Load Diff
38
antlr_3_1_source/analysis/NonLLStarDecisionException.java
Normal file
38
antlr_3_1_source/analysis/NonLLStarDecisionException.java
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2008 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.antlr.analysis;
|
||||||
|
|
||||||
|
/** Used to abort DFA construction when we find non-LL(*) decision; i.e.,
|
||||||
|
* a decision that has recursion in more than a single alt.
|
||||||
|
*/
|
||||||
|
public class NonLLStarDecisionException extends RuntimeException {
|
||||||
|
public DFA abortedDFA;
|
||||||
|
public NonLLStarDecisionException(DFA abortedDFA) {
|
||||||
|
this.abortedDFA = abortedDFA;
|
||||||
|
}
|
||||||
|
}
|
85
antlr_3_1_source/analysis/PredicateLabel.java
Normal file
85
antlr_3_1_source/analysis/PredicateLabel.java
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2008 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.antlr.analysis;
|
||||||
|
|
||||||
|
import org.antlr.tool.GrammarAST;
|
||||||
|
import org.antlr.tool.Grammar;
|
||||||
|
|
||||||
|
public class PredicateLabel extends Label {
|
||||||
|
/** A tree of semantic predicates from the grammar AST if label==SEMPRED.
|
||||||
|
* In the NFA, labels will always be exactly one predicate, but the DFA
|
||||||
|
* may have to combine a bunch of them as it collects predicates from
|
||||||
|
* multiple NFA configurations into a single DFA state.
|
||||||
|
*/
|
||||||
|
protected SemanticContext semanticContext;
|
||||||
|
|
||||||
|
/** Make a semantic predicate label */
|
||||||
|
public PredicateLabel(GrammarAST predicateASTNode) {
|
||||||
|
super(SEMPRED);
|
||||||
|
this.semanticContext = new SemanticContext.Predicate(predicateASTNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Make a semantic predicates label */
|
||||||
|
public PredicateLabel(SemanticContext semCtx) {
|
||||||
|
super(SEMPRED);
|
||||||
|
this.semanticContext = semCtx;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
return semanticContext.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if ( o==null ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ( this == o ) {
|
||||||
|
return true; // equals if same object
|
||||||
|
}
|
||||||
|
if ( !(o instanceof PredicateLabel) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return semanticContext.equals(((PredicateLabel)o).semanticContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSemanticPredicate() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SemanticContext getSemanticContext() {
|
||||||
|
return semanticContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "{"+semanticContext+"}?";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString(Grammar g) {
|
||||||
|
return toString();
|
||||||
|
}
|
||||||
|
}
|
55
antlr_3_1_source/analysis/RuleClosureTransition.java
Normal file
55
antlr_3_1_source/analysis/RuleClosureTransition.java
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.antlr.analysis;
|
||||||
|
|
||||||
|
import org.antlr.tool.Grammar;
|
||||||
|
import org.antlr.tool.Rule;
|
||||||
|
|
||||||
|
/** A transition used to reference another rule. It tracks two targets
|
||||||
|
* really: the actual transition target and the state following the
|
||||||
|
* state that refers to the other rule. Conversion of an NFA that
|
||||||
|
* falls off the end of a rule will be able to figure out who invoked
|
||||||
|
* that rule because of these special transitions.
|
||||||
|
*/
|
||||||
|
public class RuleClosureTransition extends Transition {
|
||||||
|
/** Ptr to the rule definition object for this rule ref */
|
||||||
|
public Rule rule;
|
||||||
|
|
||||||
|
/** What node to begin computations following ref to rule */
|
||||||
|
public NFAState followState;
|
||||||
|
|
||||||
|
public RuleClosureTransition(Rule rule,
|
||||||
|
NFAState ruleStart,
|
||||||
|
NFAState followState)
|
||||||
|
{
|
||||||
|
super(Label.EPSILON, ruleStart);
|
||||||
|
this.rule = rule;
|
||||||
|
this.followState = followState;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
486
antlr_3_1_source/analysis/SemanticContext.java
Normal file
486
antlr_3_1_source/analysis/SemanticContext.java
Normal file
@ -0,0 +1,486 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.antlr.analysis;
|
||||||
|
|
||||||
|
import org.antlr.stringtemplate.StringTemplate;
|
||||||
|
import org.antlr.stringtemplate.StringTemplateGroup;
|
||||||
|
import org.antlr.codegen.CodeGenerator;
|
||||||
|
import org.antlr.tool.ANTLRParser;
|
||||||
|
import org.antlr.tool.GrammarAST;
|
||||||
|
import org.antlr.tool.Grammar;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
/** A binary tree structure used to record the semantic context in which
|
||||||
|
* an NFA configuration is valid. It's either a single predicate or
|
||||||
|
* a tree representing an operation tree such as: p1&&p2 or p1||p2.
|
||||||
|
*
|
||||||
|
* For NFA o-p1->o-p2->o, create tree AND(p1,p2).
|
||||||
|
* For NFA (1)-p1->(2)
|
||||||
|
* | ^
|
||||||
|
* | |
|
||||||
|
* (3)-p2----
|
||||||
|
* we will have to combine p1 and p2 into DFA state as we will be
|
||||||
|
* adding NFA configurations for state 2 with two predicates p1,p2.
|
||||||
|
* So, set context for combined NFA config for state 2: OR(p1,p2).
|
||||||
|
*
|
||||||
|
* I have scoped the AND, NOT, OR, and Predicate subclasses of
|
||||||
|
* SemanticContext within the scope of this outer class.
|
||||||
|
*
|
||||||
|
* July 7, 2006: TJP altered OR to be set of operands. the Binary tree
|
||||||
|
* made it really hard to reduce complicated || sequences to their minimum.
|
||||||
|
* Got huge repeated || conditions.
|
||||||
|
*/
|
||||||
|
public abstract class SemanticContext {
|
||||||
|
/** Create a default value for the semantic context shared among all
|
||||||
|
* NFAConfigurations that do not have an actual semantic context.
|
||||||
|
* This prevents lots of if!=null type checks all over; it represents
|
||||||
|
* just an empty set of predicates.
|
||||||
|
*/
|
||||||
|
public static final SemanticContext EMPTY_SEMANTIC_CONTEXT = new Predicate();
|
||||||
|
|
||||||
|
/** Given a semantic context expression tree, return a tree with all
|
||||||
|
* nongated predicates set to true and then reduced. So p&&(q||r) would
|
||||||
|
* return p&&r if q is nongated but p and r are gated.
|
||||||
|
*/
|
||||||
|
public abstract SemanticContext getGatedPredicateContext();
|
||||||
|
|
||||||
|
/** Generate an expression that will evaluate the semantic context,
|
||||||
|
* given a set of output templates.
|
||||||
|
*/
|
||||||
|
public abstract StringTemplate genExpr(CodeGenerator generator,
|
||||||
|
StringTemplateGroup templates,
|
||||||
|
DFA dfa);
|
||||||
|
|
||||||
|
public abstract boolean isSyntacticPredicate();
|
||||||
|
|
||||||
|
/** Notify the indicated grammar of any syn preds used within this context */
|
||||||
|
public void trackUseOfSyntacticPredicates(Grammar g) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Predicate extends SemanticContext {
|
||||||
|
/** The AST node in tree created from the grammar holding the predicate */
|
||||||
|
public GrammarAST predicateAST;
|
||||||
|
|
||||||
|
/** Is this a {...}?=> gating predicate or a normal disambiguating {..}?
|
||||||
|
* If any predicate in expression is gated, then expression is considered
|
||||||
|
* gated.
|
||||||
|
*
|
||||||
|
* The simple Predicate object's predicate AST's type is used to set
|
||||||
|
* gated to true if type==GATED_SEMPRED.
|
||||||
|
*/
|
||||||
|
protected boolean gated = false;
|
||||||
|
|
||||||
|
/** syntactic predicates are converted to semantic predicates
|
||||||
|
* but synpreds are generated slightly differently.
|
||||||
|
*/
|
||||||
|
protected boolean synpred = false;
|
||||||
|
|
||||||
|
public static final int INVALID_PRED_VALUE = -1;
|
||||||
|
public static final int FALSE_PRED = 0;
|
||||||
|
public static final int TRUE_PRED = 1;
|
||||||
|
|
||||||
|
/** sometimes predicates are known to be true or false; we need
|
||||||
|
* a way to represent this without resorting to a target language
|
||||||
|
* value like true or TRUE.
|
||||||
|
*/
|
||||||
|
protected int constantValue = INVALID_PRED_VALUE;
|
||||||
|
|
||||||
|
public Predicate() {
|
||||||
|
predicateAST = new GrammarAST();
|
||||||
|
this.gated=false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Predicate(GrammarAST predicate) {
|
||||||
|
this.predicateAST = predicate;
|
||||||
|
this.gated =
|
||||||
|
predicate.getType()==ANTLRParser.GATED_SEMPRED ||
|
||||||
|
predicate.getType()==ANTLRParser.SYN_SEMPRED ;
|
||||||
|
this.synpred =
|
||||||
|
predicate.getType()==ANTLRParser.SYN_SEMPRED ||
|
||||||
|
predicate.getType()==ANTLRParser.BACKTRACK_SEMPRED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Predicate(Predicate p) {
|
||||||
|
this.predicateAST = p.predicateAST;
|
||||||
|
this.gated = p.gated;
|
||||||
|
this.synpred = p.synpred;
|
||||||
|
this.constantValue = p.constantValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Two predicates are the same if they are literally the same
|
||||||
|
* text rather than same node in the grammar's AST.
|
||||||
|
* Or, if they have the same constant value, return equal.
|
||||||
|
* As of July 2006 I'm not sure these are needed.
|
||||||
|
*/
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if ( !(o instanceof Predicate) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return predicateAST.getText().equals(((Predicate)o).predicateAST.getText());
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
if ( predicateAST ==null ) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return predicateAST.getText().hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public StringTemplate genExpr(CodeGenerator generator,
|
||||||
|
StringTemplateGroup templates,
|
||||||
|
DFA dfa)
|
||||||
|
{
|
||||||
|
StringTemplate eST = null;
|
||||||
|
if ( templates!=null ) {
|
||||||
|
if ( synpred ) {
|
||||||
|
eST = templates.getInstanceOf("evalSynPredicate");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
eST = templates.getInstanceOf("evalPredicate");
|
||||||
|
generator.grammar.decisionsWhoseDFAsUsesSemPreds.add(dfa);
|
||||||
|
}
|
||||||
|
String predEnclosingRuleName = predicateAST.enclosingRuleName;
|
||||||
|
/*
|
||||||
|
String decisionEnclosingRuleName =
|
||||||
|
dfa.getNFADecisionStartState().getEnclosingRule();
|
||||||
|
// if these rulenames are diff, then pred was hoisted out of rule
|
||||||
|
// Currently I don't warn you about this as it could be annoying.
|
||||||
|
// I do the translation anyway.
|
||||||
|
*/
|
||||||
|
//eST.setAttribute("pred", this.toString());
|
||||||
|
if ( generator!=null ) {
|
||||||
|
eST.setAttribute("pred",
|
||||||
|
generator.translateAction(predEnclosingRuleName,predicateAST));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
eST = new StringTemplate("$pred$");
|
||||||
|
eST.setAttribute("pred", this.toString());
|
||||||
|
return eST;
|
||||||
|
}
|
||||||
|
if ( generator!=null ) {
|
||||||
|
String description =
|
||||||
|
generator.target.getTargetStringLiteralFromString(this.toString());
|
||||||
|
eST.setAttribute("description", description);
|
||||||
|
}
|
||||||
|
return eST;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SemanticContext getGatedPredicateContext() {
|
||||||
|
if ( gated ) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSyntacticPredicate() {
|
||||||
|
return predicateAST !=null &&
|
||||||
|
( predicateAST.getType()==ANTLRParser.SYN_SEMPRED ||
|
||||||
|
predicateAST.getType()==ANTLRParser.BACKTRACK_SEMPRED );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void trackUseOfSyntacticPredicates(Grammar g) {
|
||||||
|
if ( synpred ) {
|
||||||
|
g.synPredNamesUsedInDFA.add(predicateAST.getText());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
if ( predicateAST ==null ) {
|
||||||
|
return "<nopred>";
|
||||||
|
}
|
||||||
|
return predicateAST.getText();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TruePredicate extends Predicate {
|
||||||
|
public TruePredicate() {
|
||||||
|
super();
|
||||||
|
this.constantValue = TRUE_PRED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StringTemplate genExpr(CodeGenerator generator,
|
||||||
|
StringTemplateGroup templates,
|
||||||
|
DFA dfa)
|
||||||
|
{
|
||||||
|
if ( templates!=null ) {
|
||||||
|
return templates.getInstanceOf("true");
|
||||||
|
}
|
||||||
|
return new StringTemplate("true");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "true"; // not used for code gen, just DOT and print outs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
public static class FalsePredicate extends Predicate {
|
||||||
|
public FalsePredicate() {
|
||||||
|
super();
|
||||||
|
this.constantValue = FALSE_PRED;
|
||||||
|
}
|
||||||
|
public StringTemplate genExpr(CodeGenerator generator,
|
||||||
|
StringTemplateGroup templates,
|
||||||
|
DFA dfa)
|
||||||
|
{
|
||||||
|
if ( templates!=null ) {
|
||||||
|
return templates.getInstanceOf("false");
|
||||||
|
}
|
||||||
|
return new StringTemplate("false");
|
||||||
|
}
|
||||||
|
public String toString() {
|
||||||
|
return "false"; // not used for code gen, just DOT and print outs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static class AND extends SemanticContext {
|
||||||
|
protected SemanticContext left,right;
|
||||||
|
public AND(SemanticContext a, SemanticContext b) {
|
||||||
|
this.left = a;
|
||||||
|
this.right = b;
|
||||||
|
}
|
||||||
|
public StringTemplate genExpr(CodeGenerator generator,
|
||||||
|
StringTemplateGroup templates,
|
||||||
|
DFA dfa)
|
||||||
|
{
|
||||||
|
StringTemplate eST = null;
|
||||||
|
if ( templates!=null ) {
|
||||||
|
eST = templates.getInstanceOf("andPredicates");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
eST = new StringTemplate("($left$&&$right$)");
|
||||||
|
}
|
||||||
|
eST.setAttribute("left", left.genExpr(generator,templates,dfa));
|
||||||
|
eST.setAttribute("right", right.genExpr(generator,templates,dfa));
|
||||||
|
return eST;
|
||||||
|
}
|
||||||
|
public SemanticContext getGatedPredicateContext() {
|
||||||
|
SemanticContext gatedLeft = left.getGatedPredicateContext();
|
||||||
|
SemanticContext gatedRight = right.getGatedPredicateContext();
|
||||||
|
if ( gatedLeft==null ) {
|
||||||
|
return gatedRight;
|
||||||
|
}
|
||||||
|
if ( gatedRight==null ) {
|
||||||
|
return gatedLeft;
|
||||||
|
}
|
||||||
|
return new AND(gatedLeft, gatedRight);
|
||||||
|
}
|
||||||
|
public boolean isSyntacticPredicate() {
|
||||||
|
return left.isSyntacticPredicate()||right.isSyntacticPredicate();
|
||||||
|
}
|
||||||
|
public void trackUseOfSyntacticPredicates(Grammar g) {
|
||||||
|
left.trackUseOfSyntacticPredicates(g);
|
||||||
|
right.trackUseOfSyntacticPredicates(g);
|
||||||
|
}
|
||||||
|
public String toString() {
|
||||||
|
return "("+left+"&&"+right+")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class OR extends SemanticContext {
|
||||||
|
protected Set operands;
|
||||||
|
public OR(SemanticContext a, SemanticContext b) {
|
||||||
|
operands = new HashSet();
|
||||||
|
if ( a instanceof OR ) {
|
||||||
|
operands.addAll(((OR)a).operands);
|
||||||
|
}
|
||||||
|
else if ( a!=null ) {
|
||||||
|
operands.add(a);
|
||||||
|
}
|
||||||
|
if ( b instanceof OR ) {
|
||||||
|
operands.addAll(((OR)b).operands);
|
||||||
|
}
|
||||||
|
else if ( b!=null ) {
|
||||||
|
operands.add(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public StringTemplate genExpr(CodeGenerator generator,
|
||||||
|
StringTemplateGroup templates,
|
||||||
|
DFA dfa)
|
||||||
|
{
|
||||||
|
StringTemplate eST = null;
|
||||||
|
if ( templates!=null ) {
|
||||||
|
eST = templates.getInstanceOf("orPredicates");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
eST = new StringTemplate("($first(operands)$$rest(operands):{o | ||$o$}$)");
|
||||||
|
}
|
||||||
|
for (Iterator it = operands.iterator(); it.hasNext();) {
|
||||||
|
SemanticContext semctx = (SemanticContext) it.next();
|
||||||
|
eST.setAttribute("operands", semctx.genExpr(generator,templates,dfa));
|
||||||
|
}
|
||||||
|
return eST;
|
||||||
|
}
|
||||||
|
public SemanticContext getGatedPredicateContext() {
|
||||||
|
SemanticContext result = null;
|
||||||
|
for (Iterator it = operands.iterator(); it.hasNext();) {
|
||||||
|
SemanticContext semctx = (SemanticContext) it.next();
|
||||||
|
SemanticContext gatedPred = semctx.getGatedPredicateContext();
|
||||||
|
if ( gatedPred!=null ) {
|
||||||
|
result = or(result, gatedPred);
|
||||||
|
// result = new OR(result, gatedPred);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
public boolean isSyntacticPredicate() {
|
||||||
|
for (Iterator it = operands.iterator(); it.hasNext();) {
|
||||||
|
SemanticContext semctx = (SemanticContext) it.next();
|
||||||
|
if ( semctx.isSyntacticPredicate() ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
public void trackUseOfSyntacticPredicates(Grammar g) {
|
||||||
|
for (Iterator it = operands.iterator(); it.hasNext();) {
|
||||||
|
SemanticContext semctx = (SemanticContext) it.next();
|
||||||
|
semctx.trackUseOfSyntacticPredicates(g);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public String toString() {
|
||||||
|
StringBuffer buf = new StringBuffer();
|
||||||
|
buf.append("(");
|
||||||
|
int i = 0;
|
||||||
|
for (Iterator it = operands.iterator(); it.hasNext();) {
|
||||||
|
SemanticContext semctx = (SemanticContext) it.next();
|
||||||
|
if ( i>0 ) {
|
||||||
|
buf.append("||");
|
||||||
|
}
|
||||||
|
buf.append(semctx.toString());
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
buf.append(")");
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class NOT extends SemanticContext {
|
||||||
|
protected SemanticContext ctx;
|
||||||
|
public NOT(SemanticContext ctx) {
|
||||||
|
this.ctx = ctx;
|
||||||
|
}
|
||||||
|
public StringTemplate genExpr(CodeGenerator generator,
|
||||||
|
StringTemplateGroup templates,
|
||||||
|
DFA dfa)
|
||||||
|
{
|
||||||
|
StringTemplate eST = null;
|
||||||
|
if ( templates!=null ) {
|
||||||
|
eST = templates.getInstanceOf("notPredicate");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
eST = new StringTemplate("?!($pred$)");
|
||||||
|
}
|
||||||
|
eST.setAttribute("pred", ctx.genExpr(generator,templates,dfa));
|
||||||
|
return eST;
|
||||||
|
}
|
||||||
|
public SemanticContext getGatedPredicateContext() {
|
||||||
|
SemanticContext p = ctx.getGatedPredicateContext();
|
||||||
|
if ( p==null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new NOT(p);
|
||||||
|
}
|
||||||
|
public boolean isSyntacticPredicate() {
|
||||||
|
return ctx.isSyntacticPredicate();
|
||||||
|
}
|
||||||
|
public void trackUseOfSyntacticPredicates(Grammar g) {
|
||||||
|
ctx.trackUseOfSyntacticPredicates(g);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object object) {
|
||||||
|
if ( !(object instanceof NOT) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return this.ctx.equals(((NOT)object).ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "!("+ctx+")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SemanticContext and(SemanticContext a, SemanticContext b) {
|
||||||
|
//System.out.println("AND: "+a+"&&"+b);
|
||||||
|
if ( a==EMPTY_SEMANTIC_CONTEXT || a==null ) {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
if ( b==EMPTY_SEMANTIC_CONTEXT || b==null ) {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
if ( a.equals(b) ) {
|
||||||
|
return a; // if same, just return left one
|
||||||
|
}
|
||||||
|
//System.out.println("## have to AND");
|
||||||
|
return new AND(a,b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SemanticContext or(SemanticContext a, SemanticContext b) {
|
||||||
|
//System.out.println("OR: "+a+"||"+b);
|
||||||
|
if ( a==EMPTY_SEMANTIC_CONTEXT || a==null ) {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
if ( b==EMPTY_SEMANTIC_CONTEXT || b==null ) {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
if ( a instanceof TruePredicate ) {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
if ( b instanceof TruePredicate ) {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
if ( a instanceof NOT && b instanceof Predicate ) {
|
||||||
|
NOT n = (NOT)a;
|
||||||
|
// check for !p||p
|
||||||
|
if ( n.ctx.equals(b) ) {
|
||||||
|
return new TruePredicate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( b instanceof NOT && a instanceof Predicate ) {
|
||||||
|
NOT n = (NOT)b;
|
||||||
|
// check for p||!p
|
||||||
|
if ( n.ctx.equals(a) ) {
|
||||||
|
return new TruePredicate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( a.equals(b) ) {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
//System.out.println("## have to OR");
|
||||||
|
return new OR(a,b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SemanticContext not(SemanticContext a) {
|
||||||
|
return new NOT(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
54
antlr_3_1_source/analysis/State.java
Normal file
54
antlr_3_1_source/analysis/State.java
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.antlr.analysis;
|
||||||
|
|
||||||
|
/** A generic state machine state. */
|
||||||
|
public abstract class State {
|
||||||
|
public static final int INVALID_STATE_NUMBER = -1;
|
||||||
|
|
||||||
|
public int stateNumber = INVALID_STATE_NUMBER;
|
||||||
|
|
||||||
|
/** An accept state is an end of rule state for lexers and
|
||||||
|
* parser grammar rules.
|
||||||
|
*/
|
||||||
|
protected boolean acceptState = false;
|
||||||
|
|
||||||
|
public abstract int getNumberOfTransitions();
|
||||||
|
|
||||||
|
public abstract void addTransition(Transition e);
|
||||||
|
|
||||||
|
public abstract Transition transition(int i);
|
||||||
|
|
||||||
|
public boolean isAcceptState() {
|
||||||
|
return acceptState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAcceptState(boolean acceptState) {
|
||||||
|
this.acceptState = acceptState;
|
||||||
|
}
|
||||||
|
}
|
41
antlr_3_1_source/analysis/StateCluster.java
Normal file
41
antlr_3_1_source/analysis/StateCluster.java
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.antlr.analysis;
|
||||||
|
|
||||||
|
/** A Cluster object points to the left/right (start and end) states of a
|
||||||
|
* state machine. Used to build NFAs.
|
||||||
|
*/
|
||||||
|
public class StateCluster {
|
||||||
|
public NFAState left;
|
||||||
|
public NFAState right;
|
||||||
|
|
||||||
|
public StateCluster(NFAState left, NFAState right) {
|
||||||
|
this.left = left;
|
||||||
|
this.right = right;
|
||||||
|
}
|
||||||
|
}
|
84
antlr_3_1_source/analysis/Transition.java
Normal file
84
antlr_3_1_source/analysis/Transition.java
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.antlr.analysis;
|
||||||
|
|
||||||
|
/** A generic transition between any two state machine states. It defines
|
||||||
|
* some special labels that indicate things like epsilon transitions and
|
||||||
|
* that the label is actually a set of labels or a semantic predicate.
|
||||||
|
* This is a one way link. It emanates from a state (usually via a list of
|
||||||
|
* transitions) and has a label/target pair. I have abstracted the notion
|
||||||
|
* of a Label to handle the various kinds of things it can be.
|
||||||
|
*/
|
||||||
|
public class Transition implements Comparable {
|
||||||
|
/** What label must be consumed to transition to target */
|
||||||
|
public Label label;
|
||||||
|
|
||||||
|
/** The target of this transition */
|
||||||
|
public State target;
|
||||||
|
|
||||||
|
public Transition(Label label, State target) {
|
||||||
|
this.label = label;
|
||||||
|
this.target = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Transition(int label, State target) {
|
||||||
|
this.label = new Label(label);
|
||||||
|
this.target = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEpsilon() {
|
||||||
|
return label.isEpsilon();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAction() {
|
||||||
|
return label.isAction();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSemanticPredicate() {
|
||||||
|
return label.isSemanticPredicate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
return label.hashCode() + target.stateNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
Transition other = (Transition)o;
|
||||||
|
return this.label.equals(other.label) &&
|
||||||
|
this.target.equals(other.target);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int compareTo(Object o) {
|
||||||
|
Transition other = (Transition)o;
|
||||||
|
return this.label.compareTo(other.label);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return label+"->"+target.stateNumber;
|
||||||
|
}
|
||||||
|
}
|
190
antlr_3_1_source/codegen/ACyclicDFACodeGenerator.java
Normal file
190
antlr_3_1_source/codegen/ACyclicDFACodeGenerator.java
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.antlr.codegen;
|
||||||
|
|
||||||
|
import org.antlr.analysis.*;
|
||||||
|
import org.antlr.misc.Utils;
|
||||||
|
import org.antlr.stringtemplate.StringTemplate;
|
||||||
|
import org.antlr.stringtemplate.StringTemplateGroup;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ACyclicDFACodeGenerator {
|
||||||
|
protected CodeGenerator parentGenerator;
|
||||||
|
|
||||||
|
public ACyclicDFACodeGenerator(CodeGenerator parent) {
|
||||||
|
this.parentGenerator = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StringTemplate genFixedLookaheadDecision(StringTemplateGroup templates,
|
||||||
|
DFA dfa)
|
||||||
|
{
|
||||||
|
return walkFixedDFAGeneratingStateMachine(templates, dfa, dfa.startState, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected StringTemplate walkFixedDFAGeneratingStateMachine(
|
||||||
|
StringTemplateGroup templates,
|
||||||
|
DFA dfa,
|
||||||
|
DFAState s,
|
||||||
|
int k)
|
||||||
|
{
|
||||||
|
//System.out.println("walk "+s.stateNumber+" in dfa for decision "+dfa.decisionNumber);
|
||||||
|
if ( s.isAcceptState() ) {
|
||||||
|
StringTemplate dfaST = templates.getInstanceOf("dfaAcceptState");
|
||||||
|
dfaST.setAttribute("alt", Utils.integer(s.getUniquelyPredictedAlt()));
|
||||||
|
return dfaST;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the default templates for generating a state and its edges
|
||||||
|
// can be an if-then-else structure or a switch
|
||||||
|
String dfaStateName = "dfaState";
|
||||||
|
String dfaLoopbackStateName = "dfaLoopbackState";
|
||||||
|
String dfaOptionalBlockStateName = "dfaOptionalBlockState";
|
||||||
|
String dfaEdgeName = "dfaEdge";
|
||||||
|
if ( parentGenerator.canGenerateSwitch(s) ) {
|
||||||
|
dfaStateName = "dfaStateSwitch";
|
||||||
|
dfaLoopbackStateName = "dfaLoopbackStateSwitch";
|
||||||
|
dfaOptionalBlockStateName = "dfaOptionalBlockStateSwitch";
|
||||||
|
dfaEdgeName = "dfaEdgeSwitch";
|
||||||
|
}
|
||||||
|
|
||||||
|
StringTemplate dfaST = templates.getInstanceOf(dfaStateName);
|
||||||
|
if ( dfa.getNFADecisionStartState().decisionStateType==NFAState.LOOPBACK ) {
|
||||||
|
dfaST = templates.getInstanceOf(dfaLoopbackStateName);
|
||||||
|
}
|
||||||
|
else if ( dfa.getNFADecisionStartState().decisionStateType==NFAState.OPTIONAL_BLOCK_START ) {
|
||||||
|
dfaST = templates.getInstanceOf(dfaOptionalBlockStateName);
|
||||||
|
}
|
||||||
|
dfaST.setAttribute("k", Utils.integer(k));
|
||||||
|
dfaST.setAttribute("stateNumber", Utils.integer(s.stateNumber));
|
||||||
|
dfaST.setAttribute("semPredState",
|
||||||
|
Boolean.valueOf(s.isResolvedWithPredicates()));
|
||||||
|
/*
|
||||||
|
String description = dfa.getNFADecisionStartState().getDescription();
|
||||||
|
description = parentGenerator.target.getTargetStringLiteralFromString(description);
|
||||||
|
//System.out.println("DFA: "+description+" associated with AST "+dfa.getNFADecisionStartState());
|
||||||
|
if ( description!=null ) {
|
||||||
|
dfaST.setAttribute("description", description);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
int EOTPredicts = NFA.INVALID_ALT_NUMBER;
|
||||||
|
DFAState EOTTarget = null;
|
||||||
|
//System.out.println("DFA state "+s.stateNumber);
|
||||||
|
for (int i = 0; i < s.getNumberOfTransitions(); i++) {
|
||||||
|
Transition edge = (Transition) s.transition(i);
|
||||||
|
//System.out.println("edge "+s.stateNumber+"-"+edge.label.toString()+"->"+edge.target.stateNumber);
|
||||||
|
if ( edge.label.getAtom()==Label.EOT ) {
|
||||||
|
// don't generate a real edge for EOT; track alt EOT predicts
|
||||||
|
// generate that prediction in the else clause as default case
|
||||||
|
EOTTarget = (DFAState)edge.target;
|
||||||
|
EOTPredicts = EOTTarget.getUniquelyPredictedAlt();
|
||||||
|
/*
|
||||||
|
System.out.println("DFA s"+s.stateNumber+" EOT goes to s"+
|
||||||
|
edge.target.stateNumber+" predicates alt "+
|
||||||
|
EOTPredicts);
|
||||||
|
*/
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
StringTemplate edgeST = templates.getInstanceOf(dfaEdgeName);
|
||||||
|
// If the template wants all the label values delineated, do that
|
||||||
|
if ( edgeST.getFormalArgument("labels")!=null ) {
|
||||||
|
List labels = edge.label.getSet().toList();
|
||||||
|
for (int j = 0; j < labels.size(); j++) {
|
||||||
|
Integer vI = (Integer) labels.get(j);
|
||||||
|
String label =
|
||||||
|
parentGenerator.getTokenTypeAsTargetLabel(vI.intValue());
|
||||||
|
labels.set(j, label); // rewrite List element to be name
|
||||||
|
}
|
||||||
|
edgeST.setAttribute("labels", labels);
|
||||||
|
}
|
||||||
|
else { // else create an expression to evaluate (the general case)
|
||||||
|
edgeST.setAttribute("labelExpr",
|
||||||
|
parentGenerator.genLabelExpr(templates,edge,k));
|
||||||
|
}
|
||||||
|
|
||||||
|
// stick in any gated predicates for any edge if not already a pred
|
||||||
|
if ( !edge.label.isSemanticPredicate() ) {
|
||||||
|
DFAState target = (DFAState)edge.target;
|
||||||
|
SemanticContext preds =
|
||||||
|
target.getGatedPredicatesInNFAConfigurations();
|
||||||
|
if ( preds!=null ) {
|
||||||
|
//System.out.println("preds="+target.getGatedPredicatesInNFAConfigurations());
|
||||||
|
StringTemplate predST = preds.genExpr(parentGenerator,
|
||||||
|
parentGenerator.getTemplates(),
|
||||||
|
dfa);
|
||||||
|
edgeST.setAttribute("predicates", predST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StringTemplate targetST =
|
||||||
|
walkFixedDFAGeneratingStateMachine(templates,
|
||||||
|
dfa,
|
||||||
|
(DFAState)edge.target,
|
||||||
|
k+1);
|
||||||
|
edgeST.setAttribute("targetState", targetST);
|
||||||
|
dfaST.setAttribute("edges", edgeST);
|
||||||
|
/*
|
||||||
|
System.out.println("back to DFA "+
|
||||||
|
dfa.decisionNumber+"."+s.stateNumber);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
// HANDLE EOT EDGE
|
||||||
|
if ( EOTPredicts!=NFA.INVALID_ALT_NUMBER ) {
|
||||||
|
// EOT unique predicts an alt
|
||||||
|
dfaST.setAttribute("eotPredictsAlt", Utils.integer(EOTPredicts));
|
||||||
|
}
|
||||||
|
else if ( EOTTarget!=null && EOTTarget.getNumberOfTransitions()>0 ) {
|
||||||
|
// EOT state has transitions so must split on predicates.
|
||||||
|
// Generate predicate else-if clauses and then generate
|
||||||
|
// NoViableAlt exception as else clause.
|
||||||
|
// Note: these predicates emanate from the EOT target state
|
||||||
|
// rather than the current DFAState s so the error message
|
||||||
|
// might be slightly misleading if you are looking at the
|
||||||
|
// state number. Predicates emanating from EOT targets are
|
||||||
|
// hoisted up to the state that has the EOT edge.
|
||||||
|
for (int i = 0; i < EOTTarget.getNumberOfTransitions(); i++) {
|
||||||
|
Transition predEdge = (Transition)EOTTarget.transition(i);
|
||||||
|
StringTemplate edgeST = templates.getInstanceOf(dfaEdgeName);
|
||||||
|
edgeST.setAttribute("labelExpr",
|
||||||
|
parentGenerator.genSemanticPredicateExpr(templates,predEdge));
|
||||||
|
// the target must be an accept state
|
||||||
|
//System.out.println("EOT edge");
|
||||||
|
StringTemplate targetST =
|
||||||
|
walkFixedDFAGeneratingStateMachine(templates,
|
||||||
|
dfa,
|
||||||
|
(DFAState)predEdge.target,
|
||||||
|
k+1);
|
||||||
|
edgeST.setAttribute("targetState", targetST);
|
||||||
|
dfaST.setAttribute("edges", edgeST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dfaST;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
100
antlr_3_1_source/codegen/ANTLRTokenTypes.txt
Normal file
100
antlr_3_1_source/codegen/ANTLRTokenTypes.txt
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
// $ANTLR 2.7.7 (2006-01-29): antlr.g -> ANTLRTokenTypes.txt$
|
||||||
|
ANTLR // output token vocab name
|
||||||
|
OPTIONS="options"=4
|
||||||
|
TOKENS="tokens"=5
|
||||||
|
PARSER="parser"=6
|
||||||
|
LEXER=7
|
||||||
|
RULE=8
|
||||||
|
BLOCK=9
|
||||||
|
OPTIONAL=10
|
||||||
|
CLOSURE=11
|
||||||
|
POSITIVE_CLOSURE=12
|
||||||
|
SYNPRED=13
|
||||||
|
RANGE=14
|
||||||
|
CHAR_RANGE=15
|
||||||
|
EPSILON=16
|
||||||
|
ALT=17
|
||||||
|
EOR=18
|
||||||
|
EOB=19
|
||||||
|
EOA=20
|
||||||
|
ID=21
|
||||||
|
ARG=22
|
||||||
|
ARGLIST=23
|
||||||
|
RET=24
|
||||||
|
LEXER_GRAMMAR=25
|
||||||
|
PARSER_GRAMMAR=26
|
||||||
|
TREE_GRAMMAR=27
|
||||||
|
COMBINED_GRAMMAR=28
|
||||||
|
INITACTION=29
|
||||||
|
FORCED_ACTION=30
|
||||||
|
LABEL=31
|
||||||
|
TEMPLATE=32
|
||||||
|
SCOPE="scope"=33
|
||||||
|
IMPORT="import"=34
|
||||||
|
GATED_SEMPRED=35
|
||||||
|
SYN_SEMPRED=36
|
||||||
|
BACKTRACK_SEMPRED=37
|
||||||
|
FRAGMENT="fragment"=38
|
||||||
|
DOT=39
|
||||||
|
ACTION=40
|
||||||
|
DOC_COMMENT=41
|
||||||
|
SEMI=42
|
||||||
|
LITERAL_lexer="lexer"=43
|
||||||
|
LITERAL_tree="tree"=44
|
||||||
|
LITERAL_grammar="grammar"=45
|
||||||
|
AMPERSAND=46
|
||||||
|
COLON=47
|
||||||
|
RCURLY=48
|
||||||
|
ASSIGN=49
|
||||||
|
STRING_LITERAL=50
|
||||||
|
CHAR_LITERAL=51
|
||||||
|
INT=52
|
||||||
|
STAR=53
|
||||||
|
COMMA=54
|
||||||
|
TOKEN_REF=55
|
||||||
|
LITERAL_protected="protected"=56
|
||||||
|
LITERAL_public="public"=57
|
||||||
|
LITERAL_private="private"=58
|
||||||
|
BANG=59
|
||||||
|
ARG_ACTION=60
|
||||||
|
LITERAL_returns="returns"=61
|
||||||
|
LITERAL_throws="throws"=62
|
||||||
|
LPAREN=63
|
||||||
|
OR=64
|
||||||
|
RPAREN=65
|
||||||
|
LITERAL_catch="catch"=66
|
||||||
|
LITERAL_finally="finally"=67
|
||||||
|
PLUS_ASSIGN=68
|
||||||
|
SEMPRED=69
|
||||||
|
IMPLIES=70
|
||||||
|
ROOT=71
|
||||||
|
WILDCARD=72
|
||||||
|
RULE_REF=73
|
||||||
|
NOT=74
|
||||||
|
TREE_BEGIN=75
|
||||||
|
QUESTION=76
|
||||||
|
PLUS=77
|
||||||
|
OPEN_ELEMENT_OPTION=78
|
||||||
|
CLOSE_ELEMENT_OPTION=79
|
||||||
|
REWRITE=80
|
||||||
|
ETC=81
|
||||||
|
DOLLAR=82
|
||||||
|
DOUBLE_QUOTE_STRING_LITERAL=83
|
||||||
|
DOUBLE_ANGLE_STRING_LITERAL=84
|
||||||
|
WS=85
|
||||||
|
COMMENT=86
|
||||||
|
SL_COMMENT=87
|
||||||
|
ML_COMMENT=88
|
||||||
|
STRAY_BRACKET=89
|
||||||
|
ESC=90
|
||||||
|
DIGIT=91
|
||||||
|
XDIGIT=92
|
||||||
|
NESTED_ARG_ACTION=93
|
||||||
|
NESTED_ACTION=94
|
||||||
|
ACTION_CHAR_LITERAL=95
|
||||||
|
ACTION_STRING_LITERAL=96
|
||||||
|
ACTION_ESC=97
|
||||||
|
WS_LOOP=98
|
||||||
|
INTERNAL_RULE_REF=99
|
||||||
|
WS_OPT=100
|
||||||
|
SRC=101
|
134
antlr_3_1_source/codegen/ActionScriptTarget.java
Normal file
134
antlr_3_1_source/codegen/ActionScriptTarget.java
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.antlr.codegen;
|
||||||
|
|
||||||
|
import org.antlr.Tool;
|
||||||
|
import org.antlr.stringtemplate.StringTemplate;
|
||||||
|
import org.antlr.tool.Grammar;
|
||||||
|
|
||||||
|
public class ActionScriptTarget extends Target {
|
||||||
|
|
||||||
|
public String getTargetCharLiteralFromANTLRCharLiteral(
|
||||||
|
CodeGenerator generator,
|
||||||
|
String literal) {
|
||||||
|
|
||||||
|
int c = Grammar.getCharValueFromGrammarCharLiteral(literal);
|
||||||
|
return String.valueOf(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTokenTypeAsTargetLabel(CodeGenerator generator,
|
||||||
|
int ttype) {
|
||||||
|
// use ints for predefined types;
|
||||||
|
// <invalid> <EOR> <DOWN> <UP>
|
||||||
|
if (ttype >= 0 && ttype <= 3) {
|
||||||
|
return String.valueOf(ttype);
|
||||||
|
}
|
||||||
|
|
||||||
|
String name = generator.grammar.getTokenDisplayName(ttype);
|
||||||
|
|
||||||
|
// If name is a literal, return the token type instead
|
||||||
|
if (name.charAt(0) == '\'') {
|
||||||
|
return String.valueOf(ttype);
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ActionScript doesn't support Unicode String literals that are considered "illegal"
|
||||||
|
* or are in the surrogate pair ranges. For example "/uffff" will not encode properly
|
||||||
|
* nor will "/ud800". To keep things as compact as possible we use the following encoding
|
||||||
|
* if the int is below 255, we encode as hex literal
|
||||||
|
* If the int is between 255 and 0x7fff we use a single unicode literal with the value
|
||||||
|
* If the int is above 0x7fff, we use a unicode literal of 0x80hh, where hh is the high-order
|
||||||
|
* bits followed by \xll where ll is the lower order bits of a 16-bit number.
|
||||||
|
*
|
||||||
|
* Ideally this should be improved at a future date. The most optimal way to encode this
|
||||||
|
* may be a compressed AMF encoding that is embedded using an Embed tag in ActionScript.
|
||||||
|
*
|
||||||
|
* @param v
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String encodeIntAsCharEscape(int v) {
|
||||||
|
// encode as hex
|
||||||
|
if ( v<=255 ) {
|
||||||
|
return "\\x"+ Integer.toHexString(v|0x100).substring(1,3);
|
||||||
|
}
|
||||||
|
if (v <= 0x7fff) {
|
||||||
|
String hex = Integer.toHexString(v|0x10000).substring(1,5);
|
||||||
|
return "\\u"+hex;
|
||||||
|
}
|
||||||
|
if (v > 0xffff) {
|
||||||
|
System.err.println("Warning: character literal out of range for ActionScript target " + v);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
StringBuffer buf = new StringBuffer("\\u80");
|
||||||
|
buf.append(Integer.toHexString((v >> 8) | 0x100).substring(1, 3)); // high - order bits
|
||||||
|
buf.append("\\x");
|
||||||
|
buf.append(Integer.toHexString((v & 0xff) | 0x100).substring(1, 3)); // low -order bits
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Convert long to two 32-bit numbers separted by a comma.
|
||||||
|
* ActionScript does not support 64-bit numbers, so we need to break
|
||||||
|
* the number into two 32-bit literals to give to the Bit. A number like
|
||||||
|
* 0xHHHHHHHHLLLLLLLL is broken into the following string:
|
||||||
|
* "0xLLLLLLLL, 0xHHHHHHHH"
|
||||||
|
* Note that the low order bits are first, followed by the high order bits.
|
||||||
|
* This is to match how the BitSet constructor works, where the bits are
|
||||||
|
* passed in in 32-bit chunks with low-order bits coming first.
|
||||||
|
*/
|
||||||
|
public String getTarget64BitStringFromValue(long word) {
|
||||||
|
StringBuffer buf = new StringBuffer(22); // enough for the two "0x", "," and " "
|
||||||
|
buf.append("0x");
|
||||||
|
writeHexWithPadding(buf, Integer.toHexString((int)(word & 0x00000000ffffffffL)));
|
||||||
|
buf.append(", 0x");
|
||||||
|
writeHexWithPadding(buf, Integer.toHexString((int)(word >> 32)));
|
||||||
|
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeHexWithPadding(StringBuffer buf, String digits) {
|
||||||
|
digits = digits.toUpperCase();
|
||||||
|
int padding = 8 - digits.length();
|
||||||
|
// pad left with zeros
|
||||||
|
for (int i=1; i<=padding; i++) {
|
||||||
|
buf.append('0');
|
||||||
|
}
|
||||||
|
buf.append(digits);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected StringTemplate chooseWhereCyclicDFAsGo(Tool tool,
|
||||||
|
CodeGenerator generator,
|
||||||
|
Grammar grammar,
|
||||||
|
StringTemplate recognizerST,
|
||||||
|
StringTemplate cyclicDFAST) {
|
||||||
|
return recognizerST;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
801
antlr_3_1_source/codegen/ActionTranslator.g
Normal file
801
antlr_3_1_source/codegen/ActionTranslator.g
Normal file
@ -0,0 +1,801 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2008 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
lexer grammar ActionTranslator;
|
||||||
|
options {
|
||||||
|
filter=true; // try all non-fragment rules in order specified
|
||||||
|
// output=template; TODO: can we make tokens return templates somehow?
|
||||||
|
}
|
||||||
|
|
||||||
|
@header {
|
||||||
|
package org.antlr.codegen;
|
||||||
|
import org.antlr.stringtemplate.StringTemplate;
|
||||||
|
import org.antlr.runtime.*;
|
||||||
|
import org.antlr.tool.*;
|
||||||
|
}
|
||||||
|
|
||||||
|
@members {
|
||||||
|
public List chunks = new ArrayList();
|
||||||
|
Rule enclosingRule;
|
||||||
|
int outerAltNum;
|
||||||
|
Grammar grammar;
|
||||||
|
CodeGenerator generator;
|
||||||
|
antlr.Token actionToken;
|
||||||
|
|
||||||
|
public ActionTranslator(CodeGenerator generator,
|
||||||
|
String ruleName,
|
||||||
|
GrammarAST actionAST)
|
||||||
|
{
|
||||||
|
this(new ANTLRStringStream(actionAST.token.getText()));
|
||||||
|
this.generator = generator;
|
||||||
|
this.grammar = generator.grammar;
|
||||||
|
this.enclosingRule = grammar.getLocallyDefinedRule(ruleName);
|
||||||
|
this.actionToken = actionAST.token;
|
||||||
|
this.outerAltNum = actionAST.outerAltNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ActionTranslator(CodeGenerator generator,
|
||||||
|
String ruleName,
|
||||||
|
antlr.Token actionToken,
|
||||||
|
int outerAltNum)
|
||||||
|
{
|
||||||
|
this(new ANTLRStringStream(actionToken.getText()));
|
||||||
|
this.generator = generator;
|
||||||
|
grammar = generator.grammar;
|
||||||
|
this.enclosingRule = grammar.getRule(ruleName);
|
||||||
|
this.actionToken = actionToken;
|
||||||
|
this.outerAltNum = outerAltNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return a list of strings and StringTemplate objects that
|
||||||
|
* represent the translated action.
|
||||||
|
*/
|
||||||
|
public List translateToChunks() {
|
||||||
|
// System.out.println("###\naction="+action);
|
||||||
|
Token t;
|
||||||
|
do {
|
||||||
|
t = nextToken();
|
||||||
|
} while ( t.getType()!= Token.EOF );
|
||||||
|
return chunks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String translate() {
|
||||||
|
List theChunks = translateToChunks();
|
||||||
|
//System.out.println("chunks="+a.chunks);
|
||||||
|
StringBuffer buf = new StringBuffer();
|
||||||
|
for (int i = 0; i < theChunks.size(); i++) {
|
||||||
|
Object o = (Object) theChunks.get(i);
|
||||||
|
buf.append(o);
|
||||||
|
}
|
||||||
|
//System.out.println("translated: "+buf.toString());
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List translateAction(String action) {
|
||||||
|
String rname = null;
|
||||||
|
if ( enclosingRule!=null ) {
|
||||||
|
rname = enclosingRule.name;
|
||||||
|
}
|
||||||
|
ActionTranslator translator =
|
||||||
|
new ActionTranslator(generator,
|
||||||
|
rname,
|
||||||
|
new antlr.CommonToken(ANTLRParser.ACTION,action),outerAltNum);
|
||||||
|
return translator.translateToChunks();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isTokenRefInAlt(String id) {
|
||||||
|
return enclosingRule.getTokenRefsInAlt(id, outerAltNum)!=null;
|
||||||
|
}
|
||||||
|
public boolean isRuleRefInAlt(String id) {
|
||||||
|
return enclosingRule.getRuleRefsInAlt(id, outerAltNum)!=null;
|
||||||
|
}
|
||||||
|
public Grammar.LabelElementPair getElementLabel(String id) {
|
||||||
|
return enclosingRule.getLabel(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkElementRefUniqueness(String ref, boolean isToken) {
|
||||||
|
List refs = null;
|
||||||
|
if ( isToken ) {
|
||||||
|
refs = enclosingRule.getTokenRefsInAlt(ref, outerAltNum);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
refs = enclosingRule.getRuleRefsInAlt(ref, outerAltNum);
|
||||||
|
}
|
||||||
|
if ( refs!=null && refs.size()>1 ) {
|
||||||
|
ErrorManager.grammarError(ErrorManager.MSG_NONUNIQUE_REF,
|
||||||
|
grammar,
|
||||||
|
actionToken,
|
||||||
|
ref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** For \$rulelabel.name, return the Attribute found for name. It
|
||||||
|
* will be a predefined property or a return value.
|
||||||
|
*/
|
||||||
|
public Attribute getRuleLabelAttribute(String ruleName, String attrName) {
|
||||||
|
Rule r = grammar.getRule(ruleName);
|
||||||
|
AttributeScope scope = r.getLocalAttributeScope(attrName);
|
||||||
|
if ( scope!=null && !scope.isParameterScope ) {
|
||||||
|
return scope.getAttribute(attrName);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
AttributeScope resolveDynamicScope(String scopeName) {
|
||||||
|
if ( grammar.getGlobalScope(scopeName)!=null ) {
|
||||||
|
return grammar.getGlobalScope(scopeName);
|
||||||
|
}
|
||||||
|
Rule scopeRule = grammar.getRule(scopeName);
|
||||||
|
if ( scopeRule!=null ) {
|
||||||
|
return scopeRule.ruleScope;
|
||||||
|
}
|
||||||
|
return null; // not a valid dynamic scope
|
||||||
|
}
|
||||||
|
|
||||||
|
protected StringTemplate template(String name) {
|
||||||
|
StringTemplate st = generator.getTemplates().getInstanceOf(name);
|
||||||
|
chunks.add(st);
|
||||||
|
return st;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/** $x.y x is enclosing rule, y is a return value, parameter, or
|
||||||
|
* predefined property.
|
||||||
|
*
|
||||||
|
* r[int i] returns [int j]
|
||||||
|
* : {$r.i, $r.j, $r.start, $r.stop, $r.st, $r.tree}
|
||||||
|
* ;
|
||||||
|
*/
|
||||||
|
SET_ENCLOSING_RULE_SCOPE_ATTR
|
||||||
|
: '$' x=ID '.' y=ID WS? '=' expr=ATTR_VALUE_EXPR ';'
|
||||||
|
{enclosingRule!=null &&
|
||||||
|
$x.text.equals(enclosingRule.name) &&
|
||||||
|
enclosingRule.getLocalAttributeScope($y.text)!=null}?
|
||||||
|
//{System.out.println("found \$rule.attr");}
|
||||||
|
{
|
||||||
|
StringTemplate st = null;
|
||||||
|
AttributeScope scope = enclosingRule.getLocalAttributeScope($y.text);
|
||||||
|
if ( scope.isPredefinedRuleScope ) {
|
||||||
|
if ( $y.text.equals("st") || $y.text.equals("tree") ) {
|
||||||
|
st = template("ruleSetPropertyRef_"+$y.text);
|
||||||
|
grammar.referenceRuleLabelPredefinedAttribute($x.text);
|
||||||
|
st.setAttribute("scope", $x.text);
|
||||||
|
st.setAttribute("attr", $y.text);
|
||||||
|
st.setAttribute("expr", translateAction($expr.text));
|
||||||
|
} else {
|
||||||
|
ErrorManager.grammarError(ErrorManager.MSG_WRITE_TO_READONLY_ATTR,
|
||||||
|
grammar,
|
||||||
|
actionToken,
|
||||||
|
$x.text,
|
||||||
|
$y.text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( scope.isPredefinedLexerRuleScope ) {
|
||||||
|
// this is a better message to emit than the previous one...
|
||||||
|
ErrorManager.grammarError(ErrorManager.MSG_WRITE_TO_READONLY_ATTR,
|
||||||
|
grammar,
|
||||||
|
actionToken,
|
||||||
|
$x.text,
|
||||||
|
$y.text);
|
||||||
|
}
|
||||||
|
else if ( scope.isParameterScope ) {
|
||||||
|
st = template("parameterSetAttributeRef");
|
||||||
|
st.setAttribute("attr", scope.getAttribute($y.text));
|
||||||
|
st.setAttribute("expr", translateAction($expr.text));
|
||||||
|
}
|
||||||
|
else { // must be return value
|
||||||
|
st = template("returnSetAttributeRef");
|
||||||
|
st.setAttribute("ruleDescriptor", enclosingRule);
|
||||||
|
st.setAttribute("attr", scope.getAttribute($y.text));
|
||||||
|
st.setAttribute("expr", translateAction($expr.text));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
;
|
||||||
|
ENCLOSING_RULE_SCOPE_ATTR
|
||||||
|
: '$' x=ID '.' y=ID {enclosingRule!=null &&
|
||||||
|
$x.text.equals(enclosingRule.name) &&
|
||||||
|
enclosingRule.getLocalAttributeScope($y.text)!=null}?
|
||||||
|
//{System.out.println("found \$rule.attr");}
|
||||||
|
{
|
||||||
|
if ( isRuleRefInAlt($x.text) ) {
|
||||||
|
ErrorManager.grammarError(ErrorManager.MSG_RULE_REF_AMBIG_WITH_RULE_IN_ALT,
|
||||||
|
grammar,
|
||||||
|
actionToken,
|
||||||
|
$x.text);
|
||||||
|
}
|
||||||
|
StringTemplate st = null;
|
||||||
|
AttributeScope scope = enclosingRule.getLocalAttributeScope($y.text);
|
||||||
|
if ( scope.isPredefinedRuleScope ) {
|
||||||
|
st = template("rulePropertyRef_"+$y.text);
|
||||||
|
grammar.referenceRuleLabelPredefinedAttribute($x.text);
|
||||||
|
st.setAttribute("scope", $x.text);
|
||||||
|
st.setAttribute("attr", $y.text);
|
||||||
|
}
|
||||||
|
else if ( scope.isPredefinedLexerRuleScope ) {
|
||||||
|
// perhaps not the most precise error message to use, but...
|
||||||
|
ErrorManager.grammarError(ErrorManager.MSG_RULE_HAS_NO_ARGS,
|
||||||
|
grammar,
|
||||||
|
actionToken,
|
||||||
|
$x.text);
|
||||||
|
}
|
||||||
|
else if ( scope.isParameterScope ) {
|
||||||
|
st = template("parameterAttributeRef");
|
||||||
|
st.setAttribute("attr", scope.getAttribute($y.text));
|
||||||
|
}
|
||||||
|
else { // must be return value
|
||||||
|
st = template("returnAttributeRef");
|
||||||
|
st.setAttribute("ruleDescriptor", enclosingRule);
|
||||||
|
st.setAttribute("attr", scope.getAttribute($y.text));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
/** Setting $tokenlabel.attr or $tokenref.attr where attr is predefined property of a token is an error. */
|
||||||
|
SET_TOKEN_SCOPE_ATTR
|
||||||
|
: '$' x=ID '.' y=ID WS? '='
|
||||||
|
{enclosingRule!=null && input.LA(1)!='=' &&
|
||||||
|
(enclosingRule.getTokenLabel($x.text)!=null||
|
||||||
|
isTokenRefInAlt($x.text)) &&
|
||||||
|
AttributeScope.tokenScope.getAttribute($y.text)!=null}?
|
||||||
|
//{System.out.println("found \$tokenlabel.attr or \$tokenref.attr");}
|
||||||
|
{
|
||||||
|
ErrorManager.grammarError(ErrorManager.MSG_WRITE_TO_READONLY_ATTR,
|
||||||
|
grammar,
|
||||||
|
actionToken,
|
||||||
|
$x.text,
|
||||||
|
$y.text);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
/** $tokenlabel.attr or $tokenref.attr where attr is predefined property of a token.
|
||||||
|
* If in lexer grammar, only translate for strings and tokens (rule refs)
|
||||||
|
*/
|
||||||
|
TOKEN_SCOPE_ATTR
|
||||||
|
: '$' x=ID '.' y=ID {enclosingRule!=null &&
|
||||||
|
(enclosingRule.getTokenLabel($x.text)!=null||
|
||||||
|
isTokenRefInAlt($x.text)) &&
|
||||||
|
AttributeScope.tokenScope.getAttribute($y.text)!=null &&
|
||||||
|
(grammar.type!=Grammar.LEXER ||
|
||||||
|
getElementLabel($x.text).elementRef.token.getType()==ANTLRParser.TOKEN_REF ||
|
||||||
|
getElementLabel($x.text).elementRef.token.getType()==ANTLRParser.STRING_LITERAL)}?
|
||||||
|
// {System.out.println("found \$tokenlabel.attr or \$tokenref.attr");}
|
||||||
|
{
|
||||||
|
String label = $x.text;
|
||||||
|
if ( enclosingRule.getTokenLabel($x.text)==null ) {
|
||||||
|
// \$tokenref.attr gotta get old label or compute new one
|
||||||
|
checkElementRefUniqueness($x.text, true);
|
||||||
|
label = enclosingRule.getElementLabel($x.text, outerAltNum, generator);
|
||||||
|
if ( label==null ) {
|
||||||
|
ErrorManager.grammarError(ErrorManager.MSG_FORWARD_ELEMENT_REF,
|
||||||
|
grammar,
|
||||||
|
actionToken,
|
||||||
|
"\$"+$x.text+"."+$y.text);
|
||||||
|
label = $x.text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
StringTemplate st = template("tokenLabelPropertyRef_"+$y.text);
|
||||||
|
st.setAttribute("scope", label);
|
||||||
|
st.setAttribute("attr", AttributeScope.tokenScope.getAttribute($y.text));
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
/** Setting $rulelabel.attr or $ruleref.attr where attr is a predefined property is an error
|
||||||
|
* This must also fail, if we try to access a local attribute's field, like $tree.scope = localObject
|
||||||
|
* That must be handled by LOCAL_ATTR below. ANTLR only concerns itself with the top-level scope
|
||||||
|
* attributes declared in scope {} or parameters, return values and the like.
|
||||||
|
*/
|
||||||
|
SET_RULE_SCOPE_ATTR
|
||||||
|
@init {
|
||||||
|
Grammar.LabelElementPair pair=null;
|
||||||
|
String refdRuleName=null;
|
||||||
|
}
|
||||||
|
: '$' x=ID '.' y=ID WS? '=' {enclosingRule!=null && input.LA(1)!='='}?
|
||||||
|
{
|
||||||
|
pair = enclosingRule.getRuleLabel($x.text);
|
||||||
|
refdRuleName = $x.text;
|
||||||
|
if ( pair!=null ) {
|
||||||
|
refdRuleName = pair.referencedRuleName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// supercomplicated because I can't exec the above action.
|
||||||
|
// This asserts that if it's a label or a ref to a rule proceed but only if the attribute
|
||||||
|
// is valid for that rule's scope
|
||||||
|
{(enclosingRule.getRuleLabel($x.text)!=null || isRuleRefInAlt($x.text)) &&
|
||||||
|
getRuleLabelAttribute(enclosingRule.getRuleLabel($x.text)!=null?enclosingRule.getRuleLabel($x.text).referencedRuleName:$x.text,$y.text)!=null}?
|
||||||
|
//{System.out.println("found set \$rulelabel.attr or \$ruleref.attr: "+$x.text+"."+$y.text);}
|
||||||
|
{
|
||||||
|
ErrorManager.grammarError(ErrorManager.MSG_WRITE_TO_READONLY_ATTR,
|
||||||
|
grammar,
|
||||||
|
actionToken,
|
||||||
|
$x.text,
|
||||||
|
$y.text);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
/** $rulelabel.attr or $ruleref.attr where attr is a predefined property*/
|
||||||
|
RULE_SCOPE_ATTR
|
||||||
|
@init {
|
||||||
|
Grammar.LabelElementPair pair=null;
|
||||||
|
String refdRuleName=null;
|
||||||
|
}
|
||||||
|
: '$' x=ID '.' y=ID {enclosingRule!=null}?
|
||||||
|
{
|
||||||
|
pair = enclosingRule.getRuleLabel($x.text);
|
||||||
|
refdRuleName = $x.text;
|
||||||
|
if ( pair!=null ) {
|
||||||
|
refdRuleName = pair.referencedRuleName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// supercomplicated because I can't exec the above action.
|
||||||
|
// This asserts that if it's a label or a ref to a rule proceed but only if the attribute
|
||||||
|
// is valid for that rule's scope
|
||||||
|
{(enclosingRule.getRuleLabel($x.text)!=null || isRuleRefInAlt($x.text)) &&
|
||||||
|
getRuleLabelAttribute(enclosingRule.getRuleLabel($x.text)!=null?enclosingRule.getRuleLabel($x.text).referencedRuleName:$x.text,$y.text)!=null}?
|
||||||
|
//{System.out.println("found \$rulelabel.attr or \$ruleref.attr: "+$x.text+"."+$y.text);}
|
||||||
|
{
|
||||||
|
String label = $x.text;
|
||||||
|
if ( pair==null ) {
|
||||||
|
// \$ruleref.attr gotta get old label or compute new one
|
||||||
|
checkElementRefUniqueness($x.text, false);
|
||||||
|
label = enclosingRule.getElementLabel($x.text, outerAltNum, generator);
|
||||||
|
if ( label==null ) {
|
||||||
|
ErrorManager.grammarError(ErrorManager.MSG_FORWARD_ELEMENT_REF,
|
||||||
|
grammar,
|
||||||
|
actionToken,
|
||||||
|
"\$"+$x.text+"."+$y.text);
|
||||||
|
label = $x.text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
StringTemplate st;
|
||||||
|
Rule refdRule = grammar.getRule(refdRuleName);
|
||||||
|
AttributeScope scope = refdRule.getLocalAttributeScope($y.text);
|
||||||
|
if ( scope.isPredefinedRuleScope ) {
|
||||||
|
st = template("ruleLabelPropertyRef_"+$y.text);
|
||||||
|
grammar.referenceRuleLabelPredefinedAttribute(refdRuleName);
|
||||||
|
st.setAttribute("scope", label);
|
||||||
|
st.setAttribute("attr", $y.text);
|
||||||
|
}
|
||||||
|
else if ( scope.isPredefinedLexerRuleScope ) {
|
||||||
|
st = template("lexerRuleLabelPropertyRef_"+$y.text);
|
||||||
|
grammar.referenceRuleLabelPredefinedAttribute(refdRuleName);
|
||||||
|
st.setAttribute("scope", label);
|
||||||
|
st.setAttribute("attr", $y.text);
|
||||||
|
}
|
||||||
|
else if ( scope.isParameterScope ) {
|
||||||
|
// TODO: error!
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
st = template("ruleLabelRef");
|
||||||
|
st.setAttribute("referencedRule", refdRule);
|
||||||
|
st.setAttribute("scope", label);
|
||||||
|
st.setAttribute("attr", scope.getAttribute($y.text));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
/** $label either a token label or token/rule list label like label+=expr */
|
||||||
|
LABEL_REF
|
||||||
|
: '$' ID {enclosingRule!=null &&
|
||||||
|
getElementLabel($ID.text)!=null &&
|
||||||
|
enclosingRule.getRuleLabel($ID.text)==null}?
|
||||||
|
// {System.out.println("found \$label");}
|
||||||
|
{
|
||||||
|
StringTemplate st;
|
||||||
|
Grammar.LabelElementPair pair = getElementLabel($ID.text);
|
||||||
|
if ( pair.type==Grammar.TOKEN_LABEL ||
|
||||||
|
pair.type==Grammar.CHAR_LABEL )
|
||||||
|
{
|
||||||
|
st = template("tokenLabelRef");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
st = template("listLabelRef");
|
||||||
|
}
|
||||||
|
st.setAttribute("label", $ID.text);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
/** $tokenref in a non-lexer grammar */
|
||||||
|
ISOLATED_TOKEN_REF
|
||||||
|
: '$' ID {grammar.type!=Grammar.LEXER && enclosingRule!=null && isTokenRefInAlt($ID.text)}?
|
||||||
|
//{System.out.println("found \$tokenref");}
|
||||||
|
{
|
||||||
|
String label = enclosingRule.getElementLabel($ID.text, outerAltNum, generator);
|
||||||
|
checkElementRefUniqueness($ID.text, true);
|
||||||
|
if ( label==null ) {
|
||||||
|
ErrorManager.grammarError(ErrorManager.MSG_FORWARD_ELEMENT_REF,
|
||||||
|
grammar,
|
||||||
|
actionToken,
|
||||||
|
$ID.text);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
StringTemplate st = template("tokenLabelRef");
|
||||||
|
st.setAttribute("label", label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
/** $lexerruleref from within the lexer */
|
||||||
|
ISOLATED_LEXER_RULE_REF
|
||||||
|
: '$' ID {grammar.type==Grammar.LEXER &&
|
||||||
|
enclosingRule!=null &&
|
||||||
|
isRuleRefInAlt($ID.text)}?
|
||||||
|
//{System.out.println("found \$lexerruleref");}
|
||||||
|
{
|
||||||
|
String label = enclosingRule.getElementLabel($ID.text, outerAltNum, generator);
|
||||||
|
checkElementRefUniqueness($ID.text, false);
|
||||||
|
if ( label==null ) {
|
||||||
|
ErrorManager.grammarError(ErrorManager.MSG_FORWARD_ELEMENT_REF,
|
||||||
|
grammar,
|
||||||
|
actionToken,
|
||||||
|
$ID.text);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
StringTemplate st = template("lexerRuleLabel");
|
||||||
|
st.setAttribute("label", label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
/** $y return value, parameter, predefined rule property, or token/rule
|
||||||
|
* reference within enclosing rule's outermost alt.
|
||||||
|
* y must be a "local" reference; i.e., it must be referring to
|
||||||
|
* something defined within the enclosing rule.
|
||||||
|
*
|
||||||
|
* r[int i] returns [int j]
|
||||||
|
* : {$i, $j, $start, $stop, $st, $tree}
|
||||||
|
* ;
|
||||||
|
*
|
||||||
|
* TODO: this might get the dynamic scope's elements too.!!!!!!!!!
|
||||||
|
*/
|
||||||
|
SET_LOCAL_ATTR
|
||||||
|
: '$' ID WS? '=' expr=ATTR_VALUE_EXPR ';' {enclosingRule!=null
|
||||||
|
&& enclosingRule.getLocalAttributeScope($ID.text)!=null
|
||||||
|
&& !enclosingRule.getLocalAttributeScope($ID.text).isPredefinedLexerRuleScope}?
|
||||||
|
//{System.out.println("found set \$localattr");}
|
||||||
|
{
|
||||||
|
StringTemplate st;
|
||||||
|
AttributeScope scope = enclosingRule.getLocalAttributeScope($ID.text);
|
||||||
|
if ( scope.isPredefinedRuleScope ) {
|
||||||
|
if ($ID.text.equals("tree") || $ID.text.equals("st")) {
|
||||||
|
st = template("ruleSetPropertyRef_"+$ID.text);
|
||||||
|
grammar.referenceRuleLabelPredefinedAttribute(enclosingRule.name);
|
||||||
|
st.setAttribute("scope", enclosingRule.name);
|
||||||
|
st.setAttribute("attr", $ID.text);
|
||||||
|
st.setAttribute("expr", translateAction($expr.text));
|
||||||
|
} else {
|
||||||
|
ErrorManager.grammarError(ErrorManager.MSG_WRITE_TO_READONLY_ATTR,
|
||||||
|
grammar,
|
||||||
|
actionToken,
|
||||||
|
$ID.text,
|
||||||
|
"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( scope.isParameterScope ) {
|
||||||
|
st = template("parameterSetAttributeRef");
|
||||||
|
st.setAttribute("attr", scope.getAttribute($ID.text));
|
||||||
|
st.setAttribute("expr", translateAction($expr.text));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
st = template("returnSetAttributeRef");
|
||||||
|
st.setAttribute("ruleDescriptor", enclosingRule);
|
||||||
|
st.setAttribute("attr", scope.getAttribute($ID.text));
|
||||||
|
st.setAttribute("expr", translateAction($expr.text));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
;
|
||||||
|
LOCAL_ATTR
|
||||||
|
: '$' ID {enclosingRule!=null && enclosingRule.getLocalAttributeScope($ID.text)!=null}?
|
||||||
|
//{System.out.println("found \$localattr");}
|
||||||
|
{
|
||||||
|
StringTemplate st;
|
||||||
|
AttributeScope scope = enclosingRule.getLocalAttributeScope($ID.text);
|
||||||
|
if ( scope.isPredefinedRuleScope ) {
|
||||||
|
st = template("rulePropertyRef_"+$ID.text);
|
||||||
|
grammar.referenceRuleLabelPredefinedAttribute(enclosingRule.name);
|
||||||
|
st.setAttribute("scope", enclosingRule.name);
|
||||||
|
st.setAttribute("attr", $ID.text);
|
||||||
|
}
|
||||||
|
else if ( scope.isPredefinedLexerRuleScope ) {
|
||||||
|
st = template("lexerRulePropertyRef_"+$ID.text);
|
||||||
|
st.setAttribute("scope", enclosingRule.name);
|
||||||
|
st.setAttribute("attr", $ID.text);
|
||||||
|
}
|
||||||
|
else if ( scope.isParameterScope ) {
|
||||||
|
st = template("parameterAttributeRef");
|
||||||
|
st.setAttribute("attr", scope.getAttribute($ID.text));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
st = template("returnAttributeRef");
|
||||||
|
st.setAttribute("ruleDescriptor", enclosingRule);
|
||||||
|
st.setAttribute("attr", scope.getAttribute($ID.text));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
/** $x::y the only way to access the attributes within a dynamic scope
|
||||||
|
* regardless of whether or not you are in the defining rule.
|
||||||
|
*
|
||||||
|
* scope Symbols { List names; }
|
||||||
|
* r
|
||||||
|
* scope {int i;}
|
||||||
|
* scope Symbols;
|
||||||
|
* : {$r::i=3;} s {$Symbols::names;}
|
||||||
|
* ;
|
||||||
|
* s : {$r::i; $Symbols::names;}
|
||||||
|
* ;
|
||||||
|
*/
|
||||||
|
SET_DYNAMIC_SCOPE_ATTR
|
||||||
|
: '$' x=ID '::' y=ID WS? '=' expr=ATTR_VALUE_EXPR ';'
|
||||||
|
{resolveDynamicScope($x.text)!=null &&
|
||||||
|
resolveDynamicScope($x.text).getAttribute($y.text)!=null}?
|
||||||
|
//{System.out.println("found set \$scope::attr "+ $x.text + "::" + $y.text + " to " + $expr.text);}
|
||||||
|
{
|
||||||
|
AttributeScope scope = resolveDynamicScope($x.text);
|
||||||
|
if ( scope!=null ) {
|
||||||
|
StringTemplate st = template("scopeSetAttributeRef");
|
||||||
|
st.setAttribute("scope", $x.text);
|
||||||
|
st.setAttribute("attr", scope.getAttribute($y.text));
|
||||||
|
st.setAttribute("expr", translateAction($expr.text));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// error: invalid dynamic attribute
|
||||||
|
}
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
DYNAMIC_SCOPE_ATTR
|
||||||
|
: '$' x=ID '::' y=ID
|
||||||
|
{resolveDynamicScope($x.text)!=null &&
|
||||||
|
resolveDynamicScope($x.text).getAttribute($y.text)!=null}?
|
||||||
|
//{System.out.println("found \$scope::attr "+ $x.text + "::" + $y.text);}
|
||||||
|
{
|
||||||
|
AttributeScope scope = resolveDynamicScope($x.text);
|
||||||
|
if ( scope!=null ) {
|
||||||
|
StringTemplate st = template("scopeAttributeRef");
|
||||||
|
st.setAttribute("scope", $x.text);
|
||||||
|
st.setAttribute("attr", scope.getAttribute($y.text));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// error: invalid dynamic attribute
|
||||||
|
}
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
ERROR_SCOPED_XY
|
||||||
|
: '$' x=ID '::' y=ID
|
||||||
|
{
|
||||||
|
chunks.add(getText());
|
||||||
|
generator.issueInvalidScopeError($x.text,$y.text,
|
||||||
|
enclosingRule,actionToken,
|
||||||
|
outerAltNum);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
/** To access deeper (than top of stack) scopes, use the notation:
|
||||||
|
*
|
||||||
|
* $x[-1]::y previous (just under top of stack)
|
||||||
|
* $x[-i]::y top of stack - i where the '-' MUST BE PRESENT;
|
||||||
|
* i.e., i cannot simply be negative without the '-' sign!
|
||||||
|
* $x[i]::y absolute index i (0..size-1)
|
||||||
|
* $x[0]::y is the absolute 0 indexed element (bottom of the stack)
|
||||||
|
*/
|
||||||
|
DYNAMIC_NEGATIVE_INDEXED_SCOPE_ATTR
|
||||||
|
: '$' x=ID '[' '-' expr=SCOPE_INDEX_EXPR ']' '::' y=ID
|
||||||
|
// {System.out.println("found \$scope[-...]::attr");}
|
||||||
|
{
|
||||||
|
StringTemplate st = template("scopeAttributeRef");
|
||||||
|
st.setAttribute("scope", $x.text);
|
||||||
|
st.setAttribute("attr", resolveDynamicScope($x.text).getAttribute($y.text));
|
||||||
|
st.setAttribute("negIndex", $expr.text);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
DYNAMIC_ABSOLUTE_INDEXED_SCOPE_ATTR
|
||||||
|
: '$' x=ID '[' expr=SCOPE_INDEX_EXPR ']' '::' y=ID
|
||||||
|
// {System.out.println("found \$scope[...]::attr");}
|
||||||
|
{
|
||||||
|
StringTemplate st = template("scopeAttributeRef");
|
||||||
|
st.setAttribute("scope", $x.text);
|
||||||
|
st.setAttribute("attr", resolveDynamicScope($x.text).getAttribute($y.text));
|
||||||
|
st.setAttribute("index", $expr.text);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
fragment
|
||||||
|
SCOPE_INDEX_EXPR
|
||||||
|
: (~']')+
|
||||||
|
;
|
||||||
|
|
||||||
|
/** $r y is a rule's dynamic scope or a global shared scope.
|
||||||
|
* Isolated $rulename is not allowed unless it has a dynamic scope *and*
|
||||||
|
* there is no reference to rulename in the enclosing alternative,
|
||||||
|
* which would be ambiguous. See TestAttributes.testAmbiguousRuleRef()
|
||||||
|
*/
|
||||||
|
ISOLATED_DYNAMIC_SCOPE
|
||||||
|
: '$' ID {resolveDynamicScope($ID.text)!=null}?
|
||||||
|
// {System.out.println("found isolated \$scope where scope is a dynamic scope");}
|
||||||
|
{
|
||||||
|
StringTemplate st = template("isolatedDynamicScopeRef");
|
||||||
|
st.setAttribute("scope", $ID.text);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
// antlr.g then codegen.g does these first two currently.
|
||||||
|
// don't want to duplicate that code.
|
||||||
|
|
||||||
|
/** %foo(a={},b={},...) ctor */
|
||||||
|
TEMPLATE_INSTANCE
|
||||||
|
: '%' ID '(' ( WS? ARG (',' WS? ARG)* WS? )? ')'
|
||||||
|
// {System.out.println("found \%foo(args)");}
|
||||||
|
{
|
||||||
|
String action = getText().substring(1,getText().length());
|
||||||
|
String ruleName = "<outside-of-rule>";
|
||||||
|
if ( enclosingRule!=null ) {
|
||||||
|
ruleName = enclosingRule.name;
|
||||||
|
}
|
||||||
|
StringTemplate st =
|
||||||
|
generator.translateTemplateConstructor(ruleName,
|
||||||
|
outerAltNum,
|
||||||
|
actionToken,
|
||||||
|
action);
|
||||||
|
if ( st!=null ) {
|
||||||
|
chunks.add(st);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
/** %({name-expr})(a={},...) indirect template ctor reference */
|
||||||
|
INDIRECT_TEMPLATE_INSTANCE
|
||||||
|
: '%' '(' ACTION ')' '(' ( WS? ARG (',' WS? ARG)* WS? )? ')'
|
||||||
|
// {System.out.println("found \%({...})(args)");}
|
||||||
|
{
|
||||||
|
String action = getText().substring(1,getText().length());
|
||||||
|
StringTemplate st =
|
||||||
|
generator.translateTemplateConstructor(enclosingRule.name,
|
||||||
|
outerAltNum,
|
||||||
|
actionToken,
|
||||||
|
action);
|
||||||
|
chunks.add(st);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
fragment
|
||||||
|
ARG : ID '=' ACTION
|
||||||
|
;
|
||||||
|
|
||||||
|
/** %{expr}.y = z; template attribute y of StringTemplate-typed expr to z */
|
||||||
|
SET_EXPR_ATTRIBUTE
|
||||||
|
: '%' a=ACTION '.' ID WS? '=' expr=ATTR_VALUE_EXPR ';'
|
||||||
|
// {System.out.println("found \%{expr}.y = z;");}
|
||||||
|
{
|
||||||
|
StringTemplate st = template("actionSetAttribute");
|
||||||
|
String action = $a.text;
|
||||||
|
action = action.substring(1,action.length()-1); // stuff inside {...}
|
||||||
|
st.setAttribute("st", translateAction(action));
|
||||||
|
st.setAttribute("attrName", $ID.text);
|
||||||
|
st.setAttribute("expr", translateAction($expr.text));
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
/* %x.y = z; set template attribute y of x (always set never get attr)
|
||||||
|
* to z [languages like python without ';' must still use the
|
||||||
|
* ';' which the code generator is free to remove during code gen]
|
||||||
|
*/
|
||||||
|
SET_ATTRIBUTE
|
||||||
|
: '%' x=ID '.' y=ID WS? '=' expr=ATTR_VALUE_EXPR ';'
|
||||||
|
// {System.out.println("found \%x.y = z;");}
|
||||||
|
{
|
||||||
|
StringTemplate st = template("actionSetAttribute");
|
||||||
|
st.setAttribute("st", $x.text);
|
||||||
|
st.setAttribute("attrName", $y.text);
|
||||||
|
st.setAttribute("expr", translateAction($expr.text));
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
/** Don't allow an = as first char to prevent $x == 3; kind of stuff. */
|
||||||
|
fragment
|
||||||
|
ATTR_VALUE_EXPR
|
||||||
|
: ~'=' (~';')*
|
||||||
|
;
|
||||||
|
|
||||||
|
/** %{string-expr} anonymous template from string expr */
|
||||||
|
TEMPLATE_EXPR
|
||||||
|
: '%' a=ACTION
|
||||||
|
// {System.out.println("found \%{expr}");}
|
||||||
|
{
|
||||||
|
StringTemplate st = template("actionStringConstructor");
|
||||||
|
String action = $a.text;
|
||||||
|
action = action.substring(1,action.length()-1); // stuff inside {...}
|
||||||
|
st.setAttribute("stringExpr", translateAction(action));
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
fragment
|
||||||
|
ACTION
|
||||||
|
: '{' (options {greedy=false;}:.)* '}'
|
||||||
|
;
|
||||||
|
|
||||||
|
ESC : '\\' '$' {chunks.add("\$");}
|
||||||
|
| '\\' '%' {chunks.add("\%");}
|
||||||
|
| '\\' ~('$'|'%') {chunks.add(getText());}
|
||||||
|
;
|
||||||
|
|
||||||
|
ERROR_XY
|
||||||
|
: '$' x=ID '.' y=ID
|
||||||
|
{
|
||||||
|
chunks.add(getText());
|
||||||
|
generator.issueInvalidAttributeError($x.text,$y.text,
|
||||||
|
enclosingRule,actionToken,
|
||||||
|
outerAltNum);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
ERROR_X
|
||||||
|
: '$' x=ID
|
||||||
|
{
|
||||||
|
chunks.add(getText());
|
||||||
|
generator.issueInvalidAttributeError($x.text,
|
||||||
|
enclosingRule,actionToken,
|
||||||
|
outerAltNum);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
UNKNOWN_SYNTAX
|
||||||
|
: '$'
|
||||||
|
{
|
||||||
|
chunks.add(getText());
|
||||||
|
// shouldn't need an error here. Just accept \$ if it doesn't look like anything
|
||||||
|
}
|
||||||
|
| '%' (ID|'.'|'('|')'|','|'{'|'}'|'"')*
|
||||||
|
{
|
||||||
|
chunks.add(getText());
|
||||||
|
ErrorManager.grammarError(ErrorManager.MSG_INVALID_TEMPLATE_ACTION,
|
||||||
|
grammar,
|
||||||
|
actionToken,
|
||||||
|
getText());
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
TEXT: ~('$'|'%'|'\\')+ {chunks.add(getText());}
|
||||||
|
;
|
||||||
|
|
||||||
|
fragment
|
||||||
|
ID : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'_'|'0'..'9')*
|
||||||
|
;
|
||||||
|
|
||||||
|
fragment
|
||||||
|
INT : '0'..'9'+
|
||||||
|
;
|
||||||
|
|
||||||
|
fragment
|
||||||
|
WS : (' '|'\t'|'\n'|'\r')+
|
||||||
|
;
|
3538
antlr_3_1_source/codegen/ActionTranslator.java
Normal file
3538
antlr_3_1_source/codegen/ActionTranslator.java
Normal file
File diff suppressed because it is too large
Load Diff
34
antlr_3_1_source/codegen/ActionTranslator.tokens
Normal file
34
antlr_3_1_source/codegen/ActionTranslator.tokens
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
LOCAL_ATTR=17
|
||||||
|
SET_DYNAMIC_SCOPE_ATTR=18
|
||||||
|
ISOLATED_DYNAMIC_SCOPE=24
|
||||||
|
WS=5
|
||||||
|
UNKNOWN_SYNTAX=35
|
||||||
|
DYNAMIC_ABSOLUTE_INDEXED_SCOPE_ATTR=23
|
||||||
|
SCOPE_INDEX_EXPR=21
|
||||||
|
DYNAMIC_SCOPE_ATTR=19
|
||||||
|
ISOLATED_TOKEN_REF=14
|
||||||
|
SET_ATTRIBUTE=30
|
||||||
|
SET_EXPR_ATTRIBUTE=29
|
||||||
|
ACTION=27
|
||||||
|
ERROR_X=34
|
||||||
|
TEMPLATE_INSTANCE=26
|
||||||
|
TOKEN_SCOPE_ATTR=10
|
||||||
|
ISOLATED_LEXER_RULE_REF=15
|
||||||
|
ESC=32
|
||||||
|
SET_ENCLOSING_RULE_SCOPE_ATTR=7
|
||||||
|
ATTR_VALUE_EXPR=6
|
||||||
|
RULE_SCOPE_ATTR=12
|
||||||
|
LABEL_REF=13
|
||||||
|
INT=37
|
||||||
|
ARG=25
|
||||||
|
SET_LOCAL_ATTR=16
|
||||||
|
TEXT=36
|
||||||
|
DYNAMIC_NEGATIVE_INDEXED_SCOPE_ATTR=22
|
||||||
|
SET_TOKEN_SCOPE_ATTR=9
|
||||||
|
ERROR_SCOPED_XY=20
|
||||||
|
SET_RULE_SCOPE_ATTR=11
|
||||||
|
ENCLOSING_RULE_SCOPE_ATTR=8
|
||||||
|
ERROR_XY=33
|
||||||
|
TEMPLATE_EXPR=31
|
||||||
|
INDIRECT_TEMPLATE_INSTANCE=28
|
||||||
|
ID=4
|
140
antlr_3_1_source/codegen/CPPTarget.java
Normal file
140
antlr_3_1_source/codegen/CPPTarget.java
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.antlr.codegen;
|
||||||
|
|
||||||
|
import org.antlr.stringtemplate.StringTemplate;
|
||||||
|
import org.antlr.stringtemplate.StringTemplateGroup;
|
||||||
|
import org.antlr.tool.Grammar;
|
||||||
|
import org.antlr.Tool;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class CPPTarget extends Target {
|
||||||
|
|
||||||
|
public String escapeChar( int c ) {
|
||||||
|
// System.out.println("CPPTarget.escapeChar("+c+")");
|
||||||
|
switch (c) {
|
||||||
|
case '\n' : return "\\n";
|
||||||
|
case '\t' : return "\\t";
|
||||||
|
case '\r' : return "\\r";
|
||||||
|
case '\\' : return "\\\\";
|
||||||
|
case '\'' : return "\\'";
|
||||||
|
case '"' : return "\\\"";
|
||||||
|
default :
|
||||||
|
if ( c < ' ' || c > 126 )
|
||||||
|
{
|
||||||
|
if (c > 255)
|
||||||
|
{
|
||||||
|
String s = Integer.toString(c,16);
|
||||||
|
// put leading zeroes in front of the thing..
|
||||||
|
while( s.length() < 4 )
|
||||||
|
s = '0' + s;
|
||||||
|
return "\\u" + s;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return "\\" + Integer.toString(c,8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return String.valueOf((char)c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Converts a String into a representation that can be use as a literal
|
||||||
|
* when surrounded by double-quotes.
|
||||||
|
*
|
||||||
|
* Used for escaping semantic predicate strings for exceptions.
|
||||||
|
*
|
||||||
|
* @param s The String to be changed into a literal
|
||||||
|
*/
|
||||||
|
public String escapeString(String s)
|
||||||
|
{
|
||||||
|
StringBuffer retval = new StringBuffer();
|
||||||
|
for (int i = 0; i < s.length(); i++) {
|
||||||
|
retval.append(escapeChar(s.charAt(i)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void genRecognizerHeaderFile(Tool tool,
|
||||||
|
CodeGenerator generator,
|
||||||
|
Grammar grammar,
|
||||||
|
StringTemplate headerFileST,
|
||||||
|
String extName)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
StringTemplateGroup templates = generator.getTemplates();
|
||||||
|
generator.write(headerFileST, grammar.name+extName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Convert from an ANTLR char literal found in a grammar file to
|
||||||
|
* an equivalent char literal in the target language. For Java, this
|
||||||
|
* is the identify translation; i.e., '\n' -> '\n'. Most languages
|
||||||
|
* will be able to use this 1-to-1 mapping. Expect single quotes
|
||||||
|
* around the incoming literal.
|
||||||
|
* Depending on the charvocabulary the charliteral should be prefixed with a 'L'
|
||||||
|
*/
|
||||||
|
public String getTargetCharLiteralFromANTLRCharLiteral( CodeGenerator codegen, String literal) {
|
||||||
|
int c = Grammar.getCharValueFromGrammarCharLiteral(literal);
|
||||||
|
String prefix = "'";
|
||||||
|
if( codegen.grammar.getMaxCharValue() > 255 )
|
||||||
|
prefix = "L'";
|
||||||
|
else if( (c & 0x80) != 0 ) // if in char mode prevent sign extensions
|
||||||
|
return ""+c;
|
||||||
|
return prefix+escapeChar(c)+"'";
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Convert from an ANTLR string literal found in a grammar file to
|
||||||
|
* an equivalent string literal in the target language. For Java, this
|
||||||
|
* is the identify translation; i.e., "\"\n" -> "\"\n". Most languages
|
||||||
|
* will be able to use this 1-to-1 mapping. Expect double quotes
|
||||||
|
* around the incoming literal.
|
||||||
|
* Depending on the charvocabulary the string should be prefixed with a 'L'
|
||||||
|
*/
|
||||||
|
public String getTargetStringLiteralFromANTLRStringLiteral( CodeGenerator codegen, String literal) {
|
||||||
|
StringBuffer buf = Grammar.getUnescapedStringFromGrammarStringLiteral(literal);
|
||||||
|
String prefix = "\"";
|
||||||
|
if( codegen.grammar.getMaxCharValue() > 255 )
|
||||||
|
prefix = "L\"";
|
||||||
|
return prefix+escapeString(buf.toString())+"\"";
|
||||||
|
}
|
||||||
|
/** Character constants get truncated to this value.
|
||||||
|
* TODO: This should be derived from the charVocabulary. Depending on it
|
||||||
|
* being 255 or 0xFFFF the templates should generate normal character
|
||||||
|
* constants or multibyte ones.
|
||||||
|
*/
|
||||||
|
public int getMaxCharValue( CodeGenerator codegen ) {
|
||||||
|
int maxval = 255; // codegen.grammar.get????();
|
||||||
|
if ( maxval <= 255 )
|
||||||
|
return 255;
|
||||||
|
else
|
||||||
|
return maxval;
|
||||||
|
}
|
||||||
|
}
|
57
antlr_3_1_source/codegen/CSharp2Target.java
Normal file
57
antlr_3_1_source/codegen/CSharp2Target.java
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2006 Kunle Odutola
|
||||||
|
Copyright (c) 2005 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.antlr.codegen;
|
||||||
|
|
||||||
|
import org.antlr.Tool;
|
||||||
|
import org.antlr.stringtemplate.StringTemplate;
|
||||||
|
import org.antlr.tool.Grammar;
|
||||||
|
|
||||||
|
public class CSharp2Target extends Target
|
||||||
|
{
|
||||||
|
protected StringTemplate chooseWhereCyclicDFAsGo(Tool tool,
|
||||||
|
CodeGenerator generator,
|
||||||
|
Grammar grammar,
|
||||||
|
StringTemplate recognizerST,
|
||||||
|
StringTemplate cyclicDFAST)
|
||||||
|
{
|
||||||
|
return recognizerST;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String encodeIntAsCharEscape(int v)
|
||||||
|
{
|
||||||
|
if (v <= 127)
|
||||||
|
{
|
||||||
|
String hex1 = Integer.toHexString(v | 0x10000).substring(3, 5);
|
||||||
|
return "\\x" + hex1;
|
||||||
|
}
|
||||||
|
String hex = Integer.toHexString(v | 0x10000).substring(1, 5);
|
||||||
|
return "\\u" + hex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
57
antlr_3_1_source/codegen/CSharpTarget.java
Normal file
57
antlr_3_1_source/codegen/CSharpTarget.java
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2006 Kunle Odutola
|
||||||
|
Copyright (c) 2005 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.antlr.codegen;
|
||||||
|
|
||||||
|
import org.antlr.Tool;
|
||||||
|
import org.antlr.stringtemplate.StringTemplate;
|
||||||
|
import org.antlr.tool.Grammar;
|
||||||
|
|
||||||
|
public class CSharpTarget extends Target
|
||||||
|
{
|
||||||
|
protected StringTemplate chooseWhereCyclicDFAsGo(Tool tool,
|
||||||
|
CodeGenerator generator,
|
||||||
|
Grammar grammar,
|
||||||
|
StringTemplate recognizerST,
|
||||||
|
StringTemplate cyclicDFAST)
|
||||||
|
{
|
||||||
|
return recognizerST;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String encodeIntAsCharEscape(int v)
|
||||||
|
{
|
||||||
|
if (v <= 127)
|
||||||
|
{
|
||||||
|
String hex1 = Integer.toHexString(v | 0x10000).substring(3, 5);
|
||||||
|
return "\\x" + hex1;
|
||||||
|
}
|
||||||
|
String hex = Integer.toHexString(v | 0x10000).substring(1, 5);
|
||||||
|
return "\\u" + hex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
247
antlr_3_1_source/codegen/CTarget.java
Normal file
247
antlr_3_1_source/codegen/CTarget.java
Normal file
@ -0,0 +1,247 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.antlr.codegen;
|
||||||
|
|
||||||
|
import org.antlr.Tool;
|
||||||
|
import org.antlr.stringtemplate.StringTemplate;
|
||||||
|
import org.antlr.tool.Grammar;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class CTarget extends Target {
|
||||||
|
|
||||||
|
ArrayList strings = new ArrayList();
|
||||||
|
|
||||||
|
protected void genRecognizerFile(Tool tool,
|
||||||
|
CodeGenerator generator,
|
||||||
|
Grammar grammar,
|
||||||
|
StringTemplate outputFileST)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
|
||||||
|
// Before we write this, and cause it to generate its string,
|
||||||
|
// we need to add all the string literals that we are going to match
|
||||||
|
//
|
||||||
|
outputFileST.setAttribute("literals", strings);
|
||||||
|
String fileName = generator.getRecognizerFileName(grammar.name, grammar.type);
|
||||||
|
System.out.println("Generating " + fileName);
|
||||||
|
generator.write(outputFileST, fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void genRecognizerHeaderFile(Tool tool,
|
||||||
|
CodeGenerator generator,
|
||||||
|
Grammar grammar,
|
||||||
|
StringTemplate headerFileST,
|
||||||
|
String extName)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
// Pick up the file name we are generating. This method will return a
|
||||||
|
// a file suffixed with .c, so we must substring and add the extName
|
||||||
|
// to it as we cannot assign into strings in Java.
|
||||||
|
///
|
||||||
|
String fileName = generator.getRecognizerFileName(grammar.name, grammar.type);
|
||||||
|
fileName = fileName.substring(0, fileName.length()-2) + extName;
|
||||||
|
|
||||||
|
System.out.println("Generating " + fileName);
|
||||||
|
generator.write(headerFileST, fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected StringTemplate chooseWhereCyclicDFAsGo(Tool tool,
|
||||||
|
CodeGenerator generator,
|
||||||
|
Grammar grammar,
|
||||||
|
StringTemplate recognizerST,
|
||||||
|
StringTemplate cyclicDFAST)
|
||||||
|
{
|
||||||
|
return recognizerST;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Is scope in @scope::name {action} valid for this kind of grammar?
|
||||||
|
* Targets like C++ may want to allow new scopes like headerfile or
|
||||||
|
* some such. The action names themselves are not policed at the
|
||||||
|
* moment so targets can add template actions w/o having to recompile
|
||||||
|
* ANTLR.
|
||||||
|
*/
|
||||||
|
public boolean isValidActionScope(int grammarType, String scope) {
|
||||||
|
switch (grammarType) {
|
||||||
|
case Grammar.LEXER :
|
||||||
|
if ( scope.equals("lexer") ) {return true;}
|
||||||
|
if ( scope.equals("header") ) {return true;}
|
||||||
|
if ( scope.equals("includes") ) {return true;}
|
||||||
|
if ( scope.equals("preincludes") ) {return true;}
|
||||||
|
if ( scope.equals("overrides") ) {return true;}
|
||||||
|
break;
|
||||||
|
case Grammar.PARSER :
|
||||||
|
if ( scope.equals("parser") ) {return true;}
|
||||||
|
if ( scope.equals("header") ) {return true;}
|
||||||
|
if ( scope.equals("includes") ) {return true;}
|
||||||
|
if ( scope.equals("preincludes") ) {return true;}
|
||||||
|
if ( scope.equals("overrides") ) {return true;}
|
||||||
|
break;
|
||||||
|
case Grammar.COMBINED :
|
||||||
|
if ( scope.equals("parser") ) {return true;}
|
||||||
|
if ( scope.equals("lexer") ) {return true;}
|
||||||
|
if ( scope.equals("header") ) {return true;}
|
||||||
|
if ( scope.equals("includes") ) {return true;}
|
||||||
|
if ( scope.equals("preincludes") ) {return true;}
|
||||||
|
if ( scope.equals("overrides") ) {return true;}
|
||||||
|
break;
|
||||||
|
case Grammar.TREE_PARSER :
|
||||||
|
if ( scope.equals("treeparser") ) {return true;}
|
||||||
|
if ( scope.equals("header") ) {return true;}
|
||||||
|
if ( scope.equals("includes") ) {return true;}
|
||||||
|
if ( scope.equals("preincludes") ) {return true;}
|
||||||
|
if ( scope.equals("overrides") ) {return true;}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTargetCharLiteralFromANTLRCharLiteral(
|
||||||
|
CodeGenerator generator,
|
||||||
|
String literal)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (literal.startsWith("'\\u") )
|
||||||
|
{
|
||||||
|
literal = "0x" +literal.substring(3, 7);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int c = literal.charAt(1);
|
||||||
|
|
||||||
|
if (c < 32 || c > 127) {
|
||||||
|
literal = "0x" + Integer.toHexString(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return literal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Convert from an ANTLR string literal found in a grammar file to
|
||||||
|
* an equivalent string literal in the C target.
|
||||||
|
* Because we msut support Unicode character sets and have chosen
|
||||||
|
* to have the lexer match UTF32 characters, then we must encode
|
||||||
|
* string matches to use 32 bit character arrays. Here then we
|
||||||
|
* must produce the C array and cater for the case where the
|
||||||
|
* lexer has been eoncded with a string such as "xyz\n", which looks
|
||||||
|
* slightly incogrous to me but is not incorrect.
|
||||||
|
*/
|
||||||
|
public String getTargetStringLiteralFromANTLRStringLiteral(
|
||||||
|
CodeGenerator generator,
|
||||||
|
String literal)
|
||||||
|
{
|
||||||
|
int index;
|
||||||
|
int outc;
|
||||||
|
String bytes;
|
||||||
|
StringBuffer buf = new StringBuffer();
|
||||||
|
|
||||||
|
buf.append("{ ");
|
||||||
|
|
||||||
|
// We need ot lose any escaped characters of the form \x and just
|
||||||
|
// replace them with their actual values as well as lose the surrounding
|
||||||
|
// quote marks.
|
||||||
|
//
|
||||||
|
for (int i = 1; i< literal.length()-1; i++)
|
||||||
|
{
|
||||||
|
buf.append("0x");
|
||||||
|
|
||||||
|
if (literal.charAt(i) == '\\')
|
||||||
|
{
|
||||||
|
i++; // Assume that there is a next character, this will just yield
|
||||||
|
// invalid strings if not, which is what the input would be of course - invalid
|
||||||
|
switch (literal.charAt(i))
|
||||||
|
{
|
||||||
|
case 'u':
|
||||||
|
case 'U':
|
||||||
|
buf.append(literal.substring(i+1, i+5)); // Already a hex string
|
||||||
|
i = i + 5; // Move to next string/char/escape
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'n':
|
||||||
|
case 'N':
|
||||||
|
|
||||||
|
buf.append("0A");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'r':
|
||||||
|
case 'R':
|
||||||
|
|
||||||
|
buf.append("0D");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 't':
|
||||||
|
case 'T':
|
||||||
|
|
||||||
|
buf.append("09");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'b':
|
||||||
|
case 'B':
|
||||||
|
|
||||||
|
buf.append("08");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'f':
|
||||||
|
case 'F':
|
||||||
|
|
||||||
|
buf.append("0C");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
|
||||||
|
// Anything else is what it is!
|
||||||
|
//
|
||||||
|
buf.append(Integer.toHexString((int)literal.charAt(i)).toUpperCase());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buf.append(Integer.toHexString((int)literal.charAt(i)).toUpperCase());
|
||||||
|
}
|
||||||
|
buf.append(", ");
|
||||||
|
}
|
||||||
|
buf.append(" ANTLR3_STRING_TERMINATOR}");
|
||||||
|
|
||||||
|
bytes = buf.toString();
|
||||||
|
index = strings.indexOf(bytes);
|
||||||
|
|
||||||
|
if (index == -1)
|
||||||
|
{
|
||||||
|
strings.add(bytes);
|
||||||
|
index = strings.indexOf(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
String strref = "lit_" + String.valueOf(index+1);
|
||||||
|
|
||||||
|
return strref;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
3316
antlr_3_1_source/codegen/CodeGenTreeWalker.java
Normal file
3316
antlr_3_1_source/codegen/CodeGenTreeWalker.java
Normal file
File diff suppressed because it is too large
Load Diff
2576
antlr_3_1_source/codegen/CodeGenTreeWalker.smap
Normal file
2576
antlr_3_1_source/codegen/CodeGenTreeWalker.smap
Normal file
File diff suppressed because it is too large
Load Diff
140
antlr_3_1_source/codegen/CodeGenTreeWalkerTokenTypes.java
Normal file
140
antlr_3_1_source/codegen/CodeGenTreeWalkerTokenTypes.java
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
// $ANTLR 2.7.7 (2006-01-29): "codegen.g" -> "CodeGenTreeWalker.java"$
|
||||||
|
|
||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2008 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.antlr.codegen;
|
||||||
|
import org.antlr.tool.*;
|
||||||
|
import org.antlr.analysis.*;
|
||||||
|
import org.antlr.misc.*;
|
||||||
|
import java.util.*;
|
||||||
|
import org.antlr.stringtemplate.*;
|
||||||
|
import antlr.TokenWithIndex;
|
||||||
|
import antlr.CommonToken;
|
||||||
|
|
||||||
|
public interface CodeGenTreeWalkerTokenTypes {
|
||||||
|
int EOF = 1;
|
||||||
|
int NULL_TREE_LOOKAHEAD = 3;
|
||||||
|
int OPTIONS = 4;
|
||||||
|
int TOKENS = 5;
|
||||||
|
int PARSER = 6;
|
||||||
|
int LEXER = 7;
|
||||||
|
int RULE = 8;
|
||||||
|
int BLOCK = 9;
|
||||||
|
int OPTIONAL = 10;
|
||||||
|
int CLOSURE = 11;
|
||||||
|
int POSITIVE_CLOSURE = 12;
|
||||||
|
int SYNPRED = 13;
|
||||||
|
int RANGE = 14;
|
||||||
|
int CHAR_RANGE = 15;
|
||||||
|
int EPSILON = 16;
|
||||||
|
int ALT = 17;
|
||||||
|
int EOR = 18;
|
||||||
|
int EOB = 19;
|
||||||
|
int EOA = 20;
|
||||||
|
int ID = 21;
|
||||||
|
int ARG = 22;
|
||||||
|
int ARGLIST = 23;
|
||||||
|
int RET = 24;
|
||||||
|
int LEXER_GRAMMAR = 25;
|
||||||
|
int PARSER_GRAMMAR = 26;
|
||||||
|
int TREE_GRAMMAR = 27;
|
||||||
|
int COMBINED_GRAMMAR = 28;
|
||||||
|
int INITACTION = 29;
|
||||||
|
int FORCED_ACTION = 30;
|
||||||
|
int LABEL = 31;
|
||||||
|
int TEMPLATE = 32;
|
||||||
|
int SCOPE = 33;
|
||||||
|
int IMPORT = 34;
|
||||||
|
int GATED_SEMPRED = 35;
|
||||||
|
int SYN_SEMPRED = 36;
|
||||||
|
int BACKTRACK_SEMPRED = 37;
|
||||||
|
int FRAGMENT = 38;
|
||||||
|
int DOT = 39;
|
||||||
|
int ACTION = 40;
|
||||||
|
int DOC_COMMENT = 41;
|
||||||
|
int SEMI = 42;
|
||||||
|
int LITERAL_lexer = 43;
|
||||||
|
int LITERAL_tree = 44;
|
||||||
|
int LITERAL_grammar = 45;
|
||||||
|
int AMPERSAND = 46;
|
||||||
|
int COLON = 47;
|
||||||
|
int RCURLY = 48;
|
||||||
|
int ASSIGN = 49;
|
||||||
|
int STRING_LITERAL = 50;
|
||||||
|
int CHAR_LITERAL = 51;
|
||||||
|
int INT = 52;
|
||||||
|
int STAR = 53;
|
||||||
|
int COMMA = 54;
|
||||||
|
int TOKEN_REF = 55;
|
||||||
|
int LITERAL_protected = 56;
|
||||||
|
int LITERAL_public = 57;
|
||||||
|
int LITERAL_private = 58;
|
||||||
|
int BANG = 59;
|
||||||
|
int ARG_ACTION = 60;
|
||||||
|
int LITERAL_returns = 61;
|
||||||
|
int LITERAL_throws = 62;
|
||||||
|
int LPAREN = 63;
|
||||||
|
int OR = 64;
|
||||||
|
int RPAREN = 65;
|
||||||
|
int LITERAL_catch = 66;
|
||||||
|
int LITERAL_finally = 67;
|
||||||
|
int PLUS_ASSIGN = 68;
|
||||||
|
int SEMPRED = 69;
|
||||||
|
int IMPLIES = 70;
|
||||||
|
int ROOT = 71;
|
||||||
|
int WILDCARD = 72;
|
||||||
|
int RULE_REF = 73;
|
||||||
|
int NOT = 74;
|
||||||
|
int TREE_BEGIN = 75;
|
||||||
|
int QUESTION = 76;
|
||||||
|
int PLUS = 77;
|
||||||
|
int OPEN_ELEMENT_OPTION = 78;
|
||||||
|
int CLOSE_ELEMENT_OPTION = 79;
|
||||||
|
int REWRITE = 80;
|
||||||
|
int ETC = 81;
|
||||||
|
int DOLLAR = 82;
|
||||||
|
int DOUBLE_QUOTE_STRING_LITERAL = 83;
|
||||||
|
int DOUBLE_ANGLE_STRING_LITERAL = 84;
|
||||||
|
int WS = 85;
|
||||||
|
int COMMENT = 86;
|
||||||
|
int SL_COMMENT = 87;
|
||||||
|
int ML_COMMENT = 88;
|
||||||
|
int STRAY_BRACKET = 89;
|
||||||
|
int ESC = 90;
|
||||||
|
int DIGIT = 91;
|
||||||
|
int XDIGIT = 92;
|
||||||
|
int NESTED_ARG_ACTION = 93;
|
||||||
|
int NESTED_ACTION = 94;
|
||||||
|
int ACTION_CHAR_LITERAL = 95;
|
||||||
|
int ACTION_STRING_LITERAL = 96;
|
||||||
|
int ACTION_ESC = 97;
|
||||||
|
int WS_LOOP = 98;
|
||||||
|
int INTERNAL_RULE_REF = 99;
|
||||||
|
int WS_OPT = 100;
|
||||||
|
int SRC = 101;
|
||||||
|
}
|
100
antlr_3_1_source/codegen/CodeGenTreeWalkerTokenTypes.txt
Normal file
100
antlr_3_1_source/codegen/CodeGenTreeWalkerTokenTypes.txt
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
// $ANTLR 2.7.7 (2006-01-29): codegen.g -> CodeGenTreeWalkerTokenTypes.txt$
|
||||||
|
CodeGenTreeWalker // output token vocab name
|
||||||
|
OPTIONS="options"=4
|
||||||
|
TOKENS="tokens"=5
|
||||||
|
PARSER="parser"=6
|
||||||
|
LEXER=7
|
||||||
|
RULE=8
|
||||||
|
BLOCK=9
|
||||||
|
OPTIONAL=10
|
||||||
|
CLOSURE=11
|
||||||
|
POSITIVE_CLOSURE=12
|
||||||
|
SYNPRED=13
|
||||||
|
RANGE=14
|
||||||
|
CHAR_RANGE=15
|
||||||
|
EPSILON=16
|
||||||
|
ALT=17
|
||||||
|
EOR=18
|
||||||
|
EOB=19
|
||||||
|
EOA=20
|
||||||
|
ID=21
|
||||||
|
ARG=22
|
||||||
|
ARGLIST=23
|
||||||
|
RET=24
|
||||||
|
LEXER_GRAMMAR=25
|
||||||
|
PARSER_GRAMMAR=26
|
||||||
|
TREE_GRAMMAR=27
|
||||||
|
COMBINED_GRAMMAR=28
|
||||||
|
INITACTION=29
|
||||||
|
FORCED_ACTION=30
|
||||||
|
LABEL=31
|
||||||
|
TEMPLATE=32
|
||||||
|
SCOPE="scope"=33
|
||||||
|
IMPORT="import"=34
|
||||||
|
GATED_SEMPRED=35
|
||||||
|
SYN_SEMPRED=36
|
||||||
|
BACKTRACK_SEMPRED=37
|
||||||
|
FRAGMENT="fragment"=38
|
||||||
|
DOT=39
|
||||||
|
ACTION=40
|
||||||
|
DOC_COMMENT=41
|
||||||
|
SEMI=42
|
||||||
|
LITERAL_lexer="lexer"=43
|
||||||
|
LITERAL_tree="tree"=44
|
||||||
|
LITERAL_grammar="grammar"=45
|
||||||
|
AMPERSAND=46
|
||||||
|
COLON=47
|
||||||
|
RCURLY=48
|
||||||
|
ASSIGN=49
|
||||||
|
STRING_LITERAL=50
|
||||||
|
CHAR_LITERAL=51
|
||||||
|
INT=52
|
||||||
|
STAR=53
|
||||||
|
COMMA=54
|
||||||
|
TOKEN_REF=55
|
||||||
|
LITERAL_protected="protected"=56
|
||||||
|
LITERAL_public="public"=57
|
||||||
|
LITERAL_private="private"=58
|
||||||
|
BANG=59
|
||||||
|
ARG_ACTION=60
|
||||||
|
LITERAL_returns="returns"=61
|
||||||
|
LITERAL_throws="throws"=62
|
||||||
|
LPAREN=63
|
||||||
|
OR=64
|
||||||
|
RPAREN=65
|
||||||
|
LITERAL_catch="catch"=66
|
||||||
|
LITERAL_finally="finally"=67
|
||||||
|
PLUS_ASSIGN=68
|
||||||
|
SEMPRED=69
|
||||||
|
IMPLIES=70
|
||||||
|
ROOT=71
|
||||||
|
WILDCARD=72
|
||||||
|
RULE_REF=73
|
||||||
|
NOT=74
|
||||||
|
TREE_BEGIN=75
|
||||||
|
QUESTION=76
|
||||||
|
PLUS=77
|
||||||
|
OPEN_ELEMENT_OPTION=78
|
||||||
|
CLOSE_ELEMENT_OPTION=79
|
||||||
|
REWRITE=80
|
||||||
|
ETC=81
|
||||||
|
DOLLAR=82
|
||||||
|
DOUBLE_QUOTE_STRING_LITERAL=83
|
||||||
|
DOUBLE_ANGLE_STRING_LITERAL=84
|
||||||
|
WS=85
|
||||||
|
COMMENT=86
|
||||||
|
SL_COMMENT=87
|
||||||
|
ML_COMMENT=88
|
||||||
|
STRAY_BRACKET=89
|
||||||
|
ESC=90
|
||||||
|
DIGIT=91
|
||||||
|
XDIGIT=92
|
||||||
|
NESTED_ARG_ACTION=93
|
||||||
|
NESTED_ACTION=94
|
||||||
|
ACTION_CHAR_LITERAL=95
|
||||||
|
ACTION_STRING_LITERAL=96
|
||||||
|
ACTION_ESC=97
|
||||||
|
WS_LOOP=98
|
||||||
|
INTERNAL_RULE_REF=99
|
||||||
|
WS_OPT=100
|
||||||
|
SRC=101
|
1330
antlr_3_1_source/codegen/CodeGenerator.java
Normal file
1330
antlr_3_1_source/codegen/CodeGenerator.java
Normal file
File diff suppressed because it is too large
Load Diff
47
antlr_3_1_source/codegen/JavaScriptTarget.java
Executable file
47
antlr_3_1_source/codegen/JavaScriptTarget.java
Executable file
@ -0,0 +1,47 @@
|
|||||||
|
package org.antlr.codegen;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class JavaScriptTarget extends Target {
|
||||||
|
/** Convert an int to a JavaScript Unicode character literal.
|
||||||
|
*
|
||||||
|
* The current JavaScript spec (ECMA-262) doesn't provide for octal
|
||||||
|
* notation in String literals, although some implementations support it.
|
||||||
|
* This method overrides the parent class so that characters will always
|
||||||
|
* be encoded as Unicode literals (e.g. \u0011).
|
||||||
|
*/
|
||||||
|
public String encodeIntAsCharEscape(int v) {
|
||||||
|
String hex = Integer.toHexString(v|0x10000).substring(1,5);
|
||||||
|
return "\\u"+hex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Convert long to two 32-bit numbers separted by a comma.
|
||||||
|
* JavaScript does not support 64-bit numbers, so we need to break
|
||||||
|
* the number into two 32-bit literals to give to the Bit. A number like
|
||||||
|
* 0xHHHHHHHHLLLLLLLL is broken into the following string:
|
||||||
|
* "0xLLLLLLLL, 0xHHHHHHHH"
|
||||||
|
* Note that the low order bits are first, followed by the high order bits.
|
||||||
|
* This is to match how the BitSet constructor works, where the bits are
|
||||||
|
* passed in in 32-bit chunks with low-order bits coming first.
|
||||||
|
*
|
||||||
|
* Note: stole the following two methods from the ActionScript target.
|
||||||
|
*/
|
||||||
|
public String getTarget64BitStringFromValue(long word) {
|
||||||
|
StringBuffer buf = new StringBuffer(22); // enough for the two "0x", "," and " "
|
||||||
|
buf.append("0x");
|
||||||
|
writeHexWithPadding(buf, Integer.toHexString((int)(word & 0x00000000ffffffffL)));
|
||||||
|
buf.append(", 0x");
|
||||||
|
writeHexWithPadding(buf, Integer.toHexString((int)(word >> 32)));
|
||||||
|
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeHexWithPadding(StringBuffer buf, String digits) {
|
||||||
|
digits = digits.toUpperCase();
|
||||||
|
int padding = 8 - digits.length();
|
||||||
|
// pad left with zeros
|
||||||
|
for (int i=1; i<=padding; i++) {
|
||||||
|
buf.append('0');
|
||||||
|
}
|
||||||
|
buf.append(digits);
|
||||||
|
}
|
||||||
|
}
|
44
antlr_3_1_source/codegen/JavaTarget.java
Normal file
44
antlr_3_1_source/codegen/JavaTarget.java
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.antlr.codegen;
|
||||||
|
|
||||||
|
import org.antlr.Tool;
|
||||||
|
import org.antlr.stringtemplate.StringTemplate;
|
||||||
|
import org.antlr.tool.Grammar;
|
||||||
|
|
||||||
|
public class JavaTarget extends Target {
|
||||||
|
protected StringTemplate chooseWhereCyclicDFAsGo(Tool tool,
|
||||||
|
CodeGenerator generator,
|
||||||
|
Grammar grammar,
|
||||||
|
StringTemplate recognizerST,
|
||||||
|
StringTemplate cyclicDFAST)
|
||||||
|
{
|
||||||
|
return recognizerST;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
109
antlr_3_1_source/codegen/ObjCTarget.java
Normal file
109
antlr_3_1_source/codegen/ObjCTarget.java
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005 Terence Parr
|
||||||
|
Copyright (c) 2006 Kay Roepke (Objective-C runtime)
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.antlr.codegen;
|
||||||
|
|
||||||
|
import org.antlr.stringtemplate.StringTemplate;
|
||||||
|
import org.antlr.tool.Grammar;
|
||||||
|
import org.antlr.Tool;
|
||||||
|
import org.antlr.misc.Utils;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class ObjCTarget extends Target {
|
||||||
|
protected void genRecognizerHeaderFile(Tool tool,
|
||||||
|
CodeGenerator generator,
|
||||||
|
Grammar grammar,
|
||||||
|
StringTemplate headerFileST,
|
||||||
|
String extName)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
generator.write(headerFileST, grammar.name + Grammar.grammarTypeToFileNameSuffix[grammar.type] + extName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTargetCharLiteralFromANTLRCharLiteral(CodeGenerator generator,
|
||||||
|
String literal)
|
||||||
|
{
|
||||||
|
if (literal.startsWith("'\\u") ) {
|
||||||
|
literal = "0x" +literal.substring(3, 7);
|
||||||
|
} else {
|
||||||
|
int c = literal.charAt(1); // TJP
|
||||||
|
if (c < 32 || c > 127) {
|
||||||
|
literal = "0x" + Integer.toHexString(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return literal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Convert from an ANTLR string literal found in a grammar file to
|
||||||
|
* an equivalent string literal in the target language. For Java, this
|
||||||
|
* is the translation 'a\n"' -> "a\n\"". Expect single quotes
|
||||||
|
* around the incoming literal. Just flip the quotes and replace
|
||||||
|
* double quotes with \"
|
||||||
|
*/
|
||||||
|
public String getTargetStringLiteralFromANTLRStringLiteral(CodeGenerator generator,
|
||||||
|
String literal)
|
||||||
|
{
|
||||||
|
literal = Utils.replace(literal,"\"","\\\"");
|
||||||
|
StringBuffer buf = new StringBuffer(literal);
|
||||||
|
buf.setCharAt(0,'"');
|
||||||
|
buf.setCharAt(literal.length()-1,'"');
|
||||||
|
buf.insert(0,'@');
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** If we have a label, prefix it with the recognizer's name */
|
||||||
|
public String getTokenTypeAsTargetLabel(CodeGenerator generator, int ttype) {
|
||||||
|
String name = generator.grammar.getTokenDisplayName(ttype);
|
||||||
|
// If name is a literal, return the token type instead
|
||||||
|
if ( name.charAt(0)=='\'' ) {
|
||||||
|
return String.valueOf(ttype);
|
||||||
|
}
|
||||||
|
return generator.grammar.name + Grammar.grammarTypeToFileNameSuffix[generator.grammar.type] + "_" + name;
|
||||||
|
//return super.getTokenTypeAsTargetLabel(generator, ttype);
|
||||||
|
//return this.getTokenTextAndTypeAsTargetLabel(generator, null, ttype);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Target must be able to override the labels used for token types. Sometimes also depends on the token text.*/
|
||||||
|
public String getTokenTextAndTypeAsTargetLabel(CodeGenerator generator, String text, int tokenType) {
|
||||||
|
String name = generator.grammar.getTokenDisplayName(tokenType);
|
||||||
|
// If name is a literal, return the token type instead
|
||||||
|
if ( name.charAt(0)=='\'' ) {
|
||||||
|
return String.valueOf(tokenType);
|
||||||
|
}
|
||||||
|
String textEquivalent = text == null ? name : text;
|
||||||
|
if (textEquivalent.charAt(0) >= '0' && textEquivalent.charAt(0) <= '9') {
|
||||||
|
return textEquivalent;
|
||||||
|
} else {
|
||||||
|
return generator.grammar.name + Grammar.grammarTypeToFileNameSuffix[generator.grammar.type] + "_" + textEquivalent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
78
antlr_3_1_source/codegen/Perl5Target.java
Normal file
78
antlr_3_1_source/codegen/Perl5Target.java
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2007 Ronald Blaschke
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.antlr.codegen;
|
||||||
|
|
||||||
|
import org.antlr.analysis.Label;
|
||||||
|
import org.antlr.tool.AttributeScope;
|
||||||
|
import org.antlr.tool.Grammar;
|
||||||
|
import org.antlr.tool.RuleLabelScope;
|
||||||
|
|
||||||
|
public class Perl5Target extends Target {
|
||||||
|
public Perl5Target() {
|
||||||
|
AttributeScope.tokenScope.addAttribute("self", null);
|
||||||
|
RuleLabelScope.predefinedLexerRulePropertiesScope.addAttribute("self", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTargetCharLiteralFromANTLRCharLiteral(final CodeGenerator generator,
|
||||||
|
final String literal) {
|
||||||
|
final StringBuffer buf = new StringBuffer(10);
|
||||||
|
|
||||||
|
final int c = Grammar.getCharValueFromGrammarCharLiteral(literal);
|
||||||
|
if (c < Label.MIN_CHAR_VALUE) {
|
||||||
|
buf.append("\\x{0000}");
|
||||||
|
} else if (c < targetCharValueEscape.length &&
|
||||||
|
targetCharValueEscape[c] != null) {
|
||||||
|
buf.append(targetCharValueEscape[c]);
|
||||||
|
} else if (Character.UnicodeBlock.of((char) c) ==
|
||||||
|
Character.UnicodeBlock.BASIC_LATIN &&
|
||||||
|
!Character.isISOControl((char) c)) {
|
||||||
|
// normal char
|
||||||
|
buf.append((char) c);
|
||||||
|
} else {
|
||||||
|
// must be something unprintable...use \\uXXXX
|
||||||
|
// turn on the bit above max "\\uFFFF" value so that we pad with zeros
|
||||||
|
// then only take last 4 digits
|
||||||
|
String hex = Integer.toHexString(c | 0x10000).toUpperCase().substring(1, 5);
|
||||||
|
buf.append("\\x{");
|
||||||
|
buf.append(hex);
|
||||||
|
buf.append("}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf.indexOf("\\") == -1) {
|
||||||
|
// no need for interpolation, use single quotes
|
||||||
|
buf.insert(0, '\'');
|
||||||
|
buf.append('\'');
|
||||||
|
} else {
|
||||||
|
// need string interpolation
|
||||||
|
buf.insert(0, '\"');
|
||||||
|
buf.append('\"');
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
}
|
219
antlr_3_1_source/codegen/PythonTarget.java
Normal file
219
antlr_3_1_source/codegen/PythonTarget.java
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005 Martin Traverso
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Please excuse my obvious lack of Java experience. The code here is probably
|
||||||
|
full of WTFs - though IMHO Java is the Real WTF(TM) here...
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.antlr.codegen;
|
||||||
|
import org.antlr.tool.Grammar;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class PythonTarget extends Target {
|
||||||
|
/** Target must be able to override the labels used for token types */
|
||||||
|
public String getTokenTypeAsTargetLabel(CodeGenerator generator,
|
||||||
|
int ttype) {
|
||||||
|
// use ints for predefined types;
|
||||||
|
// <invalid> <EOR> <DOWN> <UP>
|
||||||
|
if ( ttype >= 0 && ttype <= 3 ) {
|
||||||
|
return String.valueOf(ttype);
|
||||||
|
}
|
||||||
|
|
||||||
|
String name = generator.grammar.getTokenDisplayName(ttype);
|
||||||
|
|
||||||
|
// If name is a literal, return the token type instead
|
||||||
|
if ( name.charAt(0)=='\'' ) {
|
||||||
|
return String.valueOf(ttype);
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTargetCharLiteralFromANTLRCharLiteral(
|
||||||
|
CodeGenerator generator,
|
||||||
|
String literal) {
|
||||||
|
int c = Grammar.getCharValueFromGrammarCharLiteral(literal);
|
||||||
|
return String.valueOf(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List splitLines(String text) {
|
||||||
|
ArrayList l = new ArrayList();
|
||||||
|
int idx = 0;
|
||||||
|
|
||||||
|
while ( true ) {
|
||||||
|
int eol = text.indexOf("\n", idx);
|
||||||
|
if ( eol == -1 ) {
|
||||||
|
l.add(text.substring(idx));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
l.add(text.substring(idx, eol+1));
|
||||||
|
idx = eol+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List postProcessAction(List chunks, antlr.Token actionToken) {
|
||||||
|
/* TODO
|
||||||
|
- check for and report TAB usage
|
||||||
|
*/
|
||||||
|
|
||||||
|
//System.out.println("\n*** Action at " + actionToken.getLine() + ":" + actionToken.getColumn());
|
||||||
|
|
||||||
|
/* First I create a new list of chunks. String chunks are splitted into
|
||||||
|
lines and some whitespace my be added at the beginning.
|
||||||
|
|
||||||
|
As a result I get a list of chunks
|
||||||
|
- where the first line starts at column 0
|
||||||
|
- where every LF is at the end of a string chunk
|
||||||
|
*/
|
||||||
|
|
||||||
|
List nChunks = new ArrayList();
|
||||||
|
for (int i = 0; i < chunks.size(); i++) {
|
||||||
|
Object chunk = chunks.get(i);
|
||||||
|
|
||||||
|
if ( chunk instanceof String ) {
|
||||||
|
String text = (String)chunks.get(i);
|
||||||
|
if ( nChunks.size() == 0 && actionToken.getColumn() > 0 ) {
|
||||||
|
// first chunk and some 'virtual' WS at beginning
|
||||||
|
// prepend to this chunk
|
||||||
|
|
||||||
|
String ws = "";
|
||||||
|
for ( int j = 0 ; j < actionToken.getColumn() ; j++ ) {
|
||||||
|
ws += " ";
|
||||||
|
}
|
||||||
|
text = ws + text;
|
||||||
|
}
|
||||||
|
|
||||||
|
List parts = splitLines(text);
|
||||||
|
for ( int j = 0 ; j < parts.size() ; j++ ) {
|
||||||
|
chunk = parts.get(j);
|
||||||
|
nChunks.add(chunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if ( nChunks.size() == 0 && actionToken.getColumn() > 0 ) {
|
||||||
|
// first chunk and some 'virtual' WS at beginning
|
||||||
|
// add as a chunk of its own
|
||||||
|
|
||||||
|
String ws = "";
|
||||||
|
for ( int j = 0 ; j < actionToken.getColumn() ; j++ ) {
|
||||||
|
ws += " ";
|
||||||
|
}
|
||||||
|
nChunks.add(ws);
|
||||||
|
}
|
||||||
|
|
||||||
|
nChunks.add(chunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int lineNo = actionToken.getLine();
|
||||||
|
int col = 0;
|
||||||
|
|
||||||
|
// strip trailing empty lines
|
||||||
|
int lastChunk = nChunks.size() - 1;
|
||||||
|
while ( lastChunk > 0
|
||||||
|
&& nChunks.get(lastChunk) instanceof String
|
||||||
|
&& ((String)nChunks.get(lastChunk)).trim().length() == 0 )
|
||||||
|
lastChunk--;
|
||||||
|
|
||||||
|
// string leading empty lines
|
||||||
|
int firstChunk = 0;
|
||||||
|
while ( firstChunk <= lastChunk
|
||||||
|
&& nChunks.get(firstChunk) instanceof String
|
||||||
|
&& ((String)nChunks.get(firstChunk)).trim().length() == 0
|
||||||
|
&& ((String)nChunks.get(firstChunk)).endsWith("\n") ) {
|
||||||
|
lineNo++;
|
||||||
|
firstChunk++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int indent = -1;
|
||||||
|
for ( int i = firstChunk ; i <= lastChunk ; i++ ) {
|
||||||
|
Object chunk = nChunks.get(i);
|
||||||
|
|
||||||
|
//System.out.println(lineNo + ":" + col + " " + quote(chunk.toString()));
|
||||||
|
|
||||||
|
if ( chunk instanceof String ) {
|
||||||
|
String text = (String)chunk;
|
||||||
|
|
||||||
|
if ( col == 0 ) {
|
||||||
|
if ( indent == -1 ) {
|
||||||
|
// first non-blank line
|
||||||
|
// count number of leading whitespaces
|
||||||
|
|
||||||
|
indent = 0;
|
||||||
|
for ( int j = 0; j < text.length(); j++ ) {
|
||||||
|
if ( !Character.isWhitespace(text.charAt(j)) )
|
||||||
|
break;
|
||||||
|
|
||||||
|
indent++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( text.length() >= indent ) {
|
||||||
|
int j;
|
||||||
|
for ( j = 0; j < indent ; j++ ) {
|
||||||
|
if ( !Character.isWhitespace(text.charAt(j)) ) {
|
||||||
|
// should do real error reporting here...
|
||||||
|
System.err.println("Warning: badly indented line " + lineNo + " in action:");
|
||||||
|
System.err.println(text);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nChunks.set(i, text.substring(j));
|
||||||
|
}
|
||||||
|
else if ( text.trim().length() > 0 ) {
|
||||||
|
// should do real error reporting here...
|
||||||
|
System.err.println("Warning: badly indented line " + lineNo + " in action:");
|
||||||
|
System.err.println(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( text.endsWith("\n") ) {
|
||||||
|
lineNo++;
|
||||||
|
col = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
col += text.length();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// not really correct, but all I need is col to increment...
|
||||||
|
col += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nChunks;
|
||||||
|
}
|
||||||
|
}
|
73
antlr_3_1_source/codegen/RubyTarget.java
Normal file
73
antlr_3_1_source/codegen/RubyTarget.java
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005 Martin Traverso
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.antlr.codegen;
|
||||||
|
|
||||||
|
public class RubyTarget
|
||||||
|
extends Target
|
||||||
|
{
|
||||||
|
public String getTargetCharLiteralFromANTLRCharLiteral(
|
||||||
|
CodeGenerator generator,
|
||||||
|
String literal)
|
||||||
|
{
|
||||||
|
literal = literal.substring(1, literal.length() - 1);
|
||||||
|
|
||||||
|
String result = "?";
|
||||||
|
|
||||||
|
if (literal.equals("\\")) {
|
||||||
|
result += "\\\\";
|
||||||
|
}
|
||||||
|
else if (literal.equals(" ")) {
|
||||||
|
result += "\\s";
|
||||||
|
}
|
||||||
|
else if (literal.startsWith("\\u")) {
|
||||||
|
result = "0x" + literal.substring(2);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result += literal;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxCharValue(CodeGenerator generator)
|
||||||
|
{
|
||||||
|
// we don't support unicode, yet.
|
||||||
|
return 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTokenTypeAsTargetLabel(CodeGenerator generator, int ttype)
|
||||||
|
{
|
||||||
|
String name = generator.grammar.getTokenDisplayName(ttype);
|
||||||
|
// If name is a literal, return the token type instead
|
||||||
|
if ( name.charAt(0)=='\'' ) {
|
||||||
|
return generator.grammar.computeTokenNameFromLiteral(ttype, name);
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
303
antlr_3_1_source/codegen/Target.java
Normal file
303
antlr_3_1_source/codegen/Target.java
Normal file
@ -0,0 +1,303 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.antlr.codegen;
|
||||||
|
|
||||||
|
import org.antlr.Tool;
|
||||||
|
import org.antlr.analysis.Label;
|
||||||
|
import org.antlr.misc.Utils;
|
||||||
|
import org.antlr.stringtemplate.StringTemplate;
|
||||||
|
import org.antlr.tool.Grammar;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/** The code generator for ANTLR can usually be retargeted just by providing
|
||||||
|
* a new X.stg file for language X, however, sometimes the files that must
|
||||||
|
* be generated vary enough that some X-specific functionality is required.
|
||||||
|
* For example, in C, you must generate header files whereas in Java you do not.
|
||||||
|
* Other languages may want to keep DFA separate from the main
|
||||||
|
* generated recognizer file.
|
||||||
|
*
|
||||||
|
* The notion of a Code Generator target abstracts out the creation
|
||||||
|
* of the various files. As new language targets get added to the ANTLR
|
||||||
|
* system, this target class may have to be altered to handle more
|
||||||
|
* functionality. Eventually, just about all language generation issues
|
||||||
|
* will be expressible in terms of these methods.
|
||||||
|
*
|
||||||
|
* If org.antlr.codegen.XTarget class exists, it is used else
|
||||||
|
* Target base class is used. I am using a superclass rather than an
|
||||||
|
* interface for this target concept because I can add functionality
|
||||||
|
* later without breaking previously written targets (extra interface
|
||||||
|
* methods would force adding dummy functions to all code generator
|
||||||
|
* target classes).
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class Target {
|
||||||
|
|
||||||
|
/** For pure strings of Java 16-bit unicode char, how can we display
|
||||||
|
* it in the target language as a literal. Useful for dumping
|
||||||
|
* predicates and such that may refer to chars that need to be escaped
|
||||||
|
* when represented as strings. Also, templates need to be escaped so
|
||||||
|
* that the target language can hold them as a string.
|
||||||
|
*
|
||||||
|
* I have defined (via the constructor) the set of typical escapes,
|
||||||
|
* but your Target subclass is free to alter the translated chars or
|
||||||
|
* add more definitions. This is nonstatic so each target can have
|
||||||
|
* a different set in memory at same time.
|
||||||
|
*/
|
||||||
|
protected String[] targetCharValueEscape = new String[255];
|
||||||
|
|
||||||
|
public Target() {
|
||||||
|
targetCharValueEscape['\n'] = "\\n";
|
||||||
|
targetCharValueEscape['\r'] = "\\r";
|
||||||
|
targetCharValueEscape['\t'] = "\\t";
|
||||||
|
targetCharValueEscape['\b'] = "\\b";
|
||||||
|
targetCharValueEscape['\f'] = "\\f";
|
||||||
|
targetCharValueEscape['\\'] = "\\\\";
|
||||||
|
targetCharValueEscape['\''] = "\\'";
|
||||||
|
targetCharValueEscape['"'] = "\\\"";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void genRecognizerFile(Tool tool,
|
||||||
|
CodeGenerator generator,
|
||||||
|
Grammar grammar,
|
||||||
|
StringTemplate outputFileST)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
String fileName =
|
||||||
|
generator.getRecognizerFileName(grammar.name, grammar.type);
|
||||||
|
generator.write(outputFileST, fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void genRecognizerHeaderFile(Tool tool,
|
||||||
|
CodeGenerator generator,
|
||||||
|
Grammar grammar,
|
||||||
|
StringTemplate headerFileST,
|
||||||
|
String extName) // e.g., ".h"
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
// no header file by default
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void performGrammarAnalysis(CodeGenerator generator,
|
||||||
|
Grammar grammar)
|
||||||
|
{
|
||||||
|
// Build NFAs from the grammar AST
|
||||||
|
grammar.buildNFA();
|
||||||
|
|
||||||
|
// Create the DFA predictors for each decision
|
||||||
|
grammar.createLookaheadDFAs();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Is scope in @scope::name {action} valid for this kind of grammar?
|
||||||
|
* Targets like C++ may want to allow new scopes like headerfile or
|
||||||
|
* some such. The action names themselves are not policed at the
|
||||||
|
* moment so targets can add template actions w/o having to recompile
|
||||||
|
* ANTLR.
|
||||||
|
*/
|
||||||
|
public boolean isValidActionScope(int grammarType, String scope) {
|
||||||
|
switch (grammarType) {
|
||||||
|
case Grammar.LEXER :
|
||||||
|
if ( scope.equals("lexer") ) {return true;}
|
||||||
|
break;
|
||||||
|
case Grammar.PARSER :
|
||||||
|
if ( scope.equals("parser") ) {return true;}
|
||||||
|
break;
|
||||||
|
case Grammar.COMBINED :
|
||||||
|
if ( scope.equals("parser") ) {return true;}
|
||||||
|
if ( scope.equals("lexer") ) {return true;}
|
||||||
|
break;
|
||||||
|
case Grammar.TREE_PARSER :
|
||||||
|
if ( scope.equals("treeparser") ) {return true;}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Target must be able to override the labels used for token types */
|
||||||
|
public String getTokenTypeAsTargetLabel(CodeGenerator generator, int ttype) {
|
||||||
|
String name = generator.grammar.getTokenDisplayName(ttype);
|
||||||
|
// If name is a literal, return the token type instead
|
||||||
|
if ( name.charAt(0)=='\'' ) {
|
||||||
|
return String.valueOf(ttype);
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Convert from an ANTLR char literal found in a grammar file to
|
||||||
|
* an equivalent char literal in the target language. For most
|
||||||
|
* languages, this means leaving 'x' as 'x'. Actually, we need
|
||||||
|
* to escape '\u000A' so that it doesn't get converted to \n by
|
||||||
|
* the compiler. Convert the literal to the char value and then
|
||||||
|
* to an appropriate target char literal.
|
||||||
|
*
|
||||||
|
* Expect single quotes around the incoming literal.
|
||||||
|
*/
|
||||||
|
public String getTargetCharLiteralFromANTLRCharLiteral(
|
||||||
|
CodeGenerator generator,
|
||||||
|
String literal)
|
||||||
|
{
|
||||||
|
StringBuffer buf = new StringBuffer();
|
||||||
|
buf.append('\'');
|
||||||
|
int c = Grammar.getCharValueFromGrammarCharLiteral(literal);
|
||||||
|
if ( c<Label.MIN_CHAR_VALUE ) {
|
||||||
|
return "'\u0000'";
|
||||||
|
}
|
||||||
|
if ( c<targetCharValueEscape.length &&
|
||||||
|
targetCharValueEscape[c]!=null )
|
||||||
|
{
|
||||||
|
buf.append(targetCharValueEscape[c]);
|
||||||
|
}
|
||||||
|
else if ( Character.UnicodeBlock.of((char)c)==
|
||||||
|
Character.UnicodeBlock.BASIC_LATIN &&
|
||||||
|
!Character.isISOControl((char)c) )
|
||||||
|
{
|
||||||
|
// normal char
|
||||||
|
buf.append((char)c);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// must be something unprintable...use \\uXXXX
|
||||||
|
// turn on the bit above max "\\uFFFF" value so that we pad with zeros
|
||||||
|
// then only take last 4 digits
|
||||||
|
String hex = Integer.toHexString(c|0x10000).toUpperCase().substring(1,5);
|
||||||
|
buf.append("\\u");
|
||||||
|
buf.append(hex);
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.append('\'');
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Convert from an ANTLR string literal found in a grammar file to
|
||||||
|
* an equivalent string literal in the target language. For Java, this
|
||||||
|
* is the translation 'a\n"' -> "a\n\"". Expect single quotes
|
||||||
|
* around the incoming literal. Just flip the quotes and replace
|
||||||
|
* double quotes with \"
|
||||||
|
*/
|
||||||
|
public String getTargetStringLiteralFromANTLRStringLiteral(
|
||||||
|
CodeGenerator generator,
|
||||||
|
String literal)
|
||||||
|
{
|
||||||
|
literal = Utils.replace(literal,"\\\"","\""); // \" to " to normalize
|
||||||
|
literal = Utils.replace(literal,"\"","\\\""); // " to \" to escape all
|
||||||
|
StringBuffer buf = new StringBuffer(literal);
|
||||||
|
buf.setCharAt(0,'"');
|
||||||
|
buf.setCharAt(literal.length()-1,'"');
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Given a random string of Java unicode chars, return a new string with
|
||||||
|
* optionally appropriate quote characters for target language and possibly
|
||||||
|
* with some escaped characters. For example, if the incoming string has
|
||||||
|
* actual newline characters, the output of this method would convert them
|
||||||
|
* to the two char sequence \n for Java, C, C++, ... The new string has
|
||||||
|
* double-quotes around it as well. Example String in memory:
|
||||||
|
*
|
||||||
|
* a"[newlinechar]b'c[carriagereturnchar]d[tab]e\f
|
||||||
|
*
|
||||||
|
* would be converted to the valid Java s:
|
||||||
|
*
|
||||||
|
* "a\"\nb'c\rd\te\\f"
|
||||||
|
*
|
||||||
|
* or
|
||||||
|
*
|
||||||
|
* a\"\nb'c\rd\te\\f
|
||||||
|
*
|
||||||
|
* depending on the quoted arg.
|
||||||
|
*/
|
||||||
|
public String getTargetStringLiteralFromString(String s, boolean quoted) {
|
||||||
|
if ( s==null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
StringBuffer buf = new StringBuffer();
|
||||||
|
if ( quoted ) {
|
||||||
|
buf.append('"');
|
||||||
|
}
|
||||||
|
for (int i=0; i<s.length(); i++) {
|
||||||
|
int c = s.charAt(i);
|
||||||
|
if ( c!='\'' && // don't escape single quotes in strings for java
|
||||||
|
c<targetCharValueEscape.length &&
|
||||||
|
targetCharValueEscape[c]!=null )
|
||||||
|
{
|
||||||
|
buf.append(targetCharValueEscape[c]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
buf.append((char)c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( quoted ) {
|
||||||
|
buf.append('"');
|
||||||
|
}
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTargetStringLiteralFromString(String s) {
|
||||||
|
return getTargetStringLiteralFromString(s, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Convert long to 0xNNNNNNNNNNNNNNNN by default for spitting out
|
||||||
|
* with bitsets. I.e., convert bytes to hex string.
|
||||||
|
*/
|
||||||
|
public String getTarget64BitStringFromValue(long word) {
|
||||||
|
int numHexDigits = 8*2;
|
||||||
|
StringBuffer buf = new StringBuffer(numHexDigits+2);
|
||||||
|
buf.append("0x");
|
||||||
|
String digits = Long.toHexString(word);
|
||||||
|
digits = digits.toUpperCase();
|
||||||
|
int padding = numHexDigits - digits.length();
|
||||||
|
// pad left with zeros
|
||||||
|
for (int i=1; i<=padding; i++) {
|
||||||
|
buf.append('0');
|
||||||
|
}
|
||||||
|
buf.append(digits);
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String encodeIntAsCharEscape(int v) {
|
||||||
|
if ( v<=127 ) {
|
||||||
|
return "\\"+Integer.toOctalString(v);
|
||||||
|
}
|
||||||
|
String hex = Integer.toHexString(v|0x10000).substring(1,5);
|
||||||
|
return "\\u"+hex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Some targets only support ASCII or 8-bit chars/strings. For example,
|
||||||
|
* C++ will probably want to return 0xFF here.
|
||||||
|
*/
|
||||||
|
public int getMaxCharValue(CodeGenerator generator) {
|
||||||
|
return Label.MAX_CHAR_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Give target a chance to do some postprocessing on actions.
|
||||||
|
* Python for example will have to fix the indention.
|
||||||
|
*/
|
||||||
|
public List postProcessAction(List chunks, antlr.Token actionToken) {
|
||||||
|
return chunks;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
1414
antlr_3_1_source/codegen/codegen.g
Normal file
1414
antlr_3_1_source/codegen/codegen.g
Normal file
File diff suppressed because it is too large
Load Diff
375
antlr_3_1_source/codegen/templates/ANTLRCore.sti
Normal file
375
antlr_3_1_source/codegen/templates/ANTLRCore.sti
Normal file
@ -0,0 +1,375 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
interface ANTLRCore;
|
||||||
|
|
||||||
|
/** The overall file structure of a recognizer; stores methods for rules
|
||||||
|
* and cyclic DFAs plus support code.
|
||||||
|
*/
|
||||||
|
outputFile(LEXER,PARSER,TREE_PARSER, actionScope, actions,
|
||||||
|
docComment, recognizer,
|
||||||
|
name, tokens, tokenNames, rules, cyclicDFAs,
|
||||||
|
bitsets, buildTemplate, buildAST, rewriteMode, profile,
|
||||||
|
backtracking, synpreds, memoize, numRules,
|
||||||
|
fileName, ANTLRVersion, generatedTimestamp, trace,
|
||||||
|
scopes, superClass, literals);
|
||||||
|
|
||||||
|
/** The header file; make sure to define headerFileExtension() below */
|
||||||
|
optional
|
||||||
|
headerFile(LEXER,PARSER,TREE_PARSER, actionScope, actions,
|
||||||
|
docComment, recognizer,
|
||||||
|
name, tokens, tokenNames, rules, cyclicDFAs,
|
||||||
|
bitsets, buildTemplate, buildAST, rewriteMode, profile,
|
||||||
|
backtracking, synpreds, memoize, numRules,
|
||||||
|
fileName, ANTLRVersion, generatedTimestamp, trace,
|
||||||
|
scopes, superClass, literals);
|
||||||
|
|
||||||
|
lexer(grammar, name, tokens, scopes, rules, numRules, labelType,
|
||||||
|
filterMode, superClass);
|
||||||
|
|
||||||
|
parser(grammar, name, scopes, tokens, tokenNames, rules, numRules,
|
||||||
|
bitsets, ASTLabelType, superClass,
|
||||||
|
labelType, members);
|
||||||
|
|
||||||
|
/** How to generate a tree parser; same as parser except the input
|
||||||
|
* stream is a different type.
|
||||||
|
*/
|
||||||
|
treeParser(grammar, name, scopes, tokens, tokenNames, globalAction, rules,
|
||||||
|
numRules, bitsets, labelType, ASTLabelType,
|
||||||
|
superClass, members);
|
||||||
|
|
||||||
|
/** A simpler version of a rule template that is specific to the imaginary
|
||||||
|
* rules created for syntactic predicates. As they never have return values
|
||||||
|
* nor parameters etc..., just give simplest possible method. Don't do
|
||||||
|
* any of the normal memoization stuff in here either; it's a waste.
|
||||||
|
* As predicates cannot be inlined into the invoking rule, they need to
|
||||||
|
* be in a rule by themselves.
|
||||||
|
*/
|
||||||
|
synpredRule(ruleName, ruleDescriptor, block, description, nakedBlock);
|
||||||
|
|
||||||
|
/** How to generate code for a rule. This includes any return type
|
||||||
|
* data aggregates required for multiple return values.
|
||||||
|
*/
|
||||||
|
rule(ruleName,ruleDescriptor,block,emptyRule,description,exceptions,finally,memoize);
|
||||||
|
|
||||||
|
/** How to generate a rule in the lexer; naked blocks are used for
|
||||||
|
* fragment rules.
|
||||||
|
*/
|
||||||
|
lexerRule(ruleName,nakedBlock,ruleDescriptor,block,memoize);
|
||||||
|
|
||||||
|
/** How to generate code for the implicitly-defined lexer grammar rule
|
||||||
|
* that chooses between lexer rules.
|
||||||
|
*/
|
||||||
|
tokensRule(ruleName,nakedBlock,args,block,ruleDescriptor);
|
||||||
|
|
||||||
|
filteringNextToken();
|
||||||
|
|
||||||
|
filteringActionGate();
|
||||||
|
|
||||||
|
// S U B R U L E S
|
||||||
|
|
||||||
|
/** A (...) subrule with multiple alternatives */
|
||||||
|
block(alts,decls,decision,enclosingBlockLevel,blockLevel,decisionNumber,maxK,maxAlt,description);
|
||||||
|
|
||||||
|
/** A rule block with multiple alternatives */
|
||||||
|
ruleBlock(alts,decls,decision,enclosingBlockLevel,blockLevel,decisionNumber,maxK,maxAlt,description);
|
||||||
|
|
||||||
|
ruleBlockSingleAlt(alts,decls,decision,enclosingBlockLevel,blockLevel,decisionNumber,description);
|
||||||
|
|
||||||
|
/** A special case of a (...) subrule with a single alternative */
|
||||||
|
blockSingleAlt(alts,decls,decision,enclosingBlockLevel,blockLevel,decisionNumber,description);
|
||||||
|
|
||||||
|
/** A (..)+ block with 0 or more alternatives */
|
||||||
|
positiveClosureBlock(alts,decls,decision,enclosingBlockLevel,blockLevel,decisionNumber,maxK,maxAlt,description);
|
||||||
|
|
||||||
|
positiveClosureBlockSingleAlt(alts,decls,decision,enclosingBlockLevel,blockLevel,decisionNumber,maxK,maxAlt,description);
|
||||||
|
|
||||||
|
/** A (..)* block with 0 or more alternatives */
|
||||||
|
closureBlock(alts,decls,decision,enclosingBlockLevel,blockLevel,decisionNumber,maxK,maxAlt,description);
|
||||||
|
|
||||||
|
closureBlockSingleAlt(alts,decls,decision,enclosingBlockLevel,blockLevel,decisionNumber,maxK,maxAlt,description);
|
||||||
|
|
||||||
|
/** Optional blocks (x)? are translated to (x|) by before code generation
|
||||||
|
* so we can just use the normal block template
|
||||||
|
*/
|
||||||
|
optionalBlock(alts,decls,decision,enclosingBlockLevel,blockLevel,decisionNumber,maxK,maxAlt,description);
|
||||||
|
|
||||||
|
optionalBlockSingleAlt(alts,decls,decision,enclosingBlockLevel,blockLevel,decisionNumber,maxK,maxAlt,description);
|
||||||
|
|
||||||
|
/** An alternative is just a list of elements; at outermost level */
|
||||||
|
alt(elements,altNum,description,autoAST,outerAlt,treeLevel,rew);
|
||||||
|
|
||||||
|
// E L E M E N T S
|
||||||
|
|
||||||
|
/** match a token optionally with a label in front */
|
||||||
|
tokenRef(token,label,elementIndex,hetero);
|
||||||
|
|
||||||
|
/** ids+=ID */
|
||||||
|
tokenRefAndListLabel(token,label,elementIndex,hetero);
|
||||||
|
|
||||||
|
listLabel(label,elem);
|
||||||
|
|
||||||
|
/** match a character */
|
||||||
|
charRef(char,label);
|
||||||
|
|
||||||
|
/** match a character range */
|
||||||
|
charRangeRef(a,b,label);
|
||||||
|
|
||||||
|
/** For now, sets are interval tests and must be tested inline */
|
||||||
|
matchSet(s,label,elementIndex,postmatchCode);
|
||||||
|
|
||||||
|
matchSetAndListLabel(s,label,elementIndex,postmatchCode);
|
||||||
|
|
||||||
|
/** Match a string literal */
|
||||||
|
lexerStringRef(string,label);
|
||||||
|
|
||||||
|
wildcard(label,elementIndex);
|
||||||
|
|
||||||
|
wildcardAndListLabel(label,elementIndex);
|
||||||
|
|
||||||
|
/** Match . wildcard in lexer */
|
||||||
|
wildcardChar(label, elementIndex);
|
||||||
|
|
||||||
|
wildcardCharListLabel(label, elementIndex);
|
||||||
|
|
||||||
|
/** Match a rule reference by invoking it possibly with arguments
|
||||||
|
* and a return value or values.
|
||||||
|
*/
|
||||||
|
ruleRef(rule,label,elementIndex,args,scope);
|
||||||
|
|
||||||
|
/** ids+=ID */
|
||||||
|
ruleRefAndListLabel(rule,label,elementIndex,args,scope);
|
||||||
|
|
||||||
|
/** A lexer rule reference */
|
||||||
|
lexerRuleRef(rule,label,args,elementIndex,scope);
|
||||||
|
|
||||||
|
/** i+=INT in lexer */
|
||||||
|
lexerRuleRefAndListLabel(rule,label,args,elementIndex,scope);
|
||||||
|
|
||||||
|
/** EOF in the lexer */
|
||||||
|
lexerMatchEOF(label,elementIndex);
|
||||||
|
|
||||||
|
/** match ^(root children) in tree parser */
|
||||||
|
tree(root, actionsAfterRoot, children, nullableChildList,
|
||||||
|
enclosingTreeLevel, treeLevel);
|
||||||
|
|
||||||
|
/** Every predicate is used as a validating predicate (even when it is
|
||||||
|
* also hoisted into a prediction expression).
|
||||||
|
*/
|
||||||
|
validateSemanticPredicate(pred,description);
|
||||||
|
|
||||||
|
// F i x e d D F A (if-then-else)
|
||||||
|
|
||||||
|
dfaState(k,edges,eotPredictsAlt,description,stateNumber,semPredState);
|
||||||
|
|
||||||
|
/** Same as a normal DFA state except that we don't examine lookahead
|
||||||
|
* for the bypass alternative. It delays error detection but this
|
||||||
|
* is faster, smaller, and more what people expect. For (X)? people
|
||||||
|
* expect "if ( LA(1)==X ) match(X);" and that's it.
|
||||||
|
*
|
||||||
|
* If a semPredState, don't force lookahead lookup; preds might not
|
||||||
|
* need.
|
||||||
|
*/
|
||||||
|
dfaOptionalBlockState(k,edges,eotPredictsAlt,description,stateNumber,semPredState);
|
||||||
|
|
||||||
|
/** A DFA state that is actually the loopback decision of a closure
|
||||||
|
* loop. If end-of-token (EOT) predicts any of the targets then it
|
||||||
|
* should act like a default clause (i.e., no error can be generated).
|
||||||
|
* This is used only in the lexer so that for ('a')* on the end of a
|
||||||
|
* rule anything other than 'a' predicts exiting.
|
||||||
|
*
|
||||||
|
* If a semPredState, don't force lookahead lookup; preds might not
|
||||||
|
* need.
|
||||||
|
*/
|
||||||
|
dfaLoopbackState(k,edges,eotPredictsAlt,description,stateNumber,semPredState);
|
||||||
|
|
||||||
|
/** An accept state indicates a unique alternative has been predicted */
|
||||||
|
dfaAcceptState(alt);
|
||||||
|
|
||||||
|
/** A simple edge with an expression. If the expression is satisfied,
|
||||||
|
* enter to the target state. To handle gated productions, we may
|
||||||
|
* have to evaluate some predicates for this edge.
|
||||||
|
*/
|
||||||
|
dfaEdge(labelExpr, targetState, predicates);
|
||||||
|
|
||||||
|
// F i x e d D F A (switch case)
|
||||||
|
|
||||||
|
/** A DFA state where a SWITCH may be generated. The code generator
|
||||||
|
* decides if this is possible: CodeGenerator.canGenerateSwitch().
|
||||||
|
*/
|
||||||
|
dfaStateSwitch(k,edges,eotPredictsAlt,description,stateNumber,semPredState);
|
||||||
|
|
||||||
|
dfaOptionalBlockStateSwitch(k,edges,eotPredictsAlt,description,stateNumber,semPredState);
|
||||||
|
|
||||||
|
dfaLoopbackStateSwitch(k, edges,eotPredictsAlt,description,stateNumber,semPredState);
|
||||||
|
|
||||||
|
dfaEdgeSwitch(labels, targetState);
|
||||||
|
|
||||||
|
// C y c l i c D F A
|
||||||
|
|
||||||
|
/** The code to initiate execution of a cyclic DFA; this is used
|
||||||
|
* in the rule to predict an alt just like the fixed DFA case.
|
||||||
|
* The <name> attribute is inherited via the parser, lexer, ...
|
||||||
|
*/
|
||||||
|
dfaDecision(decisionNumber,description);
|
||||||
|
|
||||||
|
/** Generate the tables and support code needed for the DFAState object
|
||||||
|
* argument. Unless there is a semantic predicate (or syn pred, which
|
||||||
|
* become sem preds), all states should be encoded in the state tables.
|
||||||
|
* Consequently, cyclicDFAState/cyclicDFAEdge,eotDFAEdge templates are
|
||||||
|
* not used except for special DFA states that cannot be encoded as
|
||||||
|
* a transition table.
|
||||||
|
*/
|
||||||
|
cyclicDFA(dfa);
|
||||||
|
|
||||||
|
/** A special state in a cyclic DFA; special means has a semantic predicate
|
||||||
|
* or it's a huge set of symbols to check.
|
||||||
|
*/
|
||||||
|
cyclicDFAState(decisionNumber,stateNumber,edges,needErrorClause,semPredState);
|
||||||
|
|
||||||
|
/** Just like a fixed DFA edge, test the lookahead and indicate what
|
||||||
|
* state to jump to next if successful. Again, this is for special
|
||||||
|
* states.
|
||||||
|
*/
|
||||||
|
cyclicDFAEdge(labelExpr, targetStateNumber, edgeNumber, predicates);
|
||||||
|
|
||||||
|
/** An edge pointing at end-of-token; essentially matches any char;
|
||||||
|
* always jump to the target.
|
||||||
|
*/
|
||||||
|
eotDFAEdge(targetStateNumber,edgeNumber, predicates);
|
||||||
|
|
||||||
|
// D F A E X P R E S S I O N S
|
||||||
|
|
||||||
|
andPredicates(left,right);
|
||||||
|
|
||||||
|
orPredicates(operands);
|
||||||
|
|
||||||
|
notPredicate(pred);
|
||||||
|
|
||||||
|
evalPredicate(pred,description);
|
||||||
|
|
||||||
|
evalSynPredicate(pred,description);
|
||||||
|
|
||||||
|
lookaheadTest(atom,k,atomAsInt);
|
||||||
|
|
||||||
|
/** Sometimes a lookahead test cannot assume that LA(k) is in a temp variable
|
||||||
|
* somewhere. Must ask for the lookahead directly.
|
||||||
|
*/
|
||||||
|
isolatedLookaheadTest(atom,k,atomAsInt);
|
||||||
|
|
||||||
|
lookaheadRangeTest(lower,upper,k,rangeNumber,lowerAsInt,upperAsInt);
|
||||||
|
|
||||||
|
isolatedLookaheadRangeTest(lower,upper,k,rangeNumber,lowerAsInt,upperAsInt);
|
||||||
|
|
||||||
|
setTest(ranges);
|
||||||
|
|
||||||
|
// A T T R I B U T E S
|
||||||
|
|
||||||
|
parameterAttributeRef(attr);
|
||||||
|
parameterSetAttributeRef(attr,expr);
|
||||||
|
|
||||||
|
scopeAttributeRef(scope,attr,index,negIndex);
|
||||||
|
scopeSetAttributeRef(scope,attr,expr,index,negIndex);
|
||||||
|
|
||||||
|
/** $x is either global scope or x is rule with dynamic scope; refers
|
||||||
|
* to stack itself not top of stack. This is useful for predicates
|
||||||
|
* like {$function.size()>0 && $function::name.equals("foo")}?
|
||||||
|
*/
|
||||||
|
isolatedDynamicScopeRef(scope);
|
||||||
|
|
||||||
|
/** reference an attribute of rule; might only have single return value */
|
||||||
|
ruleLabelRef(referencedRule,scope,attr);
|
||||||
|
|
||||||
|
returnAttributeRef(ruleDescriptor,attr);
|
||||||
|
returnSetAttributeRef(ruleDescriptor,attr,expr);
|
||||||
|
|
||||||
|
/** How to translate $tokenLabel */
|
||||||
|
tokenLabelRef(label);
|
||||||
|
|
||||||
|
/** ids+=ID {$ids} or e+=expr {$e} */
|
||||||
|
listLabelRef(label);
|
||||||
|
|
||||||
|
// not sure the next are the right approach; and they are evaluated early;
|
||||||
|
// they cannot see TREE_PARSER or PARSER attributes for example. :(
|
||||||
|
|
||||||
|
tokenLabelPropertyRef_text(scope,attr);
|
||||||
|
tokenLabelPropertyRef_type(scope,attr);
|
||||||
|
tokenLabelPropertyRef_line(scope,attr);
|
||||||
|
tokenLabelPropertyRef_pos(scope,attr);
|
||||||
|
tokenLabelPropertyRef_channel(scope,attr);
|
||||||
|
tokenLabelPropertyRef_index(scope,attr);
|
||||||
|
tokenLabelPropertyRef_tree(scope,attr);
|
||||||
|
|
||||||
|
ruleLabelPropertyRef_start(scope,attr);
|
||||||
|
ruleLabelPropertyRef_stop(scope,attr);
|
||||||
|
ruleLabelPropertyRef_tree(scope,attr);
|
||||||
|
ruleLabelPropertyRef_text(scope,attr);
|
||||||
|
ruleLabelPropertyRef_st(scope,attr);
|
||||||
|
|
||||||
|
/** Isolated $RULE ref ok in lexer as it's a Token */
|
||||||
|
lexerRuleLabel(label);
|
||||||
|
|
||||||
|
lexerRuleLabelPropertyRef_type(scope,attr);
|
||||||
|
lexerRuleLabelPropertyRef_line(scope,attr);
|
||||||
|
lexerRuleLabelPropertyRef_pos(scope,attr);
|
||||||
|
lexerRuleLabelPropertyRef_channel(scope,attr);
|
||||||
|
lexerRuleLabelPropertyRef_index(scope,attr);
|
||||||
|
lexerRuleLabelPropertyRef_text(scope,attr);
|
||||||
|
|
||||||
|
// Somebody may ref $template or $tree or $stop within a rule:
|
||||||
|
rulePropertyRef_start(scope,attr);
|
||||||
|
rulePropertyRef_stop(scope,attr);
|
||||||
|
rulePropertyRef_tree(scope,attr);
|
||||||
|
rulePropertyRef_text(scope,attr);
|
||||||
|
rulePropertyRef_st(scope,attr);
|
||||||
|
|
||||||
|
lexerRulePropertyRef_text(scope,attr);
|
||||||
|
lexerRulePropertyRef_type(scope,attr);
|
||||||
|
lexerRulePropertyRef_line(scope,attr);
|
||||||
|
lexerRulePropertyRef_pos(scope,attr);
|
||||||
|
/** Undefined, but present for consistency with Token attributes; set to -1 */
|
||||||
|
lexerRulePropertyRef_index(scope,attr);
|
||||||
|
lexerRulePropertyRef_channel(scope,attr);
|
||||||
|
lexerRulePropertyRef_start(scope,attr);
|
||||||
|
lexerRulePropertyRef_stop(scope,attr);
|
||||||
|
|
||||||
|
ruleSetPropertyRef_tree(scope,attr,expr);
|
||||||
|
ruleSetPropertyRef_st(scope,attr,expr);
|
||||||
|
|
||||||
|
/** How to execute an action */
|
||||||
|
execAction(action);
|
||||||
|
|
||||||
|
// M I S C (properties, etc...)
|
||||||
|
|
||||||
|
codeFileExtension();
|
||||||
|
|
||||||
|
/** Your language needs a header file; e.g., ".h" */
|
||||||
|
optional headerFileExtension();
|
||||||
|
|
||||||
|
true();
|
||||||
|
false();
|
391
antlr_3_1_source/codegen/templates/ActionScript/AST.stg
Normal file
391
antlr_3_1_source/codegen/templates/ActionScript/AST.stg
Normal file
@ -0,0 +1,391 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
group AST;
|
||||||
|
|
||||||
|
@outputFile.imports() ::= <<
|
||||||
|
<@super.imports()>
|
||||||
|
<if(!TREE_PARSER)><! tree parser would already have imported !>
|
||||||
|
import org.antlr.runtime.tree.*;<\n>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
@genericParser.members() ::= <<
|
||||||
|
<@super.members()>
|
||||||
|
<parserMembers()>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Add an adaptor property that knows how to build trees */
|
||||||
|
parserMembers() ::= <<
|
||||||
|
protected var adaptor:TreeAdaptor = new CommonTreeAdaptor();<\n>
|
||||||
|
public function set treeAdaptor(adaptor:TreeAdaptor):void {
|
||||||
|
this.adaptor = adaptor;
|
||||||
|
}
|
||||||
|
public function get treeAdaptor():TreeAdaptor {
|
||||||
|
return adaptor;
|
||||||
|
}
|
||||||
|
>>
|
||||||
|
|
||||||
|
@returnScope.ruleReturnMembers() ::= <<
|
||||||
|
<ASTLabelType> tree;
|
||||||
|
public function get tree():Object { return tree; }
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Add a variable to track rule's return AST */
|
||||||
|
ruleDeclarations() ::= <<
|
||||||
|
<super.ruleDeclarations()>
|
||||||
|
var root_0:<ASTLabelType> = null;<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
ruleLabelDefs() ::= <<
|
||||||
|
<super.ruleLabelDefs()>
|
||||||
|
<ruleDescriptor.tokenLabels:{var <it.label.text>_tree:<ASTLabelType>=null;}; separator="\n">
|
||||||
|
<ruleDescriptor.tokenListLabels:{var <it.label.text>_tree:<ASTLabelType>=null;}; separator="\n">
|
||||||
|
<ruleDescriptor.allTokenRefsInAltsWithRewrites
|
||||||
|
:{var stream_<it>:RewriteRule<rewriteElementType>Stream=new RewriteRule<rewriteElementType>Stream(adaptor,"token <it>");}; separator="\n">
|
||||||
|
<ruleDescriptor.allRuleRefsInAltsWithRewrites
|
||||||
|
:{var stream_<it>:RewriteRuleSubtreeStream=new RewriteRuleSubtreeStream(adaptor,"rule <it>");}; separator="\n">
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** When doing auto AST construction, we must define some variables;
|
||||||
|
* These should be turned off if doing rewrites. This must be a "mode"
|
||||||
|
* as a rule could have both rewrite and AST within the same alternative
|
||||||
|
* block.
|
||||||
|
*/
|
||||||
|
@alt.declarations() ::= <<
|
||||||
|
<if(autoAST)>
|
||||||
|
<if(outerAlt)>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
root_0 = <ASTLabelType>(adaptor.nil());<\n>
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// T r a c k i n g R u l e E l e m e n t s
|
||||||
|
|
||||||
|
/** ID and track it for use in a rewrite rule */
|
||||||
|
tokenRefTrack(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefBang(...)> <! Track implies no auto AST construction!>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) <endif>stream_<token>.add(<label>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ids+=ID and track it for use in a rewrite rule; adds to ids *and*
|
||||||
|
* to the tracking list stream_ID for use in the rewrite.
|
||||||
|
*/
|
||||||
|
tokenRefTrackAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefTrack(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(ID ...) track for rewrite */
|
||||||
|
tokenRefRuleRootTrack(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefBang(...)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) <endif>stream_<token>.add(<label>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Match ^(label+=TOKEN ...) track for rewrite */
|
||||||
|
tokenRefRuleRootTrackAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefRuleRootTrack(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
wildcardTrack(label,elementIndex) ::= <<
|
||||||
|
<super.wildcard(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** rule when output=AST and tracking for rewrite */
|
||||||
|
ruleRefTrack(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<super.ruleRef(...)>
|
||||||
|
<if(backtracking)>if ( this.state.backtracking==0 ) <endif>stream_<rule.name>.add(<label>.tree);
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule when output=AST and tracking for rewrite */
|
||||||
|
ruleRefTrackAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefTrack(...)>
|
||||||
|
<listLabel(elem=label+".tree",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(rule ...) rewrite */
|
||||||
|
ruleRefRuleRootTrack(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefRuleRoot(...)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) <endif>stream_<rule>.add(<label>.tree);
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(x+=rule ...) rewrite */
|
||||||
|
ruleRefRuleRootTrackAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefRuleRootTrack(...)>
|
||||||
|
<listLabel(elem=label+".tree",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// R e w r i t e
|
||||||
|
|
||||||
|
rewriteCode(
|
||||||
|
alts, description,
|
||||||
|
referencedElementsDeep, // ALL referenced elements to right of ->
|
||||||
|
referencedTokenLabels,
|
||||||
|
referencedTokenListLabels,
|
||||||
|
referencedRuleLabels,
|
||||||
|
referencedRuleListLabels,
|
||||||
|
rewriteBlockLevel, enclosingTreeLevel, treeLevel) ::=
|
||||||
|
<<
|
||||||
|
|
||||||
|
// AST REWRITE
|
||||||
|
// elements: <referencedElementsDeep; separator=", ">
|
||||||
|
// token labels: <referencedTokenLabels; separator=", ">
|
||||||
|
// rule labels: <referencedRuleLabels; separator=", ">
|
||||||
|
// token list labels: <referencedTokenListLabels; separator=", ">
|
||||||
|
// rule list labels: <referencedRuleListLabels; separator=", ">
|
||||||
|
<if(backtracking)>
|
||||||
|
if ( this.state.backtracking==0 ) {<\n>
|
||||||
|
<endif>
|
||||||
|
<prevRuleRootRef()>.tree = root_0;
|
||||||
|
<rewriteCodeLabels()>
|
||||||
|
root_0 = <ASTLabelType>(adaptor.nil());
|
||||||
|
<alts:rewriteAlt(); separator="else ">
|
||||||
|
<! if tree parser and rewrite=true !>
|
||||||
|
<if(TREE_PARSER)>
|
||||||
|
<if(rewriteMode)>
|
||||||
|
<prevRuleRootRef()>.tree = <ASTLabelType>(adaptor.rulePostProcessing(root_0));
|
||||||
|
input.replaceChildren(adaptor.getParent(retval.start),
|
||||||
|
adaptor.getChildIndex(retval.start),
|
||||||
|
adaptor.getChildIndex(_last),
|
||||||
|
retval.tree);
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
<! if parser or rewrite!=true, we need to set result !>
|
||||||
|
<if(!TREE_PARSER)>
|
||||||
|
<prevRuleRootRef()>.tree = root_0;
|
||||||
|
<endif>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<prevRuleRootRef()>.tree = root_0;
|
||||||
|
<endif>
|
||||||
|
<if(backtracking)>
|
||||||
|
}
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteCodeLabels() ::= <<
|
||||||
|
<referencedTokenLabels
|
||||||
|
:{var stream_<it>:RewriteRule<rewriteElementType>Stream=new RewriteRule<rewriteElementType>Stream(adaptor,"token <it>",<it>);};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
<referencedTokenListLabels
|
||||||
|
:{var stream_<it>:RewriteRule<rewriteElementType>Stream=new RewriteRule<rewriteElementType>Stream(adaptor,"token <it>", list_<it>);};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
<referencedRuleLabels
|
||||||
|
:{var stream_<it>:RewriteRuleSubtreeStream=new RewriteRuleSubtreeStream(adaptor,"token <it>",<it>!=null?<it>.tree:null);};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
<referencedRuleListLabels
|
||||||
|
:{var stream_<it>:RewriteRuleSubtreeStream=new RewriteRuleSubtreeStream(adaptor,"token <it>",list_<it>);};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Generate code for an optional rewrite block; note it uses the deep ref'd element
|
||||||
|
* list rather shallow like other blocks.
|
||||||
|
*/
|
||||||
|
rewriteOptionalBlock(
|
||||||
|
alt,rewriteBlockLevel,
|
||||||
|
referencedElementsDeep, // all nested refs
|
||||||
|
referencedElements, // elements in immediately block; no nested blocks
|
||||||
|
description) ::=
|
||||||
|
<<
|
||||||
|
// <fileName>:<description>
|
||||||
|
if ( <referencedElementsDeep:{el | stream_<el>.hasNext}; separator="||"> ) {
|
||||||
|
<alt>
|
||||||
|
}
|
||||||
|
<referencedElementsDeep:{el | stream_<el>.reset();<\n>}>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteClosureBlock(
|
||||||
|
alt,rewriteBlockLevel,
|
||||||
|
referencedElementsDeep, // all nested refs
|
||||||
|
referencedElements, // elements in immediately block; no nested blocks
|
||||||
|
description) ::=
|
||||||
|
<<
|
||||||
|
// <fileName>:<description>
|
||||||
|
while ( <referencedElements:{el | stream_<el>.hasNext}; separator="||"> ) {
|
||||||
|
<alt>
|
||||||
|
}
|
||||||
|
<referencedElements:{el | stream_<el>.reset();<\n>}>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewritePositiveClosureBlock(
|
||||||
|
alt,rewriteBlockLevel,
|
||||||
|
referencedElementsDeep, // all nested refs
|
||||||
|
referencedElements, // elements in immediately block; no nested blocks
|
||||||
|
description) ::=
|
||||||
|
<<
|
||||||
|
if ( !(<referencedElements:{el | stream_<el>.hasNext}; separator="||">) ) {
|
||||||
|
throw new RewriteEarlyExitException();
|
||||||
|
}
|
||||||
|
while ( <referencedElements:{el | stream_<el>.hasNext}; separator="||"> ) {
|
||||||
|
<alt>
|
||||||
|
}
|
||||||
|
<referencedElements:{el | stream_<el>.reset();<\n>}>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteAlt(a) ::= <<
|
||||||
|
// <a.description>
|
||||||
|
<if(a.pred)>
|
||||||
|
if (<a.pred>) {
|
||||||
|
<a.alt>
|
||||||
|
}<\n>
|
||||||
|
<else>
|
||||||
|
{
|
||||||
|
<a.alt>
|
||||||
|
}<\n>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** For empty rewrites: "r : ... -> ;" */
|
||||||
|
rewriteEmptyAlt() ::= "root_0 = null;"
|
||||||
|
|
||||||
|
rewriteTree(root,children,description,enclosingTreeLevel,treeLevel) ::= <<
|
||||||
|
// <fileName>:<description>
|
||||||
|
{
|
||||||
|
var root_<treeLevel>:<ASTLabelType> = <ASTLabelType>(adaptor.nil());
|
||||||
|
<root:rewriteElement()>
|
||||||
|
<children:rewriteElement()>
|
||||||
|
adaptor.addChild(root_<enclosingTreeLevel>, root_<treeLevel>);
|
||||||
|
}<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteElementList(elements) ::= "<elements:rewriteElement()>"
|
||||||
|
|
||||||
|
rewriteElement(e) ::= <<
|
||||||
|
<@pregen()>
|
||||||
|
<e.el>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen ID or ID[args] */
|
||||||
|
rewriteTokenRef(token,elementIndex,hetero,args) ::= <<
|
||||||
|
adaptor.addChild(root_<treeLevel>, <createRewriteNodeFromElement(...)>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen $label ... where defined via label=ID */
|
||||||
|
rewriteTokenLabelRef(label,elementIndex) ::= <<
|
||||||
|
adaptor.addChild(root_<treeLevel>, stream_<label>.nextNode());<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen $label ... where defined via label+=ID */
|
||||||
|
rewriteTokenListLabelRef(label,elementIndex) ::= <<
|
||||||
|
adaptor.addChild(root_<treeLevel>, stream_<label>.nextNode());<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen ^($label ...) */
|
||||||
|
rewriteTokenLabelRefRoot(label,elementIndex) ::= <<
|
||||||
|
root_<treeLevel> = <ASTLabelType>(adaptor.becomeRoot(stream_<label>.nextNode(), root_<treeLevel>));<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen ^($label ...) where label+=... */
|
||||||
|
rewriteTokenListLabelRefRoot ::= rewriteTokenLabelRefRoot
|
||||||
|
|
||||||
|
/** Gen ^(ID ...) or ^(ID[args] ...) */
|
||||||
|
rewriteTokenRefRoot(token,elementIndex,hetero,args) ::= <<
|
||||||
|
root_<treeLevel> = <ASTLabelType>(adaptor.becomeRoot(<createRewriteNodeFromElement(...)>, root_<treeLevel>));<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteImaginaryTokenRef(args,token,hetero,elementIndex) ::= <<
|
||||||
|
adaptor.addChild(root_<treeLevel>, <createImaginaryNode(tokenType=token, ...)>));<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteImaginaryTokenRefRoot(args,token,hetero,elementIndex) ::= <<
|
||||||
|
root_<treeLevel> = <ASTLabelType>(adaptor.becomeRoot(<createImaginaryNode(tokenType=token, ...)>, root_<treeLevel>));<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** plain -> {foo} action */
|
||||||
|
rewriteAction(action) ::= <<
|
||||||
|
root_0 = <action>;<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** What is the name of the previous value of this rule's root tree? This
|
||||||
|
* let's us refer to $rule to mean previous value. I am reusing the
|
||||||
|
* variable 'tree' sitting in retval struct to hold the value of root_0 right
|
||||||
|
* before I set it during rewrites. The assign will be to retval.tree.
|
||||||
|
*/
|
||||||
|
prevRuleRootRef() ::= "retval"
|
||||||
|
|
||||||
|
rewriteRuleRef(rule) ::= <<
|
||||||
|
adaptor.addChild(root_<treeLevel>, stream_<rule>.nextTree());<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteRuleRefRoot(rule) ::= <<
|
||||||
|
root_<treeLevel> = <ASTLabelType>(adaptor.becomeRoot(stream_<rule>.nextNode(), root_<treeLevel>));<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteNodeAction(action) ::= <<
|
||||||
|
adaptor.addChild(root_<treeLevel>, <action>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteNodeActionRoot(action) ::= <<
|
||||||
|
root_<treeLevel> = <ASTLabelType>(adaptor.becomeRoot(<action>, root_<treeLevel>));<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen $ruleLabel ... where defined via ruleLabel=rule */
|
||||||
|
rewriteRuleLabelRef(label) ::= <<
|
||||||
|
adaptor.addChild(root_<treeLevel>, stream_<label>.nextTree());<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen $ruleLabel ... where defined via ruleLabel+=rule */
|
||||||
|
rewriteRuleListLabelRef(label) ::= <<
|
||||||
|
adaptor.addChild(root_<treeLevel>, stream_<label>.nextTree());<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen ^($ruleLabel ...) where ruleLabel=rule */
|
||||||
|
rewriteRuleLabelRefRoot(label) ::= <<
|
||||||
|
root_<treeLevel> = <ASTLabelType>(adaptor.becomeRoot(stream_<label>.nextNode(), root_<treeLevel>));<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen ^($ruleLabel ...) where ruleLabel+=rule */
|
||||||
|
rewriteRuleListLabelRefRoot(label) ::= <<
|
||||||
|
root_<treeLevel> = <ASTLabelType>(adaptor.becomeRoot(stream_<label>.nextNode(), root_<treeLevel>));<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
createImaginaryNode(tokenType,hetero,args) ::= <<
|
||||||
|
<if(hetero)>
|
||||||
|
<! new MethodNode(IDLabel, args) !>
|
||||||
|
new <hetero>(<tokenType><if(args)>, <args; separator=", "><endif>)
|
||||||
|
<else>
|
||||||
|
<ASTLabelType>(adaptor.create(<tokenType>, <args; separator=", "><if(!args)>"<tokenType>"<endif>))
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
createRewriteNodeFromElement(token,hetero,args) ::= <<
|
||||||
|
<if(hetero)>
|
||||||
|
new <hetero>(stream_<token>.nextToken()<if(args)>, <args; separator=", "><endif>)
|
||||||
|
<else>
|
||||||
|
<if(args)> <! must create new node from old !>
|
||||||
|
adaptor.create(<token>, <args; separator=", ">)
|
||||||
|
<else>
|
||||||
|
stream_<token>.nextNode()
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
>>
|
190
antlr_3_1_source/codegen/templates/ActionScript/ASTParser.stg
Normal file
190
antlr_3_1_source/codegen/templates/ActionScript/ASTParser.stg
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Templates for building ASTs during normal parsing.
|
||||||
|
*
|
||||||
|
* Deal with many combinations. Dimensions are:
|
||||||
|
* Auto build or rewrite
|
||||||
|
* no label, label, list label (label/no-label handled together)
|
||||||
|
* child, root
|
||||||
|
* token, set, rule, wildcard
|
||||||
|
*
|
||||||
|
* The situation is not too bad as rewrite (->) usage makes ^ and !
|
||||||
|
* invalid. There is no huge explosion of combinations.
|
||||||
|
*/
|
||||||
|
group ASTParser;
|
||||||
|
|
||||||
|
@rule.setErrorReturnValue() ::= <<
|
||||||
|
retval.tree = <ASTLabelType>(adaptor.errorNode(input, Token(retval.start), input.LT(-1), re));
|
||||||
|
<! trace("<ruleName> returns "+((CommonTree)retval.tree).toStringTree()); !>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// TOKEN AST STUFF
|
||||||
|
|
||||||
|
/** ID and output=AST */
|
||||||
|
tokenRef(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) {<endif>
|
||||||
|
<label>_tree = <createNodeFromToken(...)>;
|
||||||
|
adaptor.addChild(root_0, <label>_tree);
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ID! and output=AST (same as plain tokenRef) */
|
||||||
|
tokenRefBang(token,label,elementIndex) ::= "<super.tokenRef(...)>"
|
||||||
|
|
||||||
|
/** ID^ and output=AST */
|
||||||
|
tokenRefRuleRoot(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) {<endif>
|
||||||
|
<label>_tree = <createNodeFromToken(...)>;
|
||||||
|
root_0 = <ASTLabelType>(adaptor.becomeRoot(<label>_tree, root_0));
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ids+=ID! and output=AST */
|
||||||
|
tokenRefBangAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefBang(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** label+=TOKEN when output=AST but not rewrite alt */
|
||||||
|
tokenRefAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRef(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Match label+=TOKEN^ when output=AST but not rewrite alt */
|
||||||
|
tokenRefRuleRootAndListLabel(token,label,hetero,elementIndex) ::= <<
|
||||||
|
<tokenRefRuleRoot(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// SET AST
|
||||||
|
|
||||||
|
// the match set stuff is interesting in that it uses an argument list
|
||||||
|
// to pass code to the default matchSet; another possible way to alter
|
||||||
|
// inherited code. I don't use the region stuff because I need to pass
|
||||||
|
// different chunks depending on the operator. I don't like making
|
||||||
|
// the template name have the operator as the number of templates gets
|
||||||
|
// large but this is the most flexible--this is as opposed to having
|
||||||
|
// the code generator call matchSet then add root code or ruleroot code
|
||||||
|
// plus list label plus ... The combinations might require complicated
|
||||||
|
// rather than just added on code. Investigate that refactoring when
|
||||||
|
// I have more time.
|
||||||
|
|
||||||
|
matchSet(s,label,hetero,elementIndex,postmatchCode) ::= <<
|
||||||
|
<super.matchSet(..., postmatchCode={<if(backtracking)>if ( state.backtracking==0 ) <endif>adaptor.addChild(root_0, <createNodeFromToken(...)>);})>
|
||||||
|
>>
|
||||||
|
|
||||||
|
matchRuleBlockSet(s,label,hetero,elementIndex,postmatchCode,treeLevel="0") ::= <<
|
||||||
|
<matchSet(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
matchSetBang(s,label,elementIndex,postmatchCode) ::= "<super.matchSet(...)>"
|
||||||
|
|
||||||
|
// note there is no matchSetTrack because -> rewrites force sets to be
|
||||||
|
// plain old blocks of alts: (A|B|...|C)
|
||||||
|
|
||||||
|
matchSetRuleRoot(s,label,hetero,elementIndex,debug) ::= <<
|
||||||
|
<if(label)>
|
||||||
|
<label>=<labelType>(input.LT(1));<\n>
|
||||||
|
<endif>
|
||||||
|
<super.matchSet(..., postmatchCode={<if(backtracking)>if ( state.backtracking==0 ) <endif>root_0 = <ASTLabelType>(adaptor.becomeRoot(<createNodeFromToken(...)>, root_0));})>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// RULE REF AST
|
||||||
|
|
||||||
|
/** rule when output=AST */
|
||||||
|
ruleRef(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<super.ruleRef(...)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) <endif>adaptor.addChild(root_0, <label>.tree);
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** rule! is same as normal rule ref */
|
||||||
|
ruleRefBang(rule,label,elementIndex,args,scope) ::= "<super.ruleRef(...)>"
|
||||||
|
|
||||||
|
/** rule^ */
|
||||||
|
ruleRefRuleRoot(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<super.ruleRef(...)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) <endif>root_0 = <ASTLabelType>(adaptor.becomeRoot(<label>.tree, root_0));
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule when output=AST */
|
||||||
|
ruleRefAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRef(...)>
|
||||||
|
<listLabel(elem=label+".tree",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule! when output=AST is a rule ref with list addition */
|
||||||
|
ruleRefBangAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefBang(...)>
|
||||||
|
<listLabel(elem=label+".tree",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule^ */
|
||||||
|
ruleRefRuleRootAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefRuleRoot(...)>
|
||||||
|
<listLabel(elem=label+".tree",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// WILDCARD AST
|
||||||
|
|
||||||
|
wildcard(label,elementIndex) ::= <<
|
||||||
|
<super.wildcard(...)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) {<endif>
|
||||||
|
<label>_tree = <ASTLabelType>(adaptor.create(<label>));
|
||||||
|
adaptor.addChild(root_0, <label>_tree);
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
wildcardBang(label,elementIndex) ::= "<super.wildcard(...)>"
|
||||||
|
|
||||||
|
wildcardRuleRoot(label,elementIndex) ::= <<
|
||||||
|
<super.wildcard(...)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) {<endif>
|
||||||
|
<label>_tree = <ASTLabelType>(adaptor.create(<label>));
|
||||||
|
root_0 = <ASTLabelType>(adaptor.becomeRoot(<label>_tree, root_0));
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
createNodeFromToken(label,hetero) ::= <<
|
||||||
|
<if(hetero)>
|
||||||
|
new <hetero>(<label>) <! new MethodNode(IDLabel) !>
|
||||||
|
<else>
|
||||||
|
<ASTLabelType>(adaptor.create(<label>))
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
ruleCleanUp() ::= <<
|
||||||
|
<super.ruleCleanUp()>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) {<\n><endif>
|
||||||
|
retval.tree = <ASTLabelType>(adaptor.rulePostProcessing(root_0));
|
||||||
|
adaptor.setTokenBoundaries(retval.tree, Token(retval.start), Token(retval.stop));
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
>>
|
@ -0,0 +1,257 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Templates for building ASTs during tree parsing.
|
||||||
|
*
|
||||||
|
* Deal with many combinations. Dimensions are:
|
||||||
|
* Auto build or rewrite
|
||||||
|
* no label, label, list label (label/no-label handled together)
|
||||||
|
* child, root
|
||||||
|
* token, set, rule, wildcard
|
||||||
|
*
|
||||||
|
* Each combination has its own template except that label/no label
|
||||||
|
* is combined into tokenRef, ruleRef, ...
|
||||||
|
*/
|
||||||
|
group ASTTreeParser;
|
||||||
|
|
||||||
|
/** Add a variable to track last element matched */
|
||||||
|
ruleDeclarations() ::= <<
|
||||||
|
<super.ruleDeclarations()>
|
||||||
|
var _first_0:<ASTLabelType> = null;
|
||||||
|
var _last:<ASTLabelType> = null;<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** What to emit when there is no rewrite rule. For auto build
|
||||||
|
* mode, does nothing.
|
||||||
|
*/
|
||||||
|
noRewrite(rewriteBlockLevel, treeLevel) ::= <<
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) {<endif>
|
||||||
|
<if(rewriteMode)>
|
||||||
|
retval.tree = <ASTLabelType>(_first_0);
|
||||||
|
if ( adaptor.getParent(retval.tree)!=null && adaptor.isNil( adaptor.getParent(retval.tree) ) )
|
||||||
|
retval.tree = <ASTLabelType>(adaptor.getParent(retval.tree));
|
||||||
|
<endif>
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** match ^(root children) in tree parser; override here to
|
||||||
|
* add tree construction actions.
|
||||||
|
*/
|
||||||
|
tree(root, actionsAfterRoot, children, nullableChildList,
|
||||||
|
enclosingTreeLevel, treeLevel) ::= <<
|
||||||
|
_last = <ASTLabelType>(input.LT(1));
|
||||||
|
{
|
||||||
|
var _save_last_<treeLevel>:<ASTLabelType> = _last;
|
||||||
|
var _first_<treeLevel>:<ASTLabelType> = null;
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
var root_<treeLevel>:<ASTLabelType> = <ASTLabelType>(adaptor.nil());
|
||||||
|
<endif>
|
||||||
|
<root:element()>
|
||||||
|
<if(rewriteMode)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 )<endif>
|
||||||
|
<if(root.el.rule)>
|
||||||
|
if ( _first_<enclosingTreeLevel>==null ) _first_<enclosingTreeLevel> = <root.el.label>.tree;
|
||||||
|
<else>
|
||||||
|
if ( _first_<enclosingTreeLevel>==null ) _first_<enclosingTreeLevel> = <root.el.label>;
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
<actionsAfterRoot:element()>
|
||||||
|
<if(nullableChildList)>
|
||||||
|
if ( input.LA(1)==TokenConstants.DOWN ) {
|
||||||
|
match(input, TokenConstants.DOWN, null); <checkRuleBacktrackFailure()>
|
||||||
|
<children:element()>
|
||||||
|
match(input, TokenConstants.UP, null); <checkRuleBacktrackFailure()>
|
||||||
|
}
|
||||||
|
<else>
|
||||||
|
match(input, TokenConstants.DOWN, null); <checkRuleBacktrackFailure()>
|
||||||
|
<children:element()>
|
||||||
|
match(input, TokenConstants.UP, null); <checkRuleBacktrackFailure()>
|
||||||
|
<endif>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
adaptor.addChild(root_<enclosingTreeLevel>, root_<treeLevel>);
|
||||||
|
<endif>
|
||||||
|
_last = _save_last_<treeLevel>;
|
||||||
|
}<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// TOKEN AST STUFF
|
||||||
|
|
||||||
|
/** ID! and output=AST (same as plain tokenRef) 'cept add
|
||||||
|
* setting of _last
|
||||||
|
*/
|
||||||
|
tokenRefBang(token,label,elementIndex) ::= <<
|
||||||
|
_last = <ASTLabelType>(input.LT(1));
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ID auto construct */
|
||||||
|
tokenRef(token,label,elementIndex,hetero) ::= <<
|
||||||
|
_last = <ASTLabelType>(input.LT(1));
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) {<endif>
|
||||||
|
<if(hetero)>
|
||||||
|
<label>_tree = new <hetero>(<label>);
|
||||||
|
<else>
|
||||||
|
<label>_tree = <ASTLabelType>(adaptor.dupNode(<label>));
|
||||||
|
<endif><\n>
|
||||||
|
adaptor.addChild(root_<treeLevel>, <label>_tree);
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
<else> <! rewrite mode !>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 )<endif>
|
||||||
|
if ( _first_<treeLevel>==null ) _first_<treeLevel> = <label>;
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** label+=TOKEN auto construct */
|
||||||
|
tokenRefAndListLabel(token,label,elementIndex) ::= <<
|
||||||
|
<tokenRef(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(ID ...) auto construct */
|
||||||
|
tokenRefRuleRoot(token,label,elementIndex,hetero) ::= <<
|
||||||
|
_last = <ASTLabelType>(input.LT(1));
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) {<endif>
|
||||||
|
<if(hetero)>
|
||||||
|
<label>_tree = new <hetero>(<label>);
|
||||||
|
<else>
|
||||||
|
<label>_tree = <ASTLabelType>(adaptor.dupNode(<label>));
|
||||||
|
<endif><\n>
|
||||||
|
root_<treeLevel> = <ASTLabelType>(adaptor.becomeRoot(<label>_tree, root_<treeLevel>));
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Match ^(label+=TOKEN ...) auto construct */
|
||||||
|
tokenRefRuleRootAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefRuleRoot(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// SET AST
|
||||||
|
|
||||||
|
matchSet(s,label,hetero,elementIndex,postmatchCode) ::= <<
|
||||||
|
_last = <ASTLabelType>(input.LT(1));
|
||||||
|
<super.matchSet(..., postmatchCode={
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) {<endif>
|
||||||
|
<if(hetero)>
|
||||||
|
<label>_tree = new <hetero>(<label>);
|
||||||
|
<else>
|
||||||
|
<label>_tree = <ASTLabelType>(adaptor.dupNode(<label>));
|
||||||
|
<endif><\n>
|
||||||
|
adaptor.addChild(root_<treeLevel>, <label>_tree);
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
<endif>
|
||||||
|
}
|
||||||
|
)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
matchRuleBlockSet(s,label,hetero,elementIndex,postmatchCode,treeLevel="0") ::= <<
|
||||||
|
<matchSet(...)>
|
||||||
|
<noRewrite()> <! set return tree !>
|
||||||
|
>>
|
||||||
|
|
||||||
|
matchSetBang(s,label,elementIndex,postmatchCode) ::= <<
|
||||||
|
_last = <ASTLabelType>(input.LT(1));
|
||||||
|
<super.matchSet(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
matchSetRuleRoot(s,label,hetero,elementIndex,debug) ::= <<
|
||||||
|
<super.matchSet(..., postmatchCode={
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) {<endif>
|
||||||
|
<if(hetero)>
|
||||||
|
<label>_tree = new <hetero>(<label>);
|
||||||
|
<else>
|
||||||
|
<label>_tree = <ASTLabelType>(adaptor.dupNode(<label>));
|
||||||
|
<endif><\n>
|
||||||
|
root_<treeLevel> = <ASTLabelType>(adaptor.becomeRoot(<label>_tree, root_<treeLevel>));
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
<endif>
|
||||||
|
}
|
||||||
|
)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// RULE REF AST
|
||||||
|
|
||||||
|
/** rule auto construct */
|
||||||
|
ruleRef(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
_last = <ASTLabelType>(input.LT(1));
|
||||||
|
<super.ruleRef(...)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) <endif>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
adaptor.addChild(root_<treeLevel>, <label>.getTree());
|
||||||
|
<else> <! rewrite mode !>
|
||||||
|
if ( _first_<treeLevel>==null ) _first_<treeLevel> = <label>.tree;
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule auto construct */
|
||||||
|
ruleRefAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRef(...)>
|
||||||
|
<listLabel(elem=label+".tree",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(rule ...) auto construct */
|
||||||
|
ruleRefRuleRoot(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
_last = <ASTLabelType>(input.LT(1));
|
||||||
|
<super.ruleRef(...)>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) <endif>root_<treeLevel> = <ASTLabelType>(adaptor.becomeRoot(<label>.tree, root_<treeLevel>));
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(x+=rule ...) auto construct */
|
||||||
|
ruleRefRuleRootAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefRuleRoot(...)>
|
||||||
|
<listLabel(elem=label+".tree",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Streams for token refs are tree nodes now; override to
|
||||||
|
* change nextToken to nextNode.
|
||||||
|
*/
|
||||||
|
createRewriteNodeFromElement(token,hetero,scope) ::= <<
|
||||||
|
<if(hetero)>
|
||||||
|
new <hetero>(stream_<token>.nextNode())
|
||||||
|
<else>
|
||||||
|
stream_<token>.nextNode()
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
ruleCleanUp() ::= <<
|
||||||
|
<super.ruleCleanUp()>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) {<\n><endif>
|
||||||
|
retval.tree = <ASTLabelType>(adaptor.rulePostProcessing(root_0));
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
<endif>
|
||||||
|
>>
|
1289
antlr_3_1_source/codegen/templates/ActionScript/ActionScript.stg
Normal file
1289
antlr_3_1_source/codegen/templates/ActionScript/ActionScript.stg
Normal file
File diff suppressed because it is too large
Load Diff
547
antlr_3_1_source/codegen/templates/C/AST.stg
Normal file
547
antlr_3_1_source/codegen/templates/C/AST.stg
Normal file
@ -0,0 +1,547 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
group AST;
|
||||||
|
|
||||||
|
/** Add an adaptor property that knows how to build trees */
|
||||||
|
@headerFile.members() ::= <<
|
||||||
|
/* @headerFile.members() */
|
||||||
|
pANTLR3_BASE_TREE_ADAPTOR adaptor;
|
||||||
|
pANTLR3_VECTOR_FACTORY vectors;
|
||||||
|
/* End @headerFile.members() */
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Install the tree adaptor interface pointer and anything else that
|
||||||
|
* tree parsers and producers require.
|
||||||
|
*/
|
||||||
|
@genericParser.apifuncs() ::= <<
|
||||||
|
<if(PARSER)>
|
||||||
|
ADAPTOR = ANTLR3_TREE_ADAPTORNew(instream->tstream->tokenSource->strFactory);<\n>
|
||||||
|
<endif>
|
||||||
|
ctx->vectors = antlr3VectorFactoryNew(64);
|
||||||
|
>>
|
||||||
|
|
||||||
|
@genericParser.cleanup() ::= <<
|
||||||
|
ctx->vectors->close(ctx->vectors);
|
||||||
|
<if(PARSER)>
|
||||||
|
/* We created the adaptor so we must free it
|
||||||
|
*/
|
||||||
|
ADAPTOR->free(ADAPTOR);
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
@returnScope.ruleReturnMembers() ::= <<
|
||||||
|
|
||||||
|
<recognizer.ASTLabelType> tree;
|
||||||
|
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Add a variable to track rule's return AST */
|
||||||
|
ruleDeclarations() ::= <<
|
||||||
|
<super.ruleDeclarations()>
|
||||||
|
<ASTLabelType> root_0;<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
ruleInitializations() ::= <<
|
||||||
|
<super.ruleInitializations()>
|
||||||
|
root_0 = NULL;<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
ruleLabelDefs() ::= <<
|
||||||
|
<super.ruleLabelDefs()>
|
||||||
|
<ruleDescriptor.tokenLabels:{<ASTLabelType> <it.label.text>_tree;}; separator="\n">
|
||||||
|
<ruleDescriptor.tokenListLabels:{<ASTLabelType> <it.label.text>_tree;}; separator="\n">
|
||||||
|
<ruleDescriptor.allTokenRefsInAltsWithRewrites
|
||||||
|
:{pANTLR3_REWRITE_RULE_<rewriteElementType>_STREAM stream_<it>;}; separator="\n">
|
||||||
|
<ruleDescriptor.allRuleRefsInAltsWithRewrites
|
||||||
|
:{pANTLR3_REWRITE_RULE_SUBTREE_STREAM stream_<it>;}; separator="\n">
|
||||||
|
>>
|
||||||
|
|
||||||
|
ruleLabelInitializations() ::= <<
|
||||||
|
<super.ruleLabelInitializations()>
|
||||||
|
<ruleDescriptor.tokenLabels:{<it.label.text>_tree = NULL;}; separator="\n">
|
||||||
|
<ruleDescriptor.tokenListLabels:{<it.label.text>_tree = NULL;}; separator="\n">
|
||||||
|
<ruleDescriptor.allTokenRefsInAltsWithRewrites
|
||||||
|
:{stream_<it> = antlr3RewriteRule<rewriteElementType>StreamNewAE(ADAPTOR, RECOGNIZER, (pANTLR3_UINT8)"token <it>"); }; separator="\n">
|
||||||
|
<ruleDescriptor.allRuleRefsInAltsWithRewrites
|
||||||
|
:{stream_<it>=antlr3RewriteRuleSubtreeStreamNewAE(ADAPTOR, RECOGNIZER, (pANTLR3_UINT8)"rule <it>");}; separator="\n">
|
||||||
|
<if(ruleDescriptor.hasMultipleReturnValues)>
|
||||||
|
retval.tree = NULL;
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** a rule label including default value */
|
||||||
|
ruleLabelInitVal(label) ::= <<
|
||||||
|
<super.ruleLabelInitVal(...)>
|
||||||
|
<label.label.text>.tree = <initValue(typeName=ruleLabelType(referencedRule=label.referencedRule))>;<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** When doing auto AST construction, we must define some variables;
|
||||||
|
* These should be turned off if doing rewrites. This must be a "mode"
|
||||||
|
* as a rule could have both rewrite and AST within the same alternative
|
||||||
|
* block.
|
||||||
|
*/
|
||||||
|
@alt.declarations() ::= <<
|
||||||
|
<if(autoAST)>
|
||||||
|
<if(outerAlt)>
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
@alt.initializations() ::= <<
|
||||||
|
<if(autoAST)>
|
||||||
|
<if(outerAlt)>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
root_0 = (<ASTLabelType>)(ADAPTOR->nilNode(ADAPTOR));<\n>
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
|
||||||
|
// T r a c k i n g R u l e E l e m e n t s
|
||||||
|
//
|
||||||
|
/** ID but track it for use in a rewrite rule */
|
||||||
|
tokenRefTrack(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefBang(...)> <! Track implies no auto AST construction!>
|
||||||
|
<if(backtracking)>if ( BACKTRACKING==0 ) <endif>stream_<token>->add(stream_<token>, <label>, NULL);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ids+=ID and track it for use in a rewrite rule; adds to ids *and*
|
||||||
|
* to the tracking list stream_ID for use in the rewrite.
|
||||||
|
*/
|
||||||
|
tokenRefTrackAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefTrack(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(ID ...) track for rewrite */
|
||||||
|
tokenRefRuleRootTrack(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefBang(...)>
|
||||||
|
<if(backtracking)>if ( BACKTRACKING==0 ) <endif>stream_<token>->add(stream_<token>, <label>, NULL);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
wildcardTrack(label,elementIndex) ::= <<
|
||||||
|
<super.wildcard(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** rule when output=AST and tracking for rewrite */
|
||||||
|
ruleRefTrack(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<super.ruleRef(...)>
|
||||||
|
<if(backtracking)>if ( BACKTRACKING==0 ) <endif>stream_<rule.name>->add(stream_<rule.name>, <label>.tree, NULL);
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule when output=AST and tracking for rewrite */
|
||||||
|
ruleRefTrackAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefTrack(...)>
|
||||||
|
<listLabelTrack(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(rule ...) rewrite */
|
||||||
|
ruleRefRuleRootTrack(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefRuleRoot(...)>
|
||||||
|
<if(backtracking)>if ( BACKTRACKING==0 ) <endif>stream_<rule.name>->add(stream_<rule.name>, <label>.tree, NULL);
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(x+=rule ...) rewrite */
|
||||||
|
ruleRefRuleRootTrackAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefRuleRootTrack(...)>
|
||||||
|
<listLabelAST(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
|
||||||
|
// RULE REF AST
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Match ^(label+=TOKEN ...) track for rewrite */
|
||||||
|
tokenRefRuleRootTrackAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefRuleRootTrack(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
|
||||||
|
/* How to accumulate lists when we are doing rewrite tracking...
|
||||||
|
*/
|
||||||
|
listLabelTrack(label) ::= <<
|
||||||
|
/* listLabelTrack(label)
|
||||||
|
*/
|
||||||
|
if (list_<label> == NULL)
|
||||||
|
{
|
||||||
|
list_<label>=ctx->vectors->newVector(ctx->vectors);
|
||||||
|
}
|
||||||
|
list_<label>->add(list_<label>, <label>.tree, NULL);
|
||||||
|
>>
|
||||||
|
|
||||||
|
/* How to accumulate lists of rule outputs (only allowed with AST
|
||||||
|
* option but if the user is going to walk the tree, they will want
|
||||||
|
* all their custom elements from rule returns.
|
||||||
|
*
|
||||||
|
* Normally, we use inline structures (which the compiler lays down
|
||||||
|
* code to copy from heap allocations. However, here we want to accumulate copies
|
||||||
|
* of the returned structures because we are adding them to a list. This only makes sense if the
|
||||||
|
* grammar is not rewriting the tree as a tree rewrite only preserves the tree, not the object/structure
|
||||||
|
* returned from the rule. The rewrite will extract the tree pointer. However, if we are not going to
|
||||||
|
* do a tree re-write, then the user may wish to iterate the structures returned by the rule in
|
||||||
|
* action code and will expect the user defined returns[] elements to be available when they do this.
|
||||||
|
* Hence we cannot just preserve the tree that was returned. So, we must copy the local structure and provide
|
||||||
|
* a function that can free the allocated space. We cannot know how to free user allocated elements and
|
||||||
|
* presume that the user will know to do this using their own factories for the structures they allocate.
|
||||||
|
*/
|
||||||
|
listLabelAST(label) ::= <<
|
||||||
|
if (list_<label> == NULL)
|
||||||
|
{
|
||||||
|
list_<label>=ctx->vectors->newVector(ctx->vectors);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
RETURN_TYPE_<label> * tcopy;
|
||||||
|
|
||||||
|
tcopy = ANTLR3_CALLOC(1, sizeof(RETURN_TYPE_<label>)); /* Note no memory allocation checks! */
|
||||||
|
ANTLR3_MEMMOVE((void *)(tcopy), (const void *)&<label>, sizeof(RETURN_TYPE_<label>));
|
||||||
|
list_<label>->add(list_<label>, tcopy, freeScope); /* Add whatever the return type is */<\n>
|
||||||
|
}
|
||||||
|
>>
|
||||||
|
|
||||||
|
// R e w r i t e
|
||||||
|
|
||||||
|
rewriteCode(
|
||||||
|
alts,
|
||||||
|
description,
|
||||||
|
referencedElementsDeep, // ALL referenced elements to right of ->
|
||||||
|
referencedTokenLabels,
|
||||||
|
referencedTokenListLabels,
|
||||||
|
referencedRuleLabels,
|
||||||
|
referencedRuleListLabels,
|
||||||
|
rewriteBlockLevel,
|
||||||
|
enclosingTreeLevel,
|
||||||
|
treeLevel) ::=
|
||||||
|
<<
|
||||||
|
|
||||||
|
/* AST REWRITE
|
||||||
|
* elements : <referencedElementsDeep; separator=", ">
|
||||||
|
* token labels : <referencedTokenLabels; separator=", ">
|
||||||
|
* rule labels : <referencedRuleLabels; separator=", ">
|
||||||
|
* token list labels : <referencedTokenListLabels; separator=", ">
|
||||||
|
* rule list labels : <referencedRuleListLabels; separator=", ">
|
||||||
|
*/
|
||||||
|
<if(backtracking)>
|
||||||
|
if ( BACKTRACKING==0 ) <\n>
|
||||||
|
<endif>
|
||||||
|
{
|
||||||
|
<rewriteCodeLabelsDecl()>
|
||||||
|
<rewriteCodeLabelsInit()>
|
||||||
|
root_0 = (<ASTLabelType>)(ADAPTOR->nilNode(ADAPTOR));
|
||||||
|
<prevRuleRootRef()>.tree = root_0;
|
||||||
|
<alts:rewriteAlt(); separator="else ">
|
||||||
|
<if(TREE_PARSER)>
|
||||||
|
<if(rewriteMode)>
|
||||||
|
<prevRuleRootRef()>.tree = (<ASTLabelType>)(ADAPTOR->rulePostProcessing(ADAPTOR, root_0));
|
||||||
|
INPUT->replaceChildren(INPUT, ADAPTOR->getParent(ADAPTOR, retval.start),
|
||||||
|
ADAPTOR->getChildIndex(ADAPTOR, retval.start),
|
||||||
|
ADAPTOR->getChildIndex(ADAPTOR, _last),
|
||||||
|
retval.tree);
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
<prevRuleRootRef()>.tree = root_0; // set result root
|
||||||
|
<rewriteCodeLabelsFree()>
|
||||||
|
|
||||||
|
}
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteCodeLabelsDecl() ::= <<
|
||||||
|
<referencedTokenLabels
|
||||||
|
:{pANTLR3_REWRITE_RULE_<rewriteElementType>_STREAM stream_<it>;};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
<referencedTokenListLabels
|
||||||
|
:{pANTLR3_REWRITE_RULE_<rewriteElementType>_STREAM stream_<it>;};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
<referencedRuleLabels
|
||||||
|
:{pANTLR3_REWRITE_RULE_SUBTREE_STREAM stream_<it>;};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
<referencedRuleListLabels
|
||||||
|
:{pANTLR3_REWRITE_RULE_SUBTREE_STREAM stream_<it>;};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteCodeLabelsInit() ::= <<
|
||||||
|
<referencedTokenLabels
|
||||||
|
:{stream_<it>=antlr3RewriteRule<rewriteElementType>StreamNewAEE(ADAPTOR, RECOGNIZER, (pANTLR3_UINT8)"token <it>", <it>);};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
<referencedTokenListLabels
|
||||||
|
:{stream_<it>=antlr3RewriteRule<rewriteElementType>StreamNewAEV(ADAPTOR, RECOGNIZER, (pANTLR3_UINT8)"token <it>", list_<it>); };
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
<referencedRuleLabels
|
||||||
|
:{stream_<it>=antlr3RewriteRuleSubtreeStreamNewAEE(ADAPTOR, RECOGNIZER, (pANTLR3_UINT8)"token <it>", <it>.tree != NULL ? <it>.tree : NULL);};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
<referencedRuleListLabels
|
||||||
|
:{stream_<it>=antlr3RewriteRuleSubtreeStreamNewAEV(ADAPTOR, RECOGNIZER, (pANTLR3_UINT8)"token <it>", list_<it>);};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
>>
|
||||||
|
rewriteCodeLabelsFree() ::= <<
|
||||||
|
<referencedTokenLabels
|
||||||
|
:{stream_<it>->free(stream_<it>);};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
<referencedTokenListLabels
|
||||||
|
:{stream_<it>->free(stream_<it>);};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
<referencedRuleLabels
|
||||||
|
:{stream_<it>->free(stream_<it>);};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
<referencedRuleListLabels
|
||||||
|
:{stream_<it>->free(stream_<it>);};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Generate code for an optional rewrite block; note it uses the deep ref'd element
|
||||||
|
* list rather shallow like other blocks.
|
||||||
|
*/
|
||||||
|
rewriteOptionalBlock(
|
||||||
|
alt,
|
||||||
|
rewriteBlockLevel,
|
||||||
|
referencedElementsDeep, // all nested refs
|
||||||
|
referencedElements, // elements in immediately block; no nested blocks
|
||||||
|
description) ::=
|
||||||
|
<<
|
||||||
|
// <fileName>:<description>
|
||||||
|
{
|
||||||
|
if ( <referencedElementsDeep:{el | stream_<el>->hasNext(stream_<el>)}; separator="||"> )
|
||||||
|
{
|
||||||
|
<alt>
|
||||||
|
}
|
||||||
|
<referencedElementsDeep:{el | stream_<el>->reset(stream_<el>);<\n>}>
|
||||||
|
}<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteClosureBlock(
|
||||||
|
alt,
|
||||||
|
rewriteBlockLevel,
|
||||||
|
referencedElementsDeep, // all nested refs
|
||||||
|
referencedElements, // elements in immediately block; no nested blocks
|
||||||
|
description) ::=
|
||||||
|
<<
|
||||||
|
// <fileName>:<description>
|
||||||
|
{
|
||||||
|
while ( <referencedElements:{el | stream_<el>->hasNext(stream_<el>)}; separator="||"> )
|
||||||
|
{
|
||||||
|
<alt>
|
||||||
|
}
|
||||||
|
<referencedElements:{el | stream_<el>->reset(stream_<el>);<\n>}>
|
||||||
|
}<\n>
|
||||||
|
>>
|
||||||
|
RewriteEarlyExitException() ::=
|
||||||
|
<<
|
||||||
|
CONSTRUCTEX();
|
||||||
|
EXCEPTION->type = ANTLR3_REWRITE_EARLY_EXCEPTION;
|
||||||
|
EXCEPTION->name = (void *)ANTLR3_REWRITE_EARLY_EXCEPTION_NAME;
|
||||||
|
>>
|
||||||
|
rewritePositiveClosureBlock(
|
||||||
|
alt,
|
||||||
|
rewriteBlockLevel,
|
||||||
|
referencedElementsDeep, // all nested refs
|
||||||
|
referencedElements, // elements in immediately block; no nested blocks
|
||||||
|
description) ::=
|
||||||
|
<<
|
||||||
|
if ( !(<referencedElements:{el | stream_<el>->hasNext(stream_<el>)}; separator="||">) )
|
||||||
|
{
|
||||||
|
<RewriteEarlyExitException()>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while ( <referencedElements:{el | stream_<el>->hasNext(stream_<el>)}; separator="||"> ) {
|
||||||
|
<alt>
|
||||||
|
}
|
||||||
|
<referencedElements:{el | stream_<el>->reset(stream_<el>);<\n>}>
|
||||||
|
}
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteAlt(a) ::= <<
|
||||||
|
// <a.description>
|
||||||
|
<if(a.pred)>
|
||||||
|
if (<a.pred>)
|
||||||
|
{
|
||||||
|
<a.alt>
|
||||||
|
}<\n>
|
||||||
|
<else>
|
||||||
|
{
|
||||||
|
<a.alt>
|
||||||
|
}<\n>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** For empty rewrites: "r : ... -> ;" */
|
||||||
|
rewriteEmptyAlt() ::= "root_0 = NULL; /* \<-- rewriteEmptyAlt()) */"
|
||||||
|
|
||||||
|
rewriteTree(root,children,description,enclosingTreeLevel,treeLevel) ::= <<
|
||||||
|
// <fileName>:<description>
|
||||||
|
{
|
||||||
|
<ASTLabelType> root_<treeLevel> = (<ASTLabelType>)(ADAPTOR->nilNode(ADAPTOR));
|
||||||
|
<root:rewriteElement()>
|
||||||
|
<children:rewriteElement()>
|
||||||
|
ADAPTOR->addChild(ADAPTOR, root_<enclosingTreeLevel>, root_<treeLevel>);
|
||||||
|
}<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteElementList(elements) ::= "<elements:rewriteElement()>"
|
||||||
|
|
||||||
|
rewriteElement(e) ::= <<
|
||||||
|
<@pregen()>
|
||||||
|
<e.el>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen ID or ID[args] */
|
||||||
|
rewriteTokenRef(token,elementIndex,hetero,args) ::= <<
|
||||||
|
ADAPTOR->addChild(ADAPTOR, root_<treeLevel>, <createRewriteNodeFromElement(...)>);<\n>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen $label ... where defined via label=ID */
|
||||||
|
rewriteTokenLabelRef(label,elementIndex) ::= <<
|
||||||
|
ADAPTOR->addChild(ADAPTOR, root_<treeLevel>, stream_<label>->nextNode(stream_<label>));<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen $label ... where defined via label+=ID */
|
||||||
|
rewriteTokenListLabelRef(label,elementIndex) ::= <<
|
||||||
|
ADAPTOR->addChild(ADAPTOR, root_<treeLevel>, stream_<label>->nextNode(stream_<label>));<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen ^($label ...) */
|
||||||
|
rewriteTokenLabelRefRoot(label,elementIndex) ::= <<
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)(ADAPTOR->becomeRootToken(ADAPTOR, stream_<label>->nextToken(stream_<label>), root_<treeLevel>));<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen ^($label ...) where label+=... */
|
||||||
|
rewriteTokenListLabelRefRoot ::= rewriteTokenLabelRefRoot
|
||||||
|
|
||||||
|
/** Gen ^(ID ...) or ^(ID[args] ...) */
|
||||||
|
rewriteTokenRefRoot(token,elementIndex,hetero,args) ::= <<
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)(ADAPTOR->becomeRoot(ADAPTOR, <createRewriteNodeFromElement(...)>, root_<treeLevel>));<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteImaginaryTokenRef(args,token,hetero,elementIndex) ::= <<
|
||||||
|
ADAPTOR->addChild(ADAPTOR, root_<treeLevel>, <createImaginaryNode(tokenType=token, ...)>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteImaginaryTokenRefRoot(args,token,hetero,elementIndex) ::= <<
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)(ADAPTOR->becomeRoot(ADAPTOR, <createImaginaryNode(tokenType=token, ...)>, root_<treeLevel>));<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** plain -> {foo} action */
|
||||||
|
rewriteAction(action) ::= <<
|
||||||
|
root_0 = <action>;<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** What is the name of the previous value of this rule's root tree? This
|
||||||
|
* let's us refer to $rule to mean previous value. I am reusing the
|
||||||
|
* variable 'tree' sitting in retval struct to hold the value of root_0 right
|
||||||
|
* before I set it during rewrites. The assign will be to retval.tree.
|
||||||
|
*/
|
||||||
|
prevRuleRootRef() ::= "retval"
|
||||||
|
|
||||||
|
rewriteRuleRef(rule,dup) ::= <<
|
||||||
|
ADAPTOR->addChild(ADAPTOR, root_<treeLevel>, stream_<rule>->nextTree(stream_<rule>));<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteRuleRefRoot(rule,dup) ::= <<
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)(ADAPTOR->becomeRoot(ADAPTOR, stream_<rule>->nextNode(stream_<rule>), root_<treeLevel>));<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteNodeAction(action) ::= <<
|
||||||
|
ADAPTOR->addChild(ADAPTOR, root_<treeLevel>, <action>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteNodeActionRoot(action) ::= <<
|
||||||
|
root_<treeLevel> = (<ASLabelType>)(ADAPTOR->becomeRoot(ADAPTOR, <action>, root_<treeLevel>));<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen $ruleLabel ... where defined via ruleLabel=rule */
|
||||||
|
rewriteRuleLabelRef(label) ::= <<
|
||||||
|
ADAPTOR->addChild(ADAPTOR, root_<treeLevel>, stream_<label>->nextTree(stream_<label>));<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen $ruleLabel ... where defined via ruleLabel+=rule */
|
||||||
|
rewriteRuleListLabelRef(label) ::= <<
|
||||||
|
ADAPTOR->addChild(ADAPTOR, root_<treeLevel>, stream_<label>->nextTree(stream_<label>));<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen ^($ruleLabel ...) where ruleLabel=rule */
|
||||||
|
rewriteRuleLabelRefRoot(label) ::= <<
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)(ADAPTOR->becomeRoot(ADAPTOR, stream_<label>->nextNode(stream_<label>), root_<treeLevel>));<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen ^($ruleLabel ...) where ruleLabel+=rule */
|
||||||
|
rewriteRuleListLabelRefRoot(label) ::= <<
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)(ADAPTOR->becomeRoot((<ASTLabelType>)(stream_<label>->nextNode(stream_<label>), root_<treeLevel>));<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
createImaginaryNode(tokenType,hetero,args) ::= <<
|
||||||
|
<if(hetero)>
|
||||||
|
<! new MethodNode(IDLabel, args) !>
|
||||||
|
<hetero>New(<tokenType><if(args)>, <args; separator=", "><endif>)
|
||||||
|
<else>
|
||||||
|
<if(args)>
|
||||||
|
|
||||||
|
#if <length(args)> == 2
|
||||||
|
(<ASTLabelType>)ADAPTOR->createTypeTokenText(ADAPTOR, <tokenType>, TOKTEXT(<args; separator=", ">))
|
||||||
|
#else
|
||||||
|
(<ASTLabelType>)ADAPTOR->createTypeText(ADAPTOR, <tokenType>, (pANTLR3_UINT8)<args; separator=", ">)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
<else>
|
||||||
|
(<ASTLabelType>)ADAPTOR->createTypeText(ADAPTOR, <tokenType>, (pANTLR3_UINT8)"<tokenType>")
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
createRewriteNodeFromElement(token,hetero,args) ::= <<
|
||||||
|
<if(hetero)>
|
||||||
|
<hetero>New(stream_<token>->nextToken(stream_<token>)<if(args)>, <args; separator=", "><endif>)
|
||||||
|
<else>
|
||||||
|
<if(args)> <! must create new node from old !>
|
||||||
|
|
||||||
|
#if <length(args)> == 2
|
||||||
|
ADAPTOR->createTypeTokenText(ADAPTOR, <token>->getType(<token>, TOKTEXT(<token>, <args; separator=", ">)) /* JIMI */
|
||||||
|
#else
|
||||||
|
ADAPTOR->createTypeToken(ADAPTOR, <token>->getType(<token>, <token>, <args; separator=", ">)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
<else>
|
||||||
|
stream_<token>->nextNode(stream_<token>)
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
>>
|
76
antlr_3_1_source/codegen/templates/C/ASTDbg.stg
Normal file
76
antlr_3_1_source/codegen/templates/C/ASTDbg.stg
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Template overrides to add debugging to AST stuff. Dynamic inheritance
|
||||||
|
* hierarchy is set up as ASTDbg : AST : Dbg : Java by code generator.
|
||||||
|
*/
|
||||||
|
group ASTDbg;
|
||||||
|
|
||||||
|
parserMembers() ::= <<
|
||||||
|
protected DebugTreeAdaptor adaptor =
|
||||||
|
new DebugTreeAdaptor(null,new CommonTreeAdaptor());
|
||||||
|
public void setTreeAdaptor(TreeAdaptor adaptor) {
|
||||||
|
this.adaptor = new DebugTreeAdaptor(dbg,adaptor);
|
||||||
|
}
|
||||||
|
public TreeAdaptor getTreeAdaptor() {
|
||||||
|
return adaptor;
|
||||||
|
}<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
parserCtorBody() ::= <<
|
||||||
|
<super.parserCtorBody()>
|
||||||
|
adaptor.setDebugListener(dbg);
|
||||||
|
>>
|
||||||
|
|
||||||
|
createListenerAndHandshake() ::= <<
|
||||||
|
DebugEventSocketProxy proxy =
|
||||||
|
new DebugEventSocketProxy(this,port,<if(TREE_PARSER)>input.getTreeAdaptor()<else>adaptor<endif>);
|
||||||
|
adaptor.setDebugListener(proxy);
|
||||||
|
setDebugListener(proxy);
|
||||||
|
set<inputStreamType>(new Debug<inputStreamType>(input,proxy));
|
||||||
|
try {
|
||||||
|
proxy.handshake();
|
||||||
|
}
|
||||||
|
catch (IOException ioe) {
|
||||||
|
reportError(ioe);
|
||||||
|
}
|
||||||
|
>>
|
||||||
|
|
||||||
|
ctorForPredefinedListener() ::= <<
|
||||||
|
public <name>(<inputStreamType> input, DebugEventListener dbg) {
|
||||||
|
super(input, dbg);
|
||||||
|
<if(profile)>
|
||||||
|
Profiler p = (Profiler)dbg;
|
||||||
|
p.setParser(this);<\n>
|
||||||
|
<endif>
|
||||||
|
<parserCtorBody()>
|
||||||
|
<grammar.directDelegates:{g|<g:delegateName()> = new <g.recognizerName>(input, dbg, state, this<grammar.delegators:{g|, <g:delegateName()>}>);}; separator="\n">
|
||||||
|
}<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
@rewriteElement.pregen() ::= "dbg.location(<e.line>,<e.pos>);"
|
203
antlr_3_1_source/codegen/templates/C/ASTParser.stg
Normal file
203
antlr_3_1_source/codegen/templates/C/ASTParser.stg
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Templates for building ASTs during normal parsing.
|
||||||
|
*
|
||||||
|
* Deal with many combinations. Dimensions are:
|
||||||
|
* Auto build or rewrite
|
||||||
|
* no label, label, list label (label/no-label handled together)
|
||||||
|
* child, root
|
||||||
|
* token, set, rule, wildcard
|
||||||
|
*
|
||||||
|
* The situation is not too bad as rewrite (->) usage makes ^ and !
|
||||||
|
* invalid. There is no huge explosion of combinations.
|
||||||
|
*/
|
||||||
|
group ASTParser;
|
||||||
|
|
||||||
|
@rule.setErrorReturnValue() ::= <<
|
||||||
|
retval.tree = (<ASTLabelType>)(ADAPTOR->errorNode(ADAPTOR, INPUT, retval.start, LT(-1), EXCEPTION));
|
||||||
|
>>
|
||||||
|
|
||||||
|
// TOKEN AST STUFF
|
||||||
|
|
||||||
|
/** ID and output=AST */
|
||||||
|
tokenRef(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
<if(backtracking)>if ( BACKTRACKING==0 ) {<endif>
|
||||||
|
<label>_tree = ADAPTOR->create(ADAPTOR, <label>);
|
||||||
|
ADAPTOR->addChild(ADAPTOR, root_0, <label>_tree);
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ID! and output=AST (same as plain tokenRef) */
|
||||||
|
tokenRefBang(token,label,elementIndex) ::= "<super.tokenRef(...)>"
|
||||||
|
|
||||||
|
/** ID^ and output=AST */
|
||||||
|
tokenRefRuleRoot(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
<if(backtracking)>if ( BACKTRACKING==0 ) {<endif>
|
||||||
|
<label>_tree = <createNodeFromToken(...)>;
|
||||||
|
root_0 = (<ASTLabelType>)(ADAPTOR->becomeRoot(ADAPTOR, <label>_tree, root_0));
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ids+=ID! and output=AST */
|
||||||
|
tokenRefBangAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefBang(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
|
||||||
|
/** label+=TOKEN when output=AST but not rewrite alt */
|
||||||
|
tokenRefAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRef(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
|
||||||
|
/** Match label+=TOKEN^ when output=AST but not rewrite alt */
|
||||||
|
tokenRefRuleRootAndListLabel(token,label,hetero,elementIndex) ::= <<
|
||||||
|
<tokenRefRuleRoot(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// SET AST
|
||||||
|
|
||||||
|
// the match set stuff is interesting in that it uses an argument list
|
||||||
|
// to pass code to the default matchSet; another possible way to alter
|
||||||
|
// inherited code. I don't use the region stuff because I need to pass
|
||||||
|
// different chunks depending on the operator. I don't like making
|
||||||
|
// the template name have the operator as the number of templates gets
|
||||||
|
// large but this is the most flexible--this is as opposed to having
|
||||||
|
// the code generator call matchSet then add root code or ruleroot code
|
||||||
|
// plus list label plus ... The combinations might require complicated
|
||||||
|
// rather than just added on code. Investigate that refactoring when
|
||||||
|
// I have more time.
|
||||||
|
|
||||||
|
matchSet(s,label,hetero,elementIndex,postmatchCode) ::= <<
|
||||||
|
<super.matchSet(..., postmatchCode={<if(backtracking)>if ( BACKTRACKING==0 ) <endif>ADAPTOR->addChild(ADAPTOR, root_0, <createNodeFromToken(...)>);})>
|
||||||
|
>>
|
||||||
|
|
||||||
|
matchRuleBlockSet(s,label,hetero,elementIndex,postmatchCode,treeLevel="0") ::= <<
|
||||||
|
<matchSet(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
matchSetBang(s,label,elementIndex,postmatchCode) ::= "<super.matchSet(...)>"
|
||||||
|
|
||||||
|
// note there is no matchSetTrack because -> rewrites force sets to be
|
||||||
|
// plain old blocks of alts: (A|B|...|C)
|
||||||
|
|
||||||
|
matchSetRuleRoot(s,label,hetero,elementIndex,debug) ::= <<
|
||||||
|
<if(label)>
|
||||||
|
<label>=(<labelType>)LT(1);<\n>
|
||||||
|
<endif>
|
||||||
|
<super.matchSet(..., postmatchCode={<if(backtracking)>if ( BACKTRACKING==0 ) <endif>root_0 = (<ASTLabelType>)(ADAPTOR->becomeRoot(ADAPTOR, <createNodeFromToken(...)>, root_0));})>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// RULE REF AST
|
||||||
|
|
||||||
|
/** rule when output=AST */
|
||||||
|
ruleRef(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<super.ruleRef(...)>
|
||||||
|
<if(backtracking)>if ( BACKTRACKING==0 ) <endif>ADAPTOR->addChild(ADAPTOR, root_0, <label>.tree);
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** rule! is same as normal rule ref */
|
||||||
|
ruleRefBang(rule,label,elementIndex,args,scope) ::= "<super.ruleRef(...)>"
|
||||||
|
|
||||||
|
/** rule^ */
|
||||||
|
ruleRefRuleRoot(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<super.ruleRef(...)>
|
||||||
|
<if(backtracking)>if ( BACKTRACKING==0 ) <endif>root_0 = (<ASTLabelType>)(ADAPTOR->becomeRoot(ADAPTOR, <label>.tree, root_0));
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule when output=AST */
|
||||||
|
ruleRefAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRef(...)>
|
||||||
|
<listLabelAST(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule! when output=AST is a rule ref with list addition */
|
||||||
|
ruleRefBangAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefBang(...)>
|
||||||
|
<listLabelAST(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule^ */
|
||||||
|
ruleRefRuleRootAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefRuleRoot(...)>
|
||||||
|
<listLabelAST(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// WILDCARD AST
|
||||||
|
|
||||||
|
wildcard(label,elementIndex) ::= <<
|
||||||
|
<super.wildcard(...)>
|
||||||
|
<if(backtracking)>if ( BACKTRACKING==0 ) {<endif>
|
||||||
|
<label>_tree = (<ASTLabelType>)(ADAPTOR->create(ADAPTOR, <label>));
|
||||||
|
ADAPTOR->addChild(ADAPTOR, root_0, <label>_tree);
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
wildcardBang(label,elementIndex) ::= "<super.wildcard(...)>"
|
||||||
|
|
||||||
|
wildcardRuleRoot(label,elementIndex) ::= <<
|
||||||
|
<super.wildcard(...)>
|
||||||
|
<if(backtracking)>if ( BACKTRACKING==0 ) {<endif>
|
||||||
|
<label>_tree = (<ASTLabelType>)(ADAPTOR->create(ADAPTOR, <label>));
|
||||||
|
root_0 = (<ASTLabelType>)(ADAPTOR->becomeRoot(ADAPTOR, <label>_tree, root_0));
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
createNodeFromToken(label,hetero) ::= <<
|
||||||
|
<if(hetero)>
|
||||||
|
<hetero>New(<label>) <! new MethodNode(IDLabel) !>
|
||||||
|
<else>
|
||||||
|
(<ASTLabelType>)(ADAPTOR->create(ADAPTOR, <label>))
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
ruleCleanUp() ::= <<
|
||||||
|
<super.ruleCleanUp(...)>
|
||||||
|
<if(backtracking)>
|
||||||
|
if ( BACKTRACKING==0 ) {<\n>
|
||||||
|
<endif>
|
||||||
|
|
||||||
|
<if(!ruleDescriptor.isSynPred)>
|
||||||
|
retval.stop = LT(-1);<\n>
|
||||||
|
<endif>
|
||||||
|
retval.tree = (<ASTLabelType>)(ADAPTOR->rulePostProcessing(ADAPTOR, root_0));
|
||||||
|
ADAPTOR->setTokenBoundaries(ADAPTOR, retval.tree, retval.start, retval.stop);
|
||||||
|
<if(backtracking)>
|
||||||
|
}
|
||||||
|
<endif>
|
||||||
|
<ruleDescriptor.allTokenRefsInAltsWithRewrites
|
||||||
|
:{stream_<it>->free(stream_<it>);}; separator="\n">
|
||||||
|
<ruleDescriptor.allRuleRefsInAltsWithRewrites
|
||||||
|
:{stream_<it>->free(stream_<it>);}; separator="\n">
|
||||||
|
>>
|
309
antlr_3_1_source/codegen/templates/C/ASTTreeParser.stg
Normal file
309
antlr_3_1_source/codegen/templates/C/ASTTreeParser.stg
Normal file
@ -0,0 +1,309 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Templates for building ASTs during tree parsing.
|
||||||
|
*
|
||||||
|
* Deal with many combinations. Dimensions are:
|
||||||
|
* Auto build or rewrite
|
||||||
|
* no label, label, list label (label/no-label handled together)
|
||||||
|
* child, root
|
||||||
|
* token, set, rule, wildcard
|
||||||
|
*
|
||||||
|
* Each combination has its own template except that label/no label
|
||||||
|
* is combined into tokenRef, ruleRef, ...
|
||||||
|
*/
|
||||||
|
group ASTTreeParser;
|
||||||
|
|
||||||
|
/** Add a variable to track last element matched */
|
||||||
|
ruleDeclarations() ::= <<
|
||||||
|
<super.ruleDeclarations()>
|
||||||
|
<ASTLabelType> _last;<\n>
|
||||||
|
<ASTLabelType> _first_0;<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Add a variable to track last element matched */
|
||||||
|
ruleInitializations() ::= <<
|
||||||
|
<super.ruleInitializations()>
|
||||||
|
_last = NULL;<\n>
|
||||||
|
_first_0 = NULL;<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** What to emit when there is no rewrite rule. For auto build
|
||||||
|
* mode, does nothing.
|
||||||
|
*/
|
||||||
|
noRewrite(rewriteBlockLevel, treeLevel) ::= <<
|
||||||
|
<if(backtracking)>if ( BACKTRACKING ==0 ) {<endif>
|
||||||
|
<if(rewriteMode)>
|
||||||
|
retval.tree = (<ASTLabelType>)_first_0;
|
||||||
|
if ( ADAPTOR->getParent(ADAPTOR, retval.tree) != NULL && ADAPTOR->isNilNode(ADAPTOR, ADAPTOR->getParent(ADAPTOR, retval.tree) ) )
|
||||||
|
{
|
||||||
|
retval.tree = (<ASTLabelType>)ADAPTOR->getParent(ADAPTOR, retval.tree);
|
||||||
|
}
|
||||||
|
<endif>
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** match ^(root children) in tree parser; override here to
|
||||||
|
* add tree construction actions.
|
||||||
|
*/
|
||||||
|
tree(root, actionsAfterRoot, children, nullableChildList,
|
||||||
|
enclosingTreeLevel, treeLevel) ::= <<
|
||||||
|
_last = (<ASTLabelType>)LT(1);
|
||||||
|
{
|
||||||
|
<ASTLabelType> _save_last_<treeLevel>;
|
||||||
|
<ASTLabelType> _first_last_<treeLevel>;
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<ASTLabelType> root_<treeLevel>;
|
||||||
|
<endif>
|
||||||
|
_save_last_<treeLevel> = _last;
|
||||||
|
_first_last_<treeLevel> = NULL;
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)(ADAPTOR->nilNode(ADAPTOR));
|
||||||
|
<endif>
|
||||||
|
<root:element()>
|
||||||
|
<if(rewriteMode)>
|
||||||
|
<if(backtracking)>if ( BACKTRACKING ==0 ) {<endif>
|
||||||
|
<if(root.el.rule)>
|
||||||
|
if ( _first_<enclosingTreeLevel> == NULL ) _first_<enclosingTreeLevel> = <root.el.label>.tree;
|
||||||
|
<else>
|
||||||
|
if ( _first_<enclosingTreeLevel> == NULL ) _first_<enclosingTreeLevel> = <root.el.label>;
|
||||||
|
<endif>
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
<endif>
|
||||||
|
<actionsAfterRoot:element()>
|
||||||
|
<if(nullableChildList)>
|
||||||
|
if ( LA(1)==ANTLR3_TOKEN_DOWN ) {
|
||||||
|
MATCHT(ANTLR3_TOKEN_DOWN, NULL);
|
||||||
|
<children:element()>
|
||||||
|
MATCHT(ANTLR3_TOKEN_UP, NULL);
|
||||||
|
}
|
||||||
|
<else>
|
||||||
|
MATCHT(ANTLR3_TOKEN_DOWN, NULL);
|
||||||
|
<children:element()>
|
||||||
|
MATCHT(ANTLR3_TOKEN_UP, NULL);
|
||||||
|
<endif>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
ADAPTOR->addChild(ADAPTOR, root_<enclosingTreeLevel>, root_<treeLevel>);
|
||||||
|
<endif>
|
||||||
|
_last = _save_last_<treeLevel>;
|
||||||
|
}<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// TOKEN AST STUFF
|
||||||
|
|
||||||
|
/** ID! and output=AST (same as plain tokenRef) 'cept add
|
||||||
|
* setting of _last
|
||||||
|
*/
|
||||||
|
tokenRefBang(token,label,elementIndex) ::= <<
|
||||||
|
_last = (<ASTLabelType>)LT(1);
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ID auto construct */
|
||||||
|
tokenRef(token,label,elementIndex,hetero) ::= <<
|
||||||
|
_last = (<ASTLabelType>)LT(1);
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<if(backtracking)>if ( BACKTRACKING ==0 ) {<endif>
|
||||||
|
<if(hetero)>
|
||||||
|
<label>_tree = <hetero>New(<label>);
|
||||||
|
<else>
|
||||||
|
<label>_tree = (<ASTLabelType>)ADAPTOR->dupNode(ADAPTOR, <label>);
|
||||||
|
<endif>
|
||||||
|
ADAPTOR->addChild(ADAPTOR, root_<treeLevel>, <label>_tree);
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
<else>
|
||||||
|
<if(backtracking)>if ( BACKTRACKING ==0 ) {<endif>
|
||||||
|
if ( _first_<treeLevel> == NULL ) _first_<treeLevel> = <label>;
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** label+=TOKEN auto construct */
|
||||||
|
tokenRefAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRef(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(ID ...) auto construct */
|
||||||
|
tokenRefRuleRoot(token,label,elementIndex,hetero) ::= <<
|
||||||
|
_last = (<ASTLabelType>)LT(1);
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<if(backtracking)>if ( BACKTRACKING == 0 ) {<endif>
|
||||||
|
<if(hetero)>
|
||||||
|
<label>_tree = <hetero>New(<label>);
|
||||||
|
<else>
|
||||||
|
<label>_tree = (<ASTLabelType>)ADAPTOR->dupNode(ADAPTOR, <label>);
|
||||||
|
<endif><\n>
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)ADAPTOR->becomeRoot(ADAPTOR, <label>_tree, root_<treeLevel>);
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Match ^(label+=TOKEN ...) auto construct */
|
||||||
|
tokenRefRuleRootAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefRuleRoot(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// SET AST
|
||||||
|
|
||||||
|
matchSet(s,label,hetero,elementIndex,postmatchCode) ::= <<
|
||||||
|
_last = (<ASTLabelType>)LT(1);
|
||||||
|
<super.matchSet(..., postmatchCode={
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<if(backtracking)>if ( BACKTRACKING == 0 ) {<endif>
|
||||||
|
<if(hetero)>
|
||||||
|
<label>_tree = <hetero>New(<label>);
|
||||||
|
<else>
|
||||||
|
<label>_tree = (<ASTLabelType>)ADAPTOR->dupNode(ADAPTOR, <label>);
|
||||||
|
<endif><\n>
|
||||||
|
ADAPTOR->addChild(ADAPTOR, root_<treeLevel>, <label>_tree);
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
<endif>
|
||||||
|
}
|
||||||
|
)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
matchRuleBlockSet(s,label,hetero,elementIndex,postmatchCode,treeLevel="0") ::= <<
|
||||||
|
<matchSet(...)>
|
||||||
|
<noRewrite()> <! set return tree !>
|
||||||
|
>>
|
||||||
|
|
||||||
|
matchSetBang(s,label,elementIndex,postmatchCode) ::= <<
|
||||||
|
_last = (<ASTLabelType>)LT(1);
|
||||||
|
<super.matchSet(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
matchSetRuleRoot(s,label,hetero,elementIndex,debug) ::= <<
|
||||||
|
<super.matchSet(..., postmatchCode={
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<if(backtracking)>if ( BACKTRACKING == 0 ) {<endif>
|
||||||
|
<if(hetero)>
|
||||||
|
<label>_tree = <hetero>New(<label>);
|
||||||
|
<else>
|
||||||
|
<label>_tree = (<ASTLabelType>)ADAPTOR->dupNode(ADAPTOR, <label>);
|
||||||
|
<endif>
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)ADAPTOR->becomeRoot(ADAPTOR, <label>_tree, root_<treeLevel>);
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
<endif>
|
||||||
|
}
|
||||||
|
)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// RULE REF AST
|
||||||
|
|
||||||
|
/** rule auto construct */
|
||||||
|
ruleRef(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
_last = (<ASTLabelType>)LT(1);
|
||||||
|
<super.ruleRef(...)>
|
||||||
|
<if(backtracking)>if ( BACKTRACKING == 0 )
|
||||||
|
{
|
||||||
|
<endif>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
ADAPTOR->addChild(ADAPTOR, root_<treeLevel>, <label>.tree);
|
||||||
|
<else>
|
||||||
|
if ( _first_<treeLevel> == NULL ) _first_<treeLevel> = <label>.tree;
|
||||||
|
<endif>
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule auto construct */
|
||||||
|
ruleRefAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRef(...)>
|
||||||
|
<super.listLabelAST(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(rule ...) auto construct */
|
||||||
|
ruleRefRuleRoot(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
_last = (<ASTLabelType>)LT(1);
|
||||||
|
<super.ruleRef(...)>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<if(backtracking)>if ( BACKTRACKING == 0 ) <endif>root_<treeLevel> = (<ASTLabelType>)(ADAPTOR->becomeRoot(ADAPTOR, <label>.tree, root_<treeLevel>));
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(x+=rule ...) auto construct */
|
||||||
|
ruleRefRuleRootAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefRuleRoot(...)>
|
||||||
|
<super.listLabelAST(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** rule when output=AST and tracking for rewrite */
|
||||||
|
ruleRefTrack(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
_last = (<ASTLabelType>)LT(1);
|
||||||
|
<super.ruleRefTrack(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule when output=AST and tracking for rewrite */
|
||||||
|
ruleRefTrackAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
_last = (<ASTLabelType>)LT(1);
|
||||||
|
<super.ruleRefTrackAndListLabel(...)>
|
||||||
|
>>
|
||||||
|
/** ^(rule ...) rewrite */
|
||||||
|
ruleRefRuleRootTrack(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
_last = (<ASTLabelType>)LT(1);
|
||||||
|
<super.ruleRefRootTrack(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(x+=rule ...) rewrite */
|
||||||
|
ruleRefRuleRootTrackAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
_last = (<ASTLabelType>)LT(1);
|
||||||
|
<super.ruleRefRuleRootTrackAndListLabel(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
|
||||||
|
/** Streams for token refs are tree nodes now; override to
|
||||||
|
* change nextToken to nextNode.
|
||||||
|
*/
|
||||||
|
createRewriteNodeFromElement(token,hetero,scope) ::= <<
|
||||||
|
<if(hetero)>
|
||||||
|
<hetero>New(stream_<token>->nextNode(stream_<token>))
|
||||||
|
<else>
|
||||||
|
stream_<token>->nextNode(stream_<token>)
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
ruleCleanUp() ::= <<
|
||||||
|
<super.ruleCleanUp(...)>
|
||||||
|
<if(backtracking)>
|
||||||
|
if ( BACKTRACKING==0 ) {<\n>
|
||||||
|
<endif>
|
||||||
|
<if(!ruleDescriptor.isSynPred)>
|
||||||
|
retval.stop = LT(-1);<\n>
|
||||||
|
<endif>
|
||||||
|
retval.tree = ADAPTOR->rulePostProcessing(ADAPTOR, root_0);
|
||||||
|
<if(backtracking)>
|
||||||
|
}
|
||||||
|
<endif>
|
||||||
|
<ruleDescriptor.allTokenRefsInAltsWithRewrites
|
||||||
|
:{stream_<it>->free(stream_<it>);}; separator="\n">
|
||||||
|
<ruleDescriptor.allRuleRefsInAltsWithRewrites
|
||||||
|
:{stream_<it>->free(stream_<it>);}; separator="\n">
|
||||||
|
>>
|
3074
antlr_3_1_source/codegen/templates/C/C.stg
Normal file
3074
antlr_3_1_source/codegen/templates/C/C.stg
Normal file
File diff suppressed because it is too large
Load Diff
250
antlr_3_1_source/codegen/templates/C/Dbg.stg
Normal file
250
antlr_3_1_source/codegen/templates/C/Dbg.stg
Normal file
@ -0,0 +1,250 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
/** Template overrides to add debugging to normal C output;
|
||||||
|
* If ASTs are built, then you'll also get ASTDbg.stg loaded.
|
||||||
|
*/
|
||||||
|
group Dbg;
|
||||||
|
|
||||||
|
@genericParser.members() ::= <<
|
||||||
|
<if(grammar.grammarIsRoot)>
|
||||||
|
const char *
|
||||||
|
ruleNames[] =
|
||||||
|
{
|
||||||
|
"invalidRule", <grammar.allImportedRules:{rST | "<rST.name>"}; wrap="\n ", separator=", ">
|
||||||
|
};<\n>
|
||||||
|
<endif>
|
||||||
|
<if(grammar.grammarIsRoot)> <! grammar imports other grammar(s) !>
|
||||||
|
static ANTLR3_UINT32 ruleLevel = 0;
|
||||||
|
static ANTLR3_UINT32 getRuleLevel()
|
||||||
|
{
|
||||||
|
return ruleLevel;
|
||||||
|
}
|
||||||
|
static void incRuleLevel()
|
||||||
|
{
|
||||||
|
ruleLevel++;
|
||||||
|
}
|
||||||
|
static void decRuleLevel()
|
||||||
|
{
|
||||||
|
ruleLevel--;
|
||||||
|
}
|
||||||
|
<else> <! imported grammar !>
|
||||||
|
static ANTLR3_UINT32
|
||||||
|
getRuleLevel()
|
||||||
|
{
|
||||||
|
return <grammar.delegators:{g| <g:delegateName()>}>->getRuleLevel();
|
||||||
|
}
|
||||||
|
static void incRuleLevel()
|
||||||
|
{
|
||||||
|
<grammar.delegators:{g| <g:delegateName()>}>->incRuleLevel();
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
decRuleLevel()
|
||||||
|
{
|
||||||
|
<grammar.delegators:{g| <g:delegateName()>}>.decRuleLevel();
|
||||||
|
}
|
||||||
|
<endif>
|
||||||
|
<if(profile)>
|
||||||
|
// Profiling not yet implemented for C target
|
||||||
|
//
|
||||||
|
<endif>
|
||||||
|
<if(grammar.grammarIsRoot)>
|
||||||
|
<ctorForPredefinedListener()>
|
||||||
|
<else>
|
||||||
|
<ctorForDelegateGrammar()>
|
||||||
|
<endif>
|
||||||
|
|
||||||
|
static ANTLR3_BOOLEAN
|
||||||
|
evalPredicate(p<name> ctx, ANTLR3_BOOLEAN result, const char * predicate)
|
||||||
|
{
|
||||||
|
DBG->semanticPredicate(DBG, result, predicate);
|
||||||
|
return result;
|
||||||
|
}<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
@genericParser.debugStuff() ::= <<
|
||||||
|
<if(grammar.grammarIsRoot)>
|
||||||
|
<createListenerAndHandshake()>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
ctorForProfilingRootGrammar() ::= <<
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Basically we don't want to set any dbg listeners as root will have it. */
|
||||||
|
ctorForDelegateGrammar() ::= <<
|
||||||
|
//public <name>(<inputStreamType> input, DebugEventListener dbg, RecognizerSharedState state<grammar.delegators:{g|, <g.recognizerName> <g:delegateName()>}>) {
|
||||||
|
// super(input, dbg, state);
|
||||||
|
//parserCtorBody()
|
||||||
|
// <grammar.directDelegates:
|
||||||
|
{g|<g:delegateName()> = new <g.recognizerName>(input, this, state<grammar.delegators:{g|, <g:delegateName()>}>);}; separator="\n">
|
||||||
|
//}
|
||||||
|
>>
|
||||||
|
|
||||||
|
ctorForPredefinedListener() ::= <<
|
||||||
|
//public <name>(<inputStreamType> input, DebugEventListener dbg) {
|
||||||
|
// super(input, dbg, new RecognizerSharedState());
|
||||||
|
//<if(profile)>
|
||||||
|
// Profiler p = (Profiler)dbg;
|
||||||
|
// p.setParser(this);
|
||||||
|
//<endif>
|
||||||
|
// //parserCtorBody()
|
||||||
|
// <grammar.directDelegates:{g|<g:delegateName()> = new <g.recognizerName>(input, dbg, state, this<grammar.delegators:{g|, <g:delegateName()>}>);}; separator="\n">
|
||||||
|
//}<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
createListenerAndHandshake() ::= <<
|
||||||
|
{
|
||||||
|
// DEBUG MODE code
|
||||||
|
//
|
||||||
|
pANTLR3_DEBUG_EVENT_LISTENER proxy;
|
||||||
|
proxy = antlr3DebugListenerNew();
|
||||||
|
proxy->grammarFileName = INPUT->tokenSource->strFactory->newStr8(INPUT->tokenSource->strFactory, (pANTLR3_UINT8)ctx->getGrammarFileName());
|
||||||
|
|
||||||
|
<if(TREE_PARSER)>
|
||||||
|
proxy->adaptor = ADAPTOR;
|
||||||
|
<endif>
|
||||||
|
PARSER->setDebugListener(PARSER, proxy);
|
||||||
|
|
||||||
|
// Try to connect to the debugger (waits forever for a connection)
|
||||||
|
//
|
||||||
|
proxy->handshake(proxy);
|
||||||
|
|
||||||
|
// End DEBUG MODE code
|
||||||
|
//
|
||||||
|
}
|
||||||
|
>>
|
||||||
|
|
||||||
|
|
||||||
|
@rule.preamble() ::= <<
|
||||||
|
DBG->enterRule(DBG, getGrammarFileName(), (const char *)"<ruleName>");
|
||||||
|
if ( getRuleLevel()==0 )
|
||||||
|
{
|
||||||
|
DBG->commence(DBG);
|
||||||
|
}
|
||||||
|
incRuleLevel();
|
||||||
|
DBG->location(DBG, <ruleDescriptor.tree.line>, <ruleDescriptor.tree.column>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
@rule.postamble() ::= <<
|
||||||
|
DBG->location(DBG, <ruleDescriptor.EORNode.line>, <ruleDescriptor.EORNode.column>);<\n>
|
||||||
|
DBG->exitRule(DBG, getGrammarFileName(), (const char *)"<ruleName>");
|
||||||
|
decRuleLevel();
|
||||||
|
if ( getRuleLevel()==0 )
|
||||||
|
{
|
||||||
|
DBG->terminate(DBG);
|
||||||
|
}
|
||||||
|
<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
@synpred.start() ::= "DBG->beginBacktrack(DBG, BACKTRACKING);"
|
||||||
|
|
||||||
|
@synpred.stop() ::= "DBG->endBacktrack(DBG, BACKTRACKING, success);"
|
||||||
|
|
||||||
|
// Common debug event triggers used by region overrides below
|
||||||
|
|
||||||
|
enterSubRule() ::=
|
||||||
|
"DBG->enterSubRule(DBG, <decisionNumber>);<\n>"
|
||||||
|
|
||||||
|
exitSubRule() ::=
|
||||||
|
"DBG->exitSubRule(DBG, <decisionNumber>);<\n>"
|
||||||
|
|
||||||
|
enterDecision() ::=
|
||||||
|
"DBG->enterDecision(DBG, <decisionNumber>);<\n>"
|
||||||
|
|
||||||
|
exitDecision() ::=
|
||||||
|
"DBG->exitDecision(DBG, <decisionNumber>);<\n>"
|
||||||
|
|
||||||
|
enterAlt(n) ::= "DBG->enterAlt(DBG, <n>);<\n>"
|
||||||
|
|
||||||
|
// Region overrides that tell various constructs to add debugging triggers
|
||||||
|
|
||||||
|
@block.predecision() ::= "<enterSubRule()><enterDecision()>"
|
||||||
|
|
||||||
|
@block.postdecision() ::= "<exitDecision()>"
|
||||||
|
|
||||||
|
@block.postbranch() ::= "<exitSubRule()>"
|
||||||
|
|
||||||
|
@ruleBlock.predecision() ::= "<enterDecision()>"
|
||||||
|
|
||||||
|
@ruleBlock.postdecision() ::= "<exitDecision()>"
|
||||||
|
|
||||||
|
@ruleBlockSingleAlt.prealt() ::= "<enterAlt(n=\"1\")>"
|
||||||
|
|
||||||
|
@blockSingleAlt.prealt() ::= "<enterAlt(n=\"1\")>"
|
||||||
|
|
||||||
|
@positiveClosureBlock.preloop() ::= "<enterSubRule()>"
|
||||||
|
|
||||||
|
@positiveClosureBlock.postloop() ::= "<exitSubRule()>"
|
||||||
|
|
||||||
|
@positiveClosureBlock.predecision() ::= "<enterDecision()>"
|
||||||
|
|
||||||
|
@positiveClosureBlock.postdecision() ::= "<exitDecision()>"
|
||||||
|
|
||||||
|
@positiveClosureBlock.earlyExitException() ::=
|
||||||
|
"DBG->recognitionException(DBG, EXCEPTION);<\n>"
|
||||||
|
|
||||||
|
@closureBlock.preloop() ::= "<enterSubRule()>"
|
||||||
|
|
||||||
|
@closureBlock.postloop() ::= "<exitSubRule()>"
|
||||||
|
|
||||||
|
@closureBlock.predecision() ::= "<enterDecision()>"
|
||||||
|
|
||||||
|
@closureBlock.postdecision() ::= "<exitDecision()>"
|
||||||
|
|
||||||
|
@altSwitchCase.prealt() ::= "<enterAlt(n=i)>"
|
||||||
|
|
||||||
|
@element.prematch() ::=
|
||||||
|
"DBG->location(DBG, <it.line>, <it.pos>);"
|
||||||
|
|
||||||
|
@matchSet.mismatchedSetException() ::=
|
||||||
|
"DBG->recognitionException(DBG, EXCEPTION);"
|
||||||
|
|
||||||
|
@newNVException.noViableAltException() ::= "DBG->recognitionException(DBG, EXCEPTION);"
|
||||||
|
|
||||||
|
dfaDecision(decisionNumber,description) ::= <<
|
||||||
|
alt<decisionNumber> = cdfa<decisionNumber>.predict(ctx, RECOGNIZER, ISTREAM, &cdfa<decisionNumber>);
|
||||||
|
if (HASEXCEPTION())
|
||||||
|
{
|
||||||
|
DBG->recognitionException(DBG, EXCEPTION);
|
||||||
|
goto rule<ruleDescriptor.name>Ex;
|
||||||
|
}
|
||||||
|
<checkRuleBacktrackFailure()>
|
||||||
|
>>
|
||||||
|
|
||||||
|
@cyclicDFA.errorMethod() ::= <<
|
||||||
|
//static void
|
||||||
|
//dfaError(p<name> ctx)
|
||||||
|
//{
|
||||||
|
// DBG->recognitionException(DBG, EXCEPTION);
|
||||||
|
//}
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Force predicate validation to trigger an event */
|
||||||
|
evalPredicate(pred,description) ::= <<
|
||||||
|
evalPredicate(ctx, <pred>, (const char *)"<description>")
|
||||||
|
>>
|
403
antlr_3_1_source/codegen/templates/CSharp/AST.stg
Normal file
403
antlr_3_1_source/codegen/templates/CSharp/AST.stg
Normal file
@ -0,0 +1,403 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2007-2008 Johannes Luber
|
||||||
|
Copyright (c) 2005-2007 Kunle Odutola
|
||||||
|
Copyright (c) 2005 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
group AST;
|
||||||
|
|
||||||
|
@outputFile.imports() ::= <<
|
||||||
|
<@super.imports()>
|
||||||
|
<if(!TREE_PARSER)><! tree parser would already have imported !>
|
||||||
|
using Antlr.Runtime.Tree;<\n>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
@genericParser.members() ::= <<
|
||||||
|
<@super.members()>
|
||||||
|
<parserMembers()>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Add an adaptor property that knows how to build trees */
|
||||||
|
parserMembers() ::= <<
|
||||||
|
protected ITreeAdaptor adaptor = new CommonTreeAdaptor();<\n>
|
||||||
|
public ITreeAdaptor TreeAdaptor
|
||||||
|
{
|
||||||
|
get { return this.adaptor; }
|
||||||
|
set {
|
||||||
|
this.adaptor = value;
|
||||||
|
<grammar.directDelegates:{g|<g:delegateName()>.TreeAdaptor = this.adaptor;}>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>>
|
||||||
|
|
||||||
|
@returnScope.ruleReturnMembers() ::= <<
|
||||||
|
private <ASTLabelType> tree;
|
||||||
|
override public object Tree
|
||||||
|
{
|
||||||
|
get { return tree; }
|
||||||
|
set { tree = (<ASTLabelType>) value; }
|
||||||
|
}
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Add a variable to track rule's return AST */
|
||||||
|
ruleDeclarations() ::= <<
|
||||||
|
<super.ruleDeclarations()>
|
||||||
|
<ASTLabelType> root_0 = null;<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
ruleLabelDefs() ::= <<
|
||||||
|
<super.ruleLabelDefs()>
|
||||||
|
<ruleDescriptor.tokenLabels:{<ASTLabelType> <it.label.text>_tree=null;}; separator="\n">
|
||||||
|
<ruleDescriptor.tokenListLabels:{<ASTLabelType> <it.label.text>_tree=null;}; separator="\n">
|
||||||
|
<ruleDescriptor.allTokenRefsInAltsWithRewrites
|
||||||
|
:{RewriteRule<rewriteElementType>Stream stream_<it> = new RewriteRule<rewriteElementType>Stream(adaptor,"token <it>");}; separator="\n">
|
||||||
|
<ruleDescriptor.allRuleRefsInAltsWithRewrites
|
||||||
|
:{RewriteRuleSubtreeStream stream_<it> = new RewriteRuleSubtreeStream(adaptor,"rule <it>");}; separator="\n">
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** When doing auto AST construction, we must define some variables;
|
||||||
|
* These should be turned off if doing rewrites. This must be a "mode"
|
||||||
|
* as a rule could have both rewrite and AST within the same alternative
|
||||||
|
* block.
|
||||||
|
*/
|
||||||
|
@alt.declarations() ::= <<
|
||||||
|
<if(autoAST)>
|
||||||
|
<if(outerAlt)>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
root_0 = (<ASTLabelType>)adaptor.GetNilNode();<\n>
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// T r a c k i n g R u l e E l e m e n t s
|
||||||
|
|
||||||
|
/** ID and track it for use in a rewrite rule */
|
||||||
|
tokenRefTrack(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefBang(...)> <! Track implies no auto AST construction!>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) <endif>stream_<token>.Add(<label>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ids+=ID and track it for use in a rewrite rule; adds to ids *and*
|
||||||
|
* to the tracking list stream_ID for use in the rewrite.
|
||||||
|
*/
|
||||||
|
tokenRefTrackAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefTrack(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(ID ...) track for rewrite */
|
||||||
|
tokenRefRuleRootTrack(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefBang(...)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) <endif>stream_<token>.Add(<label>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Match ^(label+=TOKEN ...) track for rewrite */
|
||||||
|
tokenRefRuleRootTrackAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefRuleRootTrack(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
wildcardTrack(label,elementIndex) ::= <<
|
||||||
|
<super.wildcard(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** rule when output=AST and tracking for rewrite */
|
||||||
|
ruleRefTrack(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<super.ruleRef(...)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) <endif>stream_<rule.name>.Add(<label>.Tree);
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule when output=AST and tracking for rewrite */
|
||||||
|
ruleRefTrackAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefTrack(...)>
|
||||||
|
<listLabel(elem=label+".Tree",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(rule ...) rewrite */
|
||||||
|
ruleRefRuleRootTrack(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefRuleRoot(...)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) <endif>stream_<rule>.Add(<label>.Tree);
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(x+=rule ...) rewrite */
|
||||||
|
ruleRefRuleRootTrackAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefRuleRootTrack(...)>
|
||||||
|
<listLabel(elem=label+".Tree",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// R e w r i t e
|
||||||
|
|
||||||
|
rewriteCode(
|
||||||
|
alts, description,
|
||||||
|
referencedElementsDeep, // ALL referenced elements to right of ->
|
||||||
|
referencedTokenLabels,
|
||||||
|
referencedTokenListLabels,
|
||||||
|
referencedRuleLabels,
|
||||||
|
referencedRuleListLabels,
|
||||||
|
rewriteBlockLevel, enclosingTreeLevel, treeLevel) ::=
|
||||||
|
<<
|
||||||
|
|
||||||
|
// AST REWRITE
|
||||||
|
// elements: <referencedElementsDeep; separator=", ">
|
||||||
|
// token labels: <referencedTokenLabels; separator=", ">
|
||||||
|
// rule labels: <referencedRuleLabels; separator=", ">
|
||||||
|
// token list labels: <referencedTokenListLabels; separator=", ">
|
||||||
|
// rule list labels: <referencedRuleListLabels; separator=", ">
|
||||||
|
<if(backtracking)>
|
||||||
|
if ( state.backtracking==0 ) {<\n>
|
||||||
|
<endif>
|
||||||
|
<prevRuleRootRef()>.Tree = root_0;
|
||||||
|
<rewriteCodeLabels()>
|
||||||
|
root_0 = (<ASTLabelType>)adaptor.GetNilNode();
|
||||||
|
<alts:rewriteAlt(); separator="else ">
|
||||||
|
<! if tree parser and rewrite=true !>
|
||||||
|
<if(TREE_PARSER)>
|
||||||
|
<if(rewriteMode)>
|
||||||
|
<prevRuleRootRef()>.Tree = (<ASTLabelType>)adaptor.rulePostProcessing(root_0);
|
||||||
|
input.ReplaceChildren(adaptor.GetParent(retval.Start),
|
||||||
|
adaptor.GetChildIndex(retval.Start),
|
||||||
|
adaptor.GetChildIndex(_last),
|
||||||
|
retval.Tree);
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
<! if parser or rewrite!=true, we need to set result !>
|
||||||
|
<if(!TREE_PARSER)>
|
||||||
|
<prevRuleRootRef()>.Tree = root_0;
|
||||||
|
<endif>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<prevRuleRootRef()>.Tree = root_0;
|
||||||
|
<endif>
|
||||||
|
<if(backtracking)>
|
||||||
|
}
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteCodeLabels() ::= <<
|
||||||
|
<referencedTokenLabels
|
||||||
|
:{RewriteRule<rewriteElementType>Stream stream_<it> = new RewriteRule<rewriteElementType>Stream(adaptor, "token <it>", <it>);};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
<referencedTokenListLabels
|
||||||
|
:{RewriteRule<rewriteElementType>Stream stream_<it> = new RewriteRule<rewriteElementType>Stream(adaptor,"token <it>", list_<it>);};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
<referencedRuleLabels
|
||||||
|
:{RewriteRuleSubtreeStream stream_<it> = new RewriteRuleSubtreeStream(adaptor, "token <it>", (<it>!=null ? <it>.Tree : null));};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
<referencedRuleListLabels
|
||||||
|
:{RewriteRuleSubtreeStream stream_<it> = new RewriteRuleSubtreeStream(adaptor, "token <it>", list_<it>);};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Generate code for an optional rewrite block; note it uses the deep ref'd element
|
||||||
|
* list rather shallow like other blocks.
|
||||||
|
*/
|
||||||
|
rewriteOptionalBlock(
|
||||||
|
alt,rewriteBlockLevel,
|
||||||
|
referencedElementsDeep, // all nested refs
|
||||||
|
referencedElements, // elements in immediately block; no nested blocks
|
||||||
|
description) ::=
|
||||||
|
<<
|
||||||
|
// <fileName>:<description>
|
||||||
|
if ( <referencedElementsDeep:{el | stream_<el>.HasNext()}; separator=" || "> )
|
||||||
|
{
|
||||||
|
<alt>
|
||||||
|
}
|
||||||
|
<referencedElementsDeep:{el | stream_<el>.Reset();<\n>}>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteClosureBlock(
|
||||||
|
alt,rewriteBlockLevel,
|
||||||
|
referencedElementsDeep, // all nested refs
|
||||||
|
referencedElements, // elements in immediately block; no nested blocks
|
||||||
|
description) ::=
|
||||||
|
<<
|
||||||
|
// <fileName>:<description>
|
||||||
|
while ( <referencedElements:{el | stream_<el>.HasNext()}; separator=" || "> )
|
||||||
|
{
|
||||||
|
<alt>
|
||||||
|
}
|
||||||
|
<referencedElements:{el | stream_<el>.Reset();<\n>}>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewritePositiveClosureBlock(
|
||||||
|
alt,rewriteBlockLevel,
|
||||||
|
referencedElementsDeep, // all nested refs
|
||||||
|
referencedElements, // elements in immediately block; no nested blocks
|
||||||
|
description) ::=
|
||||||
|
<<
|
||||||
|
if ( !(<referencedElements:{el | stream_<el>.HasNext()}; separator=" || ">) ) {
|
||||||
|
throw new RewriteEarlyExitException();
|
||||||
|
}
|
||||||
|
while ( <referencedElements:{el | stream_<el>.HasNext()}; separator=" || "> )
|
||||||
|
{
|
||||||
|
<alt>
|
||||||
|
}
|
||||||
|
<referencedElements:{el | stream_<el>.Reset();<\n>}>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteAlt(a) ::= <<
|
||||||
|
// <a.description>
|
||||||
|
<if(a.pred)>
|
||||||
|
if (<a.pred>)
|
||||||
|
{
|
||||||
|
<a.alt>
|
||||||
|
}<\n>
|
||||||
|
<else>
|
||||||
|
{
|
||||||
|
<a.alt>
|
||||||
|
}<\n>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** For empty rewrites: "r : ... -> ;" */
|
||||||
|
rewriteEmptyAlt() ::= "root_0 = null;"
|
||||||
|
|
||||||
|
rewriteTree(root,children,description,enclosingTreeLevel,treeLevel) ::= <<
|
||||||
|
// <fileName>:<description>
|
||||||
|
{
|
||||||
|
<ASTLabelType> root_<treeLevel> = (<ASTLabelType>)adaptor.GetNilNode();
|
||||||
|
<root:rewriteElement()>
|
||||||
|
<children:rewriteElement()>
|
||||||
|
adaptor.AddChild(root_<enclosingTreeLevel>, root_<treeLevel>);
|
||||||
|
}<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteElementList(elements) ::= "<elements:rewriteElement()>"
|
||||||
|
|
||||||
|
rewriteElement(e) ::= <<
|
||||||
|
<@pregen()>
|
||||||
|
<e.el>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen ID or ID[args] */
|
||||||
|
rewriteTokenRef(token,elementIndex,hetero,args) ::= <<
|
||||||
|
adaptor.AddChild(root_<treeLevel>, <createRewriteNodeFromElement(...)>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen $label ... where defined via label=ID */
|
||||||
|
rewriteTokenLabelRef(label,elementIndex) ::= <<
|
||||||
|
adaptor.AddChild(root_<treeLevel>, stream_<label>.NextNode());<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen $label ... where defined via label+=ID */
|
||||||
|
rewriteTokenListLabelRef(label,elementIndex) ::= <<
|
||||||
|
adaptor.AddChild(root_<treeLevel>, stream_<label>.NextNode());<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen ^($label ...) */
|
||||||
|
rewriteTokenLabelRefRoot(label,elementIndex) ::= <<
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)adaptor.BecomeRoot(stream_<label>.NextNode(), root_<treeLevel>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen ^($label ...) where label+=... */
|
||||||
|
rewriteTokenListLabelRefRoot ::= rewriteTokenLabelRefRoot
|
||||||
|
|
||||||
|
/** Gen ^(ID ...) or ^(ID[args] ...) */
|
||||||
|
rewriteTokenRefRoot(token,elementIndex,hetero,args) ::= <<
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)adaptor.BecomeRoot(<createRewriteNodeFromElement(...)>, root_<treeLevel>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteImaginaryTokenRef(args,token,hetero,elementIndex) ::= <<
|
||||||
|
adaptor.AddChild(root_<treeLevel>, <createImaginaryNode(tokenType=token, ...)>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteImaginaryTokenRefRoot(args,token,hetero,elementIndex) ::= <<
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)adaptor.BecomeRoot(<createImaginaryNode(tokenType=token, ...)>, root_<treeLevel>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** plain -> {foo} action */
|
||||||
|
rewriteAction(action) ::= <<
|
||||||
|
root_0 = <action>;<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** What is the name of the previous value of this rule's root tree? This
|
||||||
|
* let's us refer to $rule to mean previous value. I am reusing the
|
||||||
|
* variable 'tree' sitting in retval struct to hold the value of root_0 right
|
||||||
|
* before I set it during rewrites. The assign will be to retval.Tree.
|
||||||
|
*/
|
||||||
|
prevRuleRootRef() ::= "retval"
|
||||||
|
|
||||||
|
rewriteRuleRef(rule) ::= <<
|
||||||
|
adaptor.AddChild(root_<treeLevel>, stream_<rule>.NextTree());<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteRuleRefRoot(rule) ::= <<
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)adaptor.BecomeRoot(stream_<rule>.NextNode(), root_<treeLevel>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteNodeAction(action) ::= <<
|
||||||
|
adaptor.AddChild(root_<treeLevel>, <action>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteNodeActionRoot(action) ::= <<
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)adaptor.BecomeRoot(<action>, root_<treeLevel>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen $ruleLabel ... where defined via ruleLabel=rule */
|
||||||
|
rewriteRuleLabelRef(label) ::= <<
|
||||||
|
adaptor.AddChild(root_<treeLevel>, stream_<label>.NextTree());<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen $ruleLabel ... where defined via ruleLabel+=rule */
|
||||||
|
rewriteRuleListLabelRef(label) ::= <<
|
||||||
|
adaptor.AddChild(root_<treeLevel>, stream_<label>.NextTree());<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen ^($ruleLabel ...) where ruleLabel=rule */
|
||||||
|
rewriteRuleLabelRefRoot(label) ::= <<
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)adaptor.BecomeRoot(stream_<label>.NextNode(), root_<treeLevel>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen ^($ruleLabel ...) where ruleLabel+=rule */
|
||||||
|
rewriteRuleListLabelRefRoot(label) ::= <<
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)adaptor.BecomeRoot(stream_<label>.NextNode(), root_<treeLevel>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
createImaginaryNode(tokenType,hetero,args) ::= <<
|
||||||
|
<if(hetero)>
|
||||||
|
<! new MethodNode(IDLabel, args) !>
|
||||||
|
new <hetero>(<tokenType><if(args)>, <args; separator=", "><endif>)
|
||||||
|
<else>
|
||||||
|
(<ASTLabelType>)adaptor.Create(<tokenType>, <args; separator=", "><if(!args)>"<tokenType>"<endif>)
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
createRewriteNodeFromElement(token,hetero,args) ::= <<
|
||||||
|
<if(hetero)>
|
||||||
|
new <hetero>(stream_<token>.NextToken()<if(args)>, <args; separator=", "><endif>)
|
||||||
|
<else>
|
||||||
|
<if(args)> <! must create new node from old !>
|
||||||
|
adaptor.Create(<token>, <args; separator=", ">)
|
||||||
|
<else>
|
||||||
|
stream_<token>.NextNode()
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
>>
|
97
antlr_3_1_source/codegen/templates/CSharp/ASTDbg.stg
Normal file
97
antlr_3_1_source/codegen/templates/CSharp/ASTDbg.stg
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2007-2008 Johannes Luber
|
||||||
|
Copyright (c) 2005-2007 Kunle Odutola
|
||||||
|
Copyright (c) 2005 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Template overrides to add debugging to AST stuff. Dynamic inheritance
|
||||||
|
* hierarchy is set up as ASTDbg : AST : Dbg : C# by code generator.
|
||||||
|
*/
|
||||||
|
group ASTDbg;
|
||||||
|
|
||||||
|
parserMembers() ::= <<
|
||||||
|
protected DebugTreeAdaptor adaptor;
|
||||||
|
public ITreeAdaptor TreeAdaptor
|
||||||
|
{
|
||||||
|
get {
|
||||||
|
<if(grammar.grammarIsRoot)>
|
||||||
|
return this.adaptor;
|
||||||
|
<else>
|
||||||
|
this.adaptor = (DebugTreeAdaptor)adaptor; // delegator sends dbg adaptor
|
||||||
|
<endif><\n>
|
||||||
|
<grammar.directDelegates:{g|<g:delegateName()>.TreeAdaptor = this.adaptor;}>
|
||||||
|
}
|
||||||
|
set { this.adaptor = new DebugTreeAdaptor(dbg, value); }
|
||||||
|
}<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
parserCtorBody() ::= <<
|
||||||
|
<super.parserCtorBody()>
|
||||||
|
>>
|
||||||
|
|
||||||
|
createListenerAndHandshake() ::= <<
|
||||||
|
DebugEventSocketProxy proxy = new DebugEventSocketProxy(this, port, adaptor);
|
||||||
|
DebugListener = proxy;
|
||||||
|
<!
|
||||||
|
Original line follows, replaced by the next two ifs:
|
||||||
|
set<inputStreamType>(new Debug<inputStreamType>(input,proxy));
|
||||||
|
!>
|
||||||
|
<if(PARSER)>
|
||||||
|
TokenStream = new DebugTokenStream(input,proxy);<\n>
|
||||||
|
<endif>
|
||||||
|
<if(TREE_PARSER)>
|
||||||
|
TokenStream = new DebugTreeNodeStream(input,proxy);<\n>
|
||||||
|
<endif>
|
||||||
|
try {
|
||||||
|
proxy.Handshake();
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
ReportError(ioe);
|
||||||
|
}
|
||||||
|
>>
|
||||||
|
|
||||||
|
@ctorForRootGrammar.finally() ::= <<
|
||||||
|
ITreeAdaptor adap = new CommonTreeAdaptor();
|
||||||
|
TreeAdaptor = adap;
|
||||||
|
proxy.TreeAdaptor = adap;
|
||||||
|
>>
|
||||||
|
|
||||||
|
@ctorForProfilingRootGrammar.finally() ::=<<
|
||||||
|
ITreeAdaptor adap = new CommonTreeAdaptor();
|
||||||
|
TreeAdaptor = adap;
|
||||||
|
proxy.TreeAdaptor = adap;
|
||||||
|
>>
|
||||||
|
|
||||||
|
@ctorForPredefinedListener.superClassRef() ::= "base(input, dbg)"
|
||||||
|
|
||||||
|
@ctorForPredefinedListener.finally() ::=<<
|
||||||
|
<if(grammar.grammarIsRoot)> <! don't create new adaptor for delegates !>
|
||||||
|
ITreeAdaptor adap = new CommonTreeAdaptor();
|
||||||
|
TreeAdaptor = adap;<\n>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
@rewriteElement.pregen() ::= "dbg.Location(<e.line>,<e.pos>);"
|
220
antlr_3_1_source/codegen/templates/CSharp/ASTParser.stg
Normal file
220
antlr_3_1_source/codegen/templates/CSharp/ASTParser.stg
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2007-2008 Johannes Luber
|
||||||
|
Copyright (c) 2005-2007 Kunle Odutola
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Templates for building ASTs during normal parsing.
|
||||||
|
*
|
||||||
|
* Deal with many combinations. Dimensions are:
|
||||||
|
* Auto build or rewrite
|
||||||
|
* no label, label, list label (label/no-label handled together)
|
||||||
|
* child, root
|
||||||
|
* token, set, rule, wildcard
|
||||||
|
*
|
||||||
|
* The situation is not too bad as rewrite (->) usage makes ^ and !
|
||||||
|
* invalid. There is no huge explosion of combinations.
|
||||||
|
*/
|
||||||
|
group ASTParser;
|
||||||
|
|
||||||
|
@rule.setErrorReturnValue() ::= <<
|
||||||
|
// Conversion of the second argument necessary, but harmless
|
||||||
|
retval.Tree = (<ASTLabelType>)adaptor.ErrorNode(input, (IToken) retval.Start, input.LT(-1), re);
|
||||||
|
<! System.Console.WriteLine("<ruleName> returns " + ((CommonTree)retval.Tree).ToStringTree()); !>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// TOKEN AST STUFF
|
||||||
|
|
||||||
|
/** ID and output=AST */
|
||||||
|
tokenRef(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
<if(backtracking)>
|
||||||
|
if ( state.backtracking == 0 )
|
||||||
|
{
|
||||||
|
<endif>
|
||||||
|
<label>_tree = <createNodeFromToken(...)>;
|
||||||
|
adaptor.AddChild(root_0, <label>_tree);
|
||||||
|
<if(backtracking)>
|
||||||
|
}
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ID! and output=AST (same as plain tokenRef) */
|
||||||
|
tokenRefBang(token,label,elementIndex) ::= "<super.tokenRef(...)>"
|
||||||
|
|
||||||
|
/** ID^ and output=AST */
|
||||||
|
tokenRefRuleRoot(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
<if(backtracking)>
|
||||||
|
if ( state.backtracking == 0 )
|
||||||
|
{
|
||||||
|
<endif>
|
||||||
|
<label>_tree = <createNodeFromToken(...)>;
|
||||||
|
root_0 = (<ASTLabelType>)adaptor.BecomeRoot(<label>_tree, root_0);
|
||||||
|
<if(backtracking)>
|
||||||
|
}
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ids+=ID! and output=AST */
|
||||||
|
tokenRefBangAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefBang(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** label+=TOKEN when output=AST but not rewrite alt */
|
||||||
|
tokenRefAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRef(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Match label+=TOKEN^ when output=AST but not rewrite alt */
|
||||||
|
tokenRefRuleRootAndListLabel(token,label,hetero,elementIndex) ::= <<
|
||||||
|
<tokenRefRuleRoot(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// SET AST
|
||||||
|
|
||||||
|
// the match set stuff is interesting in that it uses an argument list
|
||||||
|
// to pass code to the default matchSet; another possible way to alter
|
||||||
|
// inherited code. I don't use the region stuff because I need to pass
|
||||||
|
// different chunks depending on the operator. I don't like making
|
||||||
|
// the template name have the operator as the number of templates gets
|
||||||
|
// large but this is the most flexible--this is as opposed to having
|
||||||
|
// the code generator call matchSet then add root code or ruleroot code
|
||||||
|
// plus list label plus ... The combinations might require complicated
|
||||||
|
// rather than just added on code. Investigate that refactoring when
|
||||||
|
// I have more time.
|
||||||
|
|
||||||
|
matchSet(s,label,hetero,elementIndex,postmatchCode) ::= <<
|
||||||
|
<super.matchSet(..., postmatchCode={<if(backtracking)>if ( state.backtracking == 0 ) <endif>adaptor.AddChild(root_0, <createNodeFromToken(...)>);})>
|
||||||
|
>>
|
||||||
|
|
||||||
|
matchRuleBlockSet(s,label,hetero,elementIndex,postmatchCode,treeLevel="0") ::= <<
|
||||||
|
<matchSet(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
matchSetBang(s,label,elementIndex,postmatchCode) ::= "<super.matchSet(...)>"
|
||||||
|
|
||||||
|
// note there is no matchSetTrack because -> rewrites force sets to be
|
||||||
|
// plain old blocks of alts: (A|B|...|C)
|
||||||
|
|
||||||
|
matchSetRuleRoot(s,label,hetero,elementIndex,debug) ::= <<
|
||||||
|
<if(label)>
|
||||||
|
<label>=(<labelType>)input.LT(1);<\n>
|
||||||
|
<endif>
|
||||||
|
<super.matchSet(..., postmatchCode={<if(backtracking)>if ( state.backtracking == 0 ) <endif>root_0 = (<ASTLabelType>)adaptor.BecomeRoot(<createNodeFromToken(...)>, root_0);})>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// RULE REF AST
|
||||||
|
|
||||||
|
/** rule when output=AST */
|
||||||
|
ruleRef(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<super.ruleRef(...)>
|
||||||
|
<if(backtracking)>if ( state.backtracking == 0 ) <endif>adaptor.AddChild(root_0, <label>.Tree);
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** rule! is same as normal rule ref */
|
||||||
|
ruleRefBang(rule,label,elementIndex,args,scope) ::= "<super.ruleRef(...)>"
|
||||||
|
|
||||||
|
/** rule^ */
|
||||||
|
ruleRefRuleRoot(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<super.ruleRef(...)>
|
||||||
|
<if(backtracking)>if ( state.backtracking == 0 ) <endif>root_0 = (<ASTLabelType>)adaptor.BecomeRoot(<label>.Tree, root_0);
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule when output=AST */
|
||||||
|
ruleRefAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRef(...)>
|
||||||
|
<listLabel(elem=label+".Tree",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule! when output=AST is a rule ref with list addition */
|
||||||
|
ruleRefBangAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefBang(...)>
|
||||||
|
<listLabel(elem=label+".Tree",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule^ */
|
||||||
|
ruleRefRuleRootAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefRuleRoot(...)>
|
||||||
|
<listLabel(elem=label+".Tree",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// WILDCARD AST
|
||||||
|
|
||||||
|
wildcard(label,elementIndex) ::= <<
|
||||||
|
<super.wildcard(...)>
|
||||||
|
<if(backtracking)>
|
||||||
|
if ( state.backtracking == 0 )
|
||||||
|
{
|
||||||
|
<endif>
|
||||||
|
<label>_tree = (<ASTLabelType>)adaptor.Create(<label>);
|
||||||
|
adaptor.AddChild(root_0, <label>_tree);
|
||||||
|
<if(backtracking)>
|
||||||
|
}
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
wildcardBang(label,elementIndex) ::= "<super.wildcard(...)>"
|
||||||
|
|
||||||
|
wildcardRuleRoot(label,elementIndex) ::= <<
|
||||||
|
<super.wildcard(...)>
|
||||||
|
<if(backtracking)>
|
||||||
|
if ( state.backtracking == 0 )
|
||||||
|
{
|
||||||
|
<endif>
|
||||||
|
<label>_tree = (<ASTLabelType>)adaptor.Create(<label>);
|
||||||
|
root_0 = (<ASTLabelType>)adaptor.BecomeRoot(<label>_tree, root_0);
|
||||||
|
<if(backtracking)>
|
||||||
|
}
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
createNodeFromToken(label,hetero) ::= <<
|
||||||
|
<if(hetero)>
|
||||||
|
new <hetero>(<label>) <! new MethodNode(IDLabel) !>
|
||||||
|
<else>
|
||||||
|
(<ASTLabelType>)adaptor.Create(<label>)
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
ruleCleanUp() ::= <<
|
||||||
|
<super.ruleCleanUp()>
|
||||||
|
<if(backtracking)>
|
||||||
|
if ( state.backtracking==0 )
|
||||||
|
{
|
||||||
|
<endif>
|
||||||
|
retval.Tree = (<ASTLabelType>)adaptor.RulePostProcessing(root_0);
|
||||||
|
<if(!TREE_PARSER)>
|
||||||
|
adaptor.SetTokenBoundaries(retval.Tree, (IToken) retval.Start, (IToken) retval.Stop);
|
||||||
|
<endif>
|
||||||
|
<if(backtracking)>
|
||||||
|
}
|
||||||
|
<endif>
|
||||||
|
>>
|
299
antlr_3_1_source/codegen/templates/CSharp/ASTTreeParser.stg
Normal file
299
antlr_3_1_source/codegen/templates/CSharp/ASTTreeParser.stg
Normal file
@ -0,0 +1,299 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2007-2008 Johannes Luber
|
||||||
|
Copyright (c) 2005-2007 Kunle Odutola
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Templates for building ASTs during tree parsing.
|
||||||
|
*
|
||||||
|
* Deal with many combinations. Dimensions are:
|
||||||
|
* Auto build or rewrite
|
||||||
|
* no label, label, list label (label/no-label handled together)
|
||||||
|
* child, root
|
||||||
|
* token, set, rule, wildcard
|
||||||
|
*
|
||||||
|
* Each combination has its own template except that label/no label
|
||||||
|
* is combined into tokenRef, ruleRef, ...
|
||||||
|
*/
|
||||||
|
group ASTTreeParser;
|
||||||
|
|
||||||
|
/** Add a variable to track last element matched */
|
||||||
|
ruleDeclarations() ::= <<
|
||||||
|
<super.ruleDeclarations()>
|
||||||
|
<ASTLabelType> _first_0 = null;
|
||||||
|
<ASTLabelType> _last = null;<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** What to emit when there is no rewrite rule. For auto build
|
||||||
|
* mode, does nothing.
|
||||||
|
*/
|
||||||
|
noRewrite(rewriteBlockLevel, treeLevel) ::= <<
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) {<endif>
|
||||||
|
<if(rewriteMode)>
|
||||||
|
retval.Tree = (<ASTLabelType>)_first_0;
|
||||||
|
if ( adaptor.GetParent(retval.Tree)!=null && adaptor.IsNil( adaptor.GetParent(retval.Tree) ) )
|
||||||
|
retval.Tree = (<ASTLabelType>)adaptor.GetParent(retval.Tree);
|
||||||
|
<endif>
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** match ^(root children) in tree parser; override here to
|
||||||
|
* add tree construction actions.
|
||||||
|
*/
|
||||||
|
tree(root, actionsAfterRoot, children, nullableChildList,
|
||||||
|
enclosingTreeLevel, treeLevel) ::= <<
|
||||||
|
_last = (<ASTLabelType>)input.LT(1);
|
||||||
|
{
|
||||||
|
<ASTLabelType> _save_last_<treeLevel> = _last;
|
||||||
|
<ASTLabelType> _first_<treeLevel> = null;
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<ASTLabelType> root_<treeLevel> = (<ASTLabelType>)adaptor.GetNilNode();
|
||||||
|
<endif>
|
||||||
|
<root:element()>
|
||||||
|
<if(rewriteMode)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 )<endif>
|
||||||
|
<if(root.el.rule)>
|
||||||
|
if ( _first_<enclosingTreeLevel>==null ) _first_<enclosingTreeLevel> = <root.el.label>.Tree;
|
||||||
|
<else>
|
||||||
|
if ( _first_<enclosingTreeLevel>==null ) _first_<enclosingTreeLevel> = <root.el.label>;
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
<actionsAfterRoot:element()>
|
||||||
|
<if(nullableChildList)>
|
||||||
|
if ( input.LA(1) == Token.DOWN )
|
||||||
|
{
|
||||||
|
Match(input, Token.DOWN, null); <checkRuleBacktrackFailure()>
|
||||||
|
<children:element()>
|
||||||
|
Match(input, Token.UP, null); <checkRuleBacktrackFailure()>
|
||||||
|
}
|
||||||
|
<else>
|
||||||
|
Match(input, Token.DOWN, null); <checkRuleBacktrackFailure()>
|
||||||
|
<children:element()>
|
||||||
|
Match(input, Token.UP, null); <checkRuleBacktrackFailure()>
|
||||||
|
<endif>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
adaptor.AddChild(root_<enclosingTreeLevel>, root_<treeLevel>);
|
||||||
|
<endif>
|
||||||
|
_last = _save_last_<treeLevel>;
|
||||||
|
}<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// TOKEN AST STUFF
|
||||||
|
|
||||||
|
/** ID! and output=AST (same as plain tokenRef) 'cept add
|
||||||
|
* setting of _last
|
||||||
|
*/
|
||||||
|
tokenRefBang(token,label,elementIndex) ::= <<
|
||||||
|
_last = (<ASTLabelType>)input.LT(1);
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ID auto construct */
|
||||||
|
tokenRef(token,label,elementIndex,hetero) ::= <<
|
||||||
|
_last = (<ASTLabelType>)input.LT(1);
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<if(backtracking)>
|
||||||
|
if ( state.backtracking == 0 )
|
||||||
|
{
|
||||||
|
<endif>
|
||||||
|
<if(hetero)>
|
||||||
|
<label>_tree = new <hetero>(<label>);
|
||||||
|
<else>
|
||||||
|
<label>_tree = (<ASTLabelType>)adaptor.DupNode(<label>);
|
||||||
|
<endif><\n>
|
||||||
|
adaptor.AddChild(root_<treeLevel>, <label>_tree);
|
||||||
|
<if(backtracking)>
|
||||||
|
}
|
||||||
|
<endif>
|
||||||
|
<else> <! rewrite mode !>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 )<endif>
|
||||||
|
if ( _first_<treeLevel>==null ) _first_<treeLevel> = <label>;
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** label+=TOKEN auto construct */
|
||||||
|
tokenRefAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRef(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(ID ...) auto construct */
|
||||||
|
tokenRefRuleRoot(token,label,elementIndex,hetero) ::= <<
|
||||||
|
_last = (<ASTLabelType>)input.LT(1);
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<if(backtracking)>
|
||||||
|
if ( state.backtracking == 0 )
|
||||||
|
{
|
||||||
|
<endif>
|
||||||
|
<if(hetero)>
|
||||||
|
<label>_tree = new <hetero>(<label>);
|
||||||
|
<else>
|
||||||
|
<label>_tree = (<ASTLabelType>)adaptor.DupNode(<label>);
|
||||||
|
<endif><\n>
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)adaptor.BecomeRoot(<label>_tree, root_<treeLevel>);
|
||||||
|
<if(backtracking)>
|
||||||
|
}
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Match ^(label+=TOKEN ...) auto construct */
|
||||||
|
tokenRefRuleRootAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefRuleRoot(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// SET AST
|
||||||
|
|
||||||
|
matchSet(s,label,hetero,elementIndex,postmatchCode) ::= <<
|
||||||
|
_last = (<ASTLabelType>)input.LT(1);
|
||||||
|
<super.matchSet(..., postmatchCode={
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) {<endif>
|
||||||
|
<if(hetero)>
|
||||||
|
<label>_tree = new <hetero>(<label>);
|
||||||
|
<else>
|
||||||
|
<label>_tree = (<ASTLabelType>)adaptor.DupNode(<label>);
|
||||||
|
<endif><\n>
|
||||||
|
adaptor.AddChild(root_<treeLevel>, <label>_tree);
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
<endif>
|
||||||
|
}
|
||||||
|
)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
matchRuleBlockSet(s,label,hetero,elementIndex,postmatchCode,treeLevel="0") ::= <<
|
||||||
|
<matchSet(...)>
|
||||||
|
<noRewrite()> <! set return tree !>
|
||||||
|
>>
|
||||||
|
|
||||||
|
matchSetBang(s,label,elementIndex,postmatchCode) ::= <<
|
||||||
|
_last = (<ASTLabelType>)input.LT(1);
|
||||||
|
<super.matchSet(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
matchSetRuleRoot(s,label,hetero,elementIndex,debug) ::= <<
|
||||||
|
<super.matchSet(..., postmatchCode={
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) {<endif>
|
||||||
|
<if(hetero)>
|
||||||
|
<label>_tree = new <hetero>(<label>);
|
||||||
|
<else>
|
||||||
|
<label>_tree = (<ASTLabelType>)adaptor.DupNode(<label>);
|
||||||
|
<endif><\n>
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)adaptor.BecomeRoot(<label>_tree, root_<treeLevel>);
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
<endif>
|
||||||
|
}
|
||||||
|
)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// RULE REF AST
|
||||||
|
|
||||||
|
/** rule auto construct */
|
||||||
|
ruleRef(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
_last = (<ASTLabelType>)input.LT(1);
|
||||||
|
<super.ruleRef(...)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) <endif>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
adaptor.AddChild(root_<treeLevel>, <label>.Tree);
|
||||||
|
<else> <! rewrite mode !>
|
||||||
|
if ( _first_<treeLevel>==null ) _first_<treeLevel> = <label>.Tree;
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule auto construct */
|
||||||
|
ruleRefAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRef(...)>
|
||||||
|
<listLabel(elem=label+".Tree",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(rule ...) auto construct */
|
||||||
|
ruleRefRuleRoot(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
_last = (<ASTLabelType>)input.LT(1);
|
||||||
|
<super.ruleRef(...)>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<if(backtracking)>if ( state.backtracking == 0 ) <endif>root_<treeLevel> = (<ASTLabelType>)adaptor.BecomeRoot(<label>.Tree, root_<treeLevel>);
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(x+=rule ...) auto construct */
|
||||||
|
ruleRefRuleRootAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefRuleRoot(...)>
|
||||||
|
<listLabel(elem=label+".Tree",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** rule when output=AST and tracking for rewrite */
|
||||||
|
ruleRefTrack(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
_last = (<ASTLabelType>)input.LT(1);
|
||||||
|
<super.ruleRefTrack(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule when output=AST and tracking for rewrite */
|
||||||
|
ruleRefTrackAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
_last = (<ASTLabelType>)input.LT(1);
|
||||||
|
<super.ruleRefTrackAndListLabel(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(rule ...) rewrite */
|
||||||
|
ruleRefRuleRootTrack(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
_last = (<ASTLabelType>)input.LT(1);
|
||||||
|
<super.ruleRefRootTrack(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(x+=rule ...) rewrite */
|
||||||
|
ruleRefRuleRootTrackAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
_last = (<ASTLabelType>)input.LT(1);
|
||||||
|
<super.ruleRefRuleRootTrackAndListLabel(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Streams for token refs are tree nodes now; override to
|
||||||
|
* change nextToken to nextNode.
|
||||||
|
*/
|
||||||
|
createRewriteNodeFromElement(token,hetero,scope) ::= <<
|
||||||
|
<if(hetero)>
|
||||||
|
new <hetero>(stream_<token>.NextNode())
|
||||||
|
<else>
|
||||||
|
stream_<token>.NextNode()
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
ruleCleanUp() ::= <<
|
||||||
|
<super.ruleCleanUp()>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<if(backtracking)>
|
||||||
|
if ( state.backtracking==0 )
|
||||||
|
{
|
||||||
|
<endif>
|
||||||
|
retval.Tree = (<ASTLabelType>)adaptor.RulePostProcessing(root_0);
|
||||||
|
<if(backtracking)>
|
||||||
|
}
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
>>
|
1459
antlr_3_1_source/codegen/templates/CSharp/CSharp.stg
Normal file
1459
antlr_3_1_source/codegen/templates/CSharp/CSharp.stg
Normal file
File diff suppressed because it is too large
Load Diff
288
antlr_3_1_source/codegen/templates/CSharp/Dbg.stg
Normal file
288
antlr_3_1_source/codegen/templates/CSharp/Dbg.stg
Normal file
@ -0,0 +1,288 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2007-2008 Johannes Luber
|
||||||
|
Copyright (c) 2005-2007 Kunle Odutola
|
||||||
|
Copyright (c) 2005 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
/** Template overrides to add debugging to normal Java output;
|
||||||
|
* If ASTs are built, then you'll also get ASTDbg.stg loaded.
|
||||||
|
*/
|
||||||
|
group Dbg;
|
||||||
|
|
||||||
|
@outputFile.imports() ::= <<
|
||||||
|
<@super.imports()>
|
||||||
|
using Antlr.Runtime.Debug;
|
||||||
|
using IOException = System.IO.IOException;
|
||||||
|
>>
|
||||||
|
|
||||||
|
@genericParser.members() ::= <<
|
||||||
|
<if(grammar.grammarIsRoot)>
|
||||||
|
public static readonly string[] ruleNames = new string[] {
|
||||||
|
"invalidRule", <grammar.allImportedRules:{rST | "<rST.name>"}; wrap="\n ", separator=", ">
|
||||||
|
};<\n>
|
||||||
|
<endif>
|
||||||
|
<if(grammar.grammarIsRoot)> <! grammar imports other grammar(s) !>
|
||||||
|
private int ruleLevel = 0;
|
||||||
|
public int RuleLevel {
|
||||||
|
get { return ruleLevel; }
|
||||||
|
}
|
||||||
|
public void IncRuleLevel() { ruleLevel++; }
|
||||||
|
public void DecRuleLevel() { ruleLevel--; }
|
||||||
|
<if(profile)>
|
||||||
|
<ctorForProfilingRootGrammar()>
|
||||||
|
<else>
|
||||||
|
<ctorForRootGrammar()>
|
||||||
|
<endif>
|
||||||
|
<ctorForPredefinedListener()>
|
||||||
|
<else> <! imported grammar !>
|
||||||
|
public int RuleLevel {
|
||||||
|
get { return <grammar.delegators:{g| <g:delegateName()>}>.RuleLevel; }
|
||||||
|
}
|
||||||
|
public void IncRuleLevel() { <grammar.delegators:{g| <g:delegateName()>}>.IncRuleLevel(); }
|
||||||
|
public void DecRuleLevel() { <grammar.delegators:{g| <g:delegateName()>}>.DecRuleLevel(); }
|
||||||
|
<ctorForDelegateGrammar()>
|
||||||
|
<endif>
|
||||||
|
<if(profile)>
|
||||||
|
override public bool AlreadyParsedRule(IIntStream input, int ruleIndex)
|
||||||
|
{
|
||||||
|
((Profiler)dbg).ExamineRuleMemoization(input, ruleIndex, <grammar.composite.rootGrammar.recognizerName>.ruleNames[ruleIndex]);
|
||||||
|
return base.AlreadyParsedRule(input, ruleIndex);
|
||||||
|
}<\n>
|
||||||
|
override public void Memoize(IIntStream input,
|
||||||
|
int ruleIndex,
|
||||||
|
int ruleStartIndex)
|
||||||
|
{
|
||||||
|
((Profiler)dbg).Memoize(input, ruleIndex, ruleStartIndex, <grammar.composite.rootGrammar.recognizerName>.ruleNames[ruleIndex]);
|
||||||
|
base.Memoize(input, ruleIndex, ruleStartIndex);
|
||||||
|
}<\n>
|
||||||
|
<endif>
|
||||||
|
protected bool EvalPredicate(bool result, string predicate)
|
||||||
|
{
|
||||||
|
dbg.SemanticPredicate(result, predicate);
|
||||||
|
return result;
|
||||||
|
}<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
ctorForRootGrammar() ::= <<
|
||||||
|
<! bug: can't use <@super.members()> cut-n-paste instead !>
|
||||||
|
<! Same except we add port number and profile stuff if root grammar !>
|
||||||
|
public <name>(<inputStreamType> input)
|
||||||
|
: this(input, DebugEventSocketProxy.DEFAULT_DEBUGGER_PORT, new RecognizerSharedState()) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public <name>(<inputStreamType> input, int port, RecognizerSharedState state)
|
||||||
|
: base(input, state) {
|
||||||
|
<parserCtorBody()>
|
||||||
|
<createListenerAndHandshake()>
|
||||||
|
<grammar.directDelegates:{g|<g:delegateName()> = new <g.recognizerName>(input, dbg, this.state, this<grammar.delegators:{g|, <g:delegateName()>}>);}; separator="\n">
|
||||||
|
<@finally()>
|
||||||
|
}<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
ctorForProfilingRootGrammar() ::= <<
|
||||||
|
<! bug: can't use <@super.members()> cut-n-paste instead !>
|
||||||
|
public <name>(<inputStreamType> input) {
|
||||||
|
this(input, new Profiler(null), new RecognizerSharedState());
|
||||||
|
}
|
||||||
|
|
||||||
|
public <name>(<inputStreamType> input, IDebugEventListener dbg, RecognizerSharedState state)
|
||||||
|
: base(input, dbg, state) {
|
||||||
|
Profiler p = (Profiler)dbg;
|
||||||
|
p.setParser(this);
|
||||||
|
<parserCtorBody()>
|
||||||
|
<grammar.directDelegates:
|
||||||
|
{g|<g:delegateName()> = new <g.recognizerName>(input, dbg, this.state, this<grammar.delegators:{g|, <g:delegateName()>}>);}; separator="\n">
|
||||||
|
<@finally()>
|
||||||
|
}
|
||||||
|
<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
|
||||||
|
/** Basically we don't want to set any dbg listeners are root will have it. */
|
||||||
|
ctorForDelegateGrammar() ::= <<
|
||||||
|
public <name>(<inputStreamType> input, IDebugEventListener dbg, RecognizerSharedState state<grammar.delegators:{g|, <g.recognizerName> <g:delegateName()>}>)
|
||||||
|
: base(input, dbg, state) {
|
||||||
|
<parserCtorBody()>
|
||||||
|
<grammar.directDelegates:
|
||||||
|
{g|<g:delegateName()> = new <g.recognizerName>(input, this, this.state<grammar.delegators:{g|, <g:delegateName()>}>);}; separator="\n">
|
||||||
|
}<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
ctorForPredefinedListener() ::= <<
|
||||||
|
public <name>(<inputStreamType> input, IDebugEventListener dbg)
|
||||||
|
: <@superClassRef>base(input, dbg, new RecognizerSharedState())<@end> {
|
||||||
|
<if(profile)>
|
||||||
|
Profiler p = (Profiler)dbg;
|
||||||
|
p.setParser(this);
|
||||||
|
<endif>
|
||||||
|
<parserCtorBody()>
|
||||||
|
<grammar.directDelegates:{g|<g:delegateName()> = new <g.recognizerName>(input, dbg, this.state, this<grammar.delegators:{g|, <g:delegateName()>}>);}; separator="\n">
|
||||||
|
<@finally()>
|
||||||
|
}<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
createListenerAndHandshake() ::= <<
|
||||||
|
<if(TREE_PARSER)>
|
||||||
|
DebugEventSocketProxy proxy = new DebugEventSocketProxy(this, port, input.TreeAdaptor);
|
||||||
|
<else>
|
||||||
|
DebugEventSocketProxy proxy = new DebugEventSocketProxy(this, port, null);
|
||||||
|
<endif>
|
||||||
|
DebugListener = proxy;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
proxy.Handshake();
|
||||||
|
}
|
||||||
|
catch (IOException ioe)
|
||||||
|
{
|
||||||
|
ReportError(ioe);
|
||||||
|
}
|
||||||
|
>>
|
||||||
|
|
||||||
|
@genericParser.superClassName() ::= "Debug<@super.superClassName()>"
|
||||||
|
|
||||||
|
@rule.preamble() ::= <<
|
||||||
|
try {
|
||||||
|
dbg.EnterRule(GrammarFileName, "<ruleName>");
|
||||||
|
if ( RuleLevel==0 ) {dbg.Commence();}
|
||||||
|
IncRuleLevel();
|
||||||
|
dbg.Location(<ruleDescriptor.tree.line>, <ruleDescriptor.tree.column>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
@lexer.debugAddition() ::= ", dbg"
|
||||||
|
|
||||||
|
@rule.postamble() ::= <<
|
||||||
|
dbg.Location(<ruleDescriptor.EORNode.line>, <ruleDescriptor.EORNode.column>);<\n>
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
dbg.ExitRule(GrammarFileName, "<ruleName>");
|
||||||
|
DecRuleLevel();
|
||||||
|
if ( RuleLevel==0 ) {dbg.Terminate();}
|
||||||
|
}<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
@synpred.start() ::= "dbg.BeginBacktrack(state.backtracking);"
|
||||||
|
|
||||||
|
@synpred.stop() ::= "dbg.EndBacktrack(state.backtracking, success);"
|
||||||
|
|
||||||
|
// Common debug event triggers used by region overrides below
|
||||||
|
|
||||||
|
enterSubRule() ::=
|
||||||
|
"try { dbg.EnterSubRule(<decisionNumber>);<\n>"
|
||||||
|
|
||||||
|
exitSubRule() ::=
|
||||||
|
"} finally { dbg.ExitSubRule(<decisionNumber>); }<\n>"
|
||||||
|
|
||||||
|
enterDecision() ::=
|
||||||
|
"try { dbg.EnterDecision(<decisionNumber>);<\n>"
|
||||||
|
|
||||||
|
exitDecision() ::=
|
||||||
|
"} finally { dbg.ExitDecision(<decisionNumber>); }<\n>"
|
||||||
|
|
||||||
|
enterAlt(n) ::= "dbg.EnterAlt(<n>);<\n>"
|
||||||
|
|
||||||
|
// Region overrides that tell various constructs to add debugging triggers
|
||||||
|
|
||||||
|
@block.predecision() ::= "<enterSubRule()><enterDecision()>"
|
||||||
|
|
||||||
|
@block.postdecision() ::= "<exitDecision()>"
|
||||||
|
|
||||||
|
@block.postbranch() ::= "<exitSubRule()>"
|
||||||
|
|
||||||
|
@ruleBlock.predecision() ::= "<enterDecision()>"
|
||||||
|
|
||||||
|
@ruleBlock.postdecision() ::= "<exitDecision()>"
|
||||||
|
|
||||||
|
@ruleBlockSingleAlt.prealt() ::= "<enterAlt(n=\"1\")>"
|
||||||
|
|
||||||
|
@blockSingleAlt.prealt() ::= "<enterAlt(n=\"1\")>"
|
||||||
|
|
||||||
|
@positiveClosureBlock.preloop() ::= "<enterSubRule()>"
|
||||||
|
|
||||||
|
@positiveClosureBlock.postloop() ::= "<exitSubRule()>"
|
||||||
|
|
||||||
|
@positiveClosureBlock.predecision() ::= "<enterDecision()>"
|
||||||
|
|
||||||
|
@positiveClosureBlock.postdecision() ::= "<exitDecision()>"
|
||||||
|
|
||||||
|
@positiveClosureBlock.earlyExitException() ::=
|
||||||
|
"dbg.RecognitionException(eee);<\n>"
|
||||||
|
|
||||||
|
@closureBlock.preloop() ::= "<enterSubRule()>"
|
||||||
|
|
||||||
|
@closureBlock.postloop() ::= "<exitSubRule()>"
|
||||||
|
|
||||||
|
@closureBlock.predecision() ::= "<enterDecision()>"
|
||||||
|
|
||||||
|
@closureBlock.postdecision() ::= "<exitDecision()>"
|
||||||
|
|
||||||
|
@altSwitchCase.prealt() ::= "<enterAlt(n=i)>"
|
||||||
|
|
||||||
|
@element.prematch() ::=
|
||||||
|
"dbg.Location(<it.line>,<it.pos>);"
|
||||||
|
|
||||||
|
@matchSet.mismatchedSetException() ::=
|
||||||
|
"dbg.RecognitionException(mse);"
|
||||||
|
|
||||||
|
@dfaState.noViableAltException() ::= "dbg.RecognitionException(nvae_d<decisionNumber>s<stateNumber>);"
|
||||||
|
|
||||||
|
@dfaStateSwitch.noViableAltException() ::= "dbg.RecognitionException(nvae_d<decisionNumber>s<stateNumber>);"
|
||||||
|
|
||||||
|
dfaDecision(decisionNumber,description) ::= <<
|
||||||
|
try
|
||||||
|
{
|
||||||
|
isCyclicDecision = true;
|
||||||
|
<super.dfaDecision(...)>
|
||||||
|
}
|
||||||
|
catch (NoViableAltException nvae)
|
||||||
|
{
|
||||||
|
dbg.RecognitionException(nvae);
|
||||||
|
throw nvae;
|
||||||
|
}
|
||||||
|
>>
|
||||||
|
|
||||||
|
@cyclicDFA.dbgCtor() ::= <<
|
||||||
|
public DFA<dfa.decisionNumber>(BaseRecognizer recognizer, IDebugEventListener dbg) : this(recognizer)
|
||||||
|
{
|
||||||
|
this.dbg = dbg;
|
||||||
|
}
|
||||||
|
>>
|
||||||
|
|
||||||
|
@cyclicDFA.debugMember() ::= <<
|
||||||
|
IDebugEventListener dbg;
|
||||||
|
|
||||||
|
>>
|
||||||
|
|
||||||
|
@cyclicDFA.errorMethod() ::= <<
|
||||||
|
public override void Error(NoViableAltException nvae)
|
||||||
|
{
|
||||||
|
dbg.RecognitionException(nvae);
|
||||||
|
}
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Force predicate validation to trigger an event */
|
||||||
|
evalPredicate(pred,description) ::= <<
|
||||||
|
EvalPredicate(<pred>,"<description>")
|
||||||
|
>>
|
173
antlr_3_1_source/codegen/templates/CSharp/ST.stg
Normal file
173
antlr_3_1_source/codegen/templates/CSharp/ST.stg
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2007-2008 Johannes Luber
|
||||||
|
Copyright (c) 2005-2007 Kunle Odutola
|
||||||
|
Copyright (c) 2005 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
/** Template subgroup to add template rewrite output
|
||||||
|
* If debugging, then you'll also get STDbg.stg loaded.
|
||||||
|
*/
|
||||||
|
group ST;
|
||||||
|
|
||||||
|
@outputFile.imports() ::= <<
|
||||||
|
<@super.imports()>
|
||||||
|
using Antlr.StringTemplate;
|
||||||
|
using Antlr.StringTemplate.Language;
|
||||||
|
<if(!backtracking)>
|
||||||
|
using Hashtable = System.Collections.Hashtable;
|
||||||
|
<endif>
|
||||||
|
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Add this to each rule's return value struct */
|
||||||
|
@returnScope.ruleReturnMembers() ::= <<
|
||||||
|
private StringTemplate st;
|
||||||
|
public StringTemplate ST { get { return st; } set { st = value; } }
|
||||||
|
public override object Template { get { return st; } }
|
||||||
|
public override string ToString() { return (st == null) ? null : st.ToString(); }
|
||||||
|
>>
|
||||||
|
|
||||||
|
@genericParser.members() ::= <<
|
||||||
|
<@super.members()>
|
||||||
|
protected StringTemplateGroup templateLib =
|
||||||
|
new StringTemplateGroup("<name>Templates", typeof(AngleBracketTemplateLexer));
|
||||||
|
|
||||||
|
public StringTemplateGroup TemplateLib
|
||||||
|
{
|
||||||
|
get { return this.templateLib; }
|
||||||
|
set { this.templateLib = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \<summary> Allows convenient multi-value initialization:
|
||||||
|
/// "new STAttrMap().Add(...).Add(...)"
|
||||||
|
/// \</summary>
|
||||||
|
protected class STAttrMap : Hashtable
|
||||||
|
{
|
||||||
|
public STAttrMap Add(string attrName, object value)
|
||||||
|
{
|
||||||
|
base.Add(attrName, value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public STAttrMap Add(string attrName, int value)
|
||||||
|
{
|
||||||
|
base.Add(attrName, value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule when output=template */
|
||||||
|
ruleRefAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRef(...)>
|
||||||
|
<listLabel(elem=label+".Template",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteTemplate(alts) ::= <<
|
||||||
|
|
||||||
|
// TEMPLATE REWRITE
|
||||||
|
<if(backtracking)>
|
||||||
|
if ( state.backtracking==0 )
|
||||||
|
{
|
||||||
|
<alts:rewriteTemplateAlt(); separator="else ">
|
||||||
|
<if(rewriteMode)><replaceTextInLine()><endif>
|
||||||
|
}
|
||||||
|
<else>
|
||||||
|
<alts:rewriteTemplateAlt(); separator="else ">
|
||||||
|
<if(rewriteMode)><replaceTextInLine()><endif>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
replaceTextInLine() ::= <<
|
||||||
|
<if(TREE_PARSER)>
|
||||||
|
((TokenRewriteStream)input.TokenStream).Replace(
|
||||||
|
input.TreeAdaptor.GetTokenStartIndex(retval.Start),
|
||||||
|
input.TreeAdaptor.GetTokenStopIndex(retval.Start),
|
||||||
|
retval.ST);
|
||||||
|
<else>
|
||||||
|
((TokenRewriteStream)input).Replace(
|
||||||
|
((IToken)retval.Start).TokenIndex,
|
||||||
|
input.LT(-1).TokenIndex,
|
||||||
|
retval.ST);
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteTemplateAlt() ::= <<
|
||||||
|
// <it.description>
|
||||||
|
<if(it.pred)>
|
||||||
|
if (<it.pred>) {
|
||||||
|
retval.ST = <it.alt>;
|
||||||
|
}<\n>
|
||||||
|
<else>
|
||||||
|
{
|
||||||
|
retval.ST = <it.alt>;
|
||||||
|
}<\n>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteEmptyTemplate(alts) ::= <<
|
||||||
|
null;
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Invoke a template with a set of attribute name/value pairs.
|
||||||
|
* Set the value of the rule's template *after* having set
|
||||||
|
* the attributes because the rule's template might be used as
|
||||||
|
* an attribute to build a bigger template; you get a self-embedded
|
||||||
|
* template.
|
||||||
|
*/
|
||||||
|
rewriteExternalTemplate(name,args) ::= <<
|
||||||
|
templateLib.GetInstanceOf("<name>"<if(args)>,
|
||||||
|
new STAttrMap()<args:{a | .Add("<a.name>", <a.value>)}>
|
||||||
|
<endif>)
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** expr is a string expression that says what template to load */
|
||||||
|
rewriteIndirectTemplate(expr,args) ::= <<
|
||||||
|
templateLib.GetInstanceOf(<expr><if(args)>,
|
||||||
|
new STAttrMap()<args:{a | .Add("<a.name>", <a.value>)}>
|
||||||
|
<endif>)
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Invoke an inline template with a set of attribute name/value pairs */
|
||||||
|
rewriteInlineTemplate(args, template) ::= <<
|
||||||
|
new StringTemplate(templateLib, "<template>"<if(args)>,
|
||||||
|
new STAttrMap()<args:{a | .Add("<a.name>", <a.value>)}>
|
||||||
|
<endif>)
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** plain -> {foo} action */
|
||||||
|
rewriteAction(action) ::= <<
|
||||||
|
<action>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** An action has %st.attrName=expr; or %{st}.attrName=expr; */
|
||||||
|
actionSetAttribute(st,attrName,expr) ::= <<
|
||||||
|
(<st>).SetAttribute("<attrName>",<expr>);
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Translate %{stringExpr} */
|
||||||
|
actionStringConstructor(stringExpr) ::= <<
|
||||||
|
new StringTemplate(templateLib,<stringExpr>)
|
||||||
|
>>
|
403
antlr_3_1_source/codegen/templates/CSharp2/AST.stg
Normal file
403
antlr_3_1_source/codegen/templates/CSharp2/AST.stg
Normal file
@ -0,0 +1,403 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2007-2008 Johannes Luber
|
||||||
|
Copyright (c) 2005-2007 Kunle Odutola
|
||||||
|
Copyright (c) 2005 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
group AST;
|
||||||
|
|
||||||
|
@outputFile.imports() ::= <<
|
||||||
|
<@super.imports()>
|
||||||
|
<if(!TREE_PARSER)><! tree parser would already have imported !>
|
||||||
|
using Antlr.Runtime.Tree;<\n>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
@genericParser.members() ::= <<
|
||||||
|
<@super.members()>
|
||||||
|
<parserMembers()>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Add an adaptor property that knows how to build trees */
|
||||||
|
parserMembers() ::= <<
|
||||||
|
protected ITreeAdaptor adaptor = new CommonTreeAdaptor();<\n>
|
||||||
|
public ITreeAdaptor TreeAdaptor
|
||||||
|
{
|
||||||
|
get { return this.adaptor; }
|
||||||
|
set {
|
||||||
|
this.adaptor = value;
|
||||||
|
<grammar.directDelegates:{g|<g:delegateName()>.TreeAdaptor = this.adaptor;}>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>>
|
||||||
|
|
||||||
|
@returnScope.ruleReturnMembers() ::= <<
|
||||||
|
private <ASTLabelType> tree;
|
||||||
|
override public object Tree
|
||||||
|
{
|
||||||
|
get { return tree; }
|
||||||
|
set { tree = (<ASTLabelType>) value; }
|
||||||
|
}
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Add a variable to track rule's return AST */
|
||||||
|
ruleDeclarations() ::= <<
|
||||||
|
<super.ruleDeclarations()>
|
||||||
|
<ASTLabelType> root_0 = null;<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
ruleLabelDefs() ::= <<
|
||||||
|
<super.ruleLabelDefs()>
|
||||||
|
<ruleDescriptor.tokenLabels:{<ASTLabelType> <it.label.text>_tree=null;}; separator="\n">
|
||||||
|
<ruleDescriptor.tokenListLabels:{<ASTLabelType> <it.label.text>_tree=null;}; separator="\n">
|
||||||
|
<ruleDescriptor.allTokenRefsInAltsWithRewrites
|
||||||
|
:{RewriteRule<rewriteElementType>Stream stream_<it> = new RewriteRule<rewriteElementType>Stream(adaptor,"token <it>");}; separator="\n">
|
||||||
|
<ruleDescriptor.allRuleRefsInAltsWithRewrites
|
||||||
|
:{RewriteRuleSubtreeStream stream_<it> = new RewriteRuleSubtreeStream(adaptor,"rule <it>");}; separator="\n">
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** When doing auto AST construction, we must define some variables;
|
||||||
|
* These should be turned off if doing rewrites. This must be a "mode"
|
||||||
|
* as a rule could have both rewrite and AST within the same alternative
|
||||||
|
* block.
|
||||||
|
*/
|
||||||
|
@alt.declarations() ::= <<
|
||||||
|
<if(autoAST)>
|
||||||
|
<if(outerAlt)>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
root_0 = (<ASTLabelType>)adaptor.GetNilNode();<\n>
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// T r a c k i n g R u l e E l e m e n t s
|
||||||
|
|
||||||
|
/** ID and track it for use in a rewrite rule */
|
||||||
|
tokenRefTrack(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefBang(...)> <! Track implies no auto AST construction!>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) <endif>stream_<token>.Add(<label>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ids+=ID and track it for use in a rewrite rule; adds to ids *and*
|
||||||
|
* to the tracking list stream_ID for use in the rewrite.
|
||||||
|
*/
|
||||||
|
tokenRefTrackAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefTrack(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(ID ...) track for rewrite */
|
||||||
|
tokenRefRuleRootTrack(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefBang(...)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) <endif>stream_<token>.Add(<label>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Match ^(label+=TOKEN ...) track for rewrite */
|
||||||
|
tokenRefRuleRootTrackAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefRuleRootTrack(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
wildcardTrack(label,elementIndex) ::= <<
|
||||||
|
<super.wildcard(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** rule when output=AST and tracking for rewrite */
|
||||||
|
ruleRefTrack(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<super.ruleRef(...)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) <endif>stream_<rule.name>.Add(<label>.Tree);
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule when output=AST and tracking for rewrite */
|
||||||
|
ruleRefTrackAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefTrack(...)>
|
||||||
|
<listLabel(elem=label+".Tree",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(rule ...) rewrite */
|
||||||
|
ruleRefRuleRootTrack(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefRuleRoot(...)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) <endif>stream_<rule>.Add(<label>.Tree);
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(x+=rule ...) rewrite */
|
||||||
|
ruleRefRuleRootTrackAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefRuleRootTrack(...)>
|
||||||
|
<listLabel(elem=label+".Tree",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// R e w r i t e
|
||||||
|
|
||||||
|
rewriteCode(
|
||||||
|
alts, description,
|
||||||
|
referencedElementsDeep, // ALL referenced elements to right of ->
|
||||||
|
referencedTokenLabels,
|
||||||
|
referencedTokenListLabels,
|
||||||
|
referencedRuleLabels,
|
||||||
|
referencedRuleListLabels,
|
||||||
|
rewriteBlockLevel, enclosingTreeLevel, treeLevel) ::=
|
||||||
|
<<
|
||||||
|
|
||||||
|
// AST REWRITE
|
||||||
|
// elements: <referencedElementsDeep; separator=", ">
|
||||||
|
// token labels: <referencedTokenLabels; separator=", ">
|
||||||
|
// rule labels: <referencedRuleLabels; separator=", ">
|
||||||
|
// token list labels: <referencedTokenListLabels; separator=", ">
|
||||||
|
// rule list labels: <referencedRuleListLabels; separator=", ">
|
||||||
|
<if(backtracking)>
|
||||||
|
if ( state.backtracking==0 ) {<\n>
|
||||||
|
<endif>
|
||||||
|
<prevRuleRootRef()>.Tree = root_0;
|
||||||
|
<rewriteCodeLabels()>
|
||||||
|
root_0 = (<ASTLabelType>)adaptor.GetNilNode();
|
||||||
|
<alts:rewriteAlt(); separator="else ">
|
||||||
|
<! if tree parser and rewrite=true !>
|
||||||
|
<if(TREE_PARSER)>
|
||||||
|
<if(rewriteMode)>
|
||||||
|
<prevRuleRootRef()>.Tree = (<ASTLabelType>)adaptor.rulePostProcessing(root_0);
|
||||||
|
input.ReplaceChildren(adaptor.GetParent(retval.Start),
|
||||||
|
adaptor.GetChildIndex(retval.Start),
|
||||||
|
adaptor.GetChildIndex(_last),
|
||||||
|
retval.Tree);
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
<! if parser or rewrite!=true, we need to set result !>
|
||||||
|
<if(!TREE_PARSER)>
|
||||||
|
<prevRuleRootRef()>.Tree = root_0;
|
||||||
|
<endif>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<prevRuleRootRef()>.Tree = root_0;
|
||||||
|
<endif>
|
||||||
|
<if(backtracking)>
|
||||||
|
}
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteCodeLabels() ::= <<
|
||||||
|
<referencedTokenLabels
|
||||||
|
:{RewriteRule<rewriteElementType>Stream stream_<it> = new RewriteRule<rewriteElementType>Stream(adaptor, "token <it>", <it>);};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
<referencedTokenListLabels
|
||||||
|
:{RewriteRule<rewriteElementType>Stream stream_<it> = new RewriteRule<rewriteElementType>Stream(adaptor,"token <it>", list_<it>);};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
<referencedRuleLabels
|
||||||
|
:{RewriteRuleSubtreeStream stream_<it> = new RewriteRuleSubtreeStream(adaptor, "token <it>", (<it>!=null ? <it>.Tree : null));};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
<referencedRuleListLabels
|
||||||
|
:{RewriteRuleSubtreeStream stream_<it> = new RewriteRuleSubtreeStream(adaptor, "token <it>", list_<it>);};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Generate code for an optional rewrite block; note it uses the deep ref'd element
|
||||||
|
* list rather shallow like other blocks.
|
||||||
|
*/
|
||||||
|
rewriteOptionalBlock(
|
||||||
|
alt,rewriteBlockLevel,
|
||||||
|
referencedElementsDeep, // all nested refs
|
||||||
|
referencedElements, // elements in immediately block; no nested blocks
|
||||||
|
description) ::=
|
||||||
|
<<
|
||||||
|
// <fileName>:<description>
|
||||||
|
if ( <referencedElementsDeep:{el | stream_<el>.HasNext()}; separator=" || "> )
|
||||||
|
{
|
||||||
|
<alt>
|
||||||
|
}
|
||||||
|
<referencedElementsDeep:{el | stream_<el>.Reset();<\n>}>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteClosureBlock(
|
||||||
|
alt,rewriteBlockLevel,
|
||||||
|
referencedElementsDeep, // all nested refs
|
||||||
|
referencedElements, // elements in immediately block; no nested blocks
|
||||||
|
description) ::=
|
||||||
|
<<
|
||||||
|
// <fileName>:<description>
|
||||||
|
while ( <referencedElements:{el | stream_<el>.HasNext()}; separator=" || "> )
|
||||||
|
{
|
||||||
|
<alt>
|
||||||
|
}
|
||||||
|
<referencedElements:{el | stream_<el>.Reset();<\n>}>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewritePositiveClosureBlock(
|
||||||
|
alt,rewriteBlockLevel,
|
||||||
|
referencedElementsDeep, // all nested refs
|
||||||
|
referencedElements, // elements in immediately block; no nested blocks
|
||||||
|
description) ::=
|
||||||
|
<<
|
||||||
|
if ( !(<referencedElements:{el | stream_<el>.HasNext()}; separator=" || ">) ) {
|
||||||
|
throw new RewriteEarlyExitException();
|
||||||
|
}
|
||||||
|
while ( <referencedElements:{el | stream_<el>.HasNext()}; separator=" || "> )
|
||||||
|
{
|
||||||
|
<alt>
|
||||||
|
}
|
||||||
|
<referencedElements:{el | stream_<el>.Reset();<\n>}>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteAlt(a) ::= <<
|
||||||
|
// <a.description>
|
||||||
|
<if(a.pred)>
|
||||||
|
if (<a.pred>)
|
||||||
|
{
|
||||||
|
<a.alt>
|
||||||
|
}<\n>
|
||||||
|
<else>
|
||||||
|
{
|
||||||
|
<a.alt>
|
||||||
|
}<\n>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** For empty rewrites: "r : ... -> ;" */
|
||||||
|
rewriteEmptyAlt() ::= "root_0 = null;"
|
||||||
|
|
||||||
|
rewriteTree(root,children,description,enclosingTreeLevel,treeLevel) ::= <<
|
||||||
|
// <fileName>:<description>
|
||||||
|
{
|
||||||
|
<ASTLabelType> root_<treeLevel> = (<ASTLabelType>)adaptor.GetNilNode();
|
||||||
|
<root:rewriteElement()>
|
||||||
|
<children:rewriteElement()>
|
||||||
|
adaptor.AddChild(root_<enclosingTreeLevel>, root_<treeLevel>);
|
||||||
|
}<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteElementList(elements) ::= "<elements:rewriteElement()>"
|
||||||
|
|
||||||
|
rewriteElement(e) ::= <<
|
||||||
|
<@pregen()>
|
||||||
|
<e.el>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen ID or ID[args] */
|
||||||
|
rewriteTokenRef(token,elementIndex,hetero,args) ::= <<
|
||||||
|
adaptor.AddChild(root_<treeLevel>, <createRewriteNodeFromElement(...)>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen $label ... where defined via label=ID */
|
||||||
|
rewriteTokenLabelRef(label,elementIndex) ::= <<
|
||||||
|
adaptor.AddChild(root_<treeLevel>, stream_<label>.NextNode());<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen $label ... where defined via label+=ID */
|
||||||
|
rewriteTokenListLabelRef(label,elementIndex) ::= <<
|
||||||
|
adaptor.AddChild(root_<treeLevel>, stream_<label>.NextNode());<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen ^($label ...) */
|
||||||
|
rewriteTokenLabelRefRoot(label,elementIndex) ::= <<
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)adaptor.BecomeRoot(stream_<label>.NextNode(), root_<treeLevel>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen ^($label ...) where label+=... */
|
||||||
|
rewriteTokenListLabelRefRoot ::= rewriteTokenLabelRefRoot
|
||||||
|
|
||||||
|
/** Gen ^(ID ...) or ^(ID[args] ...) */
|
||||||
|
rewriteTokenRefRoot(token,elementIndex,hetero,args) ::= <<
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)adaptor.BecomeRoot(<createRewriteNodeFromElement(...)>, root_<treeLevel>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteImaginaryTokenRef(args,token,hetero,elementIndex) ::= <<
|
||||||
|
adaptor.AddChild(root_<treeLevel>, <createImaginaryNode(tokenType=token, ...)>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteImaginaryTokenRefRoot(args,token,hetero,elementIndex) ::= <<
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)adaptor.BecomeRoot(<createImaginaryNode(tokenType=token, ...)>, root_<treeLevel>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** plain -> {foo} action */
|
||||||
|
rewriteAction(action) ::= <<
|
||||||
|
root_0 = <action>;<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** What is the name of the previous value of this rule's root tree? This
|
||||||
|
* let's us refer to $rule to mean previous value. I am reusing the
|
||||||
|
* variable 'tree' sitting in retval struct to hold the value of root_0 right
|
||||||
|
* before I set it during rewrites. The assign will be to retval.Tree.
|
||||||
|
*/
|
||||||
|
prevRuleRootRef() ::= "retval"
|
||||||
|
|
||||||
|
rewriteRuleRef(rule) ::= <<
|
||||||
|
adaptor.AddChild(root_<treeLevel>, stream_<rule>.NextTree());<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteRuleRefRoot(rule) ::= <<
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)adaptor.BecomeRoot(stream_<rule>.NextNode(), root_<treeLevel>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteNodeAction(action) ::= <<
|
||||||
|
adaptor.AddChild(root_<treeLevel>, <action>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteNodeActionRoot(action) ::= <<
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)adaptor.BecomeRoot(<action>, root_<treeLevel>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen $ruleLabel ... where defined via ruleLabel=rule */
|
||||||
|
rewriteRuleLabelRef(label) ::= <<
|
||||||
|
adaptor.AddChild(root_<treeLevel>, stream_<label>.NextTree());<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen $ruleLabel ... where defined via ruleLabel+=rule */
|
||||||
|
rewriteRuleListLabelRef(label) ::= <<
|
||||||
|
adaptor.AddChild(root_<treeLevel>, stream_<label>.NextTree());<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen ^($ruleLabel ...) where ruleLabel=rule */
|
||||||
|
rewriteRuleLabelRefRoot(label) ::= <<
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)adaptor.BecomeRoot(stream_<label>.NextNode(), root_<treeLevel>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen ^($ruleLabel ...) where ruleLabel+=rule */
|
||||||
|
rewriteRuleListLabelRefRoot(label) ::= <<
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)adaptor.BecomeRoot(stream_<label>.NextNode(), root_<treeLevel>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
createImaginaryNode(tokenType,hetero,args) ::= <<
|
||||||
|
<if(hetero)>
|
||||||
|
<! new MethodNode(IDLabel, args) !>
|
||||||
|
new <hetero>(<tokenType><if(args)>, <args; separator=", "><endif>)
|
||||||
|
<else>
|
||||||
|
(<ASTLabelType>)adaptor.Create(<tokenType>, <args; separator=", "><if(!args)>"<tokenType>"<endif>)
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
createRewriteNodeFromElement(token,hetero,args) ::= <<
|
||||||
|
<if(hetero)>
|
||||||
|
new <hetero>(stream_<token>.NextToken()<if(args)>, <args; separator=", "><endif>)
|
||||||
|
<else>
|
||||||
|
<if(args)> <! must create new node from old !>
|
||||||
|
adaptor.Create(<token>, <args; separator=", ">)
|
||||||
|
<else>
|
||||||
|
stream_<token>.NextNode()
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
>>
|
97
antlr_3_1_source/codegen/templates/CSharp2/ASTDbg.stg
Normal file
97
antlr_3_1_source/codegen/templates/CSharp2/ASTDbg.stg
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2007-2008 Johannes Luber
|
||||||
|
Copyright (c) 2005-2007 Kunle Odutola
|
||||||
|
Copyright (c) 2005 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Template overrides to add debugging to AST stuff. Dynamic inheritance
|
||||||
|
* hierarchy is set up as ASTDbg : AST : Dbg : C# by code generator.
|
||||||
|
*/
|
||||||
|
group ASTDbg;
|
||||||
|
|
||||||
|
parserMembers() ::= <<
|
||||||
|
protected DebugTreeAdaptor adaptor;
|
||||||
|
public ITreeAdaptor TreeAdaptor
|
||||||
|
{
|
||||||
|
get {
|
||||||
|
<if(grammar.grammarIsRoot)>
|
||||||
|
return this.adaptor;
|
||||||
|
<else>
|
||||||
|
this.adaptor = (DebugTreeAdaptor)adaptor; // delegator sends dbg adaptor
|
||||||
|
<endif><\n>
|
||||||
|
<grammar.directDelegates:{g|<g:delegateName()>.TreeAdaptor = this.adaptor;}>
|
||||||
|
}
|
||||||
|
set { this.adaptor = new DebugTreeAdaptor(dbg, value); }
|
||||||
|
}<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
parserCtorBody() ::= <<
|
||||||
|
<super.parserCtorBody()>
|
||||||
|
>>
|
||||||
|
|
||||||
|
createListenerAndHandshake() ::= <<
|
||||||
|
DebugEventSocketProxy proxy = new DebugEventSocketProxy(this, port, adaptor);
|
||||||
|
DebugListener = proxy;
|
||||||
|
<!
|
||||||
|
Original line follows, replaced by the next two ifs:
|
||||||
|
set<inputStreamType>(new Debug<inputStreamType>(input,proxy));
|
||||||
|
!>
|
||||||
|
<if(PARSER)>
|
||||||
|
TokenStream = new DebugTokenStream(input,proxy);<\n>
|
||||||
|
<endif>
|
||||||
|
<if(TREE_PARSER)>
|
||||||
|
TokenStream = new DebugTreeNodeStream(input,proxy);<\n>
|
||||||
|
<endif>
|
||||||
|
try {
|
||||||
|
proxy.Handshake();
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
ReportError(ioe);
|
||||||
|
}
|
||||||
|
>>
|
||||||
|
|
||||||
|
@ctorForRootGrammar.finally() ::= <<
|
||||||
|
ITreeAdaptor adap = new CommonTreeAdaptor();
|
||||||
|
TreeAdaptor = adap;
|
||||||
|
proxy.TreeAdaptor = adap;
|
||||||
|
>>
|
||||||
|
|
||||||
|
@ctorForProfilingRootGrammar.finally() ::=<<
|
||||||
|
ITreeAdaptor adap = new CommonTreeAdaptor();
|
||||||
|
TreeAdaptor = adap;
|
||||||
|
proxy.TreeAdaptor = adap;
|
||||||
|
>>
|
||||||
|
|
||||||
|
@ctorForPredefinedListener.superClassRef() ::= "base(input, dbg)"
|
||||||
|
|
||||||
|
@ctorForPredefinedListener.finally() ::=<<
|
||||||
|
<if(grammar.grammarIsRoot)> <! don't create new adaptor for delegates !>
|
||||||
|
ITreeAdaptor adap = new CommonTreeAdaptor();
|
||||||
|
TreeAdaptor = adap;<\n>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
@rewriteElement.pregen() ::= "dbg.Location(<e.line>,<e.pos>);"
|
220
antlr_3_1_source/codegen/templates/CSharp2/ASTParser.stg
Normal file
220
antlr_3_1_source/codegen/templates/CSharp2/ASTParser.stg
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2007-2008 Johannes Luber
|
||||||
|
Copyright (c) 2005-2007 Kunle Odutola
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Templates for building ASTs during normal parsing.
|
||||||
|
*
|
||||||
|
* Deal with many combinations. Dimensions are:
|
||||||
|
* Auto build or rewrite
|
||||||
|
* no label, label, list label (label/no-label handled together)
|
||||||
|
* child, root
|
||||||
|
* token, set, rule, wildcard
|
||||||
|
*
|
||||||
|
* The situation is not too bad as rewrite (->) usage makes ^ and !
|
||||||
|
* invalid. There is no huge explosion of combinations.
|
||||||
|
*/
|
||||||
|
group ASTParser;
|
||||||
|
|
||||||
|
@rule.setErrorReturnValue() ::= <<
|
||||||
|
// Conversion of the second argument necessary, but harmless
|
||||||
|
retval.Tree = (<ASTLabelType>)adaptor.ErrorNode(input, (IToken) retval.Start, input.LT(-1), re);
|
||||||
|
<! System.Console.WriteLine("<ruleName> returns " + ((CommonTree)retval.Tree).ToStringTree()); !>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// TOKEN AST STUFF
|
||||||
|
|
||||||
|
/** ID and output=AST */
|
||||||
|
tokenRef(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
<if(backtracking)>
|
||||||
|
if ( state.backtracking == 0 )
|
||||||
|
{
|
||||||
|
<endif>
|
||||||
|
<label>_tree = <createNodeFromToken(...)>;
|
||||||
|
adaptor.AddChild(root_0, <label>_tree);
|
||||||
|
<if(backtracking)>
|
||||||
|
}
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ID! and output=AST (same as plain tokenRef) */
|
||||||
|
tokenRefBang(token,label,elementIndex) ::= "<super.tokenRef(...)>"
|
||||||
|
|
||||||
|
/** ID^ and output=AST */
|
||||||
|
tokenRefRuleRoot(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
<if(backtracking)>
|
||||||
|
if ( state.backtracking == 0 )
|
||||||
|
{
|
||||||
|
<endif>
|
||||||
|
<label>_tree = <createNodeFromToken(...)>;
|
||||||
|
root_0 = (<ASTLabelType>)adaptor.BecomeRoot(<label>_tree, root_0);
|
||||||
|
<if(backtracking)>
|
||||||
|
}
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ids+=ID! and output=AST */
|
||||||
|
tokenRefBangAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefBang(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** label+=TOKEN when output=AST but not rewrite alt */
|
||||||
|
tokenRefAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRef(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Match label+=TOKEN^ when output=AST but not rewrite alt */
|
||||||
|
tokenRefRuleRootAndListLabel(token,label,hetero,elementIndex) ::= <<
|
||||||
|
<tokenRefRuleRoot(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// SET AST
|
||||||
|
|
||||||
|
// the match set stuff is interesting in that it uses an argument list
|
||||||
|
// to pass code to the default matchSet; another possible way to alter
|
||||||
|
// inherited code. I don't use the region stuff because I need to pass
|
||||||
|
// different chunks depending on the operator. I don't like making
|
||||||
|
// the template name have the operator as the number of templates gets
|
||||||
|
// large but this is the most flexible--this is as opposed to having
|
||||||
|
// the code generator call matchSet then add root code or ruleroot code
|
||||||
|
// plus list label plus ... The combinations might require complicated
|
||||||
|
// rather than just added on code. Investigate that refactoring when
|
||||||
|
// I have more time.
|
||||||
|
|
||||||
|
matchSet(s,label,hetero,elementIndex,postmatchCode) ::= <<
|
||||||
|
<super.matchSet(..., postmatchCode={<if(backtracking)>if ( state.backtracking == 0 ) <endif>adaptor.AddChild(root_0, <createNodeFromToken(...)>);})>
|
||||||
|
>>
|
||||||
|
|
||||||
|
matchRuleBlockSet(s,label,hetero,elementIndex,postmatchCode,treeLevel="0") ::= <<
|
||||||
|
<matchSet(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
matchSetBang(s,label,elementIndex,postmatchCode) ::= "<super.matchSet(...)>"
|
||||||
|
|
||||||
|
// note there is no matchSetTrack because -> rewrites force sets to be
|
||||||
|
// plain old blocks of alts: (A|B|...|C)
|
||||||
|
|
||||||
|
matchSetRuleRoot(s,label,hetero,elementIndex,debug) ::= <<
|
||||||
|
<if(label)>
|
||||||
|
<label>=(<labelType>)input.LT(1);<\n>
|
||||||
|
<endif>
|
||||||
|
<super.matchSet(..., postmatchCode={<if(backtracking)>if ( state.backtracking == 0 ) <endif>root_0 = (<ASTLabelType>)adaptor.BecomeRoot(<createNodeFromToken(...)>, root_0);})>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// RULE REF AST
|
||||||
|
|
||||||
|
/** rule when output=AST */
|
||||||
|
ruleRef(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<super.ruleRef(...)>
|
||||||
|
<if(backtracking)>if ( state.backtracking == 0 ) <endif>adaptor.AddChild(root_0, <label>.Tree);
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** rule! is same as normal rule ref */
|
||||||
|
ruleRefBang(rule,label,elementIndex,args,scope) ::= "<super.ruleRef(...)>"
|
||||||
|
|
||||||
|
/** rule^ */
|
||||||
|
ruleRefRuleRoot(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<super.ruleRef(...)>
|
||||||
|
<if(backtracking)>if ( state.backtracking == 0 ) <endif>root_0 = (<ASTLabelType>)adaptor.BecomeRoot(<label>.Tree, root_0);
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule when output=AST */
|
||||||
|
ruleRefAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRef(...)>
|
||||||
|
<listLabel(elem=label+".Tree",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule! when output=AST is a rule ref with list addition */
|
||||||
|
ruleRefBangAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefBang(...)>
|
||||||
|
<listLabel(elem=label+".Tree",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule^ */
|
||||||
|
ruleRefRuleRootAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefRuleRoot(...)>
|
||||||
|
<listLabel(elem=label+".Tree",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// WILDCARD AST
|
||||||
|
|
||||||
|
wildcard(label,elementIndex) ::= <<
|
||||||
|
<super.wildcard(...)>
|
||||||
|
<if(backtracking)>
|
||||||
|
if ( state.backtracking == 0 )
|
||||||
|
{
|
||||||
|
<endif>
|
||||||
|
<label>_tree = (<ASTLabelType>)adaptor.Create(<label>);
|
||||||
|
adaptor.AddChild(root_0, <label>_tree);
|
||||||
|
<if(backtracking)>
|
||||||
|
}
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
wildcardBang(label,elementIndex) ::= "<super.wildcard(...)>"
|
||||||
|
|
||||||
|
wildcardRuleRoot(label,elementIndex) ::= <<
|
||||||
|
<super.wildcard(...)>
|
||||||
|
<if(backtracking)>
|
||||||
|
if ( state.backtracking == 0 )
|
||||||
|
{
|
||||||
|
<endif>
|
||||||
|
<label>_tree = (<ASTLabelType>)adaptor.Create(<label>);
|
||||||
|
root_0 = (<ASTLabelType>)adaptor.BecomeRoot(<label>_tree, root_0);
|
||||||
|
<if(backtracking)>
|
||||||
|
}
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
createNodeFromToken(label,hetero) ::= <<
|
||||||
|
<if(hetero)>
|
||||||
|
new <hetero>(<label>) <! new MethodNode(IDLabel) !>
|
||||||
|
<else>
|
||||||
|
(<ASTLabelType>)adaptor.Create(<label>)
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
ruleCleanUp() ::= <<
|
||||||
|
<super.ruleCleanUp()>
|
||||||
|
<if(backtracking)>
|
||||||
|
if ( state.backtracking==0 )
|
||||||
|
{
|
||||||
|
<endif>
|
||||||
|
retval.Tree = (<ASTLabelType>)adaptor.RulePostProcessing(root_0);
|
||||||
|
<if(!TREE_PARSER)>
|
||||||
|
adaptor.SetTokenBoundaries(retval.Tree, (IToken) retval.Start, (IToken) retval.Stop);
|
||||||
|
<endif>
|
||||||
|
<if(backtracking)>
|
||||||
|
}
|
||||||
|
<endif>
|
||||||
|
>>
|
299
antlr_3_1_source/codegen/templates/CSharp2/ASTTreeParser.stg
Normal file
299
antlr_3_1_source/codegen/templates/CSharp2/ASTTreeParser.stg
Normal file
@ -0,0 +1,299 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2007-2008 Johannes Luber
|
||||||
|
Copyright (c) 2005-2007 Kunle Odutola
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Templates for building ASTs during tree parsing.
|
||||||
|
*
|
||||||
|
* Deal with many combinations. Dimensions are:
|
||||||
|
* Auto build or rewrite
|
||||||
|
* no label, label, list label (label/no-label handled together)
|
||||||
|
* child, root
|
||||||
|
* token, set, rule, wildcard
|
||||||
|
*
|
||||||
|
* Each combination has its own template except that label/no label
|
||||||
|
* is combined into tokenRef, ruleRef, ...
|
||||||
|
*/
|
||||||
|
group ASTTreeParser;
|
||||||
|
|
||||||
|
/** Add a variable to track last element matched */
|
||||||
|
ruleDeclarations() ::= <<
|
||||||
|
<super.ruleDeclarations()>
|
||||||
|
<ASTLabelType> _first_0 = null;
|
||||||
|
<ASTLabelType> _last = null;<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** What to emit when there is no rewrite rule. For auto build
|
||||||
|
* mode, does nothing.
|
||||||
|
*/
|
||||||
|
noRewrite(rewriteBlockLevel, treeLevel) ::= <<
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) {<endif>
|
||||||
|
<if(rewriteMode)>
|
||||||
|
retval.Tree = (<ASTLabelType>)_first_0;
|
||||||
|
if ( adaptor.GetParent(retval.Tree)!=null && adaptor.IsNil( adaptor.GetParent(retval.Tree) ) )
|
||||||
|
retval.Tree = (<ASTLabelType>)adaptor.GetParent(retval.Tree);
|
||||||
|
<endif>
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** match ^(root children) in tree parser; override here to
|
||||||
|
* add tree construction actions.
|
||||||
|
*/
|
||||||
|
tree(root, actionsAfterRoot, children, nullableChildList,
|
||||||
|
enclosingTreeLevel, treeLevel) ::= <<
|
||||||
|
_last = (<ASTLabelType>)input.LT(1);
|
||||||
|
{
|
||||||
|
<ASTLabelType> _save_last_<treeLevel> = _last;
|
||||||
|
<ASTLabelType> _first_<treeLevel> = null;
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<ASTLabelType> root_<treeLevel> = (<ASTLabelType>)adaptor.GetNilNode();
|
||||||
|
<endif>
|
||||||
|
<root:element()>
|
||||||
|
<if(rewriteMode)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 )<endif>
|
||||||
|
<if(root.el.rule)>
|
||||||
|
if ( _first_<enclosingTreeLevel>==null ) _first_<enclosingTreeLevel> = <root.el.label>.Tree;
|
||||||
|
<else>
|
||||||
|
if ( _first_<enclosingTreeLevel>==null ) _first_<enclosingTreeLevel> = <root.el.label>;
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
<actionsAfterRoot:element()>
|
||||||
|
<if(nullableChildList)>
|
||||||
|
if ( input.LA(1) == Token.DOWN )
|
||||||
|
{
|
||||||
|
Match(input, Token.DOWN, null); <checkRuleBacktrackFailure()>
|
||||||
|
<children:element()>
|
||||||
|
Match(input, Token.UP, null); <checkRuleBacktrackFailure()>
|
||||||
|
}
|
||||||
|
<else>
|
||||||
|
Match(input, Token.DOWN, null); <checkRuleBacktrackFailure()>
|
||||||
|
<children:element()>
|
||||||
|
Match(input, Token.UP, null); <checkRuleBacktrackFailure()>
|
||||||
|
<endif>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
adaptor.AddChild(root_<enclosingTreeLevel>, root_<treeLevel>);
|
||||||
|
<endif>
|
||||||
|
_last = _save_last_<treeLevel>;
|
||||||
|
}<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// TOKEN AST STUFF
|
||||||
|
|
||||||
|
/** ID! and output=AST (same as plain tokenRef) 'cept add
|
||||||
|
* setting of _last
|
||||||
|
*/
|
||||||
|
tokenRefBang(token,label,elementIndex) ::= <<
|
||||||
|
_last = (<ASTLabelType>)input.LT(1);
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ID auto construct */
|
||||||
|
tokenRef(token,label,elementIndex,hetero) ::= <<
|
||||||
|
_last = (<ASTLabelType>)input.LT(1);
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<if(backtracking)>
|
||||||
|
if ( state.backtracking == 0 )
|
||||||
|
{
|
||||||
|
<endif>
|
||||||
|
<if(hetero)>
|
||||||
|
<label>_tree = new <hetero>(<label>);
|
||||||
|
<else>
|
||||||
|
<label>_tree = (<ASTLabelType>)adaptor.DupNode(<label>);
|
||||||
|
<endif><\n>
|
||||||
|
adaptor.AddChild(root_<treeLevel>, <label>_tree);
|
||||||
|
<if(backtracking)>
|
||||||
|
}
|
||||||
|
<endif>
|
||||||
|
<else> <! rewrite mode !>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 )<endif>
|
||||||
|
if ( _first_<treeLevel>==null ) _first_<treeLevel> = <label>;
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** label+=TOKEN auto construct */
|
||||||
|
tokenRefAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRef(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(ID ...) auto construct */
|
||||||
|
tokenRefRuleRoot(token,label,elementIndex,hetero) ::= <<
|
||||||
|
_last = (<ASTLabelType>)input.LT(1);
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<if(backtracking)>
|
||||||
|
if ( state.backtracking == 0 )
|
||||||
|
{
|
||||||
|
<endif>
|
||||||
|
<if(hetero)>
|
||||||
|
<label>_tree = new <hetero>(<label>);
|
||||||
|
<else>
|
||||||
|
<label>_tree = (<ASTLabelType>)adaptor.DupNode(<label>);
|
||||||
|
<endif><\n>
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)adaptor.BecomeRoot(<label>_tree, root_<treeLevel>);
|
||||||
|
<if(backtracking)>
|
||||||
|
}
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Match ^(label+=TOKEN ...) auto construct */
|
||||||
|
tokenRefRuleRootAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefRuleRoot(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// SET AST
|
||||||
|
|
||||||
|
matchSet(s,label,hetero,elementIndex,postmatchCode) ::= <<
|
||||||
|
_last = (<ASTLabelType>)input.LT(1);
|
||||||
|
<super.matchSet(..., postmatchCode={
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) {<endif>
|
||||||
|
<if(hetero)>
|
||||||
|
<label>_tree = new <hetero>(<label>);
|
||||||
|
<else>
|
||||||
|
<label>_tree = (<ASTLabelType>)adaptor.DupNode(<label>);
|
||||||
|
<endif><\n>
|
||||||
|
adaptor.AddChild(root_<treeLevel>, <label>_tree);
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
<endif>
|
||||||
|
}
|
||||||
|
)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
matchRuleBlockSet(s,label,hetero,elementIndex,postmatchCode,treeLevel="0") ::= <<
|
||||||
|
<matchSet(...)>
|
||||||
|
<noRewrite()> <! set return tree !>
|
||||||
|
>>
|
||||||
|
|
||||||
|
matchSetBang(s,label,elementIndex,postmatchCode) ::= <<
|
||||||
|
_last = (<ASTLabelType>)input.LT(1);
|
||||||
|
<super.matchSet(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
matchSetRuleRoot(s,label,hetero,elementIndex,debug) ::= <<
|
||||||
|
<super.matchSet(..., postmatchCode={
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) {<endif>
|
||||||
|
<if(hetero)>
|
||||||
|
<label>_tree = new <hetero>(<label>);
|
||||||
|
<else>
|
||||||
|
<label>_tree = (<ASTLabelType>)adaptor.DupNode(<label>);
|
||||||
|
<endif><\n>
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)adaptor.BecomeRoot(<label>_tree, root_<treeLevel>);
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
<endif>
|
||||||
|
}
|
||||||
|
)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// RULE REF AST
|
||||||
|
|
||||||
|
/** rule auto construct */
|
||||||
|
ruleRef(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
_last = (<ASTLabelType>)input.LT(1);
|
||||||
|
<super.ruleRef(...)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) <endif>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
adaptor.AddChild(root_<treeLevel>, <label>.Tree);
|
||||||
|
<else> <! rewrite mode !>
|
||||||
|
if ( _first_<treeLevel>==null ) _first_<treeLevel> = <label>.Tree;
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule auto construct */
|
||||||
|
ruleRefAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRef(...)>
|
||||||
|
<listLabel(elem=label+".Tree",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(rule ...) auto construct */
|
||||||
|
ruleRefRuleRoot(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
_last = (<ASTLabelType>)input.LT(1);
|
||||||
|
<super.ruleRef(...)>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<if(backtracking)>if ( state.backtracking == 0 ) <endif>root_<treeLevel> = (<ASTLabelType>)adaptor.BecomeRoot(<label>.Tree, root_<treeLevel>);
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(x+=rule ...) auto construct */
|
||||||
|
ruleRefRuleRootAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefRuleRoot(...)>
|
||||||
|
<listLabel(elem=label+".Tree",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** rule when output=AST and tracking for rewrite */
|
||||||
|
ruleRefTrack(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
_last = (<ASTLabelType>)input.LT(1);
|
||||||
|
<super.ruleRefTrack(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule when output=AST and tracking for rewrite */
|
||||||
|
ruleRefTrackAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
_last = (<ASTLabelType>)input.LT(1);
|
||||||
|
<super.ruleRefTrackAndListLabel(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(rule ...) rewrite */
|
||||||
|
ruleRefRuleRootTrack(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
_last = (<ASTLabelType>)input.LT(1);
|
||||||
|
<super.ruleRefRootTrack(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(x+=rule ...) rewrite */
|
||||||
|
ruleRefRuleRootTrackAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
_last = (<ASTLabelType>)input.LT(1);
|
||||||
|
<super.ruleRefRuleRootTrackAndListLabel(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Streams for token refs are tree nodes now; override to
|
||||||
|
* change nextToken to nextNode.
|
||||||
|
*/
|
||||||
|
createRewriteNodeFromElement(token,hetero,scope) ::= <<
|
||||||
|
<if(hetero)>
|
||||||
|
new <hetero>(stream_<token>.NextNode())
|
||||||
|
<else>
|
||||||
|
stream_<token>.NextNode()
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
ruleCleanUp() ::= <<
|
||||||
|
<super.ruleCleanUp()>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<if(backtracking)>
|
||||||
|
if ( state.backtracking==0 )
|
||||||
|
{
|
||||||
|
<endif>
|
||||||
|
retval.Tree = (<ASTLabelType>)adaptor.RulePostProcessing(root_0);
|
||||||
|
<if(backtracking)>
|
||||||
|
}
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
>>
|
1447
antlr_3_1_source/codegen/templates/CSharp2/CSharp2.stg
Normal file
1447
antlr_3_1_source/codegen/templates/CSharp2/CSharp2.stg
Normal file
File diff suppressed because it is too large
Load Diff
288
antlr_3_1_source/codegen/templates/CSharp2/Dbg.stg
Normal file
288
antlr_3_1_source/codegen/templates/CSharp2/Dbg.stg
Normal file
@ -0,0 +1,288 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2007-2008 Johannes Luber
|
||||||
|
Copyright (c) 2005-2007 Kunle Odutola
|
||||||
|
Copyright (c) 2005 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
/** Template overrides to add debugging to normal Java output;
|
||||||
|
* If ASTs are built, then you'll also get ASTDbg.stg loaded.
|
||||||
|
*/
|
||||||
|
group Dbg;
|
||||||
|
|
||||||
|
@outputFile.imports() ::= <<
|
||||||
|
<@super.imports()>
|
||||||
|
using Antlr.Runtime.Debug;
|
||||||
|
using IOException = System.IO.IOException;
|
||||||
|
>>
|
||||||
|
|
||||||
|
@genericParser.members() ::= <<
|
||||||
|
<if(grammar.grammarIsRoot)>
|
||||||
|
public static readonly string[] ruleNames = new string[] {
|
||||||
|
"invalidRule", <grammar.allImportedRules:{rST | "<rST.name>"}; wrap="\n ", separator=", ">
|
||||||
|
};<\n>
|
||||||
|
<endif>
|
||||||
|
<if(grammar.grammarIsRoot)> <! grammar imports other grammar(s) !>
|
||||||
|
private int ruleLevel = 0;
|
||||||
|
public int RuleLevel {
|
||||||
|
get { return ruleLevel; }
|
||||||
|
}
|
||||||
|
public void IncRuleLevel() { ruleLevel++; }
|
||||||
|
public void DecRuleLevel() { ruleLevel--; }
|
||||||
|
<if(profile)>
|
||||||
|
<ctorForProfilingRootGrammar()>
|
||||||
|
<else>
|
||||||
|
<ctorForRootGrammar()>
|
||||||
|
<endif>
|
||||||
|
<ctorForPredefinedListener()>
|
||||||
|
<else> <! imported grammar !>
|
||||||
|
public int RuleLevel {
|
||||||
|
get { return <grammar.delegators:{g| <g:delegateName()>}>.RuleLevel; }
|
||||||
|
}
|
||||||
|
public void IncRuleLevel() { <grammar.delegators:{g| <g:delegateName()>}>.IncRuleLevel(); }
|
||||||
|
public void DecRuleLevel() { <grammar.delegators:{g| <g:delegateName()>}>.DecRuleLevel(); }
|
||||||
|
<ctorForDelegateGrammar()>
|
||||||
|
<endif>
|
||||||
|
<if(profile)>
|
||||||
|
override public bool AlreadyParsedRule(IIntStream input, int ruleIndex)
|
||||||
|
{
|
||||||
|
((Profiler)dbg).ExamineRuleMemoization(input, ruleIndex, <grammar.composite.rootGrammar.recognizerName>.ruleNames[ruleIndex]);
|
||||||
|
return base.AlreadyParsedRule(input, ruleIndex);
|
||||||
|
}<\n>
|
||||||
|
override public void Memoize(IIntStream input,
|
||||||
|
int ruleIndex,
|
||||||
|
int ruleStartIndex)
|
||||||
|
{
|
||||||
|
((Profiler)dbg).Memoize(input, ruleIndex, ruleStartIndex, <grammar.composite.rootGrammar.recognizerName>.ruleNames[ruleIndex]);
|
||||||
|
base.Memoize(input, ruleIndex, ruleStartIndex);
|
||||||
|
}<\n>
|
||||||
|
<endif>
|
||||||
|
protected bool EvalPredicate(bool result, string predicate)
|
||||||
|
{
|
||||||
|
dbg.SemanticPredicate(result, predicate);
|
||||||
|
return result;
|
||||||
|
}<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
ctorForRootGrammar() ::= <<
|
||||||
|
<! bug: can't use <@super.members()> cut-n-paste instead !>
|
||||||
|
<! Same except we add port number and profile stuff if root grammar !>
|
||||||
|
public <name>(<inputStreamType> input)
|
||||||
|
: this(input, DebugEventSocketProxy.DEFAULT_DEBUGGER_PORT, new RecognizerSharedState()) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public <name>(<inputStreamType> input, int port, RecognizerSharedState state)
|
||||||
|
: base(input, state) {
|
||||||
|
<parserCtorBody()>
|
||||||
|
<createListenerAndHandshake()>
|
||||||
|
<grammar.directDelegates:{g|<g:delegateName()> = new <g.recognizerName>(input, dbg, this.state, this<grammar.delegators:{g|, <g:delegateName()>}>);}; separator="\n">
|
||||||
|
<@finally()>
|
||||||
|
}<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
ctorForProfilingRootGrammar() ::= <<
|
||||||
|
<! bug: can't use <@super.members()> cut-n-paste instead !>
|
||||||
|
public <name>(<inputStreamType> input) {
|
||||||
|
this(input, new Profiler(null), new RecognizerSharedState());
|
||||||
|
}
|
||||||
|
|
||||||
|
public <name>(<inputStreamType> input, IDebugEventListener dbg, RecognizerSharedState state)
|
||||||
|
: base(input, dbg, state) {
|
||||||
|
Profiler p = (Profiler)dbg;
|
||||||
|
p.setParser(this);
|
||||||
|
<parserCtorBody()>
|
||||||
|
<grammar.directDelegates:
|
||||||
|
{g|<g:delegateName()> = new <g.recognizerName>(input, dbg, this.state, this<grammar.delegators:{g|, <g:delegateName()>}>);}; separator="\n">
|
||||||
|
<@finally()>
|
||||||
|
}
|
||||||
|
<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
|
||||||
|
/** Basically we don't want to set any dbg listeners are root will have it. */
|
||||||
|
ctorForDelegateGrammar() ::= <<
|
||||||
|
public <name>(<inputStreamType> input, IDebugEventListener dbg, RecognizerSharedState state<grammar.delegators:{g|, <g.recognizerName> <g:delegateName()>}>)
|
||||||
|
: base(input, dbg, state) {
|
||||||
|
<parserCtorBody()>
|
||||||
|
<grammar.directDelegates:
|
||||||
|
{g|<g:delegateName()> = new <g.recognizerName>(input, this, this.state<grammar.delegators:{g|, <g:delegateName()>}>);}; separator="\n">
|
||||||
|
}<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
ctorForPredefinedListener() ::= <<
|
||||||
|
public <name>(<inputStreamType> input, IDebugEventListener dbg)
|
||||||
|
: <@superClassRef>base(input, dbg, new RecognizerSharedState())<@end> {
|
||||||
|
<if(profile)>
|
||||||
|
Profiler p = (Profiler)dbg;
|
||||||
|
p.setParser(this);
|
||||||
|
<endif>
|
||||||
|
<parserCtorBody()>
|
||||||
|
<grammar.directDelegates:{g|<g:delegateName()> = new <g.recognizerName>(input, dbg, this.state, this<grammar.delegators:{g|, <g:delegateName()>}>);}; separator="\n">
|
||||||
|
<@finally()>
|
||||||
|
}<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
createListenerAndHandshake() ::= <<
|
||||||
|
<if(TREE_PARSER)>
|
||||||
|
DebugEventSocketProxy proxy = new DebugEventSocketProxy(this, port, input.TreeAdaptor);
|
||||||
|
<else>
|
||||||
|
DebugEventSocketProxy proxy = new DebugEventSocketProxy(this, port, null);
|
||||||
|
<endif>
|
||||||
|
DebugListener = proxy;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
proxy.Handshake();
|
||||||
|
}
|
||||||
|
catch (IOException ioe)
|
||||||
|
{
|
||||||
|
ReportError(ioe);
|
||||||
|
}
|
||||||
|
>>
|
||||||
|
|
||||||
|
@genericParser.superClassName() ::= "Debug<@super.superClassName()>"
|
||||||
|
|
||||||
|
@rule.preamble() ::= <<
|
||||||
|
try {
|
||||||
|
dbg.EnterRule(GrammarFileName, "<ruleName>");
|
||||||
|
if ( RuleLevel==0 ) {dbg.Commence();}
|
||||||
|
IncRuleLevel();
|
||||||
|
dbg.Location(<ruleDescriptor.tree.line>, <ruleDescriptor.tree.column>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
@lexer.debugAddition() ::= ", dbg"
|
||||||
|
|
||||||
|
@rule.postamble() ::= <<
|
||||||
|
dbg.Location(<ruleDescriptor.EORNode.line>, <ruleDescriptor.EORNode.column>);<\n>
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
dbg.ExitRule(GrammarFileName, "<ruleName>");
|
||||||
|
DecRuleLevel();
|
||||||
|
if ( RuleLevel==0 ) {dbg.Terminate();}
|
||||||
|
}<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
@synpred.start() ::= "dbg.BeginBacktrack(state.backtracking);"
|
||||||
|
|
||||||
|
@synpred.stop() ::= "dbg.EndBacktrack(state.backtracking, success);"
|
||||||
|
|
||||||
|
// Common debug event triggers used by region overrides below
|
||||||
|
|
||||||
|
enterSubRule() ::=
|
||||||
|
"try { dbg.EnterSubRule(<decisionNumber>);<\n>"
|
||||||
|
|
||||||
|
exitSubRule() ::=
|
||||||
|
"} finally { dbg.ExitSubRule(<decisionNumber>); }<\n>"
|
||||||
|
|
||||||
|
enterDecision() ::=
|
||||||
|
"try { dbg.EnterDecision(<decisionNumber>);<\n>"
|
||||||
|
|
||||||
|
exitDecision() ::=
|
||||||
|
"} finally { dbg.ExitDecision(<decisionNumber>); }<\n>"
|
||||||
|
|
||||||
|
enterAlt(n) ::= "dbg.EnterAlt(<n>);<\n>"
|
||||||
|
|
||||||
|
// Region overrides that tell various constructs to add debugging triggers
|
||||||
|
|
||||||
|
@block.predecision() ::= "<enterSubRule()><enterDecision()>"
|
||||||
|
|
||||||
|
@block.postdecision() ::= "<exitDecision()>"
|
||||||
|
|
||||||
|
@block.postbranch() ::= "<exitSubRule()>"
|
||||||
|
|
||||||
|
@ruleBlock.predecision() ::= "<enterDecision()>"
|
||||||
|
|
||||||
|
@ruleBlock.postdecision() ::= "<exitDecision()>"
|
||||||
|
|
||||||
|
@ruleBlockSingleAlt.prealt() ::= "<enterAlt(n=\"1\")>"
|
||||||
|
|
||||||
|
@blockSingleAlt.prealt() ::= "<enterAlt(n=\"1\")>"
|
||||||
|
|
||||||
|
@positiveClosureBlock.preloop() ::= "<enterSubRule()>"
|
||||||
|
|
||||||
|
@positiveClosureBlock.postloop() ::= "<exitSubRule()>"
|
||||||
|
|
||||||
|
@positiveClosureBlock.predecision() ::= "<enterDecision()>"
|
||||||
|
|
||||||
|
@positiveClosureBlock.postdecision() ::= "<exitDecision()>"
|
||||||
|
|
||||||
|
@positiveClosureBlock.earlyExitException() ::=
|
||||||
|
"dbg.RecognitionException(eee);<\n>"
|
||||||
|
|
||||||
|
@closureBlock.preloop() ::= "<enterSubRule()>"
|
||||||
|
|
||||||
|
@closureBlock.postloop() ::= "<exitSubRule()>"
|
||||||
|
|
||||||
|
@closureBlock.predecision() ::= "<enterDecision()>"
|
||||||
|
|
||||||
|
@closureBlock.postdecision() ::= "<exitDecision()>"
|
||||||
|
|
||||||
|
@altSwitchCase.prealt() ::= "<enterAlt(n=i)>"
|
||||||
|
|
||||||
|
@element.prematch() ::=
|
||||||
|
"dbg.Location(<it.line>,<it.pos>);"
|
||||||
|
|
||||||
|
@matchSet.mismatchedSetException() ::=
|
||||||
|
"dbg.RecognitionException(mse);"
|
||||||
|
|
||||||
|
@dfaState.noViableAltException() ::= "dbg.RecognitionException(nvae_d<decisionNumber>s<stateNumber>);"
|
||||||
|
|
||||||
|
@dfaStateSwitch.noViableAltException() ::= "dbg.RecognitionException(nvae_d<decisionNumber>s<stateNumber>);"
|
||||||
|
|
||||||
|
dfaDecision(decisionNumber,description) ::= <<
|
||||||
|
try
|
||||||
|
{
|
||||||
|
isCyclicDecision = true;
|
||||||
|
<super.dfaDecision(...)>
|
||||||
|
}
|
||||||
|
catch (NoViableAltException nvae)
|
||||||
|
{
|
||||||
|
dbg.RecognitionException(nvae);
|
||||||
|
throw nvae;
|
||||||
|
}
|
||||||
|
>>
|
||||||
|
|
||||||
|
@cyclicDFA.dbgCtor() ::= <<
|
||||||
|
public DFA<dfa.decisionNumber>(BaseRecognizer recognizer, IDebugEventListener dbg) : this(recognizer)
|
||||||
|
{
|
||||||
|
this.dbg = dbg;
|
||||||
|
}
|
||||||
|
>>
|
||||||
|
|
||||||
|
@cyclicDFA.debugMember() ::= <<
|
||||||
|
IDebugEventListener dbg;
|
||||||
|
|
||||||
|
>>
|
||||||
|
|
||||||
|
@cyclicDFA.errorMethod() ::= <<
|
||||||
|
public override void Error(NoViableAltException nvae)
|
||||||
|
{
|
||||||
|
dbg.RecognitionException(nvae);
|
||||||
|
}
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Force predicate validation to trigger an event */
|
||||||
|
evalPredicate(pred,description) ::= <<
|
||||||
|
EvalPredicate(<pred>,"<description>")
|
||||||
|
>>
|
173
antlr_3_1_source/codegen/templates/CSharp2/ST.stg
Normal file
173
antlr_3_1_source/codegen/templates/CSharp2/ST.stg
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2007-2008 Johannes Luber
|
||||||
|
Copyright (c) 2005-2007 Kunle Odutola
|
||||||
|
Copyright (c) 2005 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
/** Template subgroup to add template rewrite output
|
||||||
|
* If debugging, then you'll also get STDbg.stg loaded.
|
||||||
|
*/
|
||||||
|
group ST;
|
||||||
|
|
||||||
|
@outputFile.imports() ::= <<
|
||||||
|
<@super.imports()>
|
||||||
|
using Antlr.StringTemplate;
|
||||||
|
using Antlr.StringTemplate.Language;
|
||||||
|
<if(!backtracking)>
|
||||||
|
using Hashtable = System.Collections.Hashtable;
|
||||||
|
<endif>
|
||||||
|
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Add this to each rule's return value struct */
|
||||||
|
@returnScope.ruleReturnMembers() ::= <<
|
||||||
|
private StringTemplate st;
|
||||||
|
public StringTemplate ST { get { return st; } set { st = value; } }
|
||||||
|
public override object Template { get { return st; } }
|
||||||
|
public override string ToString() { return (st == null) ? null : st.ToString(); }
|
||||||
|
>>
|
||||||
|
|
||||||
|
@genericParser.members() ::= <<
|
||||||
|
<@super.members()>
|
||||||
|
protected StringTemplateGroup templateLib =
|
||||||
|
new StringTemplateGroup("<name>Templates", typeof(AngleBracketTemplateLexer));
|
||||||
|
|
||||||
|
public StringTemplateGroup TemplateLib
|
||||||
|
{
|
||||||
|
get { return this.templateLib; }
|
||||||
|
set { this.templateLib = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \<summary> Allows convenient multi-value initialization:
|
||||||
|
/// "new STAttrMap().Add(...).Add(...)"
|
||||||
|
/// \</summary>
|
||||||
|
protected class STAttrMap : Hashtable
|
||||||
|
{
|
||||||
|
public STAttrMap Add(string attrName, object value)
|
||||||
|
{
|
||||||
|
base.Add(attrName, value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public STAttrMap Add(string attrName, int value)
|
||||||
|
{
|
||||||
|
base.Add(attrName, value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule when output=template */
|
||||||
|
ruleRefAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRef(...)>
|
||||||
|
<listLabel(elem=label+".Template",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteTemplate(alts) ::= <<
|
||||||
|
|
||||||
|
// TEMPLATE REWRITE
|
||||||
|
<if(backtracking)>
|
||||||
|
if ( state.backtracking==0 )
|
||||||
|
{
|
||||||
|
<alts:rewriteTemplateAlt(); separator="else ">
|
||||||
|
<if(rewriteMode)><replaceTextInLine()><endif>
|
||||||
|
}
|
||||||
|
<else>
|
||||||
|
<alts:rewriteTemplateAlt(); separator="else ">
|
||||||
|
<if(rewriteMode)><replaceTextInLine()><endif>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
replaceTextInLine() ::= <<
|
||||||
|
<if(TREE_PARSER)>
|
||||||
|
((TokenRewriteStream)input.TokenStream).Replace(
|
||||||
|
input.TreeAdaptor.GetTokenStartIndex(retval.Start),
|
||||||
|
input.TreeAdaptor.GetTokenStopIndex(retval.Start),
|
||||||
|
retval.ST);
|
||||||
|
<else>
|
||||||
|
((TokenRewriteStream)input).Replace(
|
||||||
|
((IToken)retval.Start).TokenIndex,
|
||||||
|
input.LT(-1).TokenIndex,
|
||||||
|
retval.ST);
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteTemplateAlt() ::= <<
|
||||||
|
// <it.description>
|
||||||
|
<if(it.pred)>
|
||||||
|
if (<it.pred>) {
|
||||||
|
retval.ST = <it.alt>;
|
||||||
|
}<\n>
|
||||||
|
<else>
|
||||||
|
{
|
||||||
|
retval.ST = <it.alt>;
|
||||||
|
}<\n>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteEmptyTemplate(alts) ::= <<
|
||||||
|
null;
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Invoke a template with a set of attribute name/value pairs.
|
||||||
|
* Set the value of the rule's template *after* having set
|
||||||
|
* the attributes because the rule's template might be used as
|
||||||
|
* an attribute to build a bigger template; you get a self-embedded
|
||||||
|
* template.
|
||||||
|
*/
|
||||||
|
rewriteExternalTemplate(name,args) ::= <<
|
||||||
|
templateLib.GetInstanceOf("<name>"<if(args)>,
|
||||||
|
new STAttrMap()<args:{a | .Add("<a.name>", <a.value>)}>
|
||||||
|
<endif>)
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** expr is a string expression that says what template to load */
|
||||||
|
rewriteIndirectTemplate(expr,args) ::= <<
|
||||||
|
templateLib.GetInstanceOf(<expr><if(args)>,
|
||||||
|
new STAttrMap()<args:{a | .Add("<a.name>", <a.value>)}>
|
||||||
|
<endif>)
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Invoke an inline template with a set of attribute name/value pairs */
|
||||||
|
rewriteInlineTemplate(args, template) ::= <<
|
||||||
|
new StringTemplate(templateLib, "<template>"<if(args)>,
|
||||||
|
new STAttrMap()<args:{a | .Add("<a.name>", <a.value>)}>
|
||||||
|
<endif>)
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** plain -> {foo} action */
|
||||||
|
rewriteAction(action) ::= <<
|
||||||
|
<action>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** An action has %st.attrName=expr; or %{st}.attrName=expr; */
|
||||||
|
actionSetAttribute(st,attrName,expr) ::= <<
|
||||||
|
(<st>).SetAttribute("<attrName>",<expr>);
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Translate %{stringExpr} */
|
||||||
|
actionStringConstructor(stringExpr) ::= <<
|
||||||
|
new StringTemplate(templateLib,<stringExpr>)
|
||||||
|
>>
|
393
antlr_3_1_source/codegen/templates/Java/AST.stg
Normal file
393
antlr_3_1_source/codegen/templates/Java/AST.stg
Normal file
@ -0,0 +1,393 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
group AST;
|
||||||
|
|
||||||
|
@outputFile.imports() ::= <<
|
||||||
|
<@super.imports()>
|
||||||
|
<if(!TREE_PARSER)><! tree parser would already have imported !>
|
||||||
|
import org.antlr.runtime.tree.*;<\n>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
@genericParser.members() ::= <<
|
||||||
|
<@super.members()>
|
||||||
|
<parserMembers()>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Add an adaptor property that knows how to build trees */
|
||||||
|
parserMembers() ::= <<
|
||||||
|
protected TreeAdaptor adaptor = new CommonTreeAdaptor();<\n>
|
||||||
|
public void setTreeAdaptor(TreeAdaptor adaptor) {
|
||||||
|
this.adaptor = adaptor;
|
||||||
|
<grammar.directDelegates:{g|<g:delegateName()>.setTreeAdaptor(this.adaptor);}>
|
||||||
|
}
|
||||||
|
public TreeAdaptor getTreeAdaptor() {
|
||||||
|
return adaptor;
|
||||||
|
}
|
||||||
|
>>
|
||||||
|
|
||||||
|
@returnScope.ruleReturnMembers() ::= <<
|
||||||
|
<ASTLabelType> tree;
|
||||||
|
public Object getTree() { return tree; }
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Add a variable to track rule's return AST */
|
||||||
|
ruleDeclarations() ::= <<
|
||||||
|
<super.ruleDeclarations()>
|
||||||
|
<ASTLabelType> root_0 = null;<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
ruleLabelDefs() ::= <<
|
||||||
|
<super.ruleLabelDefs()>
|
||||||
|
<ruleDescriptor.tokenLabels:{<ASTLabelType> <it.label.text>_tree=null;}; separator="\n">
|
||||||
|
<ruleDescriptor.tokenListLabels:{<ASTLabelType> <it.label.text>_tree=null;}; separator="\n">
|
||||||
|
<ruleDescriptor.allTokenRefsInAltsWithRewrites
|
||||||
|
:{RewriteRule<rewriteElementType>Stream stream_<it>=new RewriteRule<rewriteElementType>Stream(adaptor,"token <it>");}; separator="\n">
|
||||||
|
<ruleDescriptor.allRuleRefsInAltsWithRewrites
|
||||||
|
:{RewriteRuleSubtreeStream stream_<it>=new RewriteRuleSubtreeStream(adaptor,"rule <it>");}; separator="\n">
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** When doing auto AST construction, we must define some variables;
|
||||||
|
* These should be turned off if doing rewrites. This must be a "mode"
|
||||||
|
* as a rule could have both rewrite and AST within the same alternative
|
||||||
|
* block.
|
||||||
|
*/
|
||||||
|
@alt.declarations() ::= <<
|
||||||
|
<if(autoAST)>
|
||||||
|
<if(outerAlt)>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
root_0 = (<ASTLabelType>)adaptor.nil();<\n>
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// T r a c k i n g R u l e E l e m e n t s
|
||||||
|
|
||||||
|
/** ID and track it for use in a rewrite rule */
|
||||||
|
tokenRefTrack(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefBang(...)> <! Track implies no auto AST construction!>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) <endif>stream_<token>.add(<label>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ids+=ID and track it for use in a rewrite rule; adds to ids *and*
|
||||||
|
* to the tracking list stream_ID for use in the rewrite.
|
||||||
|
*/
|
||||||
|
tokenRefTrackAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefTrack(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(ID ...) track for rewrite */
|
||||||
|
tokenRefRuleRootTrack(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefBang(...)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) <endif>stream_<token>.add(<label>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Match ^(label+=TOKEN ...) track for rewrite */
|
||||||
|
tokenRefRuleRootTrackAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefRuleRootTrack(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
wildcardTrack(label,elementIndex) ::= <<
|
||||||
|
<super.wildcard(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** rule when output=AST and tracking for rewrite */
|
||||||
|
ruleRefTrack(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<super.ruleRef(...)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) <endif>stream_<rule.name>.add(<label>.getTree());
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule when output=AST and tracking for rewrite */
|
||||||
|
ruleRefTrackAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefTrack(...)>
|
||||||
|
<listLabel(elem=label+".getTree()",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(rule ...) rewrite */
|
||||||
|
ruleRefRuleRootTrack(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefRuleRoot(...)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) <endif>stream_<rule>.add(<label>.getTree());
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(x+=rule ...) rewrite */
|
||||||
|
ruleRefRuleRootTrackAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefRuleRootTrack(...)>
|
||||||
|
<listLabel(elem=label+".getTree()",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// R e w r i t e
|
||||||
|
|
||||||
|
rewriteCode(
|
||||||
|
alts, description,
|
||||||
|
referencedElementsDeep, // ALL referenced elements to right of ->
|
||||||
|
referencedTokenLabels,
|
||||||
|
referencedTokenListLabels,
|
||||||
|
referencedRuleLabels,
|
||||||
|
referencedRuleListLabels,
|
||||||
|
rewriteBlockLevel, enclosingTreeLevel, treeLevel) ::=
|
||||||
|
<<
|
||||||
|
|
||||||
|
// AST REWRITE
|
||||||
|
// elements: <referencedElementsDeep; separator=", ">
|
||||||
|
// token labels: <referencedTokenLabels; separator=", ">
|
||||||
|
// rule labels: <referencedRuleLabels; separator=", ">
|
||||||
|
// token list labels: <referencedTokenListLabels; separator=", ">
|
||||||
|
// rule list labels: <referencedRuleListLabels; separator=", ">
|
||||||
|
<if(backtracking)>
|
||||||
|
if ( state.backtracking==0 ) {<\n>
|
||||||
|
<endif>
|
||||||
|
<prevRuleRootRef()>.tree = root_0;
|
||||||
|
<rewriteCodeLabels()>
|
||||||
|
root_0 = (<ASTLabelType>)adaptor.nil();
|
||||||
|
<alts:rewriteAlt(); separator="else ">
|
||||||
|
<! if tree parser and rewrite=true !>
|
||||||
|
<if(TREE_PARSER)>
|
||||||
|
<if(rewriteMode)>
|
||||||
|
<prevRuleRootRef()>.tree = (<ASTLabelType>)adaptor.rulePostProcessing(root_0);
|
||||||
|
input.replaceChildren(adaptor.getParent(retval.start),
|
||||||
|
adaptor.getChildIndex(retval.start),
|
||||||
|
adaptor.getChildIndex(_last),
|
||||||
|
retval.tree);
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
<! if parser or tree-parser && rewrite!=true, we need to set result !>
|
||||||
|
<if(!TREE_PARSER)>
|
||||||
|
<prevRuleRootRef()>.tree = root_0;
|
||||||
|
<else>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<prevRuleRootRef()>.tree = root_0;
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
<if(backtracking)>
|
||||||
|
}
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteCodeLabels() ::= <<
|
||||||
|
<referencedTokenLabels
|
||||||
|
:{RewriteRule<rewriteElementType>Stream stream_<it>=new RewriteRule<rewriteElementType>Stream(adaptor,"token <it>",<it>);};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
<referencedTokenListLabels
|
||||||
|
:{RewriteRule<rewriteElementType>Stream stream_<it>=new RewriteRule<rewriteElementType>Stream(adaptor,"token <it>", list_<it>);};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
<referencedRuleLabels
|
||||||
|
:{RewriteRuleSubtreeStream stream_<it>=new RewriteRuleSubtreeStream(adaptor,"token <it>",<it>!=null?<it>.tree:null);};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
<referencedRuleListLabels
|
||||||
|
:{RewriteRuleSubtreeStream stream_<it>=new RewriteRuleSubtreeStream(adaptor,"token <it>",list_<it>);};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Generate code for an optional rewrite block; note it uses the deep ref'd element
|
||||||
|
* list rather shallow like other blocks.
|
||||||
|
*/
|
||||||
|
rewriteOptionalBlock(
|
||||||
|
alt,rewriteBlockLevel,
|
||||||
|
referencedElementsDeep, // all nested refs
|
||||||
|
referencedElements, // elements in immediately block; no nested blocks
|
||||||
|
description) ::=
|
||||||
|
<<
|
||||||
|
// <fileName>:<description>
|
||||||
|
if ( <referencedElementsDeep:{el | stream_<el>.hasNext()}; separator="||"> ) {
|
||||||
|
<alt>
|
||||||
|
}
|
||||||
|
<referencedElementsDeep:{el | stream_<el>.reset();<\n>}>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteClosureBlock(
|
||||||
|
alt,rewriteBlockLevel,
|
||||||
|
referencedElementsDeep, // all nested refs
|
||||||
|
referencedElements, // elements in immediately block; no nested blocks
|
||||||
|
description) ::=
|
||||||
|
<<
|
||||||
|
// <fileName>:<description>
|
||||||
|
while ( <referencedElements:{el | stream_<el>.hasNext()}; separator="||"> ) {
|
||||||
|
<alt>
|
||||||
|
}
|
||||||
|
<referencedElements:{el | stream_<el>.reset();<\n>}>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewritePositiveClosureBlock(
|
||||||
|
alt,rewriteBlockLevel,
|
||||||
|
referencedElementsDeep, // all nested refs
|
||||||
|
referencedElements, // elements in immediately block; no nested blocks
|
||||||
|
description) ::=
|
||||||
|
<<
|
||||||
|
if ( !(<referencedElements:{el | stream_<el>.hasNext()}; separator="||">) ) {
|
||||||
|
throw new RewriteEarlyExitException();
|
||||||
|
}
|
||||||
|
while ( <referencedElements:{el | stream_<el>.hasNext()}; separator="||"> ) {
|
||||||
|
<alt>
|
||||||
|
}
|
||||||
|
<referencedElements:{el | stream_<el>.reset();<\n>}>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteAlt(a) ::= <<
|
||||||
|
// <a.description>
|
||||||
|
<if(a.pred)>
|
||||||
|
if (<a.pred>) {
|
||||||
|
<a.alt>
|
||||||
|
}<\n>
|
||||||
|
<else>
|
||||||
|
{
|
||||||
|
<a.alt>
|
||||||
|
}<\n>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** For empty rewrites: "r : ... -> ;" */
|
||||||
|
rewriteEmptyAlt() ::= "root_0 = null;"
|
||||||
|
|
||||||
|
rewriteTree(root,children,description,enclosingTreeLevel,treeLevel) ::= <<
|
||||||
|
// <fileName>:<description>
|
||||||
|
{
|
||||||
|
<ASTLabelType> root_<treeLevel> = (<ASTLabelType>)adaptor.nil();
|
||||||
|
<root:rewriteElement()>
|
||||||
|
<children:rewriteElement()>
|
||||||
|
adaptor.addChild(root_<enclosingTreeLevel>, root_<treeLevel>);
|
||||||
|
}<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteElementList(elements) ::= "<elements:rewriteElement()>"
|
||||||
|
|
||||||
|
rewriteElement(e) ::= <<
|
||||||
|
<@pregen()>
|
||||||
|
<e.el>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen ID or ID[args] */
|
||||||
|
rewriteTokenRef(token,elementIndex,hetero,args) ::= <<
|
||||||
|
adaptor.addChild(root_<treeLevel>, <createRewriteNodeFromElement(...)>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen $label ... where defined via label=ID */
|
||||||
|
rewriteTokenLabelRef(label,elementIndex) ::= <<
|
||||||
|
adaptor.addChild(root_<treeLevel>, stream_<label>.nextNode());<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen $label ... where defined via label+=ID */
|
||||||
|
rewriteTokenListLabelRef(label,elementIndex) ::= <<
|
||||||
|
adaptor.addChild(root_<treeLevel>, stream_<label>.nextNode());<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen ^($label ...) */
|
||||||
|
rewriteTokenLabelRefRoot(label,elementIndex) ::= <<
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)adaptor.becomeRoot(stream_<label>.nextNode(), root_<treeLevel>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen ^($label ...) where label+=... */
|
||||||
|
rewriteTokenListLabelRefRoot ::= rewriteTokenLabelRefRoot
|
||||||
|
|
||||||
|
/** Gen ^(ID ...) or ^(ID[args] ...) */
|
||||||
|
rewriteTokenRefRoot(token,elementIndex,hetero,args) ::= <<
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)adaptor.becomeRoot(<createRewriteNodeFromElement(...)>, root_<treeLevel>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteImaginaryTokenRef(args,token,hetero,elementIndex) ::= <<
|
||||||
|
adaptor.addChild(root_<treeLevel>, <createImaginaryNode(tokenType=token, ...)>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteImaginaryTokenRefRoot(args,token,hetero,elementIndex) ::= <<
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)adaptor.becomeRoot(<createImaginaryNode(tokenType=token, ...)>, root_<treeLevel>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** plain -> {foo} action */
|
||||||
|
rewriteAction(action) ::= <<
|
||||||
|
root_0 = <action>;<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** What is the name of the previous value of this rule's root tree? This
|
||||||
|
* let's us refer to $rule to mean previous value. I am reusing the
|
||||||
|
* variable 'tree' sitting in retval struct to hold the value of root_0 right
|
||||||
|
* before I set it during rewrites. The assign will be to retval.tree.
|
||||||
|
*/
|
||||||
|
prevRuleRootRef() ::= "retval"
|
||||||
|
|
||||||
|
rewriteRuleRef(rule) ::= <<
|
||||||
|
adaptor.addChild(root_<treeLevel>, stream_<rule>.nextTree());<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteRuleRefRoot(rule) ::= <<
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)adaptor.becomeRoot(stream_<rule>.nextNode(), root_<treeLevel>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteNodeAction(action) ::= <<
|
||||||
|
adaptor.addChild(root_<treeLevel>, <action>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteNodeActionRoot(action) ::= <<
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)adaptor.becomeRoot(<action>, root_<treeLevel>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen $ruleLabel ... where defined via ruleLabel=rule */
|
||||||
|
rewriteRuleLabelRef(label) ::= <<
|
||||||
|
adaptor.addChild(root_<treeLevel>, stream_<label>.nextTree());<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen $ruleLabel ... where defined via ruleLabel+=rule */
|
||||||
|
rewriteRuleListLabelRef(label) ::= <<
|
||||||
|
adaptor.addChild(root_<treeLevel>, stream_<label>.nextTree());<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen ^($ruleLabel ...) where ruleLabel=rule */
|
||||||
|
rewriteRuleLabelRefRoot(label) ::= <<
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)adaptor.becomeRoot(stream_<label>.nextNode(), root_<treeLevel>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen ^($ruleLabel ...) where ruleLabel+=rule */
|
||||||
|
rewriteRuleListLabelRefRoot(label) ::= <<
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)adaptor.becomeRoot(stream_<label>.nextNode(), root_<treeLevel>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
createImaginaryNode(tokenType,hetero,args) ::= <<
|
||||||
|
<if(hetero)>
|
||||||
|
<! new MethodNode(IDLabel, args) !>
|
||||||
|
new <hetero>(<tokenType><if(args)>, <args; separator=", "><endif>)
|
||||||
|
<else>
|
||||||
|
(<ASTLabelType>)adaptor.create(<tokenType>, <args; separator=", "><if(!args)>"<tokenType>"<endif>)
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
createRewriteNodeFromElement(token,hetero,args) ::= <<
|
||||||
|
<if(hetero)>
|
||||||
|
new <hetero>(stream_<token>.nextToken()<if(args)>, <args; separator=", "><endif>)
|
||||||
|
<else>
|
||||||
|
<if(args)> <! must create new node from old !>
|
||||||
|
adaptor.create(<token>, <args; separator=", ">)
|
||||||
|
<else>
|
||||||
|
stream_<token>.nextNode()
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
>>
|
87
antlr_3_1_source/codegen/templates/Java/ASTDbg.stg
Normal file
87
antlr_3_1_source/codegen/templates/Java/ASTDbg.stg
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Template overrides to add debugging to AST stuff. Dynamic inheritance
|
||||||
|
* hierarchy is set up as ASTDbg : AST : Dbg : Java by code generator.
|
||||||
|
*/
|
||||||
|
group ASTDbg;
|
||||||
|
|
||||||
|
parserMembers() ::= <<
|
||||||
|
protected DebugTreeAdaptor adaptor;
|
||||||
|
public void setTreeAdaptor(TreeAdaptor adaptor) {
|
||||||
|
<if(grammar.grammarIsRoot)>
|
||||||
|
this.adaptor = new DebugTreeAdaptor(dbg,adaptor);
|
||||||
|
<else>
|
||||||
|
this.adaptor = (DebugTreeAdaptor)adaptor; // delegator sends dbg adaptor
|
||||||
|
<endif><\n>
|
||||||
|
<grammar.directDelegates:{g|<g:delegateName()>.setTreeAdaptor(this.adaptor);}>
|
||||||
|
}
|
||||||
|
public TreeAdaptor getTreeAdaptor() {
|
||||||
|
return adaptor;
|
||||||
|
}<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
parserCtorBody() ::= <<
|
||||||
|
<super.parserCtorBody()>
|
||||||
|
>>
|
||||||
|
|
||||||
|
createListenerAndHandshake() ::= <<
|
||||||
|
DebugEventSocketProxy proxy =
|
||||||
|
new DebugEventSocketProxy(this,port,<if(TREE_PARSER)>input.getTreeAdaptor()<else>adaptor<endif>);
|
||||||
|
setDebugListener(proxy);
|
||||||
|
set<inputStreamType>(new Debug<inputStreamType>(input,proxy));
|
||||||
|
try {
|
||||||
|
proxy.handshake();
|
||||||
|
}
|
||||||
|
catch (IOException ioe) {
|
||||||
|
reportError(ioe);
|
||||||
|
}
|
||||||
|
>>
|
||||||
|
|
||||||
|
@ctorForRootGrammar.finally() ::= <<
|
||||||
|
TreeAdaptor adap = new CommonTreeAdaptor();
|
||||||
|
setTreeAdaptor(adap);
|
||||||
|
proxy.setTreeAdaptor(adap);
|
||||||
|
>>
|
||||||
|
|
||||||
|
@ctorForProfilingRootGrammar.finally() ::=<<
|
||||||
|
TreeAdaptor adap = new CommonTreeAdaptor();
|
||||||
|
setTreeAdaptor(adap);
|
||||||
|
proxy.setTreeAdaptor(adap);
|
||||||
|
>>
|
||||||
|
|
||||||
|
@ctorForPredefinedListener.superClassRef() ::= "super(input, dbg);"
|
||||||
|
|
||||||
|
@ctorForPredefinedListener.finally() ::=<<
|
||||||
|
<if(grammar.grammarIsRoot)> <! don't create new adaptor for delegates !>
|
||||||
|
TreeAdaptor adap = new CommonTreeAdaptor();
|
||||||
|
setTreeAdaptor(adap);<\n>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
@rewriteElement.pregen() ::= "dbg.location(<e.line>,<e.pos>);"
|
190
antlr_3_1_source/codegen/templates/Java/ASTParser.stg
Normal file
190
antlr_3_1_source/codegen/templates/Java/ASTParser.stg
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Templates for building ASTs during normal parsing.
|
||||||
|
*
|
||||||
|
* Deal with many combinations. Dimensions are:
|
||||||
|
* Auto build or rewrite
|
||||||
|
* no label, label, list label (label/no-label handled together)
|
||||||
|
* child, root
|
||||||
|
* token, set, rule, wildcard
|
||||||
|
*
|
||||||
|
* The situation is not too bad as rewrite (->) usage makes ^ and !
|
||||||
|
* invalid. There is no huge explosion of combinations.
|
||||||
|
*/
|
||||||
|
group ASTParser;
|
||||||
|
|
||||||
|
@rule.setErrorReturnValue() ::= <<
|
||||||
|
retval.tree = (<ASTLabelType>)adaptor.errorNode(input, retval.start, input.LT(-1), re);
|
||||||
|
<! System.out.println("<ruleName> returns "+((CommonTree)retval.tree).toStringTree()); !>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// TOKEN AST STUFF
|
||||||
|
|
||||||
|
/** ID and output=AST */
|
||||||
|
tokenRef(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) {<endif>
|
||||||
|
<label>_tree = <createNodeFromToken(...)>;
|
||||||
|
adaptor.addChild(root_0, <label>_tree);
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ID! and output=AST (same as plain tokenRef) */
|
||||||
|
tokenRefBang(token,label,elementIndex) ::= "<super.tokenRef(...)>"
|
||||||
|
|
||||||
|
/** ID^ and output=AST */
|
||||||
|
tokenRefRuleRoot(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) {<endif>
|
||||||
|
<label>_tree = <createNodeFromToken(...)>;
|
||||||
|
root_0 = (<ASTLabelType>)adaptor.becomeRoot(<label>_tree, root_0);
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ids+=ID! and output=AST */
|
||||||
|
tokenRefBangAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefBang(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** label+=TOKEN when output=AST but not rewrite alt */
|
||||||
|
tokenRefAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRef(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Match label+=TOKEN^ when output=AST but not rewrite alt */
|
||||||
|
tokenRefRuleRootAndListLabel(token,label,hetero,elementIndex) ::= <<
|
||||||
|
<tokenRefRuleRoot(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// SET AST
|
||||||
|
|
||||||
|
// the match set stuff is interesting in that it uses an argument list
|
||||||
|
// to pass code to the default matchSet; another possible way to alter
|
||||||
|
// inherited code. I don't use the region stuff because I need to pass
|
||||||
|
// different chunks depending on the operator. I don't like making
|
||||||
|
// the template name have the operator as the number of templates gets
|
||||||
|
// large but this is the most flexible--this is as opposed to having
|
||||||
|
// the code generator call matchSet then add root code or ruleroot code
|
||||||
|
// plus list label plus ... The combinations might require complicated
|
||||||
|
// rather than just added on code. Investigate that refactoring when
|
||||||
|
// I have more time.
|
||||||
|
|
||||||
|
matchSet(s,label,hetero,elementIndex,postmatchCode) ::= <<
|
||||||
|
<super.matchSet(..., postmatchCode={<if(backtracking)>if ( state.backtracking==0 ) <endif>adaptor.addChild(root_0, <createNodeFromToken(...)>);})>
|
||||||
|
>>
|
||||||
|
|
||||||
|
matchRuleBlockSet(s,label,hetero,elementIndex,postmatchCode,treeLevel="0") ::= <<
|
||||||
|
<matchSet(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
matchSetBang(s,label,elementIndex,postmatchCode) ::= "<super.matchSet(...)>"
|
||||||
|
|
||||||
|
// note there is no matchSetTrack because -> rewrites force sets to be
|
||||||
|
// plain old blocks of alts: (A|B|...|C)
|
||||||
|
|
||||||
|
matchSetRuleRoot(s,label,hetero,elementIndex,debug) ::= <<
|
||||||
|
<if(label)>
|
||||||
|
<label>=(<labelType>)input.LT(1);<\n>
|
||||||
|
<endif>
|
||||||
|
<super.matchSet(..., postmatchCode={<if(backtracking)>if ( state.backtracking==0 ) <endif>root_0 = (<ASTLabelType>)adaptor.becomeRoot(<createNodeFromToken(...)>, root_0);})>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// RULE REF AST
|
||||||
|
|
||||||
|
/** rule when output=AST */
|
||||||
|
ruleRef(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<super.ruleRef(...)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) <endif>adaptor.addChild(root_0, <label>.getTree());
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** rule! is same as normal rule ref */
|
||||||
|
ruleRefBang(rule,label,elementIndex,args,scope) ::= "<super.ruleRef(...)>"
|
||||||
|
|
||||||
|
/** rule^ */
|
||||||
|
ruleRefRuleRoot(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<super.ruleRef(...)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) <endif>root_0 = (<ASTLabelType>)adaptor.becomeRoot(<label>.getTree(), root_0);
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule when output=AST */
|
||||||
|
ruleRefAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRef(...)>
|
||||||
|
<listLabel(elem=label+".getTree()",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule! when output=AST is a rule ref with list addition */
|
||||||
|
ruleRefBangAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefBang(...)>
|
||||||
|
<listLabel(elem=label+".getTree()",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule^ */
|
||||||
|
ruleRefRuleRootAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefRuleRoot(...)>
|
||||||
|
<listLabel(elem=label+".getTree()",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// WILDCARD AST
|
||||||
|
|
||||||
|
wildcard(label,elementIndex) ::= <<
|
||||||
|
<super.wildcard(...)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) {<endif>
|
||||||
|
<label>_tree = (<ASTLabelType>)adaptor.create(<label>);
|
||||||
|
adaptor.addChild(root_0, <label>_tree);
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
wildcardBang(label,elementIndex) ::= "<super.wildcard(...)>"
|
||||||
|
|
||||||
|
wildcardRuleRoot(label,elementIndex) ::= <<
|
||||||
|
<super.wildcard(...)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) {<endif>
|
||||||
|
<label>_tree = (<ASTLabelType>)adaptor.create(<label>);
|
||||||
|
root_0 = (<ASTLabelType>)adaptor.becomeRoot(<label>_tree, root_0);
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
createNodeFromToken(label,hetero) ::= <<
|
||||||
|
<if(hetero)>
|
||||||
|
new <hetero>(<label>) <! new MethodNode(IDLabel) !>
|
||||||
|
<else>
|
||||||
|
(<ASTLabelType>)adaptor.create(<label>)
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
ruleCleanUp() ::= <<
|
||||||
|
<super.ruleCleanUp()>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) {<\n><endif>
|
||||||
|
retval.tree = (<ASTLabelType>)adaptor.rulePostProcessing(root_0);
|
||||||
|
adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop);
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
>>
|
281
antlr_3_1_source/codegen/templates/Java/ASTTreeParser.stg
Normal file
281
antlr_3_1_source/codegen/templates/Java/ASTTreeParser.stg
Normal file
@ -0,0 +1,281 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Templates for building ASTs during tree parsing.
|
||||||
|
*
|
||||||
|
* Deal with many combinations. Dimensions are:
|
||||||
|
* Auto build or rewrite
|
||||||
|
* no label, label, list label (label/no-label handled together)
|
||||||
|
* child, root
|
||||||
|
* token, set, rule, wildcard
|
||||||
|
*
|
||||||
|
* Each combination has its own template except that label/no label
|
||||||
|
* is combined into tokenRef, ruleRef, ...
|
||||||
|
*/
|
||||||
|
group ASTTreeParser;
|
||||||
|
|
||||||
|
/** Add a variable to track last element matched */
|
||||||
|
ruleDeclarations() ::= <<
|
||||||
|
<super.ruleDeclarations()>
|
||||||
|
<ASTLabelType> _first_0 = null;
|
||||||
|
<ASTLabelType> _last = null;<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** What to emit when there is no rewrite rule. For auto build
|
||||||
|
* mode, does nothing.
|
||||||
|
*/
|
||||||
|
noRewrite(rewriteBlockLevel, treeLevel) ::= <<
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) {<endif>
|
||||||
|
<if(rewriteMode)>
|
||||||
|
retval.tree = (<ASTLabelType>)_first_0;
|
||||||
|
if ( adaptor.getParent(retval.tree)!=null && adaptor.isNil( adaptor.getParent(retval.tree) ) )
|
||||||
|
retval.tree = (<ASTLabelType>)adaptor.getParent(retval.tree);
|
||||||
|
<endif>
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** match ^(root children) in tree parser; override here to
|
||||||
|
* add tree construction actions.
|
||||||
|
*/
|
||||||
|
tree(root, actionsAfterRoot, children, nullableChildList,
|
||||||
|
enclosingTreeLevel, treeLevel) ::= <<
|
||||||
|
_last = (<ASTLabelType>)input.LT(1);
|
||||||
|
{
|
||||||
|
<ASTLabelType> _save_last_<treeLevel> = _last;
|
||||||
|
<ASTLabelType> _first_<treeLevel> = null;
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<ASTLabelType> root_<treeLevel> = (<ASTLabelType>)adaptor.nil();
|
||||||
|
<endif>
|
||||||
|
<root:element()>
|
||||||
|
<if(rewriteMode)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 )<endif>
|
||||||
|
<if(root.el.rule)>
|
||||||
|
if ( _first_<enclosingTreeLevel>==null ) _first_<enclosingTreeLevel> = <root.el.label>.tree;
|
||||||
|
<else>
|
||||||
|
if ( _first_<enclosingTreeLevel>==null ) _first_<enclosingTreeLevel> = <root.el.label>;
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
<actionsAfterRoot:element()>
|
||||||
|
<if(nullableChildList)>
|
||||||
|
if ( input.LA(1)==Token.DOWN ) {
|
||||||
|
match(input, Token.DOWN, null); <checkRuleBacktrackFailure()>
|
||||||
|
<children:element()>
|
||||||
|
match(input, Token.UP, null); <checkRuleBacktrackFailure()>
|
||||||
|
}
|
||||||
|
<else>
|
||||||
|
match(input, Token.DOWN, null); <checkRuleBacktrackFailure()>
|
||||||
|
<children:element()>
|
||||||
|
match(input, Token.UP, null); <checkRuleBacktrackFailure()>
|
||||||
|
<endif>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
adaptor.addChild(root_<enclosingTreeLevel>, root_<treeLevel>);
|
||||||
|
<endif>
|
||||||
|
_last = _save_last_<treeLevel>;
|
||||||
|
}<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// TOKEN AST STUFF
|
||||||
|
|
||||||
|
/** ID! and output=AST (same as plain tokenRef) 'cept add
|
||||||
|
* setting of _last
|
||||||
|
*/
|
||||||
|
tokenRefBang(token,label,elementIndex) ::= <<
|
||||||
|
_last = (<ASTLabelType>)input.LT(1);
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ID auto construct */
|
||||||
|
tokenRef(token,label,elementIndex,hetero) ::= <<
|
||||||
|
_last = (<ASTLabelType>)input.LT(1);
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) {<endif>
|
||||||
|
<if(hetero)>
|
||||||
|
<label>_tree = new <hetero>(<label>);
|
||||||
|
<else>
|
||||||
|
<label>_tree = (<ASTLabelType>)adaptor.dupNode(<label>);
|
||||||
|
<endif><\n>
|
||||||
|
adaptor.addChild(root_<treeLevel>, <label>_tree);
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
<else> <! rewrite mode !>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 )<endif>
|
||||||
|
if ( _first_<treeLevel>==null ) _first_<treeLevel> = <label>;
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** label+=TOKEN auto construct */
|
||||||
|
tokenRefAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRef(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(ID ...) auto construct */
|
||||||
|
tokenRefRuleRoot(token,label,elementIndex,hetero) ::= <<
|
||||||
|
_last = (<ASTLabelType>)input.LT(1);
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) {<endif>
|
||||||
|
<if(hetero)>
|
||||||
|
<label>_tree = new <hetero>(<label>);
|
||||||
|
<else>
|
||||||
|
<label>_tree = (<ASTLabelType>)adaptor.dupNode(<label>);
|
||||||
|
<endif><\n>
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)adaptor.becomeRoot(<label>_tree, root_<treeLevel>);
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Match ^(label+=TOKEN ...) auto construct */
|
||||||
|
tokenRefRuleRootAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefRuleRoot(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// SET AST
|
||||||
|
|
||||||
|
matchSet(s,label,hetero,elementIndex,postmatchCode) ::= <<
|
||||||
|
_last = (<ASTLabelType>)input.LT(1);
|
||||||
|
<super.matchSet(..., postmatchCode={
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) {<endif>
|
||||||
|
<if(hetero)>
|
||||||
|
<label>_tree = new <hetero>(<label>);
|
||||||
|
<else>
|
||||||
|
<label>_tree = (<ASTLabelType>)adaptor.dupNode(<label>);
|
||||||
|
<endif><\n>
|
||||||
|
adaptor.addChild(root_<treeLevel>, <label>_tree);
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
<endif>
|
||||||
|
}
|
||||||
|
)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
matchRuleBlockSet(s,label,hetero,elementIndex,postmatchCode,treeLevel="0") ::= <<
|
||||||
|
<matchSet(...)>
|
||||||
|
<noRewrite()> <! set return tree !>
|
||||||
|
>>
|
||||||
|
|
||||||
|
matchSetBang(s,label,elementIndex,postmatchCode) ::= <<
|
||||||
|
_last = (<ASTLabelType>)input.LT(1);
|
||||||
|
<super.matchSet(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
matchSetRuleRoot(s,label,hetero,elementIndex,debug) ::= <<
|
||||||
|
<super.matchSet(..., postmatchCode={
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) {<endif>
|
||||||
|
<if(hetero)>
|
||||||
|
<label>_tree = new <hetero>(<label>);
|
||||||
|
<else>
|
||||||
|
<label>_tree = (<ASTLabelType>)adaptor.dupNode(<label>);
|
||||||
|
<endif><\n>
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)adaptor.becomeRoot(<label>_tree, root_<treeLevel>);
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
<endif>
|
||||||
|
}
|
||||||
|
)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// RULE REF AST
|
||||||
|
|
||||||
|
/** rule auto construct */
|
||||||
|
ruleRef(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
_last = (<ASTLabelType>)input.LT(1);
|
||||||
|
<super.ruleRef(...)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) <endif>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
adaptor.addChild(root_<treeLevel>, <label>.getTree());
|
||||||
|
<else> <! rewrite mode !>
|
||||||
|
if ( _first_<treeLevel>==null ) _first_<treeLevel> = <label>.tree;
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule auto construct */
|
||||||
|
ruleRefAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRef(...)>
|
||||||
|
<listLabel(elem=label+".getTree()",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(rule ...) auto construct */
|
||||||
|
ruleRefRuleRoot(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
_last = (<ASTLabelType>)input.LT(1);
|
||||||
|
<super.ruleRef(...)>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) <endif>root_<treeLevel> = (<ASTLabelType>)adaptor.becomeRoot(<label>.getTree(), root_<treeLevel>);
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(x+=rule ...) auto construct */
|
||||||
|
ruleRefRuleRootAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefRuleRoot(...)>
|
||||||
|
<listLabel(elem=label+".getTree()",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** rule when output=AST and tracking for rewrite */
|
||||||
|
ruleRefTrack(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
_last = (<ASTLabelType>)input.LT(1);
|
||||||
|
<super.ruleRefTrack(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule when output=AST and tracking for rewrite */
|
||||||
|
ruleRefTrackAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
_last = (<ASTLabelType>)input.LT(1);
|
||||||
|
<super.ruleRefTrackAndListLabel(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(rule ...) rewrite */
|
||||||
|
ruleRefRuleRootTrack(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
_last = (<ASTLabelType>)input.LT(1);
|
||||||
|
<super.ruleRefRootTrack(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(x+=rule ...) rewrite */
|
||||||
|
ruleRefRuleRootTrackAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
_last = (<ASTLabelType>)input.LT(1);
|
||||||
|
<super.ruleRefRuleRootTrackAndListLabel(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Streams for token refs are tree nodes now; override to
|
||||||
|
* change nextToken to nextNode.
|
||||||
|
*/
|
||||||
|
createRewriteNodeFromElement(token,hetero,scope) ::= <<
|
||||||
|
<if(hetero)>
|
||||||
|
new <hetero>(stream_<token>.nextNode())
|
||||||
|
<else>
|
||||||
|
stream_<token>.nextNode()
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
ruleCleanUp() ::= <<
|
||||||
|
<super.ruleCleanUp()>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) {<\n><endif>
|
||||||
|
retval.tree = (<ASTLabelType>)adaptor.rulePostProcessing(root_0);
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
<endif>
|
||||||
|
>>
|
259
antlr_3_1_source/codegen/templates/Java/Dbg.stg
Normal file
259
antlr_3_1_source/codegen/templates/Java/Dbg.stg
Normal file
@ -0,0 +1,259 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
/** Template overrides to add debugging to normal Java output;
|
||||||
|
* If ASTs are built, then you'll also get ASTDbg.stg loaded.
|
||||||
|
*/
|
||||||
|
group Dbg;
|
||||||
|
|
||||||
|
@outputFile.imports() ::= <<
|
||||||
|
<@super.imports()>
|
||||||
|
import org.antlr.runtime.debug.*;
|
||||||
|
import java.io.IOException;
|
||||||
|
>>
|
||||||
|
|
||||||
|
@genericParser.members() ::= <<
|
||||||
|
<if(grammar.grammarIsRoot)>
|
||||||
|
public static final String[] ruleNames = new String[] {
|
||||||
|
"invalidRule", <grammar.allImportedRules:{rST | "<rST.name>"}; wrap="\n ", separator=", ">
|
||||||
|
};<\n>
|
||||||
|
<endif>
|
||||||
|
<if(grammar.grammarIsRoot)> <! grammar imports other grammar(s) !>
|
||||||
|
public int ruleLevel = 0;
|
||||||
|
public int getRuleLevel() { return ruleLevel; }
|
||||||
|
public void incRuleLevel() { ruleLevel++; }
|
||||||
|
public void decRuleLevel() { ruleLevel--; }
|
||||||
|
<if(profile)>
|
||||||
|
<ctorForProfilingRootGrammar()>
|
||||||
|
<else>
|
||||||
|
<ctorForRootGrammar()>
|
||||||
|
<endif>
|
||||||
|
<ctorForPredefinedListener()>
|
||||||
|
<else> <! imported grammar !>
|
||||||
|
public int getRuleLevel() { return <grammar.delegators:{g| <g:delegateName()>}>.getRuleLevel(); }
|
||||||
|
public void incRuleLevel() { <grammar.delegators:{g| <g:delegateName()>}>.incRuleLevel(); }
|
||||||
|
public void decRuleLevel() { <grammar.delegators:{g| <g:delegateName()>}>.decRuleLevel(); }
|
||||||
|
<ctorForDelegateGrammar()>
|
||||||
|
<endif>
|
||||||
|
<if(profile)>
|
||||||
|
public boolean alreadyParsedRule(IntStream input, int ruleIndex) {
|
||||||
|
((Profiler)dbg).examineRuleMemoization(input, ruleIndex, <grammar.composite.rootGrammar.recognizerName>.ruleNames[ruleIndex]);
|
||||||
|
return super.alreadyParsedRule(input, ruleIndex);
|
||||||
|
}<\n>
|
||||||
|
public void memoize(IntStream input,
|
||||||
|
int ruleIndex,
|
||||||
|
int ruleStartIndex)
|
||||||
|
{
|
||||||
|
((Profiler)dbg).memoize(input, ruleIndex, ruleStartIndex, <grammar.composite.rootGrammar.recognizerName>.ruleNames[ruleIndex]);
|
||||||
|
super.memoize(input, ruleIndex, ruleStartIndex);
|
||||||
|
}<\n>
|
||||||
|
<endif>
|
||||||
|
protected boolean evalPredicate(boolean result, String predicate) {
|
||||||
|
dbg.semanticPredicate(result, predicate);
|
||||||
|
return result;
|
||||||
|
}<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
ctorForRootGrammar() ::= <<
|
||||||
|
<! bug: can't use <@super.members()> cut-n-paste instead !>
|
||||||
|
<! Same except we add port number and profile stuff if root grammar !>
|
||||||
|
public <name>(<inputStreamType> input) {
|
||||||
|
this(input, DebugEventSocketProxy.DEFAULT_DEBUGGER_PORT, new RecognizerSharedState());
|
||||||
|
}
|
||||||
|
public <name>(<inputStreamType> input, int port, RecognizerSharedState state) {
|
||||||
|
super(input, state);
|
||||||
|
<parserCtorBody()>
|
||||||
|
<createListenerAndHandshake()>
|
||||||
|
<grammar.directDelegates:{g|<g:delegateName()> = new <g.recognizerName>(input, dbg, this.state, this<grammar.delegators:{g|, <g:delegateName()>}>);}; separator="\n">
|
||||||
|
<@finally()>
|
||||||
|
}<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
ctorForProfilingRootGrammar() ::= <<
|
||||||
|
<! bug: can't use <@super.members()> cut-n-paste instead !>
|
||||||
|
public <name>(<inputStreamType> input) {
|
||||||
|
this(input, new Profiler(null), new RecognizerSharedState());
|
||||||
|
}
|
||||||
|
public <name>(<inputStreamType> input, DebugEventListener dbg, RecognizerSharedState state) {
|
||||||
|
super(input, dbg, state);
|
||||||
|
Profiler p = (Profiler)dbg;
|
||||||
|
p.setParser(this);
|
||||||
|
<parserCtorBody()>
|
||||||
|
<grammar.directDelegates:
|
||||||
|
{g|<g:delegateName()> = new <g.recognizerName>(input, dbg, this.state, this<grammar.delegators:{g|, <g:delegateName()>}>);}; separator="\n">
|
||||||
|
<@finally()>
|
||||||
|
}
|
||||||
|
<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Basically we don't want to set any dbg listeners are root will have it. */
|
||||||
|
ctorForDelegateGrammar() ::= <<
|
||||||
|
public <name>(<inputStreamType> input, DebugEventListener dbg, RecognizerSharedState state<grammar.delegators:{g|, <g.recognizerName> <g:delegateName()>}>) {
|
||||||
|
super(input, dbg, state);
|
||||||
|
<parserCtorBody()>
|
||||||
|
<grammar.directDelegates:
|
||||||
|
{g|<g:delegateName()> = new <g.recognizerName>(input, this, this.state<grammar.delegators:{g|, <g:delegateName()>}>);}; separator="\n">
|
||||||
|
}<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
ctorForPredefinedListener() ::= <<
|
||||||
|
public <name>(<inputStreamType> input, DebugEventListener dbg) {
|
||||||
|
<@superClassRef>super(input, dbg, new RecognizerSharedState());<@end>
|
||||||
|
<if(profile)>
|
||||||
|
Profiler p = (Profiler)dbg;
|
||||||
|
p.setParser(this);
|
||||||
|
<endif>
|
||||||
|
<parserCtorBody()>
|
||||||
|
<grammar.directDelegates:{g|<g:delegateName()> = new <g.recognizerName>(input, dbg, this.state, this<grammar.delegators:{g|, <g:delegateName()>}>);}; separator="\n">
|
||||||
|
<@finally()>
|
||||||
|
}<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
createListenerAndHandshake() ::= <<
|
||||||
|
<if(TREE_PARSER)>
|
||||||
|
DebugEventSocketProxy proxy =
|
||||||
|
new DebugEventSocketProxy(this, port, input.getTreeAdaptor());<\n>
|
||||||
|
<else>
|
||||||
|
DebugEventSocketProxy proxy =
|
||||||
|
new DebugEventSocketProxy(this, port, null);<\n>
|
||||||
|
<endif>
|
||||||
|
setDebugListener(proxy);
|
||||||
|
try {
|
||||||
|
proxy.handshake();
|
||||||
|
}
|
||||||
|
catch (IOException ioe) {
|
||||||
|
reportError(ioe);
|
||||||
|
}
|
||||||
|
>>
|
||||||
|
|
||||||
|
@genericParser.superClassName() ::= "Debug<@super.superClassName()>"
|
||||||
|
|
||||||
|
@rule.preamble() ::= <<
|
||||||
|
try { dbg.enterRule(getGrammarFileName(), "<ruleName>");
|
||||||
|
if ( getRuleLevel()==0 ) {dbg.commence();}
|
||||||
|
incRuleLevel();
|
||||||
|
dbg.location(<ruleDescriptor.tree.line>, <ruleDescriptor.tree.column>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
@rule.postamble() ::= <<
|
||||||
|
dbg.location(<ruleDescriptor.EORNode.line>, <ruleDescriptor.EORNode.column>);<\n>
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
dbg.exitRule(getGrammarFileName(), "<ruleName>");
|
||||||
|
decRuleLevel();
|
||||||
|
if ( getRuleLevel()==0 ) {dbg.terminate();}
|
||||||
|
}<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
@synpred.start() ::= "dbg.beginBacktrack(state.backtracking);"
|
||||||
|
|
||||||
|
@synpred.stop() ::= "dbg.endBacktrack(state.backtracking, success);"
|
||||||
|
|
||||||
|
// Common debug event triggers used by region overrides below
|
||||||
|
|
||||||
|
enterSubRule() ::=
|
||||||
|
"try { dbg.enterSubRule(<decisionNumber>);<\n>"
|
||||||
|
|
||||||
|
exitSubRule() ::=
|
||||||
|
"} finally {dbg.exitSubRule(<decisionNumber>);}<\n>"
|
||||||
|
|
||||||
|
enterDecision() ::=
|
||||||
|
"try { dbg.enterDecision(<decisionNumber>);<\n>"
|
||||||
|
|
||||||
|
exitDecision() ::=
|
||||||
|
"} finally {dbg.exitDecision(<decisionNumber>);}<\n>"
|
||||||
|
|
||||||
|
enterAlt(n) ::= "dbg.enterAlt(<n>);<\n>"
|
||||||
|
|
||||||
|
// Region overrides that tell various constructs to add debugging triggers
|
||||||
|
|
||||||
|
@block.predecision() ::= "<enterSubRule()><enterDecision()>"
|
||||||
|
|
||||||
|
@block.postdecision() ::= "<exitDecision()>"
|
||||||
|
|
||||||
|
@block.postbranch() ::= "<exitSubRule()>"
|
||||||
|
|
||||||
|
@ruleBlock.predecision() ::= "<enterDecision()>"
|
||||||
|
|
||||||
|
@ruleBlock.postdecision() ::= "<exitDecision()>"
|
||||||
|
|
||||||
|
@ruleBlockSingleAlt.prealt() ::= "<enterAlt(n=\"1\")>"
|
||||||
|
|
||||||
|
@blockSingleAlt.prealt() ::= "<enterAlt(n=\"1\")>"
|
||||||
|
|
||||||
|
@positiveClosureBlock.preloop() ::= "<enterSubRule()>"
|
||||||
|
|
||||||
|
@positiveClosureBlock.postloop() ::= "<exitSubRule()>"
|
||||||
|
|
||||||
|
@positiveClosureBlock.predecision() ::= "<enterDecision()>"
|
||||||
|
|
||||||
|
@positiveClosureBlock.postdecision() ::= "<exitDecision()>"
|
||||||
|
|
||||||
|
@positiveClosureBlock.earlyExitException() ::=
|
||||||
|
"dbg.recognitionException(eee);<\n>"
|
||||||
|
|
||||||
|
@closureBlock.preloop() ::= "<enterSubRule()>"
|
||||||
|
|
||||||
|
@closureBlock.postloop() ::= "<exitSubRule()>"
|
||||||
|
|
||||||
|
@closureBlock.predecision() ::= "<enterDecision()>"
|
||||||
|
|
||||||
|
@closureBlock.postdecision() ::= "<exitDecision()>"
|
||||||
|
|
||||||
|
@altSwitchCase.prealt() ::= "<enterAlt(n=i)>"
|
||||||
|
|
||||||
|
@element.prematch() ::=
|
||||||
|
"dbg.location(<it.line>,<it.pos>);"
|
||||||
|
|
||||||
|
@matchSet.mismatchedSetException() ::=
|
||||||
|
"dbg.recognitionException(mse);"
|
||||||
|
|
||||||
|
@dfaState.noViableAltException() ::= "dbg.recognitionException(nvae);"
|
||||||
|
|
||||||
|
@dfaStateSwitch.noViableAltException() ::= "dbg.recognitionException(nvae);"
|
||||||
|
|
||||||
|
dfaDecision(decisionNumber,description) ::= <<
|
||||||
|
try {
|
||||||
|
isCyclicDecision = true;
|
||||||
|
<super.dfaDecision(...)>
|
||||||
|
}
|
||||||
|
catch (NoViableAltException nvae) {
|
||||||
|
dbg.recognitionException(nvae);
|
||||||
|
throw nvae;
|
||||||
|
}
|
||||||
|
>>
|
||||||
|
|
||||||
|
@cyclicDFA.errorMethod() ::= <<
|
||||||
|
public void error(NoViableAltException nvae) {
|
||||||
|
dbg.recognitionException(nvae);
|
||||||
|
}
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Force predicate validation to trigger an event */
|
||||||
|
evalPredicate(pred,description) ::= <<
|
||||||
|
evalPredicate(<pred>,"<description>")
|
||||||
|
>>
|
1344
antlr_3_1_source/codegen/templates/Java/Java.stg
Normal file
1344
antlr_3_1_source/codegen/templates/Java/Java.stg
Normal file
File diff suppressed because it is too large
Load Diff
163
antlr_3_1_source/codegen/templates/Java/ST.stg
Normal file
163
antlr_3_1_source/codegen/templates/Java/ST.stg
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
/** Template subgroup to add template rewrite output
|
||||||
|
* If debugging, then you'll also get STDbg.stg loaded.
|
||||||
|
*/
|
||||||
|
group ST;
|
||||||
|
|
||||||
|
@outputFile.imports() ::= <<
|
||||||
|
<@super.imports()>
|
||||||
|
import org.antlr.stringtemplate.*;
|
||||||
|
import org.antlr.stringtemplate.language.*;
|
||||||
|
import java.util.HashMap;
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Add this to each rule's return value struct */
|
||||||
|
@returnScope.ruleReturnMembers() ::= <<
|
||||||
|
public StringTemplate st;
|
||||||
|
public Object getTemplate() { return st; }
|
||||||
|
public String toString() { return st==null?null:st.toString(); }
|
||||||
|
>>
|
||||||
|
|
||||||
|
@genericParser.members() ::= <<
|
||||||
|
<@super.members()>
|
||||||
|
protected StringTemplateGroup templateLib =
|
||||||
|
new StringTemplateGroup("<name>Templates", AngleBracketTemplateLexer.class);
|
||||||
|
|
||||||
|
public void setTemplateLib(StringTemplateGroup templateLib) {
|
||||||
|
this.templateLib = templateLib;
|
||||||
|
}
|
||||||
|
public StringTemplateGroup getTemplateLib() {
|
||||||
|
return templateLib;
|
||||||
|
}
|
||||||
|
/** allows convenient multi-value initialization:
|
||||||
|
* "new STAttrMap().put(...).put(...)"
|
||||||
|
*/
|
||||||
|
public static class STAttrMap extends HashMap {
|
||||||
|
public STAttrMap put(String attrName, Object value) {
|
||||||
|
super.put(attrName, value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public STAttrMap put(String attrName, int value) {
|
||||||
|
super.put(attrName, new Integer(value));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule when output=template */
|
||||||
|
ruleRefAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRef(...)>
|
||||||
|
<listLabel(elem=label+".getTemplate()",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteTemplate(alts) ::= <<
|
||||||
|
|
||||||
|
// TEMPLATE REWRITE
|
||||||
|
<if(backtracking)>
|
||||||
|
if ( state.backtracking==0 ) {
|
||||||
|
<alts:rewriteTemplateAlt(); separator="else ">
|
||||||
|
<if(rewriteMode)><replaceTextInLine()><endif>
|
||||||
|
}
|
||||||
|
<else>
|
||||||
|
<alts:rewriteTemplateAlt(); separator="else ">
|
||||||
|
<if(rewriteMode)><replaceTextInLine()><endif>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
replaceTextInLine() ::= <<
|
||||||
|
<if(TREE_PARSER)>
|
||||||
|
((TokenRewriteStream)input.getTokenStream()).replace(
|
||||||
|
input.getTreeAdaptor().getTokenStartIndex(retval.start),
|
||||||
|
input.getTreeAdaptor().getTokenStopIndex(retval.start),
|
||||||
|
retval.st);
|
||||||
|
<else>
|
||||||
|
((TokenRewriteStream)input).replace(
|
||||||
|
((Token)retval.start).getTokenIndex(),
|
||||||
|
input.LT(-1).getTokenIndex(),
|
||||||
|
retval.st);
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteTemplateAlt() ::= <<
|
||||||
|
// <it.description>
|
||||||
|
<if(it.pred)>
|
||||||
|
if (<it.pred>) {
|
||||||
|
retval.st = <it.alt>;
|
||||||
|
}<\n>
|
||||||
|
<else>
|
||||||
|
{
|
||||||
|
retval.st = <it.alt>;
|
||||||
|
}<\n>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteEmptyTemplate(alts) ::= <<
|
||||||
|
null;
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Invoke a template with a set of attribute name/value pairs.
|
||||||
|
* Set the value of the rule's template *after* having set
|
||||||
|
* the attributes because the rule's template might be used as
|
||||||
|
* an attribute to build a bigger template; you get a self-embedded
|
||||||
|
* template.
|
||||||
|
*/
|
||||||
|
rewriteExternalTemplate(name,args) ::= <<
|
||||||
|
templateLib.getInstanceOf("<name>"<if(args)>,
|
||||||
|
new STAttrMap()<args:{a | .put("<a.name>", <a.value>)}>
|
||||||
|
<endif>)
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** expr is a string expression that says what template to load */
|
||||||
|
rewriteIndirectTemplate(expr,args) ::= <<
|
||||||
|
templateLib.getInstanceOf(<expr><if(args)>,
|
||||||
|
new STAttrMap()<args:{a | .put("<a.name>", <a.value>)}>
|
||||||
|
<endif>)
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Invoke an inline template with a set of attribute name/value pairs */
|
||||||
|
rewriteInlineTemplate(args, template) ::= <<
|
||||||
|
new StringTemplate(templateLib, "<template>"<if(args)>,
|
||||||
|
new STAttrMap()<args:{a | .put("<a.name>", <a.value>)}>
|
||||||
|
<endif>)
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** plain -> {foo} action */
|
||||||
|
rewriteAction(action) ::= <<
|
||||||
|
<action>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** An action has %st.attrName=expr; or %{st}.attrName=expr; */
|
||||||
|
actionSetAttribute(st,attrName,expr) ::= <<
|
||||||
|
(<st>).setAttribute("<attrName>",<expr>);
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Translate %{stringExpr} */
|
||||||
|
actionStringConstructor(stringExpr) ::= <<
|
||||||
|
new StringTemplate(templateLib,<stringExpr>)
|
||||||
|
>>
|
387
antlr_3_1_source/codegen/templates/JavaScript/AST.stg
Executable file
387
antlr_3_1_source/codegen/templates/JavaScript/AST.stg
Executable file
@ -0,0 +1,387 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
group AST;
|
||||||
|
|
||||||
|
@outputFile.imports() ::= <<
|
||||||
|
<@super.imports()>
|
||||||
|
>>
|
||||||
|
|
||||||
|
@genericParser.members() ::= <<
|
||||||
|
<@super.members()>
|
||||||
|
<parserMembers()>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Add an adaptor property that knows how to build trees */
|
||||||
|
parserMembers() ::= <<
|
||||||
|
<!protected TreeAdaptor adaptor = new CommonTreeAdaptor();<\n>!>
|
||||||
|
setTreeAdaptor: function(adaptor) {
|
||||||
|
this.adaptor = adaptor;
|
||||||
|
},
|
||||||
|
getTreeAdaptor: function() {
|
||||||
|
return this.adaptor;
|
||||||
|
},
|
||||||
|
>>
|
||||||
|
|
||||||
|
@returnScope.ruleReturnMembers() ::= <<
|
||||||
|
getTree: function() { return this.tree; }
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Add a variable to track rule's return AST */
|
||||||
|
ruleDeclarations() ::= <<
|
||||||
|
<super.ruleDeclarations()>
|
||||||
|
var root_0 = null;<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
ruleLabelDefs() ::= <<
|
||||||
|
<super.ruleLabelDefs()>
|
||||||
|
<ruleDescriptor.tokenLabels:{var <it.label.text>_tree=null;}; separator="\n">
|
||||||
|
<ruleDescriptor.tokenListLabels:{var <it.label.text>_tree=null;}; separator="\n">
|
||||||
|
<ruleDescriptor.allTokenRefsInAltsWithRewrites
|
||||||
|
:{var stream_<it>=new org.antlr.runtime.tree.RewriteRuleTokenStream(this.adaptor,"token <it>");}; separator="\n">
|
||||||
|
<ruleDescriptor.allRuleRefsInAltsWithRewrites
|
||||||
|
:{var stream_<it>=new org.antlr.runtime.tree.RewriteRuleSubtreeStream(this.adaptor,"rule <it>");}; separator="\n">
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** When doing auto AST construction, we must define some variables;
|
||||||
|
* These should be turned off if doing rewrites. This must be a "mode"
|
||||||
|
* as a rule could have both rewrite and AST within the same alternative
|
||||||
|
* block.
|
||||||
|
*/
|
||||||
|
@alt.declarations() ::= <<
|
||||||
|
<if(autoAST)>
|
||||||
|
<if(outerAlt)>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
root_0 = this.adaptor.nil();<\n>
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// T r a c k i n g R u l e E l e m e n t s
|
||||||
|
|
||||||
|
/** ID and track it for use in a rewrite rule */
|
||||||
|
tokenRefTrack(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefBang(...)> <! Track implies no auto AST construction!>
|
||||||
|
<if(backtracking)>if ( this.state.backtracking===0 ) <endif>stream_<token>.add(<label>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ids+=ID and track it for use in a rewrite rule; adds to ids *and*
|
||||||
|
* to the tracking list stream_ID for use in the rewrite.
|
||||||
|
*/
|
||||||
|
tokenRefTrackAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefTrack(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(ID ...) track for rewrite */
|
||||||
|
tokenRefRuleRootTrack(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefBang(...)>
|
||||||
|
<if(backtracking)>if ( this.state.backtracking===0 ) <endif>stream_<token>.add(<label>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Match ^(label+=TOKEN ...) track for rewrite */
|
||||||
|
tokenRefRuleRootTrackAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefRuleRootTrack(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
wildcardTrack(label,elementIndex) ::= <<
|
||||||
|
<super.wildcard(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** rule when output=AST and tracking for rewrite */
|
||||||
|
ruleRefTrack(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<super.ruleRef(...)>
|
||||||
|
<if(backtracking)>if ( this.state.backtracking===0 ) <endif>stream_<rule.name>.add(<label>.getTree());
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule when output=AST and tracking for rewrite */
|
||||||
|
ruleRefTrackAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefTrack(...)>
|
||||||
|
<listLabel(elem=label+".getTree()",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(rule ...) rewrite */
|
||||||
|
ruleRefRuleRootTrack(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefRuleRoot(...)>
|
||||||
|
<if(backtracking)>if ( this.state.backtracking===0 ) <endif>stream_<rule>.add(<label>.getTree());
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(x+=rule ...) rewrite */
|
||||||
|
ruleRefRuleRootTrackAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefRuleRootTrack(...)>
|
||||||
|
<listLabel(elem=label+".getTree()",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// R e w r i t e
|
||||||
|
|
||||||
|
rewriteCode(
|
||||||
|
alts, description,
|
||||||
|
referencedElementsDeep, // ALL referenced elements to right of ->
|
||||||
|
referencedTokenLabels,
|
||||||
|
referencedTokenListLabels,
|
||||||
|
referencedRuleLabels,
|
||||||
|
referencedRuleListLabels,
|
||||||
|
rewriteBlockLevel, enclosingTreeLevel, treeLevel) ::=
|
||||||
|
<<
|
||||||
|
|
||||||
|
// AST REWRITE
|
||||||
|
// elements: <referencedElementsDeep; separator=", ">
|
||||||
|
// token labels: <referencedTokenLabels; separator=", ">
|
||||||
|
// rule labels: <referencedRuleLabels; separator=", ">
|
||||||
|
// token list labels: <referencedTokenListLabels; separator=", ">
|
||||||
|
// rule list labels: <referencedRuleListLabels; separator=", ">
|
||||||
|
<if(backtracking)>
|
||||||
|
if ( this.state.backtracking===0 ) {<\n>
|
||||||
|
<endif>
|
||||||
|
<prevRuleRootRef()>.tree = root_0;
|
||||||
|
<rewriteCodeLabels()>
|
||||||
|
root_0 = this.adaptor.nil();
|
||||||
|
<alts:rewriteAlt(); separator="else ">
|
||||||
|
<! if tree parser and rewrite=true !>
|
||||||
|
<if(TREE_PARSER)>
|
||||||
|
<if(rewriteMode)>
|
||||||
|
<prevRuleRootRef()>.tree = this.adaptor.rulePostProcessing(root_0);
|
||||||
|
this.input.replaceChildren(this.adaptor.getParent(retval.start),
|
||||||
|
this.adaptor.getChildIndex(retval.start),
|
||||||
|
this.adaptor.getChildIndex(_last),
|
||||||
|
retval.tree);
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
<! if parser or rewrite!=true, we need to set result !>
|
||||||
|
<if(!TREE_PARSER)>
|
||||||
|
<prevRuleRootRef()>.tree = root_0;
|
||||||
|
<endif>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<prevRuleRootRef()>.tree = root_0;
|
||||||
|
<endif>
|
||||||
|
<if(backtracking)>
|
||||||
|
}
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteCodeLabels() ::= <<
|
||||||
|
<referencedTokenLabels
|
||||||
|
:{var stream_<it>=new org.antlr.runtime.tree.RewriteRule<rewriteElementType>Stream(this.adaptor,"token <it>",<it>);};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
<referencedTokenListLabels
|
||||||
|
:{var stream_<it>=new org.antlr.runtime.tree.RewriteRule<rewriteElementType>Stream(this.adaptor,"token <it>", list_<it>);};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
<referencedRuleLabels
|
||||||
|
:{var stream_<it>=new org.antlr.runtime.tree.RewriteRuleSubtreeStream(this.adaptor,"token <it>",<it>!=null?<it>.tree:null);};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
<referencedRuleListLabels
|
||||||
|
:{var stream_<it>=new org.antlr.runtime.tree.RewriteRuleSubtreeStream(this.adaptor,"token <it>",list_<it>);};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Generate code for an optional rewrite block; note it uses the deep ref'd element
|
||||||
|
* list rather shallow like other blocks.
|
||||||
|
*/
|
||||||
|
rewriteOptionalBlock(
|
||||||
|
alt,rewriteBlockLevel,
|
||||||
|
referencedElementsDeep, // all nested refs
|
||||||
|
referencedElements, // elements in immediately block; no nested blocks
|
||||||
|
description) ::=
|
||||||
|
<<
|
||||||
|
// <fileName>:<description>
|
||||||
|
if ( <referencedElementsDeep:{el | stream_<el>.hasNext()}; separator="||"> ) {
|
||||||
|
<alt>
|
||||||
|
}
|
||||||
|
<referencedElementsDeep:{el | stream_<el>.reset();<\n>}>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteClosureBlock(
|
||||||
|
alt,rewriteBlockLevel,
|
||||||
|
referencedElementsDeep, // all nested refs
|
||||||
|
referencedElements, // elements in immediately block; no nested blocks
|
||||||
|
description) ::=
|
||||||
|
<<
|
||||||
|
// <fileName>:<description>
|
||||||
|
while ( <referencedElements:{el | stream_<el>.hasNext()}; separator="||"> ) {
|
||||||
|
<alt>
|
||||||
|
}
|
||||||
|
<referencedElements:{el | stream_<el>.reset();<\n>}>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewritePositiveClosureBlock(
|
||||||
|
alt,rewriteBlockLevel,
|
||||||
|
referencedElementsDeep, // all nested refs
|
||||||
|
referencedElements, // elements in immediately block; no nested blocks
|
||||||
|
description) ::=
|
||||||
|
<<
|
||||||
|
if ( !(<referencedElements:{el | stream_<el>.hasNext()}; separator="||">) ) {
|
||||||
|
throw new org.antlr.runtime.tree.RewriteEarlyExitException();
|
||||||
|
}
|
||||||
|
while ( <referencedElements:{el | stream_<el>.hasNext()}; separator="||"> ) {
|
||||||
|
<alt>
|
||||||
|
}
|
||||||
|
<referencedElements:{el | stream_<el>.reset();<\n>}>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteAlt(a) ::= <<
|
||||||
|
// <a.description>
|
||||||
|
<if(a.pred)>
|
||||||
|
if (<a.pred>) {
|
||||||
|
<a.alt>
|
||||||
|
}<\n>
|
||||||
|
<else>
|
||||||
|
{
|
||||||
|
<a.alt>
|
||||||
|
}<\n>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** For empty rewrites: "r : ... -> ;" */
|
||||||
|
rewriteEmptyAlt() ::= "root_0 = null;"
|
||||||
|
|
||||||
|
rewriteTree(root,children,description,enclosingTreeLevel,treeLevel) ::= <<
|
||||||
|
// <fileName>:<description>
|
||||||
|
{
|
||||||
|
var root_<treeLevel> = this.adaptor.nil();
|
||||||
|
<root:rewriteElement()>
|
||||||
|
<children:rewriteElement()>
|
||||||
|
this.adaptor.addChild(root_<enclosingTreeLevel>, root_<treeLevel>);
|
||||||
|
}<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteElementList(elements) ::= "<elements:rewriteElement()>"
|
||||||
|
|
||||||
|
rewriteElement(e) ::= <<
|
||||||
|
<@pregen()>
|
||||||
|
<e.el>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen ID or ID[args] */
|
||||||
|
rewriteTokenRef(token,elementIndex,hetero,args) ::= <<
|
||||||
|
this.adaptor.addChild(root_<treeLevel>, <createRewriteNodeFromElement(...)>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen $label ... where defined via label=ID */
|
||||||
|
rewriteTokenLabelRef(label,elementIndex) ::= <<
|
||||||
|
this.adaptor.addChild(root_<treeLevel>, stream_<label>.nextNode());<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen $label ... where defined via label+=ID */
|
||||||
|
rewriteTokenListLabelRef(label,elementIndex) ::= <<
|
||||||
|
this.adaptor.addChild(root_<treeLevel>, stream_<label>.nextNode());<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen ^($label ...) */
|
||||||
|
rewriteTokenLabelRefRoot(label,elementIndex) ::= <<
|
||||||
|
root_<treeLevel> = this.adaptor.becomeRoot(stream_<label>.nextNode(), root_<treeLevel>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen ^($label ...) where label+=... */
|
||||||
|
rewriteTokenListLabelRefRoot ::= rewriteTokenLabelRefRoot
|
||||||
|
|
||||||
|
/** Gen ^(ID ...) or ^(ID[args] ...) */
|
||||||
|
rewriteTokenRefRoot(token,elementIndex,hetero,args) ::= <<
|
||||||
|
root_<treeLevel> = this.adaptor.becomeRoot(<createRewriteNodeFromElement(...)>, root_<treeLevel>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteImaginaryTokenRef(args,token,hetero,elementIndex) ::= <<
|
||||||
|
this.adaptor.addChild(root_<treeLevel>, <createImaginaryNode(tokenType=token, ...)>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteImaginaryTokenRefRoot(args,token,hetero,elementIndex) ::= <<
|
||||||
|
root_<treeLevel> = this.adaptor.becomeRoot(<createImaginaryNode(tokenType=token, ...)>, root_<treeLevel>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** plain -> {foo} action */
|
||||||
|
rewriteAction(action) ::= <<
|
||||||
|
root_0 = <action>;<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** What is the name of the previous value of this rule's root tree? This
|
||||||
|
* let's us refer to $rule to mean previous value. I am reusing the
|
||||||
|
* variable 'tree' sitting in retval struct to hold the value of root_0 right
|
||||||
|
* before I set it during rewrites. The assign will be to retval.tree.
|
||||||
|
*/
|
||||||
|
prevRuleRootRef() ::= "retval"
|
||||||
|
|
||||||
|
rewriteRuleRef(rule) ::= <<
|
||||||
|
this.adaptor.addChild(root_<treeLevel>, stream_<rule>.nextTree());<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteRuleRefRoot(rule) ::= <<
|
||||||
|
root_<treeLevel> = this.adaptor.becomeRoot(stream_<rule>.nextNode(), root_<treeLevel>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteNodeAction(action) ::= <<
|
||||||
|
this.adaptor.addChild(root_<treeLevel>, <action>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteNodeActionRoot(action) ::= <<
|
||||||
|
root_<treeLevel> = this.adaptor.becomeRoot(<action>, root_<treeLevel>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen $ruleLabel ... where defined via ruleLabel=rule */
|
||||||
|
rewriteRuleLabelRef(label) ::= <<
|
||||||
|
this.adaptor.addChild(root_<treeLevel>, stream_<label>.nextTree());<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen $ruleLabel ... where defined via ruleLabel+=rule */
|
||||||
|
rewriteRuleListLabelRef(label) ::= <<
|
||||||
|
this.adaptor.addChild(root_<treeLevel>, stream_<label>.nextTree());<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen ^($ruleLabel ...) where ruleLabel=rule */
|
||||||
|
rewriteRuleLabelRefRoot(label) ::= <<
|
||||||
|
root_<treeLevel> = this.adaptor.becomeRoot(stream_<label>.nextNode(), root_<treeLevel>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen ^($ruleLabel ...) where ruleLabel+=rule */
|
||||||
|
rewriteRuleListLabelRefRoot(label) ::= <<
|
||||||
|
root_<treeLevel> = this.adaptor.becomeRoot(stream_<label>.nextNode(), root_<treeLevel>);<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
createImaginaryNode(tokenType,hetero,args) ::= <<
|
||||||
|
<if(hetero)>
|
||||||
|
<! new MethodNode(IDLabel, args) !>
|
||||||
|
new <hetero>(<tokenType><if(args)>, <args; separator=", "><endif>)
|
||||||
|
<else>
|
||||||
|
this.adaptor.create(<tokenType>, <args; separator=", "><if(!args)>"<tokenType>"<endif>)
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
createRewriteNodeFromElement(token,hetero,args) ::= <<
|
||||||
|
<if(hetero)>
|
||||||
|
new <hetero>(stream_<token>.nextToken()<if(args)>, <args; separator=", "><endif>)
|
||||||
|
<else>
|
||||||
|
<if(args)> <! must create new node from old !>
|
||||||
|
this.adaptor.create(<token>, <args; separator=", ">)
|
||||||
|
<else>
|
||||||
|
stream_<token>.nextNode()
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
>>
|
161
antlr_3_1_source/codegen/templates/JavaScript/ASTParser.stg
Executable file
161
antlr_3_1_source/codegen/templates/JavaScript/ASTParser.stg
Executable file
@ -0,0 +1,161 @@
|
|||||||
|
/** Templates for building ASTs during normal parsing.
|
||||||
|
*
|
||||||
|
* Deal with many combinations. Dimensions are:
|
||||||
|
* Auto build or rewrite
|
||||||
|
* no label, label, list label (label/no-label handled together)
|
||||||
|
* child, root
|
||||||
|
* token, set, rule, wildcard
|
||||||
|
*
|
||||||
|
* The situation is not too bad as rewrite (->) usage makes ^ and !
|
||||||
|
* invalid. There is no huge explosion of combinations.
|
||||||
|
*/
|
||||||
|
group ASTParser;
|
||||||
|
|
||||||
|
@rule.setErrorReturnValue() ::= <<
|
||||||
|
retval.tree = this.adaptor.errorNode(this.input, retval.start, this.input.LT(-1), re);
|
||||||
|
>>
|
||||||
|
|
||||||
|
// TOKEN AST STUFF
|
||||||
|
|
||||||
|
/** ID and output=AST */
|
||||||
|
tokenRef(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
<if(backtracking)>if ( this.state.backtracking===0 ) {<endif>
|
||||||
|
<label>_tree = <createNodeFromToken(...)>;
|
||||||
|
this.adaptor.addChild(root_0, <label>_tree);
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ID! and output=AST (same as plain tokenRef) */
|
||||||
|
tokenRefBang(token,label,elementIndex) ::= "<super.tokenRef(...)>"
|
||||||
|
|
||||||
|
/** ID^ and output=AST */
|
||||||
|
tokenRefRuleRoot(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
<if(backtracking)>if ( this.state.backtracking===0 ) {<endif>
|
||||||
|
<label>_tree = <createNodeFromToken(...)>;
|
||||||
|
root_0 = this.adaptor.becomeRoot(<label>_tree, root_0);
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ids+=ID! and output=AST */
|
||||||
|
tokenRefBangAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefBang(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** label+=TOKEN when output=AST but not rewrite alt */
|
||||||
|
tokenRefAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRef(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Match label+=TOKEN^ when output=AST but not rewrite alt */
|
||||||
|
tokenRefRuleRootAndListLabel(token,label,hetero,elementIndex) ::= <<
|
||||||
|
<tokenRefRuleRoot(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// SET AST
|
||||||
|
|
||||||
|
// the match set stuff is interesting in that it uses an argument list
|
||||||
|
// to pass code to the default matchSet; another possible way to alter
|
||||||
|
// inherited code. I don't use the region stuff because I need to pass
|
||||||
|
// different chunks depending on the operator. I don't like making
|
||||||
|
// the template name have the operator as the number of templates gets
|
||||||
|
// large but this is the most flexible--this is as opposed to having
|
||||||
|
// the code generator call matchSet then add root code or ruleroot code
|
||||||
|
// plus list label plus ... The combinations might require complicated
|
||||||
|
// rather than just added on code. Investigate that refactoring when
|
||||||
|
// I have more time.
|
||||||
|
|
||||||
|
matchSet(s,label,hetero,elementIndex,postmatchCode) ::= <<
|
||||||
|
<super.matchSet(..., postmatchCode={<if(backtracking)>if ( this.state.backtracking===0 ) <endif>this.adaptor.addChild(root_0, <createNodeFromToken(...)>);})>
|
||||||
|
>>
|
||||||
|
|
||||||
|
matchRuleBlockSet(s,label,hetero,elementIndex,postmatchCode,treeLevel="0") ::= <<
|
||||||
|
<matchSet(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
matchSetBang(s,label,elementIndex,postmatchCode) ::= "<super.matchSet(...)>"
|
||||||
|
|
||||||
|
// note there is no matchSetTrack because -> rewrites force sets to be
|
||||||
|
// plain old blocks of alts: (A|B|...|C)
|
||||||
|
|
||||||
|
matchSetRuleRoot(s,label,hetero,elementIndex,debug) ::= <<
|
||||||
|
<if(label)>
|
||||||
|
<label>=input.LT(1);<\n>
|
||||||
|
<endif>
|
||||||
|
<super.matchSet(..., postmatchCode={<if(backtracking)>if ( this.state.backtracking===0 ) <endif>root_0 = this.adaptor.becomeRoot(<createNodeFromToken(...)>, root_0);})>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// RULE REF AST
|
||||||
|
|
||||||
|
/** rule when output=AST */
|
||||||
|
ruleRef(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<super.ruleRef(...)>
|
||||||
|
<if(backtracking)>if ( this.state.backtracking===0 ) <endif>this.adaptor.addChild(root_0, <label>.getTree());
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** rule! is same as normal rule ref */
|
||||||
|
ruleRefBang(rule,label,elementIndex,args,scope) ::= "<super.ruleRef(...)>"
|
||||||
|
|
||||||
|
/** rule^ */
|
||||||
|
ruleRefRuleRoot(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<super.ruleRef(...)>
|
||||||
|
<if(backtracking)>if ( this.state.backtracking===0 ) <endif>root_0 = this.adaptor.becomeRoot(<label>.getTree(), root_0);
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule when output=AST */
|
||||||
|
ruleRefAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRef(...)>
|
||||||
|
<listLabel(elem=label+".getTree()",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule! when output=AST is a rule ref with list addition */
|
||||||
|
ruleRefBangAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefBang(...)>
|
||||||
|
<listLabel(elem=label+".getTree()",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule^ */
|
||||||
|
ruleRefRuleRootAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefRuleRoot(...)>
|
||||||
|
<listLabel(elem=label+".getTree()",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// WILDCARD AST
|
||||||
|
|
||||||
|
wildcard(label,elementIndex) ::= <<
|
||||||
|
<super.wildcard(...)>
|
||||||
|
<if(backtracking)>if ( this.state.backtracking===0 ) {<endif>
|
||||||
|
<label>_tree = this.adaptor.create(<label>);
|
||||||
|
this.adaptor.addChild(root_0, <label>_tree);
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
wildcardBang(label,elementIndex) ::= "<super.wildcard(...)>"
|
||||||
|
|
||||||
|
wildcardRuleRoot(label,elementIndex) ::= <<
|
||||||
|
<super.wildcard(...)>
|
||||||
|
<if(backtracking)>if ( this.state.backtracking===0 ) {<endif>
|
||||||
|
<label>_tree = this.adaptor.create(<label>);
|
||||||
|
root_0 = this.adaptor.becomeRoot(<label>_tree, root_0);
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
createNodeFromToken(label,hetero) ::= <<
|
||||||
|
<if(hetero)>
|
||||||
|
new <hetero>(<label>) <! new MethodNode(IDLabel) !>
|
||||||
|
<else>
|
||||||
|
this.adaptor.create(<label>)
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
ruleCleanUp() ::= <<
|
||||||
|
<super.ruleCleanUp()>
|
||||||
|
<if(backtracking)>if ( this.state.backtracking===0 ) {<\n><endif>
|
||||||
|
retval.tree = this.adaptor.rulePostProcessing(root_0);
|
||||||
|
this.adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop);
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
>>
|
229
antlr_3_1_source/codegen/templates/JavaScript/ASTTreeParser.stg
Executable file
229
antlr_3_1_source/codegen/templates/JavaScript/ASTTreeParser.stg
Executable file
@ -0,0 +1,229 @@
|
|||||||
|
/** Templates for building ASTs during tree parsing.
|
||||||
|
*
|
||||||
|
* Deal with many combinations. Dimensions are:
|
||||||
|
* Auto build or rewrite
|
||||||
|
* no label, label, list label (label/no-label handled together)
|
||||||
|
* child, root
|
||||||
|
* token, set, rule, wildcard
|
||||||
|
*
|
||||||
|
* Each combination has its own template except that label/no label
|
||||||
|
* is combined into tokenRef, ruleRef, ...
|
||||||
|
*/
|
||||||
|
group ASTTreeParser;
|
||||||
|
|
||||||
|
/** Add a variable to track last element matched */
|
||||||
|
ruleDeclarations() ::= <<
|
||||||
|
<super.ruleDeclarations()>
|
||||||
|
var _first_0 = null;
|
||||||
|
var _last = null;<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** What to emit when there is no rewrite rule. For auto build
|
||||||
|
* mode, does nothing.
|
||||||
|
*/
|
||||||
|
noRewrite(rewriteBlockLevel, treeLevel) ::= <<
|
||||||
|
<if(backtracking)>if ( this.state.backtracking===0 ) {<endif>
|
||||||
|
<if(rewriteMode)>
|
||||||
|
retval.tree = _first_0;
|
||||||
|
if ( this.adaptor.getParent(retval.tree) && this.adaptor.isNil( this.adaptor.getParent(retval.tree) ) )
|
||||||
|
retval.tree = this.adaptor.getParent(retval.tree);
|
||||||
|
<endif>
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** match ^(root children) in tree parser; override here to
|
||||||
|
* add tree construction actions.
|
||||||
|
*/
|
||||||
|
tree(root, actionsAfterRoot, children, nullableChildList,
|
||||||
|
enclosingTreeLevel, treeLevel) ::= <<
|
||||||
|
_last = this.input.LT(1);
|
||||||
|
{
|
||||||
|
var _save_last_<treeLevel> = _last;
|
||||||
|
var _first_<treeLevel> = null;
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
var root_<treeLevel> = this.adaptor.nil();
|
||||||
|
<endif>
|
||||||
|
<root:element()>
|
||||||
|
<if(rewriteMode)>
|
||||||
|
<if(backtracking)>if ( this.state.backtracking===0 )<endif>
|
||||||
|
<if(root.el.rule)>
|
||||||
|
if ( !_first_<enclosingTreeLevel> ) _first_<enclosingTreeLevel> = <root.el.label>.tree;
|
||||||
|
<else>
|
||||||
|
if ( !_first_<enclosingTreeLevel> ) _first_<enclosingTreeLevel> = <root.el.label>;
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
<actionsAfterRoot:element()>
|
||||||
|
<if(nullableChildList)>
|
||||||
|
if ( this.input.LA(1)==org.antlr.runtime.Token.DOWN ) {
|
||||||
|
this.match(this.input, org.antlr.runtime.Token.DOWN, null); <checkRuleBacktrackFailure()>
|
||||||
|
<children:element()>
|
||||||
|
this.match(this.input, org.antlr.runtime.Token.UP, null); <checkRuleBacktrackFailure()>
|
||||||
|
}
|
||||||
|
<else>
|
||||||
|
this.match(this.input, org.antlr.runtime.Token.DOWN, null); <checkRuleBacktrackFailure()>
|
||||||
|
<children:element()>
|
||||||
|
this.match(this.input, org.antlr.runtime.Token.UP, null); <checkRuleBacktrackFailure()>
|
||||||
|
<endif>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
this.adaptor.addChild(root_<enclosingTreeLevel>, root_<treeLevel>);
|
||||||
|
<endif>
|
||||||
|
_last = _save_last_<treeLevel>;
|
||||||
|
}<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// TOKEN AST STUFF
|
||||||
|
|
||||||
|
/** ID! and output=AST (same as plain tokenRef) 'cept add
|
||||||
|
* setting of _last
|
||||||
|
*/
|
||||||
|
tokenRefBang(token,label,elementIndex) ::= <<
|
||||||
|
_last = this.input.LT(1);
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ID auto construct */
|
||||||
|
tokenRef(token,label,elementIndex,hetero) ::= <<
|
||||||
|
_last = this.input.LT(1);
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<if(backtracking)>if ( this.state.backtracking===0 ) {<endif>
|
||||||
|
<if(hetero)>
|
||||||
|
<label>_tree = new <hetero>(<label>);
|
||||||
|
<else>
|
||||||
|
<label>_tree = this.adaptor.dupNode(<label>);
|
||||||
|
<endif><\n>
|
||||||
|
this.adaptor.addChild(root_<treeLevel>, <label>_tree);
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
<else> <! rewrite mode !>
|
||||||
|
<if(backtracking)>if ( this.state.backtracking===0 )<endif>
|
||||||
|
if ( !_first_<treeLevel> ) _first_<treeLevel> = <label>;
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** label+=TOKEN auto construct */
|
||||||
|
tokenRefAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRef(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(ID ...) auto construct */
|
||||||
|
tokenRefRuleRoot(token,label,elementIndex,hetero) ::= <<
|
||||||
|
_last = this.input.LT(1);
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<if(backtracking)>if ( this.state.backtracking===0 ) {<endif>
|
||||||
|
<if(hetero)>
|
||||||
|
<label>_tree = new <hetero>(<label>);
|
||||||
|
<else>
|
||||||
|
<label>_tree = this.adaptor.dupNode(<label>);
|
||||||
|
<endif><\n>
|
||||||
|
root_<treeLevel> = this.adaptor.becomeRoot(<label>_tree, root_<treeLevel>);
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Match ^(label+=TOKEN ...) auto construct */
|
||||||
|
tokenRefRuleRootAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefRuleRoot(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// SET AST
|
||||||
|
|
||||||
|
matchSet(s,label,hetero,elementIndex,postmatchCode) ::= <<
|
||||||
|
_last = this.input.LT(1);
|
||||||
|
<super.matchSet(..., postmatchCode={
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<if(backtracking)>if ( this.state.backtracking===0 ) {<endif>
|
||||||
|
<if(hetero)>
|
||||||
|
<label>_tree = new <hetero>(<label>);
|
||||||
|
<else>
|
||||||
|
<label>_tree = this.adaptor.dupNode(<label>);
|
||||||
|
<endif><\n>
|
||||||
|
this.adaptor.addChild(root_<treeLevel>, <label>_tree);
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
<endif>
|
||||||
|
}
|
||||||
|
)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
matchRuleBlockSet(s,label,hetero,elementIndex,postmatchCode,treeLevel="0") ::= <<
|
||||||
|
<matchSet(...)>
|
||||||
|
<noRewrite()> <! set return tree !>
|
||||||
|
>>
|
||||||
|
|
||||||
|
matchSetBang(s,label,elementIndex,postmatchCode) ::= <<
|
||||||
|
_last = this.input.LT(1);
|
||||||
|
<super.matchSet(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
matchSetRuleRoot(s,label,hetero,elementIndex,debug) ::= <<
|
||||||
|
<super.matchSet(..., postmatchCode={
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<if(backtracking)>if ( this.state.backtracking===0 ) {<endif>
|
||||||
|
<if(hetero)>
|
||||||
|
<label>_tree = new <hetero>(<label>);
|
||||||
|
<else>
|
||||||
|
<label>_tree = this.adaptor.dupNode(<label>);
|
||||||
|
<endif><\n>
|
||||||
|
root_<treeLevel> = this.adaptor.becomeRoot(<label>_tree, root_<treeLevel>);
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
<endif>
|
||||||
|
}
|
||||||
|
)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// RULE REF AST
|
||||||
|
|
||||||
|
/** rule auto construct */
|
||||||
|
ruleRef(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
_last = this.input.LT(1);
|
||||||
|
<super.ruleRef(...)>
|
||||||
|
<if(backtracking)>if ( this.state.backtracking===0 ) <endif>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
this.adaptor.addChild(root_<treeLevel>, <label>.getTree());
|
||||||
|
<else> <! rewrite mode !>
|
||||||
|
if ( !_first_<treeLevel> ) _first_<treeLevel> = <label>.tree;
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule auto construct */
|
||||||
|
ruleRefAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRef(...)>
|
||||||
|
<listLabel(elem=label+".getTree()",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(rule ...) auto construct */
|
||||||
|
ruleRefRuleRoot(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
_last = this.input.LT(1);
|
||||||
|
<super.ruleRef(...)>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<if(backtracking)>if ( this.state.backtracking===0 ) <endif>root_<treeLevel> = this.adaptor.becomeRoot(<label>.getTree(), root_<treeLevel>);
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(x+=rule ...) auto construct */
|
||||||
|
ruleRefRuleRootAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefRuleRoot(...)>
|
||||||
|
<listLabel(elem=label+".getTree()",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Streams for token refs are tree nodes now; override to
|
||||||
|
* change nextToken to nextNode.
|
||||||
|
*/
|
||||||
|
createRewriteNodeFromElement(token,hetero,scope) ::= <<
|
||||||
|
<if(hetero)>
|
||||||
|
new <hetero>(stream_<token>.nextNode())
|
||||||
|
<else>
|
||||||
|
stream_<token>.nextNode()
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
ruleCleanUp() ::= <<
|
||||||
|
<super.ruleCleanUp()>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<if(backtracking)>if ( this.state.backtracking===0 ) {<\n><endif>
|
||||||
|
retval.tree = this.adaptor.rulePostProcessing(root_0);
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
<endif>
|
||||||
|
>>
|
1330
antlr_3_1_source/codegen/templates/JavaScript/JavaScript.stg
Executable file
1330
antlr_3_1_source/codegen/templates/JavaScript/JavaScript.stg
Executable file
File diff suppressed because it is too large
Load Diff
513
antlr_3_1_source/codegen/templates/ObjC/AST.stg
Normal file
513
antlr_3_1_source/codegen/templates/ObjC/AST.stg
Normal file
@ -0,0 +1,513 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2006, 2007 Kay Roepke
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
group AST;
|
||||||
|
|
||||||
|
@outputFile.imports() ::= <<
|
||||||
|
<@super.imports()>
|
||||||
|
<if(!TREE_PARSER)><! tree parser would already have imported !>
|
||||||
|
#import \<ANTLR/ANTLR.h><\n>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
@parserHeaderFile.ivars() ::= <<
|
||||||
|
<@super.ivars()>
|
||||||
|
<parserIVars()>
|
||||||
|
>>
|
||||||
|
|
||||||
|
@parserHeaderFile.methodsdecl() ::= <<
|
||||||
|
<@super.methodsdecl()>
|
||||||
|
<parserMethodsDecl()>
|
||||||
|
>>
|
||||||
|
|
||||||
|
@genericParser.methods() ::= <<
|
||||||
|
<@super.methods()>
|
||||||
|
<parserMethods()>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** additional init code for tree support */
|
||||||
|
@genericParser.init() ::= <<
|
||||||
|
<@super.init()>
|
||||||
|
[self setTreeAdaptor:[[[ANTLRCommonTreeAdaptor alloc] init] autorelease]];
|
||||||
|
>>
|
||||||
|
|
||||||
|
|
||||||
|
@genericParser.dealloc() ::= <<
|
||||||
|
[self setTreeAdaptor:nil];
|
||||||
|
<@super.dealloc()>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Add an adaptor property that knows how to build trees */
|
||||||
|
parserIVars() ::= <<
|
||||||
|
id\<ANTLRTreeAdaptor> treeAdaptor;
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Declaration of additional tree support methods - go in interface of parserHeaderFile() */
|
||||||
|
parserMethodsDecl() ::= <<
|
||||||
|
- (id\<ANTLRTreeAdaptor>) treeAdaptor;
|
||||||
|
- (void) setTreeAdaptor:(id\<ANTLRTreeAdaptor>)theTreeAdaptor;
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Definition of addition tree support methods - go in implementation of genericParser() */
|
||||||
|
parserMethods() ::= <<
|
||||||
|
- (id\<ANTLRTreeAdaptor>) treeAdaptor
|
||||||
|
{
|
||||||
|
return treeAdaptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) setTreeAdaptor:(id\<ANTLRTreeAdaptor>)aTreeAdaptor
|
||||||
|
{
|
||||||
|
if (aTreeAdaptor != treeAdaptor) {
|
||||||
|
[aTreeAdaptor retain];
|
||||||
|
[treeAdaptor release];
|
||||||
|
treeAdaptor = aTreeAdaptor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** addition ivars for returnscopes */
|
||||||
|
@returnScopeInterface.ivars() ::= <<
|
||||||
|
<recognizer.ASTLabelType; null="id"> tree;
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** the interface of returnScope methods */
|
||||||
|
@returnScopeInterface.methods() ::= <<
|
||||||
|
- (<recognizer.ASTLabelType; null="id">) tree;
|
||||||
|
- (void) setTree:(<recognizer.ASTLabelType; null="id">)aTree;
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** the implementation of returnScope methods */
|
||||||
|
@returnScope.methods() ::= <<
|
||||||
|
- (<ASTLabelType>) tree
|
||||||
|
{
|
||||||
|
return tree;
|
||||||
|
}
|
||||||
|
- (void) setTree:(<ASTLabelType>)aTree
|
||||||
|
{
|
||||||
|
if (tree != aTree) {
|
||||||
|
[aTree retain];
|
||||||
|
[tree release];
|
||||||
|
tree = aTree;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) dealloc
|
||||||
|
{
|
||||||
|
[self setTree:nil];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Add a variable to track rule's return AST */
|
||||||
|
ruleDeclarations() ::= <<
|
||||||
|
<super.ruleDeclarations()>
|
||||||
|
<ASTLabelType> root_0 = nil;<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
ruleLabelDefs() ::= <<
|
||||||
|
<super.ruleLabelDefs()>
|
||||||
|
<ruleDescriptor.tokenLabels:{<ASTLabelType> _<it.label.text>_tree = nil;}; separator="\n">
|
||||||
|
<ruleDescriptor.tokenListLabels:{<ASTLabelType> _<it.label.text>_tree = nil;}; separator="\n">
|
||||||
|
<ruleDescriptor.allTokenRefsInAltsWithRewrites
|
||||||
|
:{ANTLRRewriteRuleTokenStream *_stream_<it>=[[ANTLRRewriteRuleTokenStream alloc] initWithTreeAdaptor:treeAdaptor description:@"token <it>"];}; separator="\n">
|
||||||
|
<ruleDescriptor.allRuleRefsInAltsWithRewrites
|
||||||
|
:{ANTLRRewriteRuleSubtreeStream *_stream_<it>=[[ANTLRRewriteRuleSubtreeStream alloc] initWithTreeAdaptor:treeAdaptor description:@"rule <it>"];}; separator="\n">
|
||||||
|
|
||||||
|
>>
|
||||||
|
|
||||||
|
ruleCleanUp() ::= <<
|
||||||
|
<super.ruleCleanUp()>
|
||||||
|
<[ruleDescriptor.allTokenRefsInAltsWithRewrites,ruleDescriptor.allRuleRefsInAltsWithRewrites]
|
||||||
|
:{[_stream_<it> release];}; separator="\n">
|
||||||
|
<if(ruleDescriptor.hasMultipleReturnValues)>
|
||||||
|
<if(backtracking)>
|
||||||
|
if ( ![_state isBacktracking] ) {<\n>
|
||||||
|
<endif>
|
||||||
|
[_<prevRuleRootRef()> setTree:(<ASTLabelType>)[treeAdaptor postProcessTree:root_0]];
|
||||||
|
[treeAdaptor setBoundariesForTree:[_<prevRuleRootRef()> tree] fromToken:[_<prevRuleRootRef()> start] toToken:[_<prevRuleRootRef()> stop]];
|
||||||
|
<if(backtracking)>
|
||||||
|
}
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
[root_0 release];
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteCodeLabelsCleanUp() ::= <<
|
||||||
|
<referencedTokenLabels
|
||||||
|
:{[_stream_<it> release];};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
<referencedTokenListLabels
|
||||||
|
:{[_stream_<it> release];};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
<referencedRuleLabels
|
||||||
|
:{[_stream_<it> release];};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
<referencedRuleListLabels
|
||||||
|
:{[_stream_<it> release];};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** When doing auto AST construction, we must define some variables;
|
||||||
|
* These should be turned off if doing rewrites. This must be a "mode"
|
||||||
|
* as a rule could have both rewrite and AST within the same alternative
|
||||||
|
* block.
|
||||||
|
*/
|
||||||
|
@alt.declarations() ::= <<
|
||||||
|
<if(autoAST)>
|
||||||
|
<if(outerAlt)>
|
||||||
|
root_0 = (<ASTLabelType>)[treeAdaptor newEmptyTree];<\n>
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// T r a c k i n g R u l e E l e m e n t s
|
||||||
|
|
||||||
|
/** ID and track it for use in a rewrite rule */
|
||||||
|
tokenRefTrack(token,label,elementIndex) ::= <<
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
<if(backtracking)>if ( ![_state isBacktracking] ) <endif>[_stream_<token> addElement:_<label>];<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ids+=ID and track it for use in a rewrite rule; adds to ids *and*
|
||||||
|
* to the tracking list stream_ID for use in the rewrite.
|
||||||
|
*/
|
||||||
|
tokenRefTrackAndListLabel(token,label,elementIndex) ::= <<
|
||||||
|
<tokenRefTrack(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(ID ...) track for rewrite */
|
||||||
|
tokenRefRuleRootTrack(token,label,elementIndex) ::= <<
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
<if(backtracking)>if ( ![_state isBacktracking] ) <endif>[_stream_<token> addElement:_<label>];<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Match ^(label+=TOKEN ...) track for rewrite */
|
||||||
|
tokenRefRuleRootTrackAndListLabel(token,label,elementIndex) ::= <<
|
||||||
|
<tokenRefRuleRootTrack(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** rule when output=AST and tracking for rewrite */
|
||||||
|
ruleRefTrack(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<super.ruleRef(...)>
|
||||||
|
<if(backtracking)>if ( ![_state isBacktracking] ) <endif>[_stream_<rule.name> addElement:[_<label> tree]];
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule when output=AST and tracking for rewrite */
|
||||||
|
ruleRefTrackAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefTrack(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(rule ...) rewrite */
|
||||||
|
ruleRefRuleRootTrack(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<super.ruleRefRuleRoot(...)>
|
||||||
|
<if(backtracking)>if ( ![_state isBacktracking] ) <endif>[_stream_<rule.name> addElement:[_<label> tree]];<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(x+=rule ...) rewrite */
|
||||||
|
ruleRefRuleRootTrackAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefRuleRootTrack(...)>
|
||||||
|
<listLabel(elem="["+label+" tree]",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// R e w r i t e
|
||||||
|
|
||||||
|
rewriteCode(
|
||||||
|
alts, description,
|
||||||
|
referencedElementsDeep, // ALL referenced elements to right of ->
|
||||||
|
referencedTokenLabels,
|
||||||
|
referencedTokenListLabels,
|
||||||
|
referencedRuleLabels,
|
||||||
|
referencedRuleListLabels,
|
||||||
|
rewriteBlockLevel, enclosingTreeLevel, treeLevel) ::=
|
||||||
|
<<
|
||||||
|
|
||||||
|
// AST REWRITE
|
||||||
|
// elements: <referencedElementsDeep; separator=", ">
|
||||||
|
// token labels: <referencedTokenLabels; separator=", ">
|
||||||
|
// rule labels: <referencedRuleLabels; separator=", ">
|
||||||
|
// token list labels: <referencedTokenListLabels; separator=", ">
|
||||||
|
// rule list labels: <referencedRuleListLabels; separator=", ">
|
||||||
|
<if(backtracking)>
|
||||||
|
if (![_state isBacktracking]) {<\n>
|
||||||
|
<endif>
|
||||||
|
int i_0 = 0;
|
||||||
|
root_0 = (<ASTLabelType>)[treeAdaptor newEmptyTree];
|
||||||
|
[_<prevRuleRootRef()> setTree:root_0];
|
||||||
|
<rewriteCodeLabels()>
|
||||||
|
<alts:rewriteAlt(); separator="else ">
|
||||||
|
<rewriteCodeLabelsCleanUp()>
|
||||||
|
<if(backtracking)>
|
||||||
|
}
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteCodeLabels() ::= <<
|
||||||
|
<referencedTokenLabels
|
||||||
|
:{ANTLRRewriteRuleTokenStream *_stream_<it>=[[ANTLRRewriteRuleTokenStream alloc] initWithTreeAdaptor:treeAdaptor description:@"token <it>" element:_<it>];};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
<referencedTokenListLabels
|
||||||
|
:{ANTLRRewriteRuleTokenStream *_stream_<it>=[[ANTLRRewriteRuleTokenStream alloc] initWithTreeAdaptor:treeAdaptor description:@"token <it>" elements:_<it>_list];};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
<referencedRuleLabels
|
||||||
|
:{ANTLRRewriteRuleSubtreeStream *_stream_<it>=[[ANTLRRewriteRuleSubtreeStream alloc] initWithTreeAdaptor:treeAdaptor description:@"token <it>" element:_<it>!=nil?[_<it> tree]:nil];};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
<referencedRuleListLabels
|
||||||
|
:{ANTLRRewriteRuleSubtreeStream *_stream_<it>=[[ANTLRRewriteRuleSubtreeStream alloc] initWithTreeAdaptor:treeAdaptor description:@"token <it>" elements:_list_<it>];};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Generate code for an optional rewrite block; note it uses the deep ref'd element
|
||||||
|
* list rather shallow like other blocks.
|
||||||
|
*/
|
||||||
|
rewriteOptionalBlock(
|
||||||
|
alt,rewriteBlockLevel,
|
||||||
|
referencedElementsDeep, // all nested refs
|
||||||
|
referencedElements, // elements in immediately block; no nested blocks
|
||||||
|
description) ::=
|
||||||
|
<<
|
||||||
|
// <fileName>:<description>
|
||||||
|
if ( <referencedElementsDeep:{el | [_stream_<el> hasNext]}; separator="||"> ) {
|
||||||
|
<alt>
|
||||||
|
}
|
||||||
|
<referencedElementsDeep:{el | [_stream_<el> reset];<\n>}>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteClosureBlock(
|
||||||
|
alt,rewriteBlockLevel,
|
||||||
|
referencedElementsDeep, // all nested refs
|
||||||
|
referencedElements, // elements in immediately block; no nested blocks
|
||||||
|
description) ::=
|
||||||
|
<<
|
||||||
|
// <fileName>:<description>
|
||||||
|
while ( <referencedElements:{el | [_stream_<el> hasNext]}; separator="||"> ) {
|
||||||
|
<alt>
|
||||||
|
}
|
||||||
|
<referencedElements:{el | [_stream_<el> reset];<\n>}>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewritePositiveClosureBlock(
|
||||||
|
alt,rewriteBlockLevel,
|
||||||
|
referencedElementsDeep, // all nested refs
|
||||||
|
referencedElements, // elements in immediately block; no nested blocks
|
||||||
|
description) ::=
|
||||||
|
<<
|
||||||
|
// <fileName>:<description>
|
||||||
|
{
|
||||||
|
if ( !(<referencedElements:{el | [_stream_<el> hasNext]}; separator="||">) ) {
|
||||||
|
@throw [NSException exceptionWithName:@"RewriteEarlyExitException" reason:nil userInfo:nil];
|
||||||
|
}
|
||||||
|
while ( <referencedElements:{el | [_stream_<el> hasNext]}; separator="||"> ) {
|
||||||
|
<alt>
|
||||||
|
}
|
||||||
|
<referencedElements:{el | [_stream_<el> reset];<\n>}>
|
||||||
|
}
|
||||||
|
>>
|
||||||
|
|
||||||
|
|
||||||
|
rewriteAlt(a) ::= <<
|
||||||
|
// <a.description>
|
||||||
|
<if(a.pred)>
|
||||||
|
if (<a.pred>) {
|
||||||
|
<a.alt>
|
||||||
|
}<\n>
|
||||||
|
<else>
|
||||||
|
{
|
||||||
|
<a.alt>
|
||||||
|
}<\n>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** For empty rewrites: "r : ... -> ;" */
|
||||||
|
rewriteEmptyAlt() ::= "root_0 = nil;"
|
||||||
|
|
||||||
|
rewriteTree(root,children,description,enclosingTreeLevel,treeLevel) ::= <<
|
||||||
|
// <fileName>:<description>
|
||||||
|
{
|
||||||
|
<ASTLabelType> root_<treeLevel> = (<ASTLabelType>)[treeAdaptor newEmptyTree];
|
||||||
|
<root:rewriteElement()>
|
||||||
|
<children:rewriteElement()>
|
||||||
|
[treeAdaptor addChild:root_<treeLevel> toTree:root_<enclosingTreeLevel>];
|
||||||
|
[root_<treeLevel> release];
|
||||||
|
}<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteElementList(elements) ::= "<elements:rewriteElement()>"
|
||||||
|
|
||||||
|
rewriteElement(e) ::= <<
|
||||||
|
<@pregen()>
|
||||||
|
<e.el>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen ID or ID[args] */
|
||||||
|
rewriteTokenRef(token,elementIndex,hetero,args) ::= <<
|
||||||
|
<if(args)>
|
||||||
|
id\<ANTLRTree> _<token>_tree = [treeAdaptor newTreeWithToken:_<token>]; // TODO: args: <args; separator=", ">
|
||||||
|
<endif>
|
||||||
|
[treeAdaptor addChild:<if(args)>_<token>_tree<else>[_stream_<token> next]<endif> toTree:root_<treeLevel>];
|
||||||
|
<if(args)>
|
||||||
|
[_<token>_tree release];<\n>
|
||||||
|
<endif>
|
||||||
|
<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen $label ... where defined via label=ID */
|
||||||
|
rewriteTokenLabelRef(label,elementIndex) ::= <<
|
||||||
|
[treeAdaptor addChild:[_stream_<label> next] toTree:root_<treeLevel>];<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen $label ... where defined via label+=ID */
|
||||||
|
rewriteTokenListLabelRef(label,elementIndex) ::= <<
|
||||||
|
[treeAdaptor addChild:[_stream_<label> next] toTree:root_<treeLevel>];<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen ^($label ...) */
|
||||||
|
rewriteTokenLabelRefRoot(label,elementIndex) ::= <<
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)[treeAdaptor makeNode:[_stream_<label> next] parentOf:root_<treeLevel>];<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen ^($label ...) where label+=... */
|
||||||
|
rewriteTokenListLabelRefRoot ::= rewriteTokenLabelRefRoot
|
||||||
|
|
||||||
|
/** Gen ^(ID ...) or ^(ID[args] ...) */
|
||||||
|
rewriteTokenRefRoot(token,elementIndex,hetero,args) ::= <<
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)[treeAdaptor makeNode:[_stream_<token> next] parentOf:root_<treeLevel>];<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteImaginaryTokenRef(args,token,hetero,elementIndex) ::= <<
|
||||||
|
<if(first(rest(args)))><! got two arguments - means create from token with custom text!>
|
||||||
|
id\<ANTLRTree> _<token>_tree = [treeAdaptor newTreeWithToken:<first(args)> tokenType:<token> text:@<first(rest(args))>];
|
||||||
|
[treeAdaptor addChild:_<token>_tree toTree:root_<treeLevel>];
|
||||||
|
[_<token>_tree release];<\n>
|
||||||
|
<else><! at most one argument !>
|
||||||
|
<if(first(args))>
|
||||||
|
id\<ANTLRTree> _<token>_tree = [treeAdaptor newTreeWithToken:<first(args)> tokenType:<token>];
|
||||||
|
[treeAdaptor addChild:_<token>_tree toTree:root_<treeLevel>];
|
||||||
|
[_<token>_tree release];<\n>
|
||||||
|
<else><! no argument at all !>
|
||||||
|
id\<ANTLRTree> _<token>_tree = [treeAdaptor newTreeWithTokenType:<token> text:[tokenNames objectAtIndex:<token>]];
|
||||||
|
[treeAdaptor addChild:_<token>_tree toTree:root_<treeLevel>];
|
||||||
|
[_<token>_tree release];<\n>
|
||||||
|
<endif><! one arg !>
|
||||||
|
<endif><! two args !>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteImaginaryTokenRefRoot(args,token,hetero,elementIndex) ::= <<
|
||||||
|
<if(first(rest(args)))><! got two arguments - means create from token with custom text!>
|
||||||
|
id\<ANTLRTree> _<token>_tree = [treeAdaptor newTreeWithToken:<first(args)> tokenType:<token> text:@<first(rest(args))>];
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)[treeAdaptor makeNode:_<token>_tree parentOf:root_<treeLevel>];
|
||||||
|
[_<token>_tree release];<\n>
|
||||||
|
<else><! at most one argument !>
|
||||||
|
<if(first(args))>
|
||||||
|
id\<ANTLRTree> _<token>_tree = [treeAdaptor newTreeWithToken:<first(args)> tokenType:<token>];
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)[treeAdaptor makeNode:_<token>_tree parentOf:root_<treeLevel>];
|
||||||
|
[_<token>_tree release];<\n>
|
||||||
|
<else><! no argument at all !>id\<ANTLRTree> _<token>_tree = [treeAdaptor newTreeWithTokenType:<token> text:[tokenNames objectAtIndex:<token>]];
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)[treeAdaptor makeNode:_<token>_tree parentOf:root_<treeLevel>];
|
||||||
|
[_<token>_tree release];<\n>
|
||||||
|
<endif><! one arg !>
|
||||||
|
<endif><! two args !>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** plain -> {foo} action */
|
||||||
|
rewriteAction(action) ::= <<
|
||||||
|
root_0 = <action>;<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** What is the name of the previous value of this rule's root tree? This
|
||||||
|
* let's us refer to $rule to mean previous value. I am reusing the
|
||||||
|
* variable 'tree' sitting in retval struct to hold the value of root_0 right
|
||||||
|
* before I set it during rewrites. The assign will be to retval.tree.
|
||||||
|
*/
|
||||||
|
prevRuleRootRef() ::= "retval"
|
||||||
|
|
||||||
|
rewriteRuleRef(rule) ::= <<
|
||||||
|
[treeAdaptor addChild:[_stream_<rule> next] toTree:root_<treeLevel>];<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteRuleRefRoot(rule) ::= <<
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)[treeAdaptor makeNode:(id\<ANTLRTree>)[_stream_<rule> next] parentOf:root_<treeLevel>];<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteNodeAction(action) ::= <<
|
||||||
|
[treeAdaptor addChild:<action> toTree:root_<treeLevel>];<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteNodeActionRoot(action) ::= <<
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)[treeAdaptor makeNode:<action> parentOf:root_<treeLevel>];<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen $ruleLabel ... where defined via ruleLabel=rule */
|
||||||
|
rewriteRuleLabelRef(label) ::= <<
|
||||||
|
[treeAdaptor addChild:[_<label> tree] toTree:root_<treeLevel>];<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen $ruleLabel ... where defined via ruleLabel+=rule */
|
||||||
|
rewriteRuleListLabelRef(label) ::= <<
|
||||||
|
[treeAdaptor addChild:[(ANTLR<if(TREE_PARSER)>Tree<else>Parser<endif>RuleReturnScope *)[_stream_<label> next] tree] toTree:root_<treeLevel>];<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen ^($ruleLabel ...) where ruleLabel=rule */
|
||||||
|
rewriteRuleLabelRefRoot(label) ::= <<
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)[treeAdaptor makeNode:[_<label> tree] parentOf:root_<treeLevel>];<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen ^($ruleLabel ...) where ruleLabel+=rule */
|
||||||
|
rewriteRuleListLabelRefRoot(label) ::= <<
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)[treeAdaptor makeNode:[(ANTLR<if(TREE_PARSER)>Tree<else>Parser<endif>RuleReturnScope *)[_stream_<label> next] tree] parentOf:root_<treeLevel>];<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
createImaginaryNode(tokenType,hetero,args) ::= <<
|
||||||
|
<if(hetero)>
|
||||||
|
<! new MethodNode(IDLabel, args) !>
|
||||||
|
new <hetero>(<tokenType><if(args)>, <args; separator=", "><endif>)
|
||||||
|
<else>
|
||||||
|
(<ASTLabelType>)adaptor.create(<tokenType>, <args; separator=", "><if(!args)>"<tokenType>"<endif>)
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
createRewriteNodeFromElement(token,hetero,args) ::= <<
|
||||||
|
<if(hetero)>
|
||||||
|
new <hetero>(stream_<token>.nextToken()<if(args)>, <args; separator=", "><endif>)
|
||||||
|
<else>
|
||||||
|
<if(args)> <! must create new node from old !>
|
||||||
|
adaptor.create(<token>, <args; separator=", ">)
|
||||||
|
<else>
|
||||||
|
stream_<token>.nextNode()
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
>>
|
46
antlr_3_1_source/codegen/templates/ObjC/ASTDbg.stg
Normal file
46
antlr_3_1_source/codegen/templates/ObjC/ASTDbg.stg
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2006 Kay Roepke
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
group ASTDbg;
|
||||||
|
|
||||||
|
/*
|
||||||
|
parserMembers() ::= <<
|
||||||
|
protected TreeAdaptor adaptor =
|
||||||
|
new DebugTreeAdaptor(dbg,new CommonTreeAdaptor());
|
||||||
|
public void setTreeAdaptor(TreeAdaptor adaptor) {
|
||||||
|
this.adaptor = new DebugTreeAdaptor(dbg,adaptor);
|
||||||
|
}
|
||||||
|
public TreeAdaptor getTreeAdaptor() {
|
||||||
|
return adaptor;
|
||||||
|
}<\n>
|
||||||
|
>>
|
||||||
|
*/
|
||||||
|
|
||||||
|
@treeParserHeaderFile.superClassName ::= "ANTLRDebugTreeParser"
|
||||||
|
|
||||||
|
@rewriteElement.pregen() ::= "[debugListener locationLine:<e.line> column:<e.pos>];"
|
189
antlr_3_1_source/codegen/templates/ObjC/ASTParser.stg
Normal file
189
antlr_3_1_source/codegen/templates/ObjC/ASTParser.stg
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2007 Kay Roepke
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Templates for building ASTs during normal parsing.
|
||||||
|
*
|
||||||
|
* Deal with many combinations. Dimensions are:
|
||||||
|
* Auto build or rewrite
|
||||||
|
* no label, label, list label (label/no-label handled together)
|
||||||
|
* child, root
|
||||||
|
* token, set, rule, wildcard
|
||||||
|
*
|
||||||
|
* The situation is not too bad as rewrite (->) usage makes ^ and !
|
||||||
|
* invalid. There is no huge explosion of combinations.
|
||||||
|
*/
|
||||||
|
group ASTParser;
|
||||||
|
|
||||||
|
// TOKEN AST STUFF
|
||||||
|
|
||||||
|
/** ID and output=AST */
|
||||||
|
tokenRef(token,label,hetero,elementIndex) ::= <<
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
<if(backtracking)>if ( backtracking == 0 ) {<endif>
|
||||||
|
_<label>_tree = (<ASTLabelType>)[treeAdaptor newTreeWithToken:_<label>];
|
||||||
|
[treeAdaptor addChild:_<label>_tree toTree:root_0];
|
||||||
|
[_<label>_tree release];
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ID! and output=AST (same as plain tokenRef) */
|
||||||
|
tokenRefBang(token,label,elementIndex) ::= "<super.tokenRef(...)>"
|
||||||
|
|
||||||
|
/** ID^ and output=AST */
|
||||||
|
tokenRefRuleRoot(token,label,hetero,elementIndex) ::= <<
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
<if(backtracking)>if ( backtracking == 0 ) {<endif>
|
||||||
|
_<label>_tree = (<ASTLabelType>)[treeAdaptor newTreeWithToken:_<label>];
|
||||||
|
root_0 = (<ASTLabelType>)[treeAdaptor makeNode:_<label>_tree parentOf:root_0];
|
||||||
|
[_<label>_tree release];
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ids+=ID! and output=AST */
|
||||||
|
tokenRefBangAndListLabel(token,label,elementIndex) ::= <<
|
||||||
|
<tokenRefBang(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** label+=TOKEN when output=AST but not rewrite alt */
|
||||||
|
tokenRefAndListLabel(token,label,hetero,elementIndex) ::= <<
|
||||||
|
<tokenRef(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Match label+=TOKEN^ when output=AST but not rewrite alt */
|
||||||
|
tokenRefRuleRootAndListLabel(token,label,hetero,elementIndex) ::= <<
|
||||||
|
<tokenRefRuleRoot(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// SET AST
|
||||||
|
|
||||||
|
// the match set stuff is interesting in that it uses an argument list
|
||||||
|
// to pass code to the default matchSet; another possible way to alter
|
||||||
|
// inherited code. I don't use the region stuff because I need to pass
|
||||||
|
// different chunks depending on the operator. I don't like making
|
||||||
|
// the template name have the operator as the number of templates gets
|
||||||
|
// large but this is the most flexible--this is as opposed to having
|
||||||
|
// the code generator call matchSet then add root code or ruleroot code
|
||||||
|
// plus list label plus ... The combinations might require complicated
|
||||||
|
// rather than just added on code. Investigate that refactoring when
|
||||||
|
// I have more time.
|
||||||
|
|
||||||
|
// TODO: add support for heterogeneous trees
|
||||||
|
|
||||||
|
matchSet(s,label,hetero,elementIndex,postmatchCode) ::= <<
|
||||||
|
<super.matchSet(..., postmatchCode={
|
||||||
|
<if(backtracking)>if (backtracking == 0) {<endif>
|
||||||
|
_<label>_tree = (<ASTLabelType>)[treeAdaptor newTreeWithToken:_<label>];
|
||||||
|
[treeAdaptor addChild:_<label>_tree toTree:root_0];
|
||||||
|
[_<label>_tree release];
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
})>
|
||||||
|
>>
|
||||||
|
|
||||||
|
matchSetBang(s,label,elementIndex,postmatchCode) ::= "<super.matchSet(...)>"
|
||||||
|
|
||||||
|
// note there is no matchSetTrack because -> rewrites force sets to be
|
||||||
|
// plain old blocks of alts: (A|B|...|C)
|
||||||
|
|
||||||
|
matchSetRuleRoot(s,label,hetero,elementIndex,debug) ::= <<
|
||||||
|
<super.matchSet(..., postmatchCode={
|
||||||
|
<if(backtracking)>if (backtracking == 0) {<endif>
|
||||||
|
_<label>_tree = (<ASTLabelType>)[treeAdaptor newTreeWithToken:_<label>];
|
||||||
|
root_0 = (<ASTLabelType>)[treeAdaptor makeNode:_<label>_tree parentOf:root_0];
|
||||||
|
[_<label>_tree release];
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
})>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// RULE REF AST
|
||||||
|
|
||||||
|
/** rule when output=AST */
|
||||||
|
ruleRef(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<super.ruleRef(...)>
|
||||||
|
<if(backtracking)>if (backtracking == 0) <endif>[treeAdaptor addChild:[_<label> tree] toTree:root_0];
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** rule! is same as normal rule ref */
|
||||||
|
ruleRefBang(rule,label,elementIndex,args,scope) ::= "<super.ruleRef(...)>"
|
||||||
|
|
||||||
|
/** rule^ */
|
||||||
|
ruleRefRuleRoot(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<super.ruleRef(...)>
|
||||||
|
<if(backtracking)>if (backtracking == 0) <endif>root_0 = (<ASTLabelType>)[treeAdaptor makeNode:[_<label> tree] parentOf:root_0];
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule when output=AST */
|
||||||
|
ruleRefAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRef(...)>
|
||||||
|
<listLabel(elem="["+label+" tree]",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule! when output=AST is a rule ref with list addition */
|
||||||
|
ruleRefBangAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefBang(...)>
|
||||||
|
<listLabel(elem="["+label+" tree]",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule^ */
|
||||||
|
ruleRefRuleRootAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefRuleRoot(...)>
|
||||||
|
<listLabel(elem="["+label+" tree]",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// WILDCARD AST
|
||||||
|
|
||||||
|
wildcard(label,elementIndex) ::= <<
|
||||||
|
<super.wildcard(...)>
|
||||||
|
<if(backtracking)>if (backtracking == 0) {<endif>
|
||||||
|
_<label>_tree = (<ASTLabelType>)[treeAdaptor newTreeWithToken:_<label>];
|
||||||
|
[treeAdaptor addChild:_<label>_tree toTree:root_0];
|
||||||
|
[_<label>_tree release];
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
wildcardBang(label,elementIndex) ::= "<super.wildcard(...)>"
|
||||||
|
|
||||||
|
wildcardRuleRoot(label,elementIndex) ::= <<
|
||||||
|
<super.wildcard(...)>
|
||||||
|
<if(backtracking)>if (backtracking == 0) {<endif>
|
||||||
|
_<label>_tree = (<ASTLabelType>)[treeAdaptor newTreeWithToken:_<label>];
|
||||||
|
root_0 = (<ASTLabelType>)[treeAdaptor makeNode:_<label>_tree parentOf:root_0];
|
||||||
|
[_<label>_tree release];
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
|
||||||
|
createNodeFromToken(label,hetero) ::= <<
|
||||||
|
<if(hetero)>
|
||||||
|
new <hetero>(<label>) <! new MethodNode(IDLabel) !>
|
||||||
|
<else>
|
||||||
|
(<ASTLabelType>)adaptor.create(<label>)
|
||||||
|
<endif>
|
||||||
|
>>
|
129
antlr_3_1_source/codegen/templates/ObjC/ASTTreeParser.stg
Normal file
129
antlr_3_1_source/codegen/templates/ObjC/ASTTreeParser.stg
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2007 Kay Roepke
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
group ASTTreeParser;
|
||||||
|
|
||||||
|
/** match ^(root children) in tree parser; override here to
|
||||||
|
* add tree construction actions.
|
||||||
|
*/
|
||||||
|
tree(root, actionsAfterRoot, children, nullableChildList,
|
||||||
|
enclosingTreeLevel, treeLevel) ::= <<
|
||||||
|
{
|
||||||
|
<ASTLabelType> root_<treeLevel> = [treeAdapator newEmptyTree];
|
||||||
|
<root:element()>
|
||||||
|
<actionsAfterRoot:element()>
|
||||||
|
<if(nullableChildList)>
|
||||||
|
if ( [input LA:1] == ANTLRTokenTypeDOWN ) {
|
||||||
|
[self match:input tokenType:ANTLRTokenTypeDOWN follow:nil]; <checkRuleBacktrackFailure()>
|
||||||
|
<children:element()>
|
||||||
|
[self match:input tokenType:ANTLRTokenTypeUP follow:nil]; <checkRuleBacktrackFailure()>
|
||||||
|
}
|
||||||
|
<else>
|
||||||
|
[self match:input tokenType:ANTLRTokenTypeDOWN follow:nil]; <checkRuleBacktrackFailure()>
|
||||||
|
<children:element()>
|
||||||
|
[self match:input tokenType:ANTLRTokenTypeUP follow:nil]; <checkRuleBacktrackFailure()>
|
||||||
|
<endif>
|
||||||
|
[root_<treeLevel> release];
|
||||||
|
}<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** What to emit when there is no rewrite. For auto build
|
||||||
|
* mode, does nothing.
|
||||||
|
*/
|
||||||
|
noRewrite(rewriteBlockLevel, treeLevel) ::= <<
|
||||||
|
<if(rewriteMode)>retval.tree = (<ASTLabelType>)retval.start;<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// TOKEN AST STUFF
|
||||||
|
|
||||||
|
/** ID auto construct */
|
||||||
|
tokenRef(token,label,elementIndex) ::= <<
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) {<endif>
|
||||||
|
<label>_tree = (<ASTLabelType>)adaptor.dupNode(<label>);
|
||||||
|
adaptor.addChild(root_<treeLevel>, <label>_tree);
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** label+=TOKEN auto construct */
|
||||||
|
tokenRefAndListLabel(token,label,elementIndex) ::= <<
|
||||||
|
<tokenRef(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(ID ...) auto construct */
|
||||||
|
tokenRefRuleRoot(token,label,elementIndex) ::= <<
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) {<endif>
|
||||||
|
<label>_tree = (<ASTLabelType>)adaptor.dupNode(<label>);
|
||||||
|
root_<treeLevel> = (<ASTLabelType>)adaptor.becomeRoot(<label>_tree, root_<treeLevel>);
|
||||||
|
<if(backtracking)>}<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Match ^(label+=TOKEN ...) auto construct */
|
||||||
|
tokenRefRuleRootAndListLabel(token,label,elementIndex) ::= <<
|
||||||
|
<tokenRefRuleRoot(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// RULE REF AST
|
||||||
|
|
||||||
|
/** rule auto construct */
|
||||||
|
ruleRef(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<super.ruleRef(...)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) <endif>adaptor.addChild(root_<treeLevel>, <label>.getTree());
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule auto construct */
|
||||||
|
ruleRefAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRef(...)>
|
||||||
|
<listLabel(elem=label+".getTree()",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(rule ...) auto construct */
|
||||||
|
ruleRefRuleRoot(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<super.ruleRef(...)>
|
||||||
|
<if(backtracking)>if ( state.backtracking==0 ) <endif>root_<treeLevel> = (<ASTLabelType>)adaptor.becomeRoot(<label>.getTree(), root_<treeLevel>);
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(x+=rule ...) auto construct */
|
||||||
|
ruleRefRuleRootAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefRuleRoot(...)>
|
||||||
|
<listLabel(elem=label+".getTree()",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Streams for token refs are tree nodes now; override to
|
||||||
|
* change nextToken to nextNode.
|
||||||
|
*/
|
||||||
|
createRewriteNodeFromElement(token,hetero,scope) ::= <<
|
||||||
|
#error Heterogeneous tree support not implemented.
|
||||||
|
<if(hetero)>
|
||||||
|
new <hetero>(stream_<token>.nextNode())
|
||||||
|
<else>
|
||||||
|
stream_<token>.nextNode()
|
||||||
|
<endif>
|
||||||
|
>>
|
178
antlr_3_1_source/codegen/templates/ObjC/Dbg.stg
Normal file
178
antlr_3_1_source/codegen/templates/ObjC/Dbg.stg
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2006 Kay Roepke
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
/** Template overrides to add debugging to normal Objective-C output;
|
||||||
|
* If ASTs are built, then you'll also get ASTDbg.stg loaded.
|
||||||
|
*/
|
||||||
|
group Dbg;
|
||||||
|
|
||||||
|
@headerFile.imports() ::= <<
|
||||||
|
<@super.imports()>
|
||||||
|
#import \<ANTLR/ANTLRDebug.h>
|
||||||
|
>>
|
||||||
|
|
||||||
|
@parserHeaderFile.ivars() ::= <<
|
||||||
|
int ruleLevel;
|
||||||
|
NSArray *ruleNames;
|
||||||
|
>>
|
||||||
|
|
||||||
|
@parserHeaderFile.methodsdecl() ::= <<
|
||||||
|
-(BOOL) evalPredicate:(NSString *)predicate matched:(BOOL)result;<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
@genericParser.init() ::= <<
|
||||||
|
ruleNames = [[NSArray alloc] initWithObjects:<rules:{rST | @"<rST.ruleName>"}; separator=", ", wrap="\n ">, nil];<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
@genericParser.dealloc() ::= <<
|
||||||
|
[ruleNames release];<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
@genericParser.methods() ::= <<
|
||||||
|
-(BOOL) evalPredicate:(NSString *)predicate matched:(BOOL)result
|
||||||
|
{
|
||||||
|
[debugListener semanticPredicate:predicate matched:result];
|
||||||
|
return result;
|
||||||
|
}<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/* bug: can't use @super.superClassName()> */
|
||||||
|
@parserHeaderFile.superClassName() ::= "ANTLRDebug<if(TREE_PARSER)>Tree<endif>Parser"
|
||||||
|
|
||||||
|
@rule.preamble() ::= <<
|
||||||
|
@try { [debugListener enterRule:@"<ruleName>"];
|
||||||
|
if ( ruleLevel==0 ) [debugListener commence];
|
||||||
|
ruleLevel++;
|
||||||
|
[debugListener locationLine:<ruleDescriptor.tree.line> column:<ruleDescriptor.tree.column>];<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
@rule.postamble() ::= <<
|
||||||
|
[debugListener locationLine:<ruleDescriptor.EORNode.line> column:<ruleDescriptor.EORNode.column>];<\n>
|
||||||
|
}
|
||||||
|
@finally {
|
||||||
|
[debugListener exitRule:@"<ruleName>"];
|
||||||
|
ruleLevel--;
|
||||||
|
if ( ruleLevel==0 ) [debugListener terminate];
|
||||||
|
}<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/* these are handled in the runtime for now.
|
||||||
|
* stinks, but that's the easiest way to avoid having to generate two
|
||||||
|
* methods for each synpred
|
||||||
|
|
||||||
|
@synpred.start() ::= "[debugListener beginBacktrack:backtracking];"
|
||||||
|
|
||||||
|
@synpred.stop() ::= "[debugListener endBacktrack:backtracking wasSuccessful:success];"
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Common debug event triggers used by region overrides below
|
||||||
|
|
||||||
|
enterSubRule() ::=
|
||||||
|
"@try { [debugListener enterSubRule:<decisionNumber>];<\n>"
|
||||||
|
|
||||||
|
exitSubRule() ::=
|
||||||
|
"} @finally { [debugListener exitSubRule:<decisionNumber>]; }<\n>"
|
||||||
|
|
||||||
|
enterDecision() ::=
|
||||||
|
"@try { [debugListener enterDecision:<decisionNumber>];<\n>"
|
||||||
|
|
||||||
|
exitDecision() ::=
|
||||||
|
"} @finally { [debugListener exitDecision:<decisionNumber>]; }<\n>"
|
||||||
|
|
||||||
|
enterAlt(n) ::= "[debugListener enterAlt:<n>];<\n>"
|
||||||
|
|
||||||
|
// Region overrides that tell various constructs to add debugging triggers
|
||||||
|
|
||||||
|
@block.predecision() ::= "<enterSubRule()><enterDecision()>"
|
||||||
|
|
||||||
|
@block.postdecision() ::= "<exitDecision()>"
|
||||||
|
|
||||||
|
@block.postbranch() ::= "<exitSubRule()>"
|
||||||
|
|
||||||
|
@ruleBlock.predecision() ::= "<enterDecision()>"
|
||||||
|
|
||||||
|
@ruleBlock.postdecision() ::= "<exitDecision()>"
|
||||||
|
|
||||||
|
@ruleBlockSingleAlt.prealt() ::= "<enterAlt(n=\"1\")>"
|
||||||
|
|
||||||
|
@blockSingleAlt.prealt() ::= "<enterAlt(n=\"1\")>"
|
||||||
|
|
||||||
|
@positiveClosureBlock.preloop() ::= "<enterSubRule()>"
|
||||||
|
|
||||||
|
@positiveClosureBlock.postloop() ::= "<exitSubRule()>"
|
||||||
|
|
||||||
|
@positiveClosureBlock.predecision() ::= "<enterDecision()>"
|
||||||
|
|
||||||
|
@positiveClosureBlock.postdecision() ::= "<exitDecision()>"
|
||||||
|
|
||||||
|
@positiveClosureBlock.earlyExitException() ::=
|
||||||
|
"[debugListener recognitionException:eee];<\n>"
|
||||||
|
|
||||||
|
@closureBlock.preloop() ::= "<enterSubRule()>"
|
||||||
|
|
||||||
|
@closureBlock.postloop() ::= "<exitSubRule()>"
|
||||||
|
|
||||||
|
@closureBlock.predecision() ::= "<enterDecision()>"
|
||||||
|
|
||||||
|
@closureBlock.postdecision() ::= "<exitDecision()>"
|
||||||
|
|
||||||
|
@altSwitchCase.prealt() ::= "<enterAlt(n=i)>"
|
||||||
|
|
||||||
|
@element.prematch() ::=
|
||||||
|
"[debugListener locationLine:<it.line> column:<it.pos>];"
|
||||||
|
|
||||||
|
@matchSet.mismatchedSetException() ::=
|
||||||
|
"[debugListener recognitionException:mse];"
|
||||||
|
|
||||||
|
@dfaState.noViableAltException() ::= "[debugListener recognitionException:nvae];"
|
||||||
|
|
||||||
|
@dfaStateSwitch.noViableAltException() ::= "[debugListener recognitionException:nvae];"
|
||||||
|
|
||||||
|
dfaDecision(decisionNumber,description) ::= <<
|
||||||
|
@try {
|
||||||
|
// isCyclicDecision is only necessary for the Profiler. Which I didn't do, yet.
|
||||||
|
// isCyclicDecision = YES;
|
||||||
|
<super.dfaDecision(...)>
|
||||||
|
}
|
||||||
|
@catch (ANTLRNoViableAltException *nvae) {
|
||||||
|
[debugListener recognitionException:nvae];
|
||||||
|
@throw nvae;
|
||||||
|
}
|
||||||
|
>>
|
||||||
|
|
||||||
|
@cyclicDFA.errorMethod() ::= <<
|
||||||
|
-(void) error:(ANTLRNoViableAltException *)nvae
|
||||||
|
{
|
||||||
|
[[recognizer debugListener] recognitionException:nvae];
|
||||||
|
}
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Force predicate validation to trigger an event */
|
||||||
|
evalPredicate(pred,description) ::= <<
|
||||||
|
[self evalPredicate:@"<description>" result:<pred>];
|
||||||
|
>>
|
1502
antlr_3_1_source/codegen/templates/ObjC/ObjC.stg
Normal file
1502
antlr_3_1_source/codegen/templates/ObjC/ObjC.stg
Normal file
File diff suppressed because it is too large
Load Diff
1314
antlr_3_1_source/codegen/templates/Perl5/Perl5.stg
Normal file
1314
antlr_3_1_source/codegen/templates/Perl5/Perl5.stg
Normal file
File diff suppressed because it is too large
Load Diff
440
antlr_3_1_source/codegen/templates/Python/AST.stg
Normal file
440
antlr_3_1_source/codegen/templates/Python/AST.stg
Normal file
@ -0,0 +1,440 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* in sync with Java/AST.stg revision 36 */
|
||||||
|
|
||||||
|
group AST;
|
||||||
|
|
||||||
|
finishedBacktracking(block) ::= <<
|
||||||
|
<if(backtracking)>
|
||||||
|
if self._state.backtracking == 0:
|
||||||
|
<block>
|
||||||
|
<else>
|
||||||
|
<block>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
@outputFile.imports() ::= <<
|
||||||
|
<@super.imports()>
|
||||||
|
<if(!TREE_PARSER)><! tree parser would already have imported !>
|
||||||
|
from antlr3.tree import *<\n>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Add an adaptor property that knows how to build trees */
|
||||||
|
@genericParser.init() ::= <<
|
||||||
|
<@super.init()>
|
||||||
|
self._adaptor = CommonTreeAdaptor()
|
||||||
|
>>
|
||||||
|
|
||||||
|
@genericParser.members() ::= <<
|
||||||
|
<@super.members()>
|
||||||
|
def getTreeAdaptor(self):
|
||||||
|
return self._adaptor
|
||||||
|
|
||||||
|
def setTreeAdaptor(self, adaptor):
|
||||||
|
self._adaptor = adaptor
|
||||||
|
<grammar.directDelegates:{g|<g:delegateName()>.adaptor = adaptor}; separator="\n">
|
||||||
|
|
||||||
|
adaptor = property(getTreeAdaptor, setTreeAdaptor)
|
||||||
|
>>
|
||||||
|
|
||||||
|
@returnScope.ruleReturnInit() ::= <<
|
||||||
|
self.tree = None
|
||||||
|
>>
|
||||||
|
|
||||||
|
|
||||||
|
/** Add a variable to track rule's return AST */
|
||||||
|
ruleDeclarations() ::= <<
|
||||||
|
<super.ruleDeclarations()>
|
||||||
|
root_0 = None<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
ruleLabelDefs() ::= <<
|
||||||
|
<super.ruleLabelDefs()>
|
||||||
|
<ruleDescriptor.tokenLabels:{<it.label.text>_tree = None}; separator="\n">
|
||||||
|
<ruleDescriptor.tokenListLabels:{<it.label.text>_tree = None}; separator="\n">
|
||||||
|
<ruleDescriptor.allTokenRefsInAltsWithRewrites
|
||||||
|
:{stream_<it> = RewriteRule<rewriteElementType>Stream(self._adaptor, "token <it>")}; separator="\n">
|
||||||
|
<ruleDescriptor.allRuleRefsInAltsWithRewrites
|
||||||
|
:{stream_<it> = RewriteRuleSubtreeStream(self._adaptor, "rule <it>")}; separator="\n">
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** When doing auto AST construction, we must define some variables;
|
||||||
|
* These should be turned off if doing rewrites. This must be a "mode"
|
||||||
|
* as a rule could have both rewrite and AST within the same alternative
|
||||||
|
* block.
|
||||||
|
*/
|
||||||
|
@alt.declarations() ::= <<
|
||||||
|
<if(autoAST)>
|
||||||
|
<if(outerAlt)>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
root_0 = self._adaptor.nil()<\n>
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
|
||||||
|
// // T r a c k i n g R u l e E l e m e n t s
|
||||||
|
|
||||||
|
/** ID and track it for use in a rewrite rule */
|
||||||
|
tokenRefTrack(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefBang(...)> <! Track implies no auto AST construction!>
|
||||||
|
<finishedBacktracking({stream_<token>.add(<label>)})>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ids+=ID and track it for use in a rewrite rule; adds to ids *and*
|
||||||
|
* to the tracking list stream_ID for use in the rewrite.
|
||||||
|
*/
|
||||||
|
tokenRefTrackAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefTrack(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(ID ...) track for rewrite */
|
||||||
|
tokenRefRuleRootTrack(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefBang(...)>
|
||||||
|
<finishedBacktracking({stream_<token>.add(<label>)})>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Match ^(label+=TOKEN ...) track for rewrite */
|
||||||
|
tokenRefRuleRootTrackAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefRuleRootTrack(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
wildcardTrack(label,elementIndex) ::= <<
|
||||||
|
<super.wildcard(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** rule when output=AST and tracking for rewrite */
|
||||||
|
ruleRefTrack(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<super.ruleRef(...)>
|
||||||
|
<finishedBacktracking({stream_<rule.name>.add(<label>.tree)})>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule when output=AST and tracking for rewrite */
|
||||||
|
ruleRefTrackAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefTrack(...)>
|
||||||
|
<listLabel(elem=label+".tree",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(rule ...) rewrite */
|
||||||
|
ruleRefRuleRootTrack(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefRuleRoot(...)>
|
||||||
|
<finishedBacktracking({stream_<rule.name>.add(<label>.tree)})>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(x+=rule ...) rewrite */
|
||||||
|
ruleRefRuleRootTrackAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefRuleRootTrack(...)>
|
||||||
|
<listLabel(elem=label+".tree",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// R e w r i t e
|
||||||
|
|
||||||
|
rewriteCode(
|
||||||
|
alts, description,
|
||||||
|
referencedElementsDeep, // ALL referenced elements to right of ->
|
||||||
|
referencedTokenLabels,
|
||||||
|
referencedTokenListLabels,
|
||||||
|
referencedRuleLabels,
|
||||||
|
referencedRuleListLabels,
|
||||||
|
rewriteBlockLevel, enclosingTreeLevel, treeLevel) ::=
|
||||||
|
<<
|
||||||
|
# AST Rewrite
|
||||||
|
# elements: <referencedElementsDeep; separator=", ">
|
||||||
|
# token labels: <referencedTokenLabels; separator=", ">
|
||||||
|
# rule labels: <referencedRuleLabels; separator=", ">
|
||||||
|
# token list labels: <referencedTokenListLabels; separator=", ">
|
||||||
|
# rule list labels: <referencedRuleListLabels; separator=", ">
|
||||||
|
<finishedBacktracking({
|
||||||
|
<prevRuleRootRef()>.tree = root_0
|
||||||
|
<rewriteCodeLabels()>
|
||||||
|
root_0 = self._adaptor.nil()
|
||||||
|
<first(alts):rewriteAltFirst(); anchor>
|
||||||
|
|
||||||
|
<rest(alts):{a | el<rewriteAltRest(a)>}; anchor, separator="\n\n">
|
||||||
|
|
||||||
|
<! if tree parser and rewrite=true !>
|
||||||
|
<if(TREE_PARSER)>
|
||||||
|
<if(rewriteMode)>
|
||||||
|
<prevRuleRootRef()>.tree = self._adaptor.rulePostProcessing(root_0)
|
||||||
|
self.input.replaceChildren(
|
||||||
|
self._adaptor.getParent(retval.start),
|
||||||
|
self._adaptor.getChildIndex(retval.start),
|
||||||
|
self._adaptor.getChildIndex(_last),
|
||||||
|
retval.tree
|
||||||
|
)<\n>
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
|
||||||
|
<! if parser or tree-parser and rewrite!=true, we need to set result !>
|
||||||
|
<if(!TREE_PARSER)>
|
||||||
|
<prevRuleRootRef()>.tree = root_0<\n>
|
||||||
|
<else>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<prevRuleRootRef()>.tree = root_0<\n>
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
})>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteCodeLabels() ::= <<
|
||||||
|
<referencedTokenLabels
|
||||||
|
:{stream_<it> = RewriteRule<rewriteElementType>Stream(self._adaptor, "token <it>", <it>)};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
<referencedTokenListLabels
|
||||||
|
:{stream_<it> = RewriteRule<rewriteElementType>Stream(self._adaptor, "token <it>", list_<it>)};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
<referencedRuleLabels
|
||||||
|
:{
|
||||||
|
if <it> is not None:
|
||||||
|
stream_<it> = RewriteRuleSubtreeStream(self._adaptor, "token <it>", <it>.tree)
|
||||||
|
else:
|
||||||
|
stream_<it> = RewriteRuleSubtreeStream(self._adaptor, "token <it>", None)
|
||||||
|
};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
<referencedRuleListLabels
|
||||||
|
:{stream_<it> = RewriteRuleSubtreeStream(self._adaptor, "token <it>", list_<it>)};
|
||||||
|
separator="\n"
|
||||||
|
>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Generate code for an optional rewrite block; note it uses the deep ref'd element
|
||||||
|
* list rather shallow like other blocks.
|
||||||
|
*/
|
||||||
|
rewriteOptionalBlock(
|
||||||
|
alt,rewriteBlockLevel,
|
||||||
|
referencedElementsDeep, // all nested refs
|
||||||
|
referencedElements, // elements in immediately block; no nested blocks
|
||||||
|
description) ::=
|
||||||
|
<<
|
||||||
|
# <fileName>:<description>
|
||||||
|
if <referencedElementsDeep:{el | stream_<el>.hasNext()}; separator=" or ">:
|
||||||
|
<alt>
|
||||||
|
|
||||||
|
<referencedElementsDeep:{el | stream_<el>.reset();<\n>}>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteClosureBlock(
|
||||||
|
alt,rewriteBlockLevel,
|
||||||
|
referencedElementsDeep, // all nested refs
|
||||||
|
referencedElements, // elements in immediately block; no nested blocks
|
||||||
|
description) ::=
|
||||||
|
<<
|
||||||
|
# <fileName>:<description>
|
||||||
|
while <referencedElements:{el | stream_<el>.hasNext()}; separator=" or ">:
|
||||||
|
<alt>
|
||||||
|
|
||||||
|
<referencedElements:{el | stream_<el>.reset();<\n>}>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewritePositiveClosureBlock(
|
||||||
|
alt,rewriteBlockLevel,
|
||||||
|
referencedElementsDeep, // all nested refs
|
||||||
|
referencedElements, // elements in immediately block; no nested blocks
|
||||||
|
description) ::=
|
||||||
|
<<
|
||||||
|
# <fileName>:<description>
|
||||||
|
if not (<referencedElements:{el | stream_<el>.hasNext()}; separator=" or ">):
|
||||||
|
raise RewriteEarlyExitException()
|
||||||
|
|
||||||
|
while <referencedElements:{el | stream_<el>.hasNext()}; separator=" or ">:
|
||||||
|
<alt>
|
||||||
|
|
||||||
|
<referencedElements:{el | stream_<el>.reset()<\n>}>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteAltRest(a) ::= <<
|
||||||
|
<if(a.pred)>
|
||||||
|
if <a.pred>:
|
||||||
|
# <a.description>
|
||||||
|
<a.alt>
|
||||||
|
<else>
|
||||||
|
se: <! little hack to get if .. elif .. else block right !>
|
||||||
|
# <a.description>
|
||||||
|
<a.alt>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteAltFirst(a) ::= <<
|
||||||
|
<if(a.pred)>
|
||||||
|
if <a.pred>:
|
||||||
|
# <a.description>
|
||||||
|
<a.alt>
|
||||||
|
<else>
|
||||||
|
# <a.description>
|
||||||
|
<a.alt>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** For empty rewrites: "r : ... -> ;" */
|
||||||
|
rewriteEmptyAlt() ::= "root_0 = None"
|
||||||
|
|
||||||
|
rewriteTree(root,children,description,enclosingTreeLevel,treeLevel) ::= <<
|
||||||
|
# <fileName>:<description>
|
||||||
|
root_<treeLevel> = self._adaptor.nil()
|
||||||
|
<root:rewriteElement()>
|
||||||
|
<children:rewriteElement()>
|
||||||
|
self._adaptor.addChild(root_<enclosingTreeLevel>, root_<treeLevel>)<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteElementList(elements) ::= "<elements:rewriteElement()>"
|
||||||
|
|
||||||
|
rewriteElement(e) ::= <<
|
||||||
|
<@pregen()>
|
||||||
|
<e.el>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen ID or ID[args] */
|
||||||
|
rewriteTokenRef(token,elementIndex,hetero,args) ::= <<
|
||||||
|
self._adaptor.addChild(root_<treeLevel>, <createRewriteNodeFromElement(...)>)<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen $label ... where defined via label=ID */
|
||||||
|
rewriteTokenLabelRef(label,elementIndex) ::= <<
|
||||||
|
self._adaptor.addChild(root_<treeLevel>, stream_<label>.nextNode())<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen $label ... where defined via label+=ID */
|
||||||
|
rewriteTokenListLabelRef(label,elementIndex) ::= <<
|
||||||
|
self._adaptor.addChild(root_<treeLevel>, stream_<label>.nextNode())<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen ^($label ...) */
|
||||||
|
rewriteTokenLabelRefRoot(label,elementIndex) ::= <<
|
||||||
|
root_<treeLevel> = self._adaptor.becomeRoot(stream_<label>.nextNode(), root_<treeLevel>)<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen ^($label ...) where label+=... */
|
||||||
|
rewriteTokenListLabelRefRoot ::= rewriteTokenLabelRefRoot
|
||||||
|
|
||||||
|
/** Gen ^(ID ...) or ^(ID[args] ...) */
|
||||||
|
rewriteTokenRefRoot(token,elementIndex,hetero,args) ::= <<
|
||||||
|
root_<treeLevel> = self._adaptor.becomeRoot(<createRewriteNodeFromElement(...)>, root_<treeLevel>)<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteImaginaryTokenRef(args,token,hetero,elementIndex) ::= <<
|
||||||
|
self._adaptor.addChild(root_<treeLevel>, <createImaginaryNode(tokenType=token, ...)>)<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteImaginaryTokenRefRoot(args,token,hetero,elementIndex) ::= <<
|
||||||
|
root_<treeLevel> = self._adaptor.becomeRoot(<createImaginaryNode(tokenType=token, ...)>, root_<treeLevel>)<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** plain -> {foo} action */
|
||||||
|
rewriteAction(action) ::= <<
|
||||||
|
<!FIXME(96,untested)!>
|
||||||
|
root_0 = <action><\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** What is the name of the previous value of this rule's root tree? This
|
||||||
|
* let's us refer to $rule to mean previous value. I am reusing the
|
||||||
|
* variable 'tree' sitting in retval struct to hold the value of root_0 right
|
||||||
|
* before I set it during rewrites. The assign will be to retval.tree.
|
||||||
|
*/
|
||||||
|
prevRuleRootRef() ::= "retval"
|
||||||
|
|
||||||
|
rewriteRuleRef(rule) ::= <<
|
||||||
|
self._adaptor.addChild(root_<treeLevel>, stream_<rule>.nextTree())<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteRuleRefRoot(rule) ::= <<
|
||||||
|
root_<treeLevel> = self._adaptor.becomeRoot(stream_<rule>.nextNode(), root_<treeLevel>)<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteNodeAction(action) ::= <<
|
||||||
|
self._adaptor.addChild(root_<treeLevel>, <action>)<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteNodeActionRoot(action) ::= <<
|
||||||
|
root_<treeLevel> = self._adaptor.becomeRoot(<action>, root_<treeLevel>)<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen $ruleLabel ... where defined via ruleLabel=rule */
|
||||||
|
rewriteRuleLabelRef(label) ::= <<
|
||||||
|
self._adaptor.addChild(root_<treeLevel>, stream_<label>.nextTree())<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen $ruleLabel ... where defined via ruleLabel+=rule */
|
||||||
|
rewriteRuleListLabelRef(label) ::= <<
|
||||||
|
self._adaptor.addChild(root_<treeLevel>, stream_<label>.nextTree())<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen ^($ruleLabel ...) where ruleLabel=rule */
|
||||||
|
rewriteRuleLabelRefRoot(label) ::= <<
|
||||||
|
root_<treeLevel> = self._adaptor.becomeRoot(stream_<label>.nextNode(), root_<treeLevel>)<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Gen ^($ruleLabel ...) where ruleLabel+=rule */
|
||||||
|
rewriteRuleListLabelRefRoot(label) ::= <<
|
||||||
|
root_<treeLevel> = self._adaptor.becomeRoot(stream_<label>.nextNode(), root_<treeLevel>)<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
createImaginaryNode(tokenType,hetero,args) ::= <<
|
||||||
|
<if(hetero)>
|
||||||
|
<! new MethodNode(IDLabel, args) !>
|
||||||
|
<hetero>(<tokenType><if(args)>, <args; separator=", "><endif>)
|
||||||
|
<else>
|
||||||
|
<if (!args)>self._adaptor.createFromType(<tokenType>, "<tokenType>")
|
||||||
|
<else>self._adaptor.create(<tokenType>, <args; separator=", ">)
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
//<! need to call different adaptor.create*() methods depending of argument count !>
|
||||||
|
//<if (!args)>self._adaptor.createFromType(<tokenType>, "<tokenType>")
|
||||||
|
//<else><if (!rest(args))>self._adaptor.createFromType(<tokenType>, <first(args)>)
|
||||||
|
//<else><if (!rest(rest(args)))>self._adaptor.createFromToken(<tokenType>, <first(args)>, <first(rest(args))>)
|
||||||
|
//<endif>
|
||||||
|
//<endif>
|
||||||
|
//<endif>
|
||||||
|
|
||||||
|
|
||||||
|
createRewriteNodeFromElement(token,hetero,args) ::= <<
|
||||||
|
<if(hetero)>
|
||||||
|
<hetero>(stream_<token>.nextToken()<if(args)>, <args; separator=", "><endif>)
|
||||||
|
<else>
|
||||||
|
<if(args)> <! must create new node from old !>
|
||||||
|
<! need to call different adaptor.create*() methods depending of argument count !>
|
||||||
|
<if (!args)>self._adaptor.createFromType(<token>, "<token>")
|
||||||
|
<else><if (!rest(args))>self._adaptor.createFromToken(<token>, <first(args)>)
|
||||||
|
<else><if (!rest(rest(args)))>self._adaptor.createFromToken(<token>, <first(args)>, <first(rest(args))>)
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
<else>
|
||||||
|
stream_<token>.nextNode()
|
||||||
|
<endif>
|
||||||
|
<endif>
|
||||||
|
>>
|
198
antlr_3_1_source/codegen/templates/Python/ASTParser.stg
Normal file
198
antlr_3_1_source/codegen/templates/Python/ASTParser.stg
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Templates for building ASTs during normal parsing.
|
||||||
|
*
|
||||||
|
* Deal with many combinations. Dimensions are:
|
||||||
|
* Auto build or rewrite
|
||||||
|
* no label, label, list label (label/no-label handled together)
|
||||||
|
* child, root
|
||||||
|
* token, set, rule, wildcard
|
||||||
|
*
|
||||||
|
* The situation is not too bad as rewrite (->) usage makes ^ and !
|
||||||
|
* invalid. There is no huge explosion of combinations.
|
||||||
|
*/
|
||||||
|
group ASTParser;
|
||||||
|
|
||||||
|
finishedBacktracking(block) ::= <<
|
||||||
|
<if(backtracking)>
|
||||||
|
if self._state.backtracking == 0:
|
||||||
|
<block>
|
||||||
|
<else>
|
||||||
|
<block>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
@rule.setErrorReturnValue() ::= <<
|
||||||
|
retval.tree = self._adaptor.errorNode(self.input, retval.start, self.input.LT(-1), re)
|
||||||
|
>>
|
||||||
|
|
||||||
|
// TOKEN AST STUFF
|
||||||
|
|
||||||
|
/** ID and output=AST */
|
||||||
|
tokenRef(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
<finishedBacktracking({
|
||||||
|
<label>_tree = <createNodeFromToken(...)>
|
||||||
|
self._adaptor.addChild(root_0, <label>_tree)
|
||||||
|
})>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ID! and output=AST (same as plain tokenRef) */
|
||||||
|
tokenRefBang(token,label,elementIndex) ::= "<super.tokenRef(...)>"
|
||||||
|
|
||||||
|
/** ID^ and output=AST */
|
||||||
|
tokenRefRuleRoot(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
<finishedBacktracking({
|
||||||
|
<label>_tree = <createNodeFromToken(...)>
|
||||||
|
root_0 = self._adaptor.becomeRoot(<label>_tree, root_0)
|
||||||
|
})>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ids+=ID! and output=AST */
|
||||||
|
tokenRefBangAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefBang(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** label+=TOKEN when output=AST but not rewrite alt */
|
||||||
|
tokenRefAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRef(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Match label+=TOKEN^ when output=AST but not rewrite alt */
|
||||||
|
tokenRefRuleRootAndListLabel(token,label,hetero,elementIndex) ::= <<
|
||||||
|
<tokenRefRuleRoot(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// SET AST
|
||||||
|
|
||||||
|
// the match set stuff is interesting in that it uses an argument list
|
||||||
|
// to pass code to the default matchSet; another possible way to alter
|
||||||
|
// inherited code. I don't use the region stuff because I need to pass
|
||||||
|
// different chunks depending on the operator. I don't like making
|
||||||
|
// the template name have the operator as the number of templates gets
|
||||||
|
// large but this is the most flexible--this is as opposed to having
|
||||||
|
// the code generator call matchSet then add root code or ruleroot code
|
||||||
|
// plus list label plus ... The combinations might require complicated
|
||||||
|
// rather than just added on code. Investigate that refactoring when
|
||||||
|
// I have more time.
|
||||||
|
|
||||||
|
matchSet(s,label,hetero,elementIndex,postmatchCode) ::= <<
|
||||||
|
<super.matchSet(..., postmatchCode={<finishedBacktracking({self._adaptor.addChild(root_0, <createNodeFromToken(...)>)})>})>
|
||||||
|
>>
|
||||||
|
|
||||||
|
matchRuleBlockSet(s,label,hetero,elementIndex,postmatchCode,treeLevel="0") ::= <<
|
||||||
|
<matchSet(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
matchSetBang(s,label,elementIndex,postmatchCode) ::= "<super.matchSet(...)>"
|
||||||
|
|
||||||
|
// note there is no matchSetTrack because -> rewrites force sets to be
|
||||||
|
// plain old blocks of alts: (A|B|...|C)
|
||||||
|
|
||||||
|
matchSetRuleRoot(s,label,hetero,elementIndex,debug) ::= <<
|
||||||
|
<if(label)>
|
||||||
|
<label> = self.input.LT(1)<\n>
|
||||||
|
<endif>
|
||||||
|
<super.matchSet(..., postmatchCode={<finishedBacktracking({root_0 = self._adaptor.becomeRoot(<createNodeFromToken(...)>, root_0)})>})>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// RULE REF AST
|
||||||
|
|
||||||
|
/** rule when output=AST */
|
||||||
|
ruleRef(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<super.ruleRef(...)>
|
||||||
|
<finishedBacktracking({self._adaptor.addChild(root_0, <label>.tree)})>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** rule! is same as normal rule ref */
|
||||||
|
ruleRefBang(rule,label,elementIndex,args,scope) ::= "<super.ruleRef(...)>"
|
||||||
|
|
||||||
|
/** rule^ */
|
||||||
|
ruleRefRuleRoot(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<super.ruleRef(...)>
|
||||||
|
<finishedBacktracking({root_0 = self._adaptor.becomeRoot(<label>.tree, root_0)})>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule when output=AST */
|
||||||
|
ruleRefAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRef(...)>
|
||||||
|
<listLabel(elem=label+".tree",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule! when output=AST is a rule ref with list addition */
|
||||||
|
ruleRefBangAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefBang(...)>
|
||||||
|
<listLabel(elem=label+".tree",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule^ */
|
||||||
|
ruleRefRuleRootAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefRuleRoot(...)>
|
||||||
|
<listLabel(elem=label+".tree",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// WILDCARD AST
|
||||||
|
|
||||||
|
wildcard(label,elementIndex) ::= <<
|
||||||
|
<super.wildcard(...)>
|
||||||
|
<finishedBacktracking({
|
||||||
|
<label>_tree = self._adaptor.createWithPayload(<label>)
|
||||||
|
self._adaptor.addChild(root_0, <label>_tree)
|
||||||
|
})>
|
||||||
|
>>
|
||||||
|
|
||||||
|
wildcardBang(label,elementIndex) ::= "<super.wildcard(...)>"
|
||||||
|
|
||||||
|
wildcardRuleRoot(label,elementIndex) ::= <<
|
||||||
|
<super.wildcard(...)>
|
||||||
|
<finishedBacktracking({
|
||||||
|
<label>_tree = self._adaptor.createWithPayload(<label>)
|
||||||
|
root_0 = self._adaptor.becomeRoot(<label>_tree, root_0)
|
||||||
|
})>
|
||||||
|
>>
|
||||||
|
|
||||||
|
createNodeFromToken(label,hetero) ::= <<
|
||||||
|
<if(hetero)>
|
||||||
|
<hetero>(<label>) <! new MethodNode(IDLabel) !>
|
||||||
|
<else>
|
||||||
|
self._adaptor.createWithPayload(<label>)
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
ruleCleanUp() ::= <<
|
||||||
|
<super.ruleCleanUp()>
|
||||||
|
<finishedBacktracking({
|
||||||
|
retval.tree = self._adaptor.rulePostProcessing(root_0)
|
||||||
|
self._adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop)
|
||||||
|
})>
|
||||||
|
>>
|
295
antlr_3_1_source/codegen/templates/Python/ASTTreeParser.stg
Normal file
295
antlr_3_1_source/codegen/templates/Python/ASTTreeParser.stg
Normal file
@ -0,0 +1,295 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Templates for building ASTs during tree parsing.
|
||||||
|
*
|
||||||
|
* Deal with many combinations. Dimensions are:
|
||||||
|
* Auto build or rewrite
|
||||||
|
* no label, label, list label (label/no-label handled together)
|
||||||
|
* child, root
|
||||||
|
* token, set, rule, wildcard
|
||||||
|
*
|
||||||
|
* Each combination has its own template except that label/no label
|
||||||
|
* is combined into tokenRef, ruleRef, ...
|
||||||
|
*/
|
||||||
|
group ASTTreeParser;
|
||||||
|
|
||||||
|
finishedBacktracking(block) ::= <<
|
||||||
|
<if(backtracking)>
|
||||||
|
if self._state.backtracking == 0:
|
||||||
|
<block>
|
||||||
|
<else>
|
||||||
|
<block>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Add a variable to track last element matched */
|
||||||
|
ruleDeclarations() ::= <<
|
||||||
|
<super.ruleDeclarations()>
|
||||||
|
_first_0 = None
|
||||||
|
_last = None<\n>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** What to emit when there is no rewrite rule. For auto build
|
||||||
|
* mode, does nothing.
|
||||||
|
*/
|
||||||
|
noRewrite(rewriteBlockLevel, treeLevel) ::= <<
|
||||||
|
<finishedBacktracking({
|
||||||
|
<if(rewriteMode)>
|
||||||
|
retval.tree = _first_0
|
||||||
|
if self._adaptor.getParent(retval.tree) is not None and self._adaptor.isNil(self._adaptor.getParent(retval.tree)):
|
||||||
|
retval.tree = self._adaptor.getParent(retval.tree)
|
||||||
|
<endif>
|
||||||
|
})>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** match ^(root children) in tree parser; override here to
|
||||||
|
* add tree construction actions.
|
||||||
|
*/
|
||||||
|
tree(root, actionsAfterRoot, children, nullableChildList,
|
||||||
|
enclosingTreeLevel, treeLevel) ::= <<
|
||||||
|
_last = self.input.LT(1)
|
||||||
|
_save_last_<treeLevel> = _last
|
||||||
|
_first_<treeLevel> = None
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
root_<treeLevel> = self._adaptor.nil()<\n>
|
||||||
|
<endif>
|
||||||
|
<root:element()>
|
||||||
|
<if(rewriteMode)>
|
||||||
|
<finishedBacktracking({
|
||||||
|
<if(root.el.rule)>
|
||||||
|
if _first_<enclosingTreeLevel> is None:
|
||||||
|
_first_<enclosingTreeLevel> = <root.el.label>.tree<\n>
|
||||||
|
<else>
|
||||||
|
if _first_<enclosingTreeLevel> is None:
|
||||||
|
_first_<enclosingTreeLevel> = <root.el.label><\n>
|
||||||
|
<endif>
|
||||||
|
})>
|
||||||
|
<endif>
|
||||||
|
<actionsAfterRoot:element()>
|
||||||
|
<if(nullableChildList)>
|
||||||
|
if self.input.LA(1) == DOWN:
|
||||||
|
self.match(self.input, DOWN, None)
|
||||||
|
<children:element()>
|
||||||
|
self.match(self.input, UP, None)
|
||||||
|
|
||||||
|
<else>
|
||||||
|
self.match(self.input, DOWN, None)
|
||||||
|
<children:element()>
|
||||||
|
self.match(self.input, UP, None)<\n>
|
||||||
|
<endif>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
self._adaptor.addChild(root_<enclosingTreeLevel>, root_<treeLevel>)<\n>
|
||||||
|
<endif>
|
||||||
|
_last = _save_last_<treeLevel>
|
||||||
|
|
||||||
|
>>
|
||||||
|
|
||||||
|
// TOKEN AST STUFF
|
||||||
|
|
||||||
|
/** ID! and output=AST (same as plain tokenRef) 'cept add
|
||||||
|
* setting of _last
|
||||||
|
*/
|
||||||
|
tokenRefBang(token,label,elementIndex) ::= <<
|
||||||
|
_last = self.input.LT(1)
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ID auto construct */
|
||||||
|
tokenRef(token,label,elementIndex,hetero) ::= <<
|
||||||
|
_last = self.input.LT(1)
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<finishedBacktracking({
|
||||||
|
<if(hetero)>
|
||||||
|
<label>_tree = <hetero>(<label>)
|
||||||
|
<else>
|
||||||
|
<label>_tree = self._adaptor.dupNode(<label>)
|
||||||
|
<endif><\n>
|
||||||
|
self._adaptor.addChild(root_<treeLevel>, <label>_tree)
|
||||||
|
})>
|
||||||
|
<else> <! rewrite mode !>
|
||||||
|
<finishedBacktracking({
|
||||||
|
if _first_<treeLevel> is None:
|
||||||
|
_first_<treeLevel> = <label><\n>
|
||||||
|
})>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** label+=TOKEN auto construct */
|
||||||
|
tokenRefAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRef(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(ID ...) auto construct */
|
||||||
|
tokenRefRuleRoot(token,label,elementIndex,hetero) ::= <<
|
||||||
|
_last = self.input.LT(1)
|
||||||
|
<super.tokenRef(...)>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<finishedBacktracking({
|
||||||
|
<if(hetero)>
|
||||||
|
<label>_tree = <hetero>(<label>)
|
||||||
|
<else>
|
||||||
|
<label>_tree = self._adaptor.dupNode(<label>)
|
||||||
|
<endif><\n>
|
||||||
|
root_<treeLevel> = self._adaptor.becomeRoot(<label>_tree, root_<treeLevel>)
|
||||||
|
})>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Match ^(label+=TOKEN ...) auto construct */
|
||||||
|
tokenRefRuleRootAndListLabel(token,label,elementIndex,hetero) ::= <<
|
||||||
|
<tokenRefRuleRoot(...)>
|
||||||
|
<listLabel(elem=label,...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// SET AST
|
||||||
|
matchSet(s,label,hetero,elementIndex,postmatchCode) ::= <<
|
||||||
|
_last = self.input.LT(1)
|
||||||
|
<super.matchSet(..., postmatchCode={
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<finishedBacktracking({
|
||||||
|
<if(hetero)>
|
||||||
|
<label>_tree = <hetero>(<label>)
|
||||||
|
<else>
|
||||||
|
<label>_tree = self._adaptor.dupNode(<label>)
|
||||||
|
<endif><\n>
|
||||||
|
self._adaptor.addChild(root_<treeLevel>, <label>_tree)
|
||||||
|
})>
|
||||||
|
<endif>
|
||||||
|
})>
|
||||||
|
>>
|
||||||
|
|
||||||
|
matchRuleBlockSet(s,label,hetero,elementIndex,postmatchCode,treeLevel="0") ::= <<
|
||||||
|
<matchSet(...)>
|
||||||
|
<noRewrite()> <! set return tree !>
|
||||||
|
>>
|
||||||
|
|
||||||
|
matchSetBang(s,label,elementIndex,postmatchCode) ::= <<
|
||||||
|
_last = self.input.LT(1)
|
||||||
|
<super.matchSet(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
matchSetRuleRoot(s,label,hetero,elementIndex,debug) ::= <<
|
||||||
|
<super.matchSet(..., postmatchCode={
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<finishedBacktracking({
|
||||||
|
<if(hetero)>
|
||||||
|
<label>_tree = <hetero>(<label>)
|
||||||
|
<else>
|
||||||
|
<label>_tree = self._adaptor.dupNode(<label>)
|
||||||
|
<endif><\n>
|
||||||
|
root_<treeLevel> = self._adaptor.becomeRoot(<label>_tree, root_<treeLevel>)
|
||||||
|
})>
|
||||||
|
<endif>
|
||||||
|
})>
|
||||||
|
>>
|
||||||
|
|
||||||
|
// RULE REF AST
|
||||||
|
|
||||||
|
/** rule auto construct */
|
||||||
|
ruleRef(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
_last = self.input.LT(1)
|
||||||
|
<super.ruleRef(...)>
|
||||||
|
<finishedBacktracking({
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
self._adaptor.addChild(root_<treeLevel>, <label>.tree)
|
||||||
|
<else> <! rewrite mode !>
|
||||||
|
if _first_<treeLevel> is None:
|
||||||
|
_first_<treeLevel> = <label>.tree<\n>
|
||||||
|
<endif>
|
||||||
|
})>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule auto construct */
|
||||||
|
ruleRefAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRef(...)>
|
||||||
|
<listLabel(elem=label+".tree",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(rule ...) auto construct */
|
||||||
|
ruleRefRuleRoot(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
_last = self.input.LT(1)
|
||||||
|
<super.ruleRef(...)>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<finishedBacktracking({
|
||||||
|
root_<treeLevel> = self._adaptor.becomeRoot(<label>.tree, root_<treeLevel>)
|
||||||
|
})>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(x+=rule ...) auto construct */
|
||||||
|
ruleRefRuleRootAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRefRuleRoot(...)>
|
||||||
|
<listLabel(elem=label+".tree",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** rule when output=AST and tracking for rewrite */
|
||||||
|
ruleRefTrack(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
_last = self.input.LT(1)
|
||||||
|
<super.ruleRefTrack(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule when output=AST and tracking for rewrite */
|
||||||
|
ruleRefTrackAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
_last = self.input.LT(1)
|
||||||
|
<super.ruleRefTrackAndListLabel(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(rule ...) rewrite */
|
||||||
|
ruleRefRuleRootTrack(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
_last = self.input.LT(1)
|
||||||
|
<super.ruleRefRootTrack(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** ^(x+=rule ...) rewrite */
|
||||||
|
ruleRefRuleRootTrackAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
_last = self.input.LT(1)
|
||||||
|
<super.ruleRefRuleRootTrackAndListLabel(...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Streams for token refs are tree nodes now; override to
|
||||||
|
* change nextToken to nextNode.
|
||||||
|
*/
|
||||||
|
createRewriteNodeFromElement(token,hetero,scope) ::= <<
|
||||||
|
<if(hetero)>
|
||||||
|
<hetero>(stream_<token>.nextNode())
|
||||||
|
<else>
|
||||||
|
stream_<token>.nextNode()
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
ruleCleanUp() ::= <<
|
||||||
|
<super.ruleCleanUp()>
|
||||||
|
<if(!rewriteMode)>
|
||||||
|
<finishedBacktracking({
|
||||||
|
retval.tree = self._adaptor.rulePostProcessing(root_0)
|
||||||
|
})>
|
||||||
|
<endif>
|
||||||
|
>>
|
1412
antlr_3_1_source/codegen/templates/Python/Python.stg
Normal file
1412
antlr_3_1_source/codegen/templates/Python/Python.stg
Normal file
File diff suppressed because it is too large
Load Diff
181
antlr_3_1_source/codegen/templates/Python/ST.stg
Normal file
181
antlr_3_1_source/codegen/templates/Python/ST.stg
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
/*
|
||||||
|
[The "BSD licence"]
|
||||||
|
Copyright (c) 2005-2006 Terence Parr
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
/** Template subgroup to add template rewrite output
|
||||||
|
* If debugging, then you'll also get STDbg.stg loaded.
|
||||||
|
*/
|
||||||
|
group ST;
|
||||||
|
|
||||||
|
@outputFile.imports() ::= <<
|
||||||
|
<@super.imports()>
|
||||||
|
import stringtemplate3
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Add this to each rule's return value struct */
|
||||||
|
@returnScope.ruleReturnInit() ::= <<
|
||||||
|
self.st = None
|
||||||
|
>>
|
||||||
|
|
||||||
|
@returnScope.ruleReturnMembers() ::= <<
|
||||||
|
def getTemplate(self):
|
||||||
|
return self.st
|
||||||
|
|
||||||
|
def toString(self):
|
||||||
|
if self.st is not None:
|
||||||
|
return self.st.toString()
|
||||||
|
return None
|
||||||
|
__str__ = toString
|
||||||
|
|
||||||
|
>>
|
||||||
|
|
||||||
|
@genericParser.init() ::= <<
|
||||||
|
<@super.init()>
|
||||||
|
self.templateLib = stringtemplate3.StringTemplateGroup(
|
||||||
|
'<name>Templates', lexer='angle-bracket'
|
||||||
|
)
|
||||||
|
|
||||||
|
>>
|
||||||
|
|
||||||
|
@genericParser.members() ::= <<
|
||||||
|
<@super.members()>
|
||||||
|
def setTemplateLib(self, templateLib):
|
||||||
|
self.templateLib = templateLib
|
||||||
|
|
||||||
|
def getTemplateLib(self):
|
||||||
|
return self.templateLib
|
||||||
|
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** x+=rule when output=template */
|
||||||
|
ruleRefAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
||||||
|
<ruleRef(...)>
|
||||||
|
<listLabel(elem=label+".st",...)>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteTemplate(alts) ::= <<
|
||||||
|
# TEMPLATE REWRITE
|
||||||
|
<if(backtracking)>
|
||||||
|
if self._state.backtracking == 0:
|
||||||
|
<first(alts):rewriteTemplateAltFirst()>
|
||||||
|
<rest(alts):{el<rewriteTemplateAlt()>}>
|
||||||
|
<if(rewriteMode)><replaceTextInLine()><endif>
|
||||||
|
|
||||||
|
<else>
|
||||||
|
<first(alts):rewriteTemplateAltFirst()>
|
||||||
|
<rest(alts):{el<rewriteTemplateAlt()>}>
|
||||||
|
<if(rewriteMode)><replaceTextInLine()><endif>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
replaceTextInLine() ::= <<
|
||||||
|
<if(TREE_PARSER)>
|
||||||
|
self.input.getTokenStream().replace(
|
||||||
|
self.input.getTreeAdaptor().getTokenStartIndex(retval.start),
|
||||||
|
self.input.getTreeAdaptor().getTokenStopIndex(retval.start),
|
||||||
|
retval.st
|
||||||
|
)
|
||||||
|
<else>
|
||||||
|
self.input.replace(
|
||||||
|
retval.start.getTokenIndex(),
|
||||||
|
self.input.LT(-1).getTokenIndex(),
|
||||||
|
retval.st
|
||||||
|
)
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteTemplateAltFirst() ::= <<
|
||||||
|
<if(it.pred)>
|
||||||
|
if <it.pred>:
|
||||||
|
# <it.description>
|
||||||
|
retval.st = <it.alt>
|
||||||
|
<\n>
|
||||||
|
<else>
|
||||||
|
# <it.description>
|
||||||
|
retval.st = <it.alt>
|
||||||
|
<\n>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteTemplateAlt() ::= <<
|
||||||
|
<if(it.pred)>
|
||||||
|
if <it.pred>:
|
||||||
|
# <it.description>
|
||||||
|
retval.st = <it.alt>
|
||||||
|
<\n>
|
||||||
|
<else>
|
||||||
|
se:
|
||||||
|
# <it.description>
|
||||||
|
retval.st = <it.alt>
|
||||||
|
<\n>
|
||||||
|
<endif>
|
||||||
|
>>
|
||||||
|
|
||||||
|
rewriteEmptyTemplate(alts) ::= <<
|
||||||
|
None
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Invoke a template with a set of attribute name/value pairs.
|
||||||
|
* Set the value of the rule's template *after* having set
|
||||||
|
* the attributes because the rule's template might be used as
|
||||||
|
* an attribute to build a bigger template; you get a self-embedded
|
||||||
|
* template.
|
||||||
|
*/
|
||||||
|
rewriteExternalTemplate(name,args) ::= <<
|
||||||
|
self.templateLib.getInstanceOf("<name>"<if(args)>,
|
||||||
|
attributes={<args:{a | "<a.name>": <a.value>}; separator=", ">}<endif>)
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** expr is a string expression that says what template to load */
|
||||||
|
rewriteIndirectTemplate(expr,args) ::= <<
|
||||||
|
self.templateLib.getInstanceOf(<expr><if(args)>,
|
||||||
|
attributes={<args:{a | "<a.name>": <a.value>}; separator=", ">}<endif>)
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Invoke an inline template with a set of attribute name/value pairs */
|
||||||
|
rewriteInlineTemplate(args, template) ::= <<
|
||||||
|
stringtemplate3.StringTemplate(
|
||||||
|
"<template>",
|
||||||
|
group=self.templateLib<if(args)>,
|
||||||
|
attributes={<args:{a | "<a.name>": <a.value>}; separator=", ">}
|
||||||
|
<endif>
|
||||||
|
)
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** plain -> {foo} action */
|
||||||
|
rewriteAction(action) ::= <<
|
||||||
|
<action>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** An action has %st.attrName=expr; or %{st}.attrName=expr; */
|
||||||
|
actionSetAttribute(st,attrName,expr) ::= <<
|
||||||
|
(<st>)["<attrName>"] = <expr>
|
||||||
|
>>
|
||||||
|
|
||||||
|
/** Translate %{stringExpr} */
|
||||||
|
actionStringConstructor(stringExpr) ::= <<
|
||||||
|
stringtemplate3.StringTemplate(<stringExpr>, group=self.templateLib)
|
||||||
|
>>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user