mirror of
https://github.com/esp8266/Arduino.git
synced 2025-06-20 21:01:25 +03:00
First integration of the Arduino code in Processing 5503: PreProcessor and Compiler have been integrated with changes to the Sketch.
Compilation still has problems (Thread error on success, and can't handle non-pde files in a sketch). Modified the Mac OS X make.sh to copy the hardware, avr tools, and example over. Removing some of the antlr stuff. Disabling the Commander (command-line execution) for now. Added Library, LibraryManager, and Target. Added support for prefixed preferences (e.g. for boards and programmers).
This commit is contained in:
@ -74,6 +74,7 @@ public class Base {
|
||||
static private File examplesFolder;
|
||||
static private File librariesFolder;
|
||||
static private File toolsFolder;
|
||||
static private File hardwareFolder;
|
||||
|
||||
// maps imported packages to their library folder
|
||||
static HashMap<String, File> importToLibraryTable;
|
||||
@ -186,7 +187,7 @@ public class Base {
|
||||
"p { font: 11pt \"Lucida Grande\"; margin-top: 8px }"+
|
||||
"</style> </head> <body>" +
|
||||
"<b>The standard menu bar has been disabled.</b>" +
|
||||
"<p>Due to an Apple bug, the Processing menu bar " +
|
||||
"<p>Due to an Apple bug, the Arduino menu bar " +
|
||||
"is unusable on Mac OS X 10.5. <br>" +
|
||||
"As a workaround, the menu bar will be placed inside " +
|
||||
"the editor window. This <br>setting can be changed in the " +
|
||||
@ -224,7 +225,7 @@ public class Base {
|
||||
platform.setLookAndFeel();
|
||||
} catch (Exception e) {
|
||||
System.err.println("Non-fatal error while setting the Look & Feel.");
|
||||
System.err.println("The error message follows, however Processing should run fine.");
|
||||
System.err.println("The error message follows, however Arduino should run fine.");
|
||||
System.err.println(e.getMessage());
|
||||
//e.printStackTrace();
|
||||
}
|
||||
@ -272,7 +273,7 @@ public class Base {
|
||||
} catch (ClassNotFoundException cnfe) {
|
||||
Base.showPlatforms();
|
||||
Base.showError("Please install JDK 1.5 or later",
|
||||
"Processing requires a full JDK (not just a JRE)\n" +
|
||||
"Arduino requires a full JDK (not just a JRE)\n" +
|
||||
"to run. Please install JDK 1.5 or later.\n" +
|
||||
"More information can be found in the reference.", cnfe);
|
||||
}
|
||||
@ -298,9 +299,9 @@ public class Base {
|
||||
if (!skechbookFolder.exists()) {
|
||||
Base.showWarning("Sketchbook folder disappeared",
|
||||
"The sketchbook folder no longer exists.\n" +
|
||||
"Processing will switch to the default sketchbook\n" +
|
||||
"Arduino will switch to the default sketchbook\n" +
|
||||
"location, and create a new sketchbook folder if\n" +
|
||||
"necessary. Procesing will then stop talking about\n" +
|
||||
"necessary. Arduino will then stop talking about\n" +
|
||||
"himself in the third person.", null);
|
||||
sketchbookPath = null;
|
||||
}
|
||||
@ -668,7 +669,7 @@ public class Base {
|
||||
public void handleOpenPrompt() {
|
||||
// get the frontmost window frame for placing file dialog
|
||||
FileDialog fd = new FileDialog(activeEditor,
|
||||
"Open a Processing sketch...",
|
||||
"Open an Arduino sketch...",
|
||||
FileDialog.LOAD);
|
||||
// This was annoying people, so disabled it in 0125.
|
||||
//fd.setDirectory(Preferences.get("sketchbook.path"));
|
||||
@ -792,7 +793,7 @@ public class Base {
|
||||
"p { font: 11pt \"Lucida Grande\"; margin-top: 8px }"+
|
||||
"</style> </head>" +
|
||||
"<b>Are you sure you want to Quit?</b>" +
|
||||
"<p>Closing the last open sketch will quit Processing.";
|
||||
"<p>Closing the last open sketch will quit Arduino.";
|
||||
|
||||
int result = JOptionPane.showOptionDialog(editor,
|
||||
prompt,
|
||||
@ -1022,7 +1023,7 @@ public class Base {
|
||||
} else {
|
||||
showWarning("Sketch Does Not Exist",
|
||||
"The selected sketch no longer exists.\n" +
|
||||
"You may need to restart Processing to update\n" +
|
||||
"You may need to restart Arduino to update\n" +
|
||||
"the sketchbook menu.", null);
|
||||
}
|
||||
}
|
||||
@ -1310,7 +1311,7 @@ public class Base {
|
||||
settingsFolder = platform.getSettingsFolder();
|
||||
} catch (Exception e) {
|
||||
showError("Problem getting data folder",
|
||||
"Error getting the Processing data folder.", e);
|
||||
"Error getting the Arduino data folder.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1318,7 +1319,7 @@ public class Base {
|
||||
if (!settingsFolder.exists()) {
|
||||
if (!settingsFolder.mkdirs()) {
|
||||
showError("Settings issues",
|
||||
"Processing cannot run because it could not\n" +
|
||||
"Arduino cannot run because it could not\n" +
|
||||
"create a folder to store your settings.", null);
|
||||
}
|
||||
}
|
||||
@ -1396,7 +1397,30 @@ public class Base {
|
||||
static public String getToolsPath() {
|
||||
return toolsFolder.getAbsolutePath();
|
||||
}
|
||||
|
||||
|
||||
|
||||
static public File getHardwareFolder() {
|
||||
// calculate on the fly because it's needed by Preferences.init() to find
|
||||
// the boards.txt and programmers.txt preferences files (which happens
|
||||
// before the other folders / paths get cached).
|
||||
return getContentFile("hardware");
|
||||
}
|
||||
|
||||
|
||||
static public String getHardwarePath() {
|
||||
return getHardwareFolder().getAbsolutePath();
|
||||
}
|
||||
|
||||
|
||||
static public String getAvrBasePath() {
|
||||
if(Base.isLinux()) {
|
||||
return ""; // avr tools are installed system-wide and in the path
|
||||
} else {
|
||||
return getHardwarePath() + File.separator + "tools" +
|
||||
File.separator + "avr" + File.separator + "bin" + File.separator;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static public File getSketchbookFolder() {
|
||||
return new File(Preferences.get("sketchbook.path"));
|
||||
@ -1426,7 +1450,7 @@ public class Base {
|
||||
|
||||
if (!result) {
|
||||
showError("You forgot your sketchbook",
|
||||
"Processing cannot run because it could not\n" +
|
||||
"Arduino cannot run because it could not\n" +
|
||||
"create a folder to store your sketchbook.", null);
|
||||
}
|
||||
|
||||
|
@ -1561,7 +1561,10 @@ public class Editor extends JFrame implements RunnerListener {
|
||||
presenting = present;
|
||||
|
||||
try {
|
||||
String appletClassName = sketch.compile();
|
||||
// XXX: DAM: don't hardcode this to "arduino"
|
||||
String appletClassName = sketch.compile(
|
||||
new Target(Base.getHardwarePath() + File.separator + "cores",
|
||||
"arduino"));
|
||||
if (appletClassName != null) {
|
||||
runtime = new Runner(sketch, appletClassName, presenting, Editor.this);
|
||||
|
||||
|
@ -71,7 +71,7 @@ public class Platform {
|
||||
public File getSettingsFolder() throws Exception {
|
||||
// otherwise make a .processing directory int the user's home dir
|
||||
File home = new File(System.getProperty("user.home"));
|
||||
File dataFolder = new File(home, ".processing");
|
||||
File dataFolder = new File(home, ".arduino");
|
||||
return dataFolder;
|
||||
|
||||
/*
|
||||
|
@ -146,6 +146,7 @@ public class Preferences {
|
||||
|
||||
static Hashtable defaults;
|
||||
static Hashtable table = new Hashtable();;
|
||||
static Hashtable prefixes = new Hashtable();
|
||||
static File preferencesFile;
|
||||
|
||||
|
||||
@ -221,6 +222,25 @@ public class Preferences {
|
||||
// "You'll need to reinstall Processing.", te);
|
||||
// }
|
||||
}
|
||||
|
||||
try {
|
||||
load(new FileInputStream(new File(Base.getHardwareFolder(), "boards.txt")),
|
||||
"boards");
|
||||
} catch (Exception ex) {
|
||||
Base.showError("Error reading board definitions",
|
||||
"Error reading the board definitions file (" +
|
||||
new File(Base.getHardwareFolder(), "boards.txt").getAbsolutePath() + "). " +
|
||||
"Please re-download or re-unzip Arduino.\n", ex);
|
||||
}
|
||||
|
||||
try {
|
||||
load(new FileInputStream(new File(Base.getHardwareFolder(), "programmers.txt")),
|
||||
"programmers");
|
||||
} catch (Exception ex) {
|
||||
Base.showError("Error reading programmers definitions",
|
||||
"Error reading the programmers definitions file. " +
|
||||
"Please re-download or re-unzip Arduino.\n", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -701,6 +721,16 @@ public class Preferences {
|
||||
|
||||
|
||||
static protected void load(InputStream input) throws IOException {
|
||||
load(input, table);
|
||||
}
|
||||
|
||||
static protected void load(InputStream input, String prefix) throws IOException {
|
||||
Map table = new LinkedHashMap();
|
||||
prefixes.put(prefix, table);
|
||||
load(input, table);
|
||||
}
|
||||
|
||||
static protected void load(InputStream input, Map table) throws IOException {
|
||||
String[] lines = PApplet.loadStrings(input); // Reads as UTF-8
|
||||
for (String line : lines) {
|
||||
if ((line.length() == 0) ||
|
||||
@ -755,6 +785,18 @@ public class Preferences {
|
||||
//}
|
||||
|
||||
static public String get(String attribute /*, String defaultValue */) {
|
||||
// if the attribute starts with a prefix used by one of our subsidiary
|
||||
// preference files, look up the attribute in that file's Hashtable
|
||||
// (don't override with or fallback to the main file). otherwise,
|
||||
// look up the attribute in the main file's Hashtable.
|
||||
Map table = Preferences.table;
|
||||
if (attribute.indexOf('.') != -1) {
|
||||
String prefix = attribute.substring(0, attribute.indexOf('.'));
|
||||
if (prefixes.containsKey(prefix)) {
|
||||
table = (Map) prefixes.get(prefix);
|
||||
attribute = attribute.substring(attribute.indexOf('.') + 1);
|
||||
}
|
||||
}
|
||||
return (String) table.get(attribute);
|
||||
/*
|
||||
//String value = (properties != null) ?
|
||||
@ -767,6 +809,28 @@ public class Preferences {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the top-level key prefixes defined in the subsidiary file loaded with
|
||||
* the given prefix. For example, if the file contains:
|
||||
* foo.count=1
|
||||
* bar.count=2
|
||||
* baz.count=3
|
||||
* this will return { "foo", "bar", "baz" }.
|
||||
*/
|
||||
static public Iterator getSubKeys(String prefix) {
|
||||
if (!prefixes.containsKey(prefix))
|
||||
return null;
|
||||
Set subkeys = new LinkedHashSet();
|
||||
for (Iterator i = ((Map) prefixes.get(prefix)).keySet().iterator(); i.hasNext(); ) {
|
||||
String subkey = (String) i.next();
|
||||
if (subkey.indexOf('.') != -1)
|
||||
subkey = subkey.substring(0, subkey.indexOf('.'));
|
||||
subkeys.add(subkey);
|
||||
}
|
||||
return subkeys.iterator();
|
||||
}
|
||||
|
||||
|
||||
static public String getDefault(String attribute) {
|
||||
return (String) defaults.get(attribute);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
595
app/src/processing/app/debug/Library.java
Executable file
595
app/src/processing/app/debug/Library.java
Executable file
@ -0,0 +1,595 @@
|
||||
/*
|
||||
Library.java - Library System for Wiring
|
||||
Copyright (c) 2006 Nicholas Zambetti. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package processing.app.debug;
|
||||
|
||||
import processing.app.Base;
|
||||
import processing.app.Preferences;
|
||||
import processing.app.syntax.*;
|
||||
import processing.app.debug.RunnerException;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.*;
|
||||
|
||||
import processing.core.*;
|
||||
|
||||
/*
|
||||
* Provides information about and builds a library
|
||||
*/
|
||||
public class Library implements MessageConsumer{
|
||||
|
||||
private File libFolder;
|
||||
private File utilityFolder;
|
||||
private LibraryManager libManager;
|
||||
RunnerException exception;
|
||||
|
||||
static final String BUGS_URL = "https://developer.berlios.de/bugs/?group_id=3590";
|
||||
static final String SUPER_BADNESS = "Compiler error, please submit this code to " + BUGS_URL;
|
||||
|
||||
/*
|
||||
* Create a Library
|
||||
*/
|
||||
public Library(LibraryManager manager, File folder)
|
||||
{
|
||||
libFolder = folder;
|
||||
libManager = manager;
|
||||
utilityFolder = getUtilityFolder();
|
||||
|
||||
// for debug output
|
||||
/*
|
||||
System.out.println("library: " + getName());
|
||||
System.out.println("folder: " + getFolder());
|
||||
System.out.println("utility: " + utilityFolder);
|
||||
System.out.println("built: " + isBuilt());
|
||||
System.out.println("buildable: " + isBuildable());
|
||||
System.out.println("o files: " + getObjectFiles().length);
|
||||
System.out.println("c files: " + getCSourceFiles().length);
|
||||
System.out.println("cpp files: " + getCPPSourceFiles().length);
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* Directory of library
|
||||
* @return File object of library's folder
|
||||
*/
|
||||
public File getFolder()
|
||||
{
|
||||
return libFolder;
|
||||
}
|
||||
|
||||
/*
|
||||
* The name of library
|
||||
* @return String with library name, derived from folder
|
||||
* note: this will be eventually taken from xml description file
|
||||
*/
|
||||
public String getName()
|
||||
{
|
||||
return libFolder.getName();
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests if library is built
|
||||
* @return True if library has .o files, false otherwise
|
||||
*/
|
||||
public boolean isBuilt()
|
||||
{
|
||||
if(getObjectFiles().length >= (getCSourceFiles().length + getCPPSourceFiles().length)){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests if library is buildable
|
||||
* @return True if library has source files, false otherwise
|
||||
*/
|
||||
public boolean isBuildable()
|
||||
{
|
||||
if(0 < (getCSourceFiles().length + getCPPSourceFiles().length)){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests if library is unbuilt but buildable
|
||||
* @return True if library has .cpp files but no .o files, false otherwise
|
||||
*/
|
||||
public boolean isUnbuiltBuildable()
|
||||
{
|
||||
if(isBuildable()){
|
||||
if(!isBuilt()){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Scans for library "utility" folder
|
||||
* @return File object of library's "utility" folder, or null
|
||||
*/
|
||||
private File getUtilityFolder()
|
||||
{
|
||||
FileFilter filter = new FileFilter() {
|
||||
public boolean accept(File file) {
|
||||
if(file.isDirectory()){
|
||||
if((file.getName()).equalsIgnoreCase("utility")){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
File[] files = libFolder.listFiles(filter);
|
||||
if(files.length > 0){
|
||||
return files[0];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* Finds examples folder
|
||||
* @return "examples" folder as file object or null
|
||||
*/
|
||||
private File getExamplesFolder()
|
||||
{
|
||||
FileFilter filter = new FileFilter() {
|
||||
public boolean accept(File file) {
|
||||
if(file.isDirectory()){
|
||||
if((file.getName()).equalsIgnoreCase("examples")){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
File[] files = libFolder.listFiles(filter);
|
||||
if(files.length > 0){
|
||||
return files[0];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* Populates example menu or submenu with files
|
||||
*/
|
||||
private void populateWithExamples(File folder, JMenu menu, ActionListener listener) {
|
||||
FileFilter onlyfolders = new FileFilter() {
|
||||
public boolean accept(File file) {
|
||||
return file.isDirectory();
|
||||
}
|
||||
};
|
||||
File[] folders = folder.listFiles(onlyfolders);
|
||||
File file;
|
||||
JMenu submenu;
|
||||
JMenuItem item;
|
||||
for(int i = 0; i < folders.length; ++i){
|
||||
file = new File(folders[i], folders[i].getName() + ".pde");
|
||||
if(file.exists()){
|
||||
item = new JMenuItem(folders[i].getName());
|
||||
item.setActionCommand(file.getAbsolutePath());
|
||||
item.addActionListener(listener);
|
||||
menu.add(item);
|
||||
}else{
|
||||
submenu = new JMenu(folders[i].getName());
|
||||
populateWithExamples(folders[i], submenu, listener);
|
||||
menu.add(submenu);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Builds and returns an examples menu
|
||||
* @return JMenu object with example files, or null if none
|
||||
*/
|
||||
public JMenu getExamplesMenu(ActionListener listener) {
|
||||
JMenu submenu;
|
||||
File examplesFolder = getExamplesFolder();
|
||||
if(null != examplesFolder){
|
||||
submenu = new JMenu("Library-" + getName());
|
||||
populateWithExamples(examplesFolder, submenu, listener);
|
||||
return submenu;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* List of object files for linking
|
||||
* @return Array of object files as File objects
|
||||
*/
|
||||
private File[] getObjectFiles(File folder)
|
||||
{
|
||||
FileFilter onlyObjectFiles = new FileFilter() {
|
||||
public boolean accept(File file) {
|
||||
return (file.getName()).endsWith(".o");
|
||||
}
|
||||
};
|
||||
return folder.listFiles(onlyObjectFiles);
|
||||
}
|
||||
public File[] getObjectFiles()
|
||||
{
|
||||
if(null == utilityFolder){
|
||||
return getObjectFiles(libFolder);
|
||||
}
|
||||
File[] libraryObjects = getObjectFiles(libFolder);
|
||||
File[] utilityObjects = getObjectFiles(utilityFolder);
|
||||
File[] objects = new File[libraryObjects.length + utilityObjects.length];
|
||||
System.arraycopy(libraryObjects, 0, objects, 0, libraryObjects.length);
|
||||
System.arraycopy(utilityObjects, 0, objects, libraryObjects.length, utilityObjects.length);
|
||||
return objects;
|
||||
}
|
||||
|
||||
/*
|
||||
* List of header source files for inclusion
|
||||
* @return Array of header source files as File objects
|
||||
*/
|
||||
public File[] getHeaderFiles()
|
||||
{
|
||||
FileFilter onlyHFiles = new FileFilter() {
|
||||
public boolean accept(File file) {
|
||||
return (file.getName()).endsWith(".h");
|
||||
}
|
||||
};
|
||||
return libFolder.listFiles(onlyHFiles);
|
||||
}
|
||||
|
||||
/*
|
||||
* List of library's C source files for compiling
|
||||
* @return Array of C source files as File objects
|
||||
*/
|
||||
private File[] getCSourceFiles(File folder)
|
||||
{
|
||||
FileFilter onlyCFiles = new FileFilter() {
|
||||
public boolean accept(File file) {
|
||||
return (file.getName()).endsWith(".c");
|
||||
}
|
||||
};
|
||||
return folder.listFiles(onlyCFiles);
|
||||
}
|
||||
private File[] getCSourceFiles()
|
||||
{
|
||||
if(null == utilityFolder){
|
||||
return getCSourceFiles(libFolder);
|
||||
}
|
||||
File[] librarySources = getCSourceFiles(libFolder);
|
||||
File[] utilitySources = getCSourceFiles(utilityFolder);
|
||||
File[] sources = new File[librarySources.length + utilitySources.length];
|
||||
System.arraycopy(librarySources, 0, sources, 0, librarySources.length);
|
||||
System.arraycopy(utilitySources, 0, sources, librarySources.length, utilitySources.length);
|
||||
return sources;
|
||||
}
|
||||
|
||||
/*
|
||||
* List of C++ source files for compiling
|
||||
* @return Array of C++ source files as File objects
|
||||
*/
|
||||
private File[] getCPPSourceFiles(File folder)
|
||||
{
|
||||
FileFilter onlyCPPFiles = new FileFilter() {
|
||||
public boolean accept(File file) {
|
||||
return (file.getName()).endsWith(".cpp");
|
||||
}
|
||||
};
|
||||
return folder.listFiles(onlyCPPFiles);
|
||||
}
|
||||
private File[] getCPPSourceFiles()
|
||||
{
|
||||
if(null == utilityFolder){
|
||||
return getCPPSourceFiles(libFolder);
|
||||
}
|
||||
File[] librarySources = getCPPSourceFiles(libFolder);
|
||||
File[] utilitySources = getCPPSourceFiles(utilityFolder);
|
||||
File[] sources = new File[librarySources.length + utilitySources.length];
|
||||
System.arraycopy(librarySources, 0, sources, 0, librarySources.length);
|
||||
System.arraycopy(utilitySources, 0, sources, librarySources.length, utilitySources.length);
|
||||
return sources;
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to build library
|
||||
* @return true on successful build, false otherwise
|
||||
*/
|
||||
public boolean build() throws RunnerException
|
||||
{
|
||||
// fail if library is not buildable (contains no sources)
|
||||
if(!isBuildable()){
|
||||
return false;
|
||||
}
|
||||
|
||||
String userdir = System.getProperty("user.dir") + File.separator;
|
||||
String avrBasePath;
|
||||
if(Base.isMacOS()) {
|
||||
avrBasePath = new String("hardware/tools/avr/bin/");
|
||||
}
|
||||
else if(Base.isLinux()) {
|
||||
avrBasePath = new String("");
|
||||
}
|
||||
else {
|
||||
avrBasePath = new String(userdir + "hardware/tools/avr/bin/");
|
||||
}
|
||||
|
||||
String[] baseCompileCommandC = new String[] {
|
||||
avrBasePath + "avr-gcc",
|
||||
"-c",
|
||||
"-g",
|
||||
"-Os",
|
||||
"-Wall",
|
||||
"-ffunction-sections", // place each function in its own section
|
||||
"-fdata-sections",
|
||||
"-mmcu=" + Preferences.get("boards." + Preferences.get("board") + ".build.mcu"),
|
||||
"-DF_CPU=" + Preferences.get("boards." + Preferences.get("board") + ".build.f_cpu"),
|
||||
"-I" + libManager.getTarget().getPath(),
|
||||
"-I" + getFolder(),
|
||||
};
|
||||
|
||||
String[] baseCompileCommandCPP = new String[] {
|
||||
avrBasePath + "avr-g++",
|
||||
"-c",
|
||||
"-g",
|
||||
"-Os",
|
||||
"-Wall",
|
||||
"-fno-exceptions",
|
||||
"-ffunction-sections", // place each function in its own section
|
||||
"-fdata-sections",
|
||||
"-mmcu=" + Preferences.get("boards." + Preferences.get("board") + ".build.mcu"),
|
||||
"-DF_CPU=" + Preferences.get("boards." + Preferences.get("board") + ".build.f_cpu"),
|
||||
"-I" + libManager.getTarget().getPath(),
|
||||
"-I" + getFolder(),
|
||||
};
|
||||
|
||||
// use built lib directories in include paths when searching for headers
|
||||
// this allows libs to use other libs easily
|
||||
int extraSpots = 2; // two spots for file path and -o portions
|
||||
utilityFolder = getUtilityFolder(); // refresh status of utility folder
|
||||
if(null != utilityFolder){
|
||||
extraSpots = 3; // an extra spot for utility folder as include
|
||||
}
|
||||
String[] libDirs = libManager.getFolderPaths();
|
||||
String[] compileCommandC = new String[baseCompileCommandC.length + libDirs.length + extraSpots];
|
||||
String[] compileCommandCPP = new String[baseCompileCommandCPP.length + libDirs.length + extraSpots];
|
||||
System.arraycopy(baseCompileCommandC, 0, compileCommandC, 0, baseCompileCommandC.length);
|
||||
System.arraycopy(baseCompileCommandCPP, 0, compileCommandCPP, 0, baseCompileCommandCPP.length);
|
||||
for (int i = 0; i < libDirs.length; ++i) {
|
||||
compileCommandC[baseCompileCommandC.length + i] = "-I" + libDirs[i];
|
||||
compileCommandCPP[baseCompileCommandCPP.length + i] = "-I" + libDirs[i];
|
||||
}
|
||||
|
||||
// add this library's "utility" folder to inclusion paths
|
||||
if(null != utilityFolder){
|
||||
compileCommandC[compileCommandC.length - 3] = "-I" + utilityFolder.getPath();
|
||||
compileCommandCPP[compileCommandCPP.length - 3] = "-I" + utilityFolder.getPath();
|
||||
}
|
||||
|
||||
File[] sourcesC = getCSourceFiles();
|
||||
File[] sourcesCPP = getCPPSourceFiles();
|
||||
|
||||
// execute the compiler, and create threads to deal
|
||||
// with the input and error streams
|
||||
//
|
||||
int result = 0;
|
||||
try {
|
||||
String pathSansExtension;
|
||||
Process process;
|
||||
boolean compiling = true;
|
||||
|
||||
// compile c sources
|
||||
for(int i = 0; i < sourcesC.length; ++i) {
|
||||
pathSansExtension = sourcesC[i].getPath();
|
||||
pathSansExtension = pathSansExtension.substring(0, pathSansExtension.length() - 2); // -2 because ".c"
|
||||
|
||||
compileCommandC[compileCommandC.length - 2] = sourcesC[i].getPath();
|
||||
compileCommandC[compileCommandC.length - 1] = "-o" + pathSansExtension + ".o";
|
||||
|
||||
process = Runtime.getRuntime().exec(compileCommandC);
|
||||
new MessageSiphon(process.getInputStream(), this);
|
||||
new MessageSiphon(process.getErrorStream(), this);
|
||||
|
||||
// wait for the process to finish. if interrupted
|
||||
// before waitFor returns, continue waiting
|
||||
//
|
||||
compiling = true;
|
||||
while (compiling) {
|
||||
try {
|
||||
result = process.waitFor();
|
||||
//System.out.println("result is " + result);
|
||||
compiling = false;
|
||||
} catch (InterruptedException ignored) { }
|
||||
}
|
||||
if (exception != null) {
|
||||
//exception.hideStackTrace = true;
|
||||
throw exception;
|
||||
}
|
||||
if(result != 0){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// compile c++ sources
|
||||
for(int i = 0; i < sourcesCPP.length; ++i) {
|
||||
pathSansExtension = sourcesCPP[i].getPath();
|
||||
pathSansExtension = pathSansExtension.substring(0, pathSansExtension.length() - 4); // -4 because ".cpp"
|
||||
|
||||
compileCommandCPP[compileCommandCPP.length - 2] = sourcesCPP[i].getPath();
|
||||
compileCommandCPP[compileCommandCPP.length - 1] = "-o" + pathSansExtension + ".o";
|
||||
|
||||
process = Runtime.getRuntime().exec(compileCommandCPP);
|
||||
new MessageSiphon(process.getInputStream(), this);
|
||||
new MessageSiphon(process.getErrorStream(), this);
|
||||
|
||||
// wait for the process to finish. if interrupted
|
||||
// before waitFor returns, continue waiting
|
||||
//
|
||||
compiling = true;
|
||||
while (compiling) {
|
||||
try {
|
||||
result = process.waitFor();
|
||||
//System.out.println("result is " + result);
|
||||
compiling = false;
|
||||
} catch (InterruptedException ignored) { }
|
||||
}
|
||||
if (exception != null) {
|
||||
//exception.hideStackTrace = true;
|
||||
throw exception;
|
||||
}
|
||||
if(result != 0){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
String msg = e.getMessage();
|
||||
if ((msg != null) && (msg.indexOf("avr-gcc: not found") != -1)) {
|
||||
Base.showWarning("Compiler error",
|
||||
"Could not find the compiler.\n" +
|
||||
"avr-gcc is missing from your PATH,\n" +
|
||||
"see readme.txt for help.", null);
|
||||
return false;
|
||||
|
||||
} else if ((msg != null) && (msg.indexOf("avr-g++: not found") != -1)) {
|
||||
Base.showWarning("Compiler error",
|
||||
"Could not find the compiler.\n" +
|
||||
"avr-g++ is missing from your PATH,\n" +
|
||||
"see readme.txt for help.", null);
|
||||
return false;
|
||||
|
||||
} else {
|
||||
e.printStackTrace();
|
||||
result = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// an error was queued up by message()
|
||||
if (exception != null) {
|
||||
throw exception;
|
||||
}
|
||||
|
||||
if (result != 0 && result != 1 ) {
|
||||
Base.openURL(BUGS_URL);
|
||||
throw new RunnerException(SUPER_BADNESS);
|
||||
}
|
||||
|
||||
// success would mean that 'result' is set to zero
|
||||
return (result == 0); // ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Part of the MessageConsumer interface, this is called
|
||||
* whenever a piece (usually a line) of error message is spewed
|
||||
* out from the compiler. The errors are parsed for their contents
|
||||
* and line number, which is then reported back to Editor.
|
||||
*/
|
||||
public void message(String inString) {
|
||||
// This receives messages as full lines, so a newline needs
|
||||
// to be added as they're printed to the console.
|
||||
|
||||
// always print all compilation output for library writers!
|
||||
String outString = "";
|
||||
|
||||
// shorten file paths so that they are friendlier
|
||||
int start = 0;
|
||||
int end = 0;
|
||||
String substring = libFolder.getPath() + File.separator;
|
||||
StringBuffer result = new StringBuffer();
|
||||
while ((end = inString.indexOf(substring, start)) >= 0) {
|
||||
result.append(inString.substring(start, end));
|
||||
start = end + substring.length();
|
||||
}
|
||||
result.append(inString.substring(start));
|
||||
outString = result.toString();
|
||||
|
||||
System.err.print(outString);
|
||||
|
||||
// prepare error for throwing
|
||||
if (inString.indexOf("error") != -1){
|
||||
exception = new RunnerException("Error building library \"" + getName() + "\"");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles loading of keywords file.
|
||||
* It is recommended that a # sign be used for comments
|
||||
* inside keywords.txt.
|
||||
*/
|
||||
public void addSyntaxColors(PdeKeywords keywords) {
|
||||
File keywordsFile = new File(libFolder.getPath() + File.separator + "keywords.txt");
|
||||
|
||||
// do not bother if no keywords file to read
|
||||
// should reprimand negligent library writers?!
|
||||
if(!keywordsFile.exists() || !keywordsFile.canRead()){
|
||||
return;
|
||||
}
|
||||
|
||||
try{
|
||||
// open file stream in the verbose java way
|
||||
InputStream input = new FileInputStream(keywordsFile);
|
||||
InputStreamReader isr = new InputStreamReader(input);
|
||||
BufferedReader reader = new BufferedReader(isr);
|
||||
|
||||
String line = null;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
|
||||
// skip empty and whitespace lines
|
||||
if (line.trim().length() == 0){
|
||||
continue;
|
||||
}
|
||||
|
||||
// skip lines without tabs
|
||||
if (line.indexOf('\t') == -1){
|
||||
continue;
|
||||
}
|
||||
|
||||
String pieces[] = PApplet.split(line, '\t');
|
||||
|
||||
if (pieces.length >= 2) {
|
||||
String keyword = pieces[0].trim();
|
||||
String coloring = pieces[1].trim();
|
||||
|
||||
if (coloring.length() > 0) {
|
||||
// text will be KEYWORD or LITERAL
|
||||
boolean isKey = (coloring.charAt(0) == 'K');
|
||||
|
||||
// KEYWORD1 -> 0, KEYWORD2 -> 1, etc
|
||||
int num = coloring.charAt(coloring.length() - 1) - '1';
|
||||
|
||||
byte id = (byte)((isKey ? Token.KEYWORD1 : Token.LITERAL1) + num);
|
||||
|
||||
//System.out.println("got " + (isKey ? "keyword" : "literal") + (num+1) + " for " + keyword);
|
||||
|
||||
// XXX: DAM: PdeKeywords.getKeywordColoring().add(keyword, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// close file stream
|
||||
reader.close();
|
||||
} catch (Exception e) {
|
||||
Base.showError("Problem Loading Keywords",
|
||||
"Could not load or interpret 'keywords.txt' in " + getName() + " library.\n" +
|
||||
"This must be corrected before distributing.", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
274
app/src/processing/app/debug/LibraryManager.java
Executable file
274
app/src/processing/app/debug/LibraryManager.java
Executable file
@ -0,0 +1,274 @@
|
||||
/*
|
||||
LibraryManager.java - Library System for Wiring
|
||||
Copyright (c) 2006-07 Nicholas Zambetti. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package processing.app.debug;
|
||||
|
||||
import processing.app.Base;
|
||||
import processing.app.Preferences;
|
||||
import processing.app.syntax.*;
|
||||
import processing.app.debug.RunnerException;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
import java.awt.event.*;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
/*
|
||||
* Provides information about and builds libraries
|
||||
*/
|
||||
public class LibraryManager {
|
||||
|
||||
private File libDir;
|
||||
private List libraries = new ArrayList();
|
||||
private Target target;
|
||||
|
||||
/*
|
||||
* Create a LibraryManager.
|
||||
*/
|
||||
public LibraryManager() throws IOException
|
||||
{
|
||||
String userDir = System.getProperty("user.dir") + File.separator;
|
||||
libDir = new File(Base.getHardwareFolder(), "libraries");
|
||||
// target = new Target(
|
||||
// System.getProperty("user.dir") + File.separator + "hardware" +
|
||||
// File.separator + "cores",
|
||||
// Preferences.get("boards." + Preferences.get("board") + ".build.core"));
|
||||
target = new Target(Base.getHardwarePath() + File.separator + "cores",
|
||||
"arduino");
|
||||
refreshLibraries();
|
||||
}
|
||||
|
||||
public Target getTarget()
|
||||
{
|
||||
return target;
|
||||
}
|
||||
|
||||
/*
|
||||
* Scans for libraries and refreshes internal list
|
||||
*/
|
||||
private void refreshLibraries()
|
||||
{
|
||||
FileFilter onlyDirs = new FileFilter() {
|
||||
public boolean accept(File file) {
|
||||
return file.isDirectory();
|
||||
}
|
||||
};
|
||||
libraries.clear();
|
||||
File[] libs = libDir.listFiles(onlyDirs);
|
||||
for(int i = 0; i < libs.length; ++i){
|
||||
libraries.add(new Library(this, libs[i]));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a collection of all library objects
|
||||
* @return A read-only collection of Library objects
|
||||
*/
|
||||
public Collection getAll() {
|
||||
refreshLibraries();
|
||||
return Collections.unmodifiableList(libraries);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a collection of all built library objects
|
||||
* @return A read-only collection of built Library objects
|
||||
*/
|
||||
public Collection getBuiltLibraries() {
|
||||
refreshLibraries();
|
||||
List builtLibraries = new ArrayList();
|
||||
Library library;
|
||||
ListIterator libIterator = libraries.listIterator();
|
||||
while(libIterator.hasNext()){
|
||||
library = (Library)libIterator.next();
|
||||
if(library.isBuilt()){
|
||||
builtLibraries.add(library);
|
||||
}
|
||||
}
|
||||
return Collections.unmodifiableList(builtLibraries);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a collection of all buildable library objects
|
||||
* @return A read-only collection of built Library objects
|
||||
*/
|
||||
public Collection getLibrariesToBuild() {
|
||||
refreshLibraries();
|
||||
List buildableLibraries = new ArrayList();
|
||||
Library library;
|
||||
ListIterator libIterator = libraries.listIterator();
|
||||
while(libIterator.hasNext()){
|
||||
library = (Library)libIterator.next();
|
||||
if(library.isUnbuiltBuildable()){
|
||||
buildableLibraries.add(library);
|
||||
}
|
||||
}
|
||||
return Collections.unmodifiableList(buildableLibraries);
|
||||
}
|
||||
|
||||
/*
|
||||
* Rebuilds built libraries
|
||||
* @return Number of libraries built as int, -1 & exception on error
|
||||
*/
|
||||
public int rebuildAllBuilt() throws RunnerException {
|
||||
Collection builtLibraries = getBuiltLibraries();
|
||||
Library library;
|
||||
Iterator libIterator = builtLibraries.iterator();
|
||||
int countBuilt = 0;
|
||||
while(libIterator.hasNext()){
|
||||
library = (Library)libIterator.next();
|
||||
//System.out.println("Building library \"" + library.getName() + "\"");
|
||||
try {
|
||||
if(library.build()){
|
||||
++countBuilt;
|
||||
}else{
|
||||
return -1;
|
||||
}
|
||||
}catch (RunnerException re) {
|
||||
throw new RunnerException(re.getMessage());
|
||||
} catch (Exception ex) {
|
||||
throw new RunnerException(ex.toString());
|
||||
}
|
||||
}
|
||||
return countBuilt;
|
||||
}
|
||||
|
||||
/*
|
||||
* Gathers paths to object files
|
||||
* @return Array of strings of paths to object files
|
||||
*/
|
||||
public String[] getObjectFiles() {
|
||||
ArrayList filesArrayList = new ArrayList();
|
||||
Collection builtLibraries = getBuiltLibraries();
|
||||
Library library;
|
||||
File[] files;
|
||||
Iterator libIterator = builtLibraries.iterator();
|
||||
while(libIterator.hasNext()){
|
||||
library = (Library)libIterator.next();
|
||||
files = library.getObjectFiles();
|
||||
for(int i = 0; i < files.length; ++i){
|
||||
filesArrayList.add(files[i].getPath());
|
||||
}
|
||||
}
|
||||
String[] filesArray = new String[filesArrayList.size()];
|
||||
filesArrayList.toArray(filesArray);
|
||||
return filesArray;
|
||||
}
|
||||
|
||||
/*
|
||||
* Gathers filenames of header files
|
||||
* @return Array of strings of filenames of header files
|
||||
*/
|
||||
public String[] getHeaderFiles() {
|
||||
ArrayList filesArrayList = new ArrayList();
|
||||
Collection builtLibraries = getBuiltLibraries();
|
||||
Library library;
|
||||
File[] files;
|
||||
Iterator libIterator = builtLibraries.iterator();
|
||||
while(libIterator.hasNext()){
|
||||
library = (Library)libIterator.next();
|
||||
files = library.getHeaderFiles();
|
||||
for(int i = 0; i < files.length; ++i){
|
||||
filesArrayList.add(files[i].getName());
|
||||
}
|
||||
}
|
||||
String[] filesArray = new String[filesArrayList.size()];
|
||||
filesArrayList.toArray(filesArray);
|
||||
return filesArray;
|
||||
}
|
||||
|
||||
/*
|
||||
* Gathers paths to library folders
|
||||
* @return Array of strings of paths to library folders
|
||||
*/
|
||||
public String[] getFolderPaths() {
|
||||
ArrayList foldersArrayList = new ArrayList();
|
||||
//Collection builtLibraries = getBuiltLibraries();
|
||||
Collection libraries = getAll();
|
||||
Library library;
|
||||
//Iterator libIterator = builtLibraries.iterator();
|
||||
Iterator libIterator = libraries.iterator();
|
||||
while(libIterator.hasNext()){
|
||||
library = (Library)libIterator.next();
|
||||
foldersArrayList.add(library.getFolder().getPath());
|
||||
}
|
||||
String[] foldersArray = new String[foldersArrayList.size()];
|
||||
foldersArrayList.toArray(foldersArray);
|
||||
return foldersArray;
|
||||
}
|
||||
|
||||
/*
|
||||
* Builds unbuilt libraries
|
||||
* @return Number of libraries built as int, -1 & exception on error
|
||||
*/
|
||||
public int buildAllUnbuilt() throws RunnerException {
|
||||
Collection buildableLibraries = getLibrariesToBuild();
|
||||
Library library;
|
||||
Iterator libIterator = buildableLibraries.iterator();
|
||||
int countBuilt = 0;
|
||||
while(libIterator.hasNext()){
|
||||
library = (Library)libIterator.next();
|
||||
//System.out.println("Building library \"" + library.getName() + "\"");
|
||||
try {
|
||||
if(library.build()){
|
||||
++countBuilt;
|
||||
}else{
|
||||
return -1;
|
||||
}
|
||||
}catch (RunnerException re) {
|
||||
throw new RunnerException(re.getMessage());
|
||||
} catch (Exception ex) {
|
||||
throw new RunnerException(ex.toString());
|
||||
}
|
||||
}
|
||||
return countBuilt;
|
||||
}
|
||||
|
||||
/*
|
||||
* Populates examples menu with library folders
|
||||
*/
|
||||
public void populateExamplesMenu(JMenu examplesMenu, ActionListener listener) {
|
||||
Library library;
|
||||
Collection libraries = getBuiltLibraries();
|
||||
Iterator iterator = libraries.iterator();
|
||||
JMenu libraryExamples;
|
||||
while(iterator.hasNext()){
|
||||
library = (Library)iterator.next();
|
||||
libraryExamples = library.getExamplesMenu(listener);
|
||||
if(null != libraryExamples){
|
||||
examplesMenu.add(libraryExamples);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Add syntax coloring
|
||||
*/
|
||||
public void addSyntaxColoring(PdeKeywords keywords) {
|
||||
Library library;
|
||||
Collection libraries = getBuiltLibraries();
|
||||
Iterator iterator = libraries.iterator();
|
||||
while(iterator.hasNext()){
|
||||
library = (Library)iterator.next();
|
||||
library.addSyntaxColors(keywords);
|
||||
}
|
||||
}
|
||||
}
|
@ -44,7 +44,7 @@ class MessageSiphon implements Runnable {
|
||||
// bubble up in time (i.e. compile errors have a weird delay)
|
||||
//thread.setPriority(Thread.MIN_PRIORITY);
|
||||
thread.setPriority(Thread.MAX_PRIORITY-1);
|
||||
//thread.start();
|
||||
thread.start();
|
||||
}
|
||||
|
||||
|
||||
|
79
app/src/processing/app/debug/Target.java
Normal file
79
app/src/processing/app/debug/Target.java
Normal file
@ -0,0 +1,79 @@
|
||||
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Target - represents a target platform
|
||||
Part of the Arduino project - http://arduino.berlios.de/
|
||||
|
||||
Copyright (c) 2005
|
||||
David A. Mellis
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
$Id: Target.java 85 2006-01-12 23:24:12Z mellis $
|
||||
*/
|
||||
|
||||
package processing.app.debug;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Represents a target platform (e.g. Wiring board, Arduino board).
|
||||
*/
|
||||
public class Target {
|
||||
String path;
|
||||
List sources = new ArrayList();
|
||||
List objects = new ArrayList();
|
||||
|
||||
/**
|
||||
* Create a Target.
|
||||
* @param path the directory containing config, source, and object files for
|
||||
* the target platform.
|
||||
*/
|
||||
public Target(String base, String target) throws IOException {
|
||||
path = base + File.separator + target;
|
||||
String[] files = (new File(path)).list();
|
||||
|
||||
if (files == null)
|
||||
throw new IOException("Target platform: \"" + target + "\" not found.\n" +
|
||||
"Make sure that \"build.target\" in the \n" +
|
||||
"preferences file points to a subdirectory of \n" +
|
||||
base);
|
||||
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
if (files[i].endsWith(".c") || files[i].endsWith(".cpp"))
|
||||
sources.add(files[i]);
|
||||
if (files[i].endsWith(".o"))
|
||||
objects.add(files[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public String getPath() { return path; }
|
||||
|
||||
/**
|
||||
* The source files in the library for the target platform.
|
||||
* @return A read-only collection of strings containing the name of each source file.
|
||||
*/
|
||||
public Collection getSourceFilenames() {
|
||||
return Collections.unmodifiableList(sources);
|
||||
}
|
||||
|
||||
/**
|
||||
* The object files in the library for the target platform.
|
||||
* @return A read-only collection of strings containing the name of each object file.
|
||||
*/
|
||||
public Collection getObjectFilenames() {
|
||||
return Collections.unmodifiableList(objects);
|
||||
}
|
||||
}
|
@ -80,12 +80,12 @@ public class Platform extends processing.app.Platform {
|
||||
|
||||
|
||||
public File getSettingsFolder() throws Exception {
|
||||
return new File(getLibraryFolder(), "Processing");
|
||||
return new File(getLibraryFolder(), "Arduino");
|
||||
}
|
||||
|
||||
|
||||
public File getDefaultSketchbookFolder() throws Exception {
|
||||
return new File(getDocumentsFolder(), "Processing");
|
||||
return new File(getDocumentsFolder(), "Arduino");
|
||||
/*
|
||||
// looking for /Users/blah/Documents/Processing
|
||||
try {
|
||||
|
@ -1,936 +0,0 @@
|
||||
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
package processing.app.preproc;
|
||||
|
||||
import processing.app.*;
|
||||
import processing.app.debug.RunnerException;
|
||||
|
||||
|
||||
/* Based on original code copyright (c) 2003 Andy Tripp <atripp@comcast.net>.
|
||||
* shipped under GPL with permission.
|
||||
*/
|
||||
|
||||
//import antlr.*;
|
||||
import antlr.collections.*;
|
||||
//import antlr.collections.impl.*;
|
||||
import java.io.*;
|
||||
//import java.util.*;
|
||||
|
||||
/**
|
||||
* PDEEmitter: A class that can take an ANTLR Java AST and produce
|
||||
* reasonably formatted Java code from it. To use it, create a
|
||||
* PDEEmitter object, call setOut() if you want to print to something
|
||||
* other than System.out, and then call print(), passing the
|
||||
* AST. Typically, the AST node that you pass would be the root of a
|
||||
* tree - the ROOT_ID node that represents a Java file.
|
||||
*/
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class PdeEmitter implements PdeTokenTypes
|
||||
{
|
||||
private PrintStream out = System.out;
|
||||
private PrintStream debug = System.err;
|
||||
//private static int ALL = -1;
|
||||
private java.util.Stack stack = new java.util.Stack();
|
||||
private static String[] tokenNames;
|
||||
private final static int ROOT_ID = 0;
|
||||
static {
|
||||
setupTokenNames();
|
||||
}
|
||||
|
||||
/*
|
||||
private static Hashtable publicMethods;
|
||||
private static final String publicMethodList[] = {
|
||||
"setup", "draw", //"loop",
|
||||
"mousePressed", "mouseReleased", "mouseClicked",
|
||||
"mouseEntered", "mouseExited",
|
||||
"mouseMoved", "mouseDragged",
|
||||
"keyPressed", "keyReleased", "keyTyped"
|
||||
};
|
||||
|
||||
static {
|
||||
publicMethods = new Hashtable();
|
||||
for (int i = 0; i < publicMethodList.length; i++) {
|
||||
publicMethods.put(publicMethodList[i], new Object());
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// Map each AST token type to a String
|
||||
private static void setupTokenNames() {
|
||||
tokenNames = new String[200];
|
||||
for (int i=0; i<tokenNames.length; i++) {
|
||||
tokenNames[i] = "ERROR:" + i;
|
||||
}
|
||||
|
||||
tokenNames[POST_INC]="++";
|
||||
tokenNames[POST_DEC]="--";
|
||||
tokenNames[UNARY_MINUS]="-";
|
||||
tokenNames[UNARY_PLUS]="+";
|
||||
tokenNames[STAR]="*";
|
||||
tokenNames[ASSIGN]="=";
|
||||
tokenNames[PLUS_ASSIGN]="+=";
|
||||
tokenNames[MINUS_ASSIGN]="-=";
|
||||
tokenNames[STAR_ASSIGN]="*=";
|
||||
tokenNames[DIV_ASSIGN]="/=";
|
||||
tokenNames[MOD_ASSIGN]="%=";
|
||||
tokenNames[SR_ASSIGN]=">>=";
|
||||
tokenNames[BSR_ASSIGN]=">>>=";
|
||||
tokenNames[SL_ASSIGN]="<<=";
|
||||
tokenNames[BAND_ASSIGN]="&=";
|
||||
tokenNames[BXOR_ASSIGN]="^=";
|
||||
tokenNames[BOR_ASSIGN]="|=";
|
||||
tokenNames[QUESTION]="?";
|
||||
tokenNames[LOR]="||";
|
||||
tokenNames[LAND]="&&";
|
||||
tokenNames[BOR]="|";
|
||||
tokenNames[BXOR]="^";
|
||||
tokenNames[BAND]="&";
|
||||
tokenNames[NOT_EQUAL]="!=";
|
||||
tokenNames[EQUAL]="==";
|
||||
tokenNames[LT]="<";
|
||||
tokenNames[GT]=">";
|
||||
tokenNames[LE]="<=";
|
||||
tokenNames[GE]=">=";
|
||||
tokenNames[SL]="<<";
|
||||
tokenNames[SR]=">>";
|
||||
tokenNames[BSR]=">>>";
|
||||
tokenNames[PLUS]="+";
|
||||
tokenNames[MINUS]="-";
|
||||
tokenNames[DIV]="/";
|
||||
tokenNames[MOD]="%";
|
||||
tokenNames[INC]="++";
|
||||
tokenNames[DEC]="--";
|
||||
tokenNames[BNOT]="~";
|
||||
tokenNames[LNOT]="!";
|
||||
tokenNames[FINAL]="final";
|
||||
tokenNames[ABSTRACT]="abstract";
|
||||
tokenNames[LITERAL_package]="package";
|
||||
tokenNames[LITERAL_import]="import";
|
||||
tokenNames[LITERAL_void]="void";
|
||||
tokenNames[LITERAL_boolean]="boolean";
|
||||
tokenNames[LITERAL_byte]="byte";
|
||||
tokenNames[LITERAL_char]="char";
|
||||
tokenNames[LITERAL_short]="short";
|
||||
tokenNames[LITERAL_int]="int";
|
||||
tokenNames[LITERAL_float]="float";
|
||||
tokenNames[LITERAL_long]="long";
|
||||
tokenNames[LITERAL_double]="double";
|
||||
tokenNames[LITERAL_private]="private";
|
||||
tokenNames[LITERAL_public]="public";
|
||||
tokenNames[LITERAL_protected]="protected";
|
||||
tokenNames[LITERAL_static]="static";
|
||||
tokenNames[LITERAL_transient]="transient";
|
||||
tokenNames[LITERAL_native]="native";
|
||||
tokenNames[LITERAL_threadsafe]="threadsafe";
|
||||
tokenNames[LITERAL_synchronized]="synchronized";
|
||||
tokenNames[LITERAL_volatile]="volatile";
|
||||
tokenNames[LITERAL_class]="class";
|
||||
tokenNames[LITERAL_extends]="extends";
|
||||
tokenNames[LITERAL_interface]="interface";
|
||||
tokenNames[LITERAL_implements]="implements";
|
||||
tokenNames[LITERAL_throws]="throws";
|
||||
tokenNames[LITERAL_if]="if";
|
||||
tokenNames[LITERAL_else]="else";
|
||||
tokenNames[LITERAL_for]="for";
|
||||
tokenNames[LITERAL_while]="while";
|
||||
tokenNames[LITERAL_do]="do";
|
||||
tokenNames[LITERAL_break]="break";
|
||||
tokenNames[LITERAL_continue]="continue";
|
||||
tokenNames[LITERAL_return]="return";
|
||||
tokenNames[LITERAL_switch]="switch";
|
||||
tokenNames[LITERAL_throw]="throw";
|
||||
tokenNames[LITERAL_case]="case";
|
||||
tokenNames[LITERAL_default]="default";
|
||||
tokenNames[LITERAL_try]="try";
|
||||
tokenNames[LITERAL_finally]="finally";
|
||||
tokenNames[LITERAL_catch]="catch";
|
||||
tokenNames[LITERAL_instanceof]="instanceof";
|
||||
tokenNames[LITERAL_this]="this";
|
||||
tokenNames[LITERAL_super]="super";
|
||||
tokenNames[LITERAL_true]="true";
|
||||
tokenNames[LITERAL_false]="false";
|
||||
tokenNames[LITERAL_null]="null";
|
||||
tokenNames[LITERAL_new]="new";
|
||||
tokenNames[LITERAL_color]="int"; // PDE specific alias
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a PrintStream to print to. System.out is the default.
|
||||
* @param out the PrintStream to print to
|
||||
*/
|
||||
public void setOut(PrintStream out) {
|
||||
this.out = out;
|
||||
}
|
||||
private String name(AST ast) {
|
||||
return tokenNames[ast.getType()];
|
||||
}
|
||||
private String name(int type) {
|
||||
return tokenNames[type];
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a child of the given AST that has the given type
|
||||
* @returns a child AST of the given type. If it can't find a child of the
|
||||
* given type, return null.
|
||||
*/
|
||||
private AST getChild(AST ast, int childType) {
|
||||
AST child = ast.getFirstChild();
|
||||
while (child != null) {
|
||||
if (child.getType() == childType) {
|
||||
// debug.println("getChild: found:" + name(ast));
|
||||
return child;
|
||||
}
|
||||
child = child.getNextSibling();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump the list of hidden tokens linked to after the AST node passed in.
|
||||
* Most hidden tokens are dumped from this function.
|
||||
*/
|
||||
private void dumpHiddenAfter(AST ast) {
|
||||
dumpHiddenTokens(((antlr.CommonASTWithHiddenTokens)ast).getHiddenAfter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump the list of hidden tokens linked to before the AST node passed in.
|
||||
* The only time hidden tokens need to be dumped with this function is when
|
||||
* dealing parts of the tree where automatic tree construction was
|
||||
* turned off with the ! operator in the grammar file and the nodes were
|
||||
* manually constructed in such a way that the usual tokens don't have the
|
||||
* necessary hiddenAfter links.
|
||||
*/
|
||||
private void dumpHiddenBefore(AST ast) {
|
||||
|
||||
antlr.CommonHiddenStreamToken
|
||||
child = null,
|
||||
parent = ((antlr.CommonASTWithHiddenTokens)ast).getHiddenBefore();
|
||||
|
||||
// if there aren't any hidden tokens here, quietly return
|
||||
//
|
||||
if (parent == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// traverse back to the head of the list of tokens before this node
|
||||
do {
|
||||
child = parent;
|
||||
parent = child.getHiddenBefore();
|
||||
} while (parent != null);
|
||||
|
||||
// dump that list
|
||||
dumpHiddenTokens(child);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump the list of hidden tokens linked to from the token passed in.
|
||||
*/
|
||||
private void dumpHiddenTokens(antlr.CommonHiddenStreamToken t) {
|
||||
for ( ; t != null ; t=PdePreprocessor.filter.getHiddenAfter(t) ) {
|
||||
out.print(t.getText());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the children of the given AST
|
||||
* @param ast The AST to print
|
||||
* @returns true iff anything was printed
|
||||
*/
|
||||
private boolean printChildren(AST ast) throws RunnerException {
|
||||
boolean ret = false;
|
||||
AST child = ast.getFirstChild();
|
||||
while (child != null) {
|
||||
ret = true;
|
||||
print(child);
|
||||
child = child.getNextSibling();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether an AST has any children or not.
|
||||
* @return true iff the AST has at least one child
|
||||
*/
|
||||
private boolean hasChildren(AST ast) {
|
||||
return (ast.getFirstChild() != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the best node in the subtree for printing. This really means
|
||||
* the next node which could potentially have hiddenBefore data. It's
|
||||
* usually the first printable leaf, but not always.
|
||||
*
|
||||
* @param includeThisNode Should this node be included in the search?
|
||||
* If false, only descendants are searched.
|
||||
*
|
||||
* @return the first printable leaf node in an AST
|
||||
*/
|
||||
private AST getBestPrintableNode(AST ast, boolean includeThisNode) {
|
||||
AST child;
|
||||
|
||||
if (includeThisNode) {
|
||||
child = ast;
|
||||
} else {
|
||||
child = ast.getFirstChild();
|
||||
}
|
||||
|
||||
if (child != null) {
|
||||
|
||||
switch (child.getType()) {
|
||||
|
||||
// the following node types are printing nodes that print before
|
||||
// any children, but then also recurse over children. So they
|
||||
// may have hiddenBefore chains that need to be printed first. Many
|
||||
// statements and all unary expression types qualify. Return these
|
||||
// nodes directly
|
||||
case CLASS_DEF:
|
||||
case LITERAL_if:
|
||||
case LITERAL_for:
|
||||
case LITERAL_while:
|
||||
case LITERAL_do:
|
||||
case LITERAL_break:
|
||||
case LITERAL_continue:
|
||||
case LITERAL_return:
|
||||
case LITERAL_switch:
|
||||
case LITERAL_try:
|
||||
case LITERAL_throw:
|
||||
case LITERAL_synchronized:
|
||||
case LITERAL_assert:
|
||||
case BNOT:
|
||||
case LNOT:
|
||||
case INC:
|
||||
case DEC:
|
||||
case UNARY_MINUS:
|
||||
case UNARY_PLUS:
|
||||
return child;
|
||||
|
||||
// Some non-terminal node types (at the moment, I only know of
|
||||
// MODIFIERS, but there may be other such types), can be
|
||||
// leaves in the tree but not have any children. If this is
|
||||
// such a node, move on to the next sibling.
|
||||
case MODIFIERS:
|
||||
if (child.getFirstChild() == null ) {
|
||||
return getBestPrintableNode(child.getNextSibling(), false);
|
||||
}
|
||||
// new jikes doesn't like fallthrough, so just duplicated here:
|
||||
return getBestPrintableNode(child, false);
|
||||
|
||||
default:
|
||||
return getBestPrintableNode(child, false);
|
||||
}
|
||||
}
|
||||
|
||||
return ast;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a binary operator
|
||||
*/
|
||||
private void printBinaryOperator(AST ast) throws RunnerException {
|
||||
print(ast.getFirstChild());
|
||||
out.print(name(ast));
|
||||
dumpHiddenAfter(ast);
|
||||
print(ast.getFirstChild().getNextSibling());
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the given AST. Call this function to print your PDE code.
|
||||
*
|
||||
* It works by making recursive calls to print children.
|
||||
* So the code below is one big "switch" statement on the passed AST type.
|
||||
*/
|
||||
public void print (AST ast) throws RunnerException {
|
||||
if (ast == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
AST parent = null;
|
||||
if (!stack.isEmpty()) {
|
||||
parent = (AST) stack.peek();
|
||||
}
|
||||
stack.push(ast);
|
||||
|
||||
AST child1 = ast.getFirstChild();
|
||||
AST child2 = null;
|
||||
AST child3 = null;
|
||||
if (child1 != null) {
|
||||
child2 = child1.getNextSibling();
|
||||
if (child2 != null) {
|
||||
child3 = child2.getNextSibling();
|
||||
}
|
||||
}
|
||||
|
||||
switch(ast.getType()) {
|
||||
// The top of the tree looks like this:
|
||||
// ROOT_ID "Whatever.java"
|
||||
// package
|
||||
// imports
|
||||
// class definition
|
||||
case ROOT_ID:
|
||||
dumpHiddenTokens(PdePreprocessor.filter.getInitialHiddenToken());
|
||||
printChildren(ast);
|
||||
break;
|
||||
|
||||
// supporting a "package" statement in a PDE program has
|
||||
// a bunch of issues with it that need to dealt in the compilation
|
||||
// code too, so this isn't actually tested.
|
||||
case PACKAGE_DEF:
|
||||
out.print("package");
|
||||
dumpHiddenAfter(ast);
|
||||
print(ast.getFirstChild());
|
||||
break;
|
||||
|
||||
// IMPORT has exactly one child
|
||||
case IMPORT:
|
||||
out.print("import");
|
||||
dumpHiddenAfter(ast);
|
||||
print(ast.getFirstChild());
|
||||
break;
|
||||
|
||||
case CLASS_DEF:
|
||||
case INTERFACE_DEF:
|
||||
print(getChild(ast, MODIFIERS));
|
||||
if (ast.getType() == CLASS_DEF) {
|
||||
out.print("class");
|
||||
} else {
|
||||
out.print("interface");
|
||||
}
|
||||
dumpHiddenBefore(getChild(ast, IDENT));
|
||||
print(getChild(ast, IDENT));
|
||||
print(getChild(ast, EXTENDS_CLAUSE));
|
||||
print(getChild(ast, IMPLEMENTS_CLAUSE));
|
||||
print(getChild(ast, OBJBLOCK));
|
||||
break;
|
||||
|
||||
case EXTENDS_CLAUSE:
|
||||
if (hasChildren(ast)) {
|
||||
out.print("extends");
|
||||
dumpHiddenBefore(getBestPrintableNode(ast, false));
|
||||
printChildren(ast);
|
||||
}
|
||||
break;
|
||||
|
||||
case IMPLEMENTS_CLAUSE:
|
||||
if (hasChildren(ast)) {
|
||||
out.print("implements");
|
||||
dumpHiddenBefore(getBestPrintableNode(ast, false));
|
||||
printChildren(ast);
|
||||
}
|
||||
break;
|
||||
|
||||
// DOT always has exactly two children.
|
||||
case DOT:
|
||||
print(child1);
|
||||
out.print(".");
|
||||
dumpHiddenAfter(ast);
|
||||
print(child2);
|
||||
break;
|
||||
|
||||
case MODIFIERS:
|
||||
case OBJBLOCK:
|
||||
case CTOR_DEF:
|
||||
//case METHOD_DEF:
|
||||
case PARAMETERS:
|
||||
case PARAMETER_DEF:
|
||||
case VARIABLE_DEF:
|
||||
case TYPE:
|
||||
case SLIST:
|
||||
case ELIST:
|
||||
case ARRAY_DECLARATOR:
|
||||
case TYPECAST:
|
||||
case EXPR:
|
||||
case ARRAY_INIT:
|
||||
case FOR_INIT:
|
||||
case FOR_CONDITION:
|
||||
case FOR_ITERATOR:
|
||||
case METHOD_CALL:
|
||||
case INSTANCE_INIT:
|
||||
case INDEX_OP:
|
||||
case SUPER_CTOR_CALL:
|
||||
case CTOR_CALL:
|
||||
printChildren(ast);
|
||||
break;
|
||||
|
||||
case METHOD_DEF:
|
||||
// kids seem to be: MODIFIERS TYPE setup PARAMETERS
|
||||
//AST parent = (AST) stack.peek();
|
||||
AST modifiersChild = ast.getFirstChild();
|
||||
AST typeChild = modifiersChild.getNextSibling();
|
||||
AST methodNameChild = typeChild.getNextSibling();
|
||||
AST parametersChild = methodNameChild.getNextSibling();
|
||||
|
||||
// to output, use print(child) on each of the four
|
||||
|
||||
String methodName = methodNameChild.getText();
|
||||
if (methodName.equals("main")) {
|
||||
PdePreprocessor.foundMain = true;
|
||||
}
|
||||
|
||||
/*
|
||||
// 1. figure out if this is setup, draw, or loop
|
||||
String methodName = methodNameChild.getText();
|
||||
if (publicMethods.get(methodName) != null) {
|
||||
// make sure this feller is public
|
||||
boolean foundPublic = false;
|
||||
AST child = modifiersChild.getFirstChild();
|
||||
while (child != null) {
|
||||
if (child.getText().equals("public")) {
|
||||
foundPublic = true;
|
||||
child = null;
|
||||
} else {
|
||||
//out.print("." + child.getText() + ".");
|
||||
child = child.getNextSibling();
|
||||
}
|
||||
}
|
||||
if (!foundPublic) {
|
||||
out.print("public ");
|
||||
}
|
||||
*/
|
||||
|
||||
// if this method doesn't have a specifier, make it public
|
||||
// (useful for setup/keyPressed/etc)
|
||||
boolean foundSpecifier = false;
|
||||
AST child = modifiersChild.getFirstChild();
|
||||
while (child != null) {
|
||||
String childText = child.getText();
|
||||
if (childText.equals("public") ||
|
||||
childText.equals("protected") ||
|
||||
childText.equals("private")) {
|
||||
foundSpecifier = true;
|
||||
child = null;
|
||||
} else {
|
||||
//out.print("." + child.getText() + ".");
|
||||
child = child.getNextSibling();
|
||||
}
|
||||
}
|
||||
if (!foundSpecifier) {
|
||||
out.print("public ");
|
||||
}
|
||||
printChildren(ast); // everything is fine
|
||||
break;
|
||||
|
||||
// if we have two children, it's of the form "a=0"
|
||||
// if just one child, it's of the form "=0" (where the
|
||||
// lhs is above this AST).
|
||||
case ASSIGN:
|
||||
if (child2 != null) {
|
||||
print(child1);
|
||||
out.print("=");
|
||||
dumpHiddenAfter(ast);
|
||||
print(child2);
|
||||
}
|
||||
else {
|
||||
out.print("=");
|
||||
dumpHiddenAfter(ast);
|
||||
print(child1);
|
||||
}
|
||||
break;
|
||||
|
||||
// binary operators:
|
||||
case PLUS:
|
||||
case MINUS:
|
||||
case DIV:
|
||||
case MOD:
|
||||
case NOT_EQUAL:
|
||||
case EQUAL:
|
||||
case LT:
|
||||
case GT:
|
||||
case LE:
|
||||
case GE:
|
||||
case LOR:
|
||||
case LAND:
|
||||
case BOR:
|
||||
case BXOR:
|
||||
case BAND:
|
||||
case SL:
|
||||
case SR:
|
||||
case BSR:
|
||||
case LITERAL_instanceof:
|
||||
case PLUS_ASSIGN:
|
||||
case MINUS_ASSIGN:
|
||||
case STAR_ASSIGN:
|
||||
case DIV_ASSIGN:
|
||||
case MOD_ASSIGN:
|
||||
case SR_ASSIGN:
|
||||
case BSR_ASSIGN:
|
||||
case SL_ASSIGN:
|
||||
case BAND_ASSIGN:
|
||||
case BXOR_ASSIGN:
|
||||
case BOR_ASSIGN:
|
||||
printBinaryOperator(ast);
|
||||
break;
|
||||
|
||||
|
||||
case LITERAL_for:
|
||||
out.print(name(ast));
|
||||
dumpHiddenAfter(ast);
|
||||
printChildren(ast);
|
||||
break;
|
||||
|
||||
case POST_INC:
|
||||
case POST_DEC:
|
||||
print(child1);
|
||||
out.print(name(ast));
|
||||
dumpHiddenAfter(ast);
|
||||
break;
|
||||
|
||||
// unary operators:
|
||||
case BNOT:
|
||||
case LNOT:
|
||||
case INC:
|
||||
case DEC:
|
||||
case UNARY_MINUS:
|
||||
case UNARY_PLUS:
|
||||
out.print(name(ast));
|
||||
dumpHiddenAfter(ast);
|
||||
print(child1);
|
||||
break;
|
||||
|
||||
case LITERAL_new:
|
||||
out.print("new");
|
||||
dumpHiddenAfter(ast);
|
||||
print(child1);
|
||||
print(child2);
|
||||
// "new String[] {...}": the stuff in {} is child3
|
||||
if (child3 != null) {
|
||||
print(child3);
|
||||
}
|
||||
break;
|
||||
|
||||
case LITERAL_return:
|
||||
out.print("return");
|
||||
dumpHiddenAfter(ast);
|
||||
print(child1);
|
||||
break;
|
||||
|
||||
case STATIC_INIT:
|
||||
out.print("static");
|
||||
dumpHiddenBefore(getBestPrintableNode(ast, false));
|
||||
print(child1);
|
||||
break;
|
||||
|
||||
case LITERAL_switch:
|
||||
out.print("switch");
|
||||
dumpHiddenAfter(ast);
|
||||
printChildren(ast);
|
||||
break;
|
||||
|
||||
case CASE_GROUP:
|
||||
printChildren(ast);
|
||||
break;
|
||||
|
||||
case LITERAL_case:
|
||||
out.print("case");
|
||||
dumpHiddenAfter(ast);
|
||||
printChildren(ast);
|
||||
break;
|
||||
|
||||
case LITERAL_default:
|
||||
out.print("default");
|
||||
dumpHiddenAfter(ast);
|
||||
printChildren(ast);
|
||||
break;
|
||||
|
||||
case NUM_INT:
|
||||
case CHAR_LITERAL:
|
||||
case STRING_LITERAL:
|
||||
case NUM_FLOAT:
|
||||
case NUM_LONG:
|
||||
out.print(ast.getText());
|
||||
dumpHiddenAfter(ast);
|
||||
break;
|
||||
|
||||
case LITERAL_synchronized: // 0137 to fix bug #136
|
||||
out.print(name(ast));
|
||||
dumpHiddenAfter(ast);
|
||||
printChildren(ast);
|
||||
break;
|
||||
|
||||
case LITERAL_private:
|
||||
case LITERAL_public:
|
||||
case LITERAL_protected:
|
||||
case LITERAL_static:
|
||||
case LITERAL_transient:
|
||||
case LITERAL_native:
|
||||
case LITERAL_threadsafe:
|
||||
//case LITERAL_synchronized: // 0137 to fix bug #136
|
||||
case LITERAL_volatile:
|
||||
case FINAL:
|
||||
case ABSTRACT:
|
||||
case LITERAL_package:
|
||||
case LITERAL_void:
|
||||
case LITERAL_boolean:
|
||||
case LITERAL_byte:
|
||||
case LITERAL_char:
|
||||
case LITERAL_short:
|
||||
case LITERAL_int:
|
||||
case LITERAL_float:
|
||||
case LITERAL_long:
|
||||
case LITERAL_double:
|
||||
case LITERAL_true:
|
||||
case LITERAL_false:
|
||||
case LITERAL_null:
|
||||
case SEMI:
|
||||
case LITERAL_this:
|
||||
case LITERAL_super:
|
||||
case LITERAL_continue:
|
||||
case LITERAL_break:
|
||||
out.print(name(ast));
|
||||
dumpHiddenAfter(ast);
|
||||
break;
|
||||
|
||||
case EMPTY_STAT:
|
||||
case EMPTY_FIELD:
|
||||
break;
|
||||
|
||||
// yuck: Distinguish between "import x.y.*" and "x = 1 * 3"
|
||||
case STAR:
|
||||
if (hasChildren(ast)) { // the binary mult. operator
|
||||
printBinaryOperator(ast);
|
||||
}
|
||||
else { // the special "*" in import:
|
||||
out.print("*");
|
||||
dumpHiddenAfter(ast);
|
||||
}
|
||||
break;
|
||||
|
||||
case LITERAL_throws:
|
||||
out.print("throws");
|
||||
dumpHiddenAfter(ast);
|
||||
printChildren(ast);
|
||||
break;
|
||||
|
||||
case LITERAL_if:
|
||||
out.print("if");
|
||||
dumpHiddenAfter(ast);
|
||||
print(child1); // the "if" condition: an EXPR
|
||||
print(child2); // the "then" clause is an SLIST
|
||||
if (child3 != null) {
|
||||
out.print("else");
|
||||
dumpHiddenBefore(getBestPrintableNode(child3, true));
|
||||
print(child3); // optional "else" clause: an SLIST
|
||||
}
|
||||
break;
|
||||
|
||||
case LITERAL_while:
|
||||
out.print("while");
|
||||
dumpHiddenAfter(ast);
|
||||
printChildren(ast);
|
||||
break;
|
||||
|
||||
case LITERAL_do:
|
||||
out.print("do");
|
||||
dumpHiddenAfter(ast);
|
||||
print(child1); // an SLIST
|
||||
out.print("while");
|
||||
dumpHiddenBefore(getBestPrintableNode(child2, false));
|
||||
print(child2); // an EXPR
|
||||
break;
|
||||
|
||||
case LITERAL_try:
|
||||
out.print("try");
|
||||
dumpHiddenAfter(ast);
|
||||
printChildren(ast);
|
||||
break;
|
||||
|
||||
case LITERAL_catch:
|
||||
out.print("catch");
|
||||
dumpHiddenAfter(ast);
|
||||
printChildren(ast);
|
||||
break;
|
||||
|
||||
// the first child is the "try" and the second is the SLIST
|
||||
case LITERAL_finally:
|
||||
out.print("finally");
|
||||
dumpHiddenAfter(ast);
|
||||
printChildren(ast);
|
||||
break;
|
||||
|
||||
case LITERAL_throw:
|
||||
out.print("throw");
|
||||
dumpHiddenAfter(ast);
|
||||
print(child1);
|
||||
break;
|
||||
|
||||
// the dreaded trinary operator
|
||||
case QUESTION:
|
||||
print(child1);
|
||||
out.print("?");
|
||||
dumpHiddenAfter(ast);
|
||||
print(child2);
|
||||
print(child3);
|
||||
break;
|
||||
|
||||
// pde specific or modified tokens start here
|
||||
|
||||
// Image -> BImage, Font -> BFont as appropriate
|
||||
case IDENT:
|
||||
/*
|
||||
if (ast.getText().equals("Image") &&
|
||||
Preferences.getBoolean("preproc.substitute_image")) { //, true)) {
|
||||
out.print("BImage");
|
||||
} else if (ast.getText().equals("Font") &&
|
||||
Preferences.getBoolean("preproc.substitute_font")) { //, true)) {
|
||||
out.print("BFont");
|
||||
} else {
|
||||
*/
|
||||
out.print(ast.getText());
|
||||
//}
|
||||
dumpHiddenAfter(ast);
|
||||
break;
|
||||
|
||||
// the color datatype is just an alias for int
|
||||
case LITERAL_color:
|
||||
out.print("int");
|
||||
dumpHiddenAfter(ast);
|
||||
break;
|
||||
|
||||
case WEBCOLOR_LITERAL:
|
||||
if (ast.getText().length() != 6) {
|
||||
System.err.println("Internal error: incorrect length of webcolor " +
|
||||
"literal should have been detected sooner.");
|
||||
break;
|
||||
}
|
||||
out.print("0xff" + ast.getText());
|
||||
dumpHiddenAfter(ast);
|
||||
break;
|
||||
|
||||
// allow for stuff like int(43.2).
|
||||
case CONSTRUCTOR_CAST:
|
||||
|
||||
AST nonTerminalTypeNode = child1;
|
||||
AST terminalTypeNode = child1.getFirstChild();
|
||||
AST exprToCast = child2;
|
||||
|
||||
/*
|
||||
// if this is a string type, add .valueOf()
|
||||
if (nonTerminalTypeNode.getType() == PdeRecognizer.TYPE &&
|
||||
terminalTypeNode.getText().equals("String")) {
|
||||
|
||||
out.print(terminalTypeNode.getText() + ".valueOf");
|
||||
dumpHiddenAfter(terminalTypeNode);
|
||||
print(exprToCast);
|
||||
|
||||
// if the expresion to be cast is a string literal, try and parse it.
|
||||
//
|
||||
// ideally, we'd be able to do this for all expressions with a
|
||||
// string type, not just string literals. however, the parser
|
||||
// doesn't currently track expression type, and for full
|
||||
// functionality, we'd need to do semantic analysis to handle
|
||||
// imports so that we could know the return types of method calls.
|
||||
//
|
||||
} else if (exprToCast.getFirstChild().getType() == STRING_LITERAL ) {
|
||||
|
||||
switch (terminalTypeNode.getType()) {
|
||||
|
||||
case PdeRecognizer.LITERAL_byte:
|
||||
out.print("Byte.parseByte");
|
||||
dumpHiddenAfter(terminalTypeNode);
|
||||
print(exprToCast);
|
||||
break;
|
||||
|
||||
case PdeRecognizer.LITERAL_double:
|
||||
out.print("(new Double");
|
||||
dumpHiddenAfter(terminalTypeNode);
|
||||
out.print(exprToCast.getFirstChild().getText() + ").doubleValue()");
|
||||
dumpHiddenAfter(exprToCast.getFirstChild());
|
||||
break;
|
||||
|
||||
case PdeRecognizer.LITERAL_float:
|
||||
out.print("(new Float");
|
||||
dumpHiddenAfter(terminalTypeNode);
|
||||
out.print(exprToCast.getFirstChild().getText() + ").floatValue()");
|
||||
dumpHiddenAfter(exprToCast.getFirstChild());
|
||||
break;
|
||||
|
||||
case PdeRecognizer.LITERAL_int:
|
||||
case PdeRecognizer.LITERAL_color:
|
||||
out.print("Integer.parseInt");
|
||||
dumpHiddenAfter(terminalTypeNode);
|
||||
print(exprToCast);
|
||||
break;
|
||||
|
||||
case PdeRecognizer.LITERAL_long:
|
||||
out.print("Long.parseLong");
|
||||
break;
|
||||
|
||||
case PdeRecognizer.LITERAL_short:
|
||||
out.print("Short.parseShort");
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new RunnerException(Compiler.SUPER_BADNESS);
|
||||
}
|
||||
|
||||
// for builtin types, use regular casting syntax
|
||||
} else {
|
||||
*/
|
||||
|
||||
// result of below is (int)(4.0
|
||||
//out.print("(");
|
||||
//out.print(terminalTypeNode.getText() + ")"); // typename
|
||||
//dumpHiddenAfter(terminalTypeNode);
|
||||
//print(exprToCast);
|
||||
//}
|
||||
|
||||
//out.print("(");
|
||||
String pooType = terminalTypeNode.getText();
|
||||
out.print("PApplet.parse" +
|
||||
Character.toUpperCase(pooType.charAt(0)) +
|
||||
pooType.substring(1));
|
||||
dumpHiddenAfter(terminalTypeNode); // the left paren
|
||||
print(exprToCast);
|
||||
//out.print("x)");
|
||||
|
||||
break;
|
||||
|
||||
|
||||
// making floating point literals default to floats, not doubles
|
||||
case NUM_DOUBLE:
|
||||
out.print(ast.getText());
|
||||
if (Preferences.getBoolean("preproc.substitute_floats")) { //, true) ) {
|
||||
out.print("f");
|
||||
}
|
||||
dumpHiddenAfter(ast);
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
debug.println("Invalid type:" + ast.getType());
|
||||
break;
|
||||
|
||||
|
||||
/* The following are tokens, but I don't think JavaRecognizer
|
||||
ever produces an AST with one of these types:
|
||||
case COMMA:
|
||||
case LITERAL_implements:
|
||||
case LITERAL_class:
|
||||
case LITERAL_extends:
|
||||
case EOF:
|
||||
case NULL_TREE_LOOKAHEAD:
|
||||
case BLOCK:
|
||||
case LABELED_STAT: // refuse to implement on moral grounds :)
|
||||
case LITERAL_import:
|
||||
case LBRACK:
|
||||
case RBRACK:
|
||||
case LCURLY:
|
||||
case RCURLY:
|
||||
case LPAREN:
|
||||
case RPAREN:
|
||||
case LITERAL_else: // else is a child of "if" AST
|
||||
case COLON: // part of the trinary operator
|
||||
case WS: // whitespace
|
||||
case ESC:
|
||||
case HEX_DIGIT:
|
||||
case VOCAB:
|
||||
|
||||
case EXPONENT: // exponents and float suffixes are left in the NUM_FLOAT
|
||||
case FLOAT_SUFFIX
|
||||
*/
|
||||
}
|
||||
|
||||
stack.pop();
|
||||
}
|
||||
}
|
@ -1,10 +1,12 @@
|
||||
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
PdePreprocessor - wrapper for default ANTLR-generated parser
|
||||
Part of the Processing project - http://processing.org
|
||||
Part of the Wiring project - http://wiring.org.co
|
||||
|
||||
Copyright (c) 2004-08 Ben Fry and Casey Reas
|
||||
Copyright (c) 2004-05 Hernando Barragan
|
||||
|
||||
Processing version Copyright (c) 2004-05 Ben Fry and Casey Reas
|
||||
Copyright (c) 2001-04 Massachusetts Institute of Technology
|
||||
|
||||
ANTLR-generated parser and several supporting classes written
|
||||
@ -28,169 +30,201 @@
|
||||
package processing.app.preproc;
|
||||
|
||||
import processing.app.*;
|
||||
import processing.app.debug.Target;
|
||||
import processing.core.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import antlr.*;
|
||||
import antlr.collections.*;
|
||||
import antlr.collections.impl.*;
|
||||
|
||||
import com.oroinc.text.regex.*;
|
||||
|
||||
|
||||
/**
|
||||
* Class that orchestrates preprocessing p5 syntax into straight Java.
|
||||
* <P/>
|
||||
* <B>Current Preprocessor Subsitutions:</B>
|
||||
* <UL>
|
||||
* <LI>any function not specified as being protected or private will
|
||||
* be made 'public'. this means that <TT>void setup()</TT> becomes
|
||||
* <TT>public void setup()</TT>. This is important to note when
|
||||
* coding with core.jar outside of the PDE.
|
||||
* <LI><TT>compiler.substitute_floats</TT> (currently "substitute_f")
|
||||
* treat doubles as floats, i.e. 12.3 becomes 12.3f so that people
|
||||
* don't have to add f after their numbers all the time since it's
|
||||
* confusing for beginners.
|
||||
* <LI><TT>compiler.enhanced_casting</TT> byte(), char(), int(), float()
|
||||
* works for casting. this is basic in the current implementation, but
|
||||
* should be expanded as described above. color() works similarly to int(),
|
||||
* however there is also a *function* called color(r, g, b) in p5.
|
||||
* <LI><TT>compiler.color_datatype</TT> 'color' is aliased to 'int'
|
||||
* as a datatype to represent ARGB packed into a single int, commonly
|
||||
* used in p5 for pixels[] and other color operations. this is just a
|
||||
* search/replace type thing, and it can be used interchangeably with int.
|
||||
* <LI><TT>compiler.web_colors</TT> (currently "inline_web_colors")
|
||||
* color c = #cc0080; should unpack to 0xffcc0080 (the ff at the top is
|
||||
* so that the color is opaque), which is just an int.
|
||||
* </UL>
|
||||
* <B>Other preprocessor functionality</B>
|
||||
* <UL>
|
||||
* <LI>detects what 'mode' the program is in: static (no function
|
||||
* brackets at all, just assumes everything is in draw), active
|
||||
* (setup plus draw or loop), and java mode (full java support).
|
||||
* http://processing.org/reference/environment/
|
||||
* </UL>
|
||||
* <P/>
|
||||
* The PDE Preprocessor is based on the Java Grammar that comes with
|
||||
* ANTLR 2.7.2. Moving it forward to a new version of the grammar
|
||||
* shouldn't be too difficult.
|
||||
* <P/>
|
||||
* Here's some info about the various files in this directory:
|
||||
* <P/>
|
||||
* <TT>java.g:</TT> this is the ANTLR grammar for Java 1.3/1.4 from the
|
||||
* ANTLR distribution. It is in the public domain. The only change to
|
||||
* this file from the original this file is the uncommenting of the
|
||||
* clauses required to support assert().
|
||||
* <P/>
|
||||
* <TT>java.tree.g:</TT> this describes the Abstract Syntax Tree (AST)
|
||||
* generated by java.g. It is only here as a reference for coders hacking
|
||||
* on the preprocessor, it is not built or used at all. Note that pde.g
|
||||
* overrides some of the java.g rules so that in PDE ASTs, there are a
|
||||
* few minor differences. Also in the public domain.
|
||||
* <P/>
|
||||
* <TT>pde.g:</TT> this is the grammar and lexer for the PDE language
|
||||
* itself. It subclasses the java.g grammar and lexer. There are a couple
|
||||
* of overrides to java.g that I hope to convince the ANTLR folks to fold
|
||||
* back into their grammar, but most of this file is highly specific to
|
||||
* PDE itself.
|
||||
* <TT>PdeEmitter.java:</TT> this class traverses the AST generated by
|
||||
* the PDE Recognizer, and emits it as Java code, doing any necessary
|
||||
* transformations along the way. It is based on JavaEmitter.java,
|
||||
* available from antlr.org, written by Andy Tripp <atripp@comcast.net>,
|
||||
* who has given permission for it to be distributed under the GPL.
|
||||
* <P/>
|
||||
* <TT>ExtendedCommonASTWithHiddenTokens.java:</TT> this adds a necessary
|
||||
* initialize() method, as well as a number of methods to allow for XML
|
||||
* serialization of the parse tree in a such a way that the hidden tokens
|
||||
* are visible. Much of the code is taken from the original
|
||||
* CommonASTWithHiddenTokens class. I hope to convince the ANTLR folks
|
||||
* to fold these changes back into that class so that this file will be
|
||||
* unnecessary.
|
||||
* <P/>
|
||||
* <TT>TokenStreamCopyingHiddenTokenFilter.java:</TT> this class provides
|
||||
* TokenStreamHiddenTokenFilters with the concept of tokens which can be
|
||||
* copied so that they are seen by both the hidden token stream as well
|
||||
* as the parser itself. This is useful when one wants to use an
|
||||
* existing parser (like the Java parser included with ANTLR) that throws
|
||||
* away some tokens to create a parse tree which can be used to spit out
|
||||
* a copy of the code with only minor modifications. Partially derived
|
||||
* from ANTLR code. I hope to convince the ANTLR folks to fold this
|
||||
* functionality back into ANTLR proper as well.
|
||||
* <P/>
|
||||
* <TT>whitespace_test.pde:</TT> a torture test to ensure that the
|
||||
* preprocessor is correctly preserving whitespace, comments, and other
|
||||
* hidden tokens correctly. See the comments in the code for details about
|
||||
* how to run the test.
|
||||
* <P/>
|
||||
* All other files in this directory are generated at build time by ANTLR
|
||||
* itself. The ANTLR manual goes into a fair amount of detail about the
|
||||
* what each type of file is for.
|
||||
* <P/>
|
||||
*/
|
||||
public class PdePreprocessor {
|
||||
|
||||
String[] defaultImports;
|
||||
static final int JDK11 = 0;
|
||||
static final int JDK13 = 1;
|
||||
static final int JDK14 = 2;
|
||||
|
||||
// these ones have the .* at the end, since a class name might be at the end
|
||||
// instead of .* which would make trouble other classes using this can lop
|
||||
// off the . and anything after it to produce a package name consistently.
|
||||
//static String defaultImports[][] = new String[3][];
|
||||
|
||||
// these ones have the .* at the end, since a class name
|
||||
// might be at the end instead of .* whcih would make trouble
|
||||
// other classes using this can lop of the . and anything after
|
||||
// it to produce a package name consistently.
|
||||
//public String extraImports[];
|
||||
ArrayList<String> programImports;
|
||||
|
||||
// imports just from the code folder, treated differently
|
||||
// than the others, since the imports are auto-generated.
|
||||
ArrayList<String> codeFolderImports;
|
||||
|
||||
static public final int STATIC = 0; // formerly BEGINNER
|
||||
static public final int ACTIVE = 1; // formerly INTERMEDIATE
|
||||
static public final int JAVA = 2; // formerly ADVANCED
|
||||
|
||||
// static to make it easier for the antlr preproc to get at it
|
||||
static public int programType;
|
||||
static public boolean foundMain;
|
||||
static public int programType = -1;
|
||||
|
||||
String indent;
|
||||
|
||||
PrintStream stream;
|
||||
Reader programReader;
|
||||
String buildPath;
|
||||
String name;
|
||||
|
||||
// used for calling the ASTFactory to get the root node
|
||||
private static final int ROOT_ID = 0;
|
||||
// stores number of built user-defined function prototypes
|
||||
public int prototypeCount = 0;
|
||||
|
||||
// stores number of included library headers written
|
||||
public int headerCount = 0;
|
||||
|
||||
/**
|
||||
* These may change in-between (if the prefs panel adds this option)
|
||||
* so grab them here on construction.
|
||||
*/
|
||||
public PdePreprocessor() {}
|
||||
|
||||
/**
|
||||
* Used by PdeEmitter.dumpHiddenTokens()
|
||||
*/
|
||||
public static TokenStreamCopyingHiddenTokenFilter filter;
|
||||
|
||||
static String advClassName = "";
|
||||
//public static TokenStreamCopyingHiddenTokenFilter filter;
|
||||
|
||||
/**
|
||||
* Returns the index of the first character that's not whitespace, a comment
|
||||
* or a pre-processor directive.
|
||||
*/
|
||||
public int firstStatement(String in) {
|
||||
PatternMatcherInput input = new PatternMatcherInput(in);
|
||||
PatternCompiler compiler = new Perl5Compiler();
|
||||
PatternMatcher matcher = new Perl5Matcher();
|
||||
Pattern pattern = null;
|
||||
|
||||
try {
|
||||
pattern = compiler.compile(
|
||||
// XXX: doesn't properly handle special single-quoted characters
|
||||
// whitespace
|
||||
"\\s+" + "|" +
|
||||
// multi-line comment
|
||||
"(/\\*[^*]*(?:\\*(?!/)[^*]*)*\\*/)" + "|" +
|
||||
// single-line comment
|
||||
"(//.*?$)" + "|" +
|
||||
// pre-processor directive
|
||||
"(#(?:\\\\\\n|.)*)",
|
||||
Perl5Compiler.MULTILINE_MASK);
|
||||
} catch (MalformedPatternException e) {
|
||||
throw new RuntimeException("Internal error in firstStatement()", e);
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
while (matcher.matchesPrefix(input, pattern)) {
|
||||
i = matcher.getMatch().endOffset(0);
|
||||
input.setCurrentOffset(i);
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips comments, pre-processor directives, single- and double-quoted
|
||||
* strings from a string.
|
||||
* @param in the String to strip
|
||||
* @return the stripped String
|
||||
*/
|
||||
public String strip(String in) throws MalformedPatternException {
|
||||
PatternCompiler compiler = new Perl5Compiler();
|
||||
PatternMatcher matcher = new Perl5Matcher();
|
||||
Pattern pattern = compiler.compile(
|
||||
// XXX: doesn't properly handle special single-quoted characters
|
||||
// single-quoted character
|
||||
"('.')" + "|" +
|
||||
// double-quoted string
|
||||
"(\"(?:[^\"\\\\]|\\\\.)*\")" + "|" +
|
||||
// multi-line comment
|
||||
"(/\\*[^*]*(?:\\*(?!/)[^*]*)*\\*/)" + "|" +
|
||||
// single-line comment
|
||||
"(//.*?$)" + "|" +
|
||||
// pre-processor directive
|
||||
"(^\\s*#.*?$)",
|
||||
Perl5Compiler.MULTILINE_MASK);
|
||||
|
||||
while (matcher.contains(in, pattern)) {
|
||||
MatchResult result = matcher.getMatch();
|
||||
// XXX: should preserve newlines in the result so that line numbers of
|
||||
// the stripped string correspond to those in the original source.
|
||||
in = in.substring(0, result.beginOffset(0)) + " " + in.substring(result.endOffset(0));
|
||||
}
|
||||
|
||||
return in;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the contents of all top-level curly brace pairs {}.
|
||||
* @param in the String to collapse
|
||||
* @return the collapsed String
|
||||
*/
|
||||
private String collapseBraces(String in) {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
int nesting = 0;
|
||||
int start = 0;
|
||||
|
||||
// XXX: need to keep newlines inside braces so we can determine the line
|
||||
// number of a prototype
|
||||
for (int i = 0; i < in.length(); i++) {
|
||||
if (in.charAt(i) == '{') {
|
||||
if (nesting == 0) {
|
||||
buffer.append(in.substring(start, i + 1)); // include the '{'
|
||||
}
|
||||
nesting++;
|
||||
}
|
||||
if (in.charAt(i) == '}') {
|
||||
nesting--;
|
||||
if (nesting == 0) {
|
||||
start = i; // include the '}'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buffer.append(in.substring(start));
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
public List prototypes(String in) throws MalformedPatternException {
|
||||
in = collapseBraces(strip(in));
|
||||
|
||||
PatternMatcherInput input = new PatternMatcherInput(in);
|
||||
PatternCompiler compiler = new Perl5Compiler();
|
||||
PatternMatcher matcher = new Perl5Matcher();
|
||||
// XXX: doesn't handle ... varargs
|
||||
// XXX: doesn't handle function pointers
|
||||
Pattern pattern = compiler.compile(
|
||||
"[\\w\\[\\]\\*]+\\s+[\\[\\]\\*\\w\\s]+\\([,\\[\\]\\*\\w\\s]*\\)(?=\\s*\\{)");
|
||||
List matches = new ArrayList();
|
||||
|
||||
while (matcher.contains(input, pattern)) {
|
||||
matches.add(matcher.getMatch().group(0) + ";");
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Setup a new preprocessor.
|
||||
* preprocesses a pde file and write out a java file
|
||||
* @param pretty true if should also space out/indent lines
|
||||
* @return the classname of the exported Java
|
||||
*/
|
||||
public PdePreprocessor() { }
|
||||
|
||||
|
||||
public int writePrefix(String program, String buildPath,
|
||||
String name, String codeFolderPackages[]) throws FileNotFoundException {
|
||||
this.buildPath = buildPath;
|
||||
this.name = name;
|
||||
|
||||
int tabSize = Preferences.getInteger("editor.tabs.size");
|
||||
char[] indentChars = new char[tabSize];
|
||||
Arrays.fill(indentChars, ' ');
|
||||
indent = new String(indentChars);
|
||||
|
||||
// need to reset whether or not this has a main()
|
||||
foundMain = false;
|
||||
|
||||
//public String write(String program, String buildPath, String name,
|
||||
// String extraImports[]) throws java.lang.Exception {
|
||||
public String write(String program, String buildPath,
|
||||
String name, String codeFolderPackages[],
|
||||
Target target)
|
||||
throws java.lang.Exception {
|
||||
// if the program ends with no CR or LF an OutOfMemoryError will happen.
|
||||
// not gonna track down the bug now, so here's a hack for it:
|
||||
// http://dev.processing.org/bugs/show_bug.cgi?id=5
|
||||
program += "\n";
|
||||
// bug filed at http://dev.processing.org/bugs/show_bug.cgi?id=5
|
||||
//if ((program.length() > 0) &&
|
||||
//program.charAt(program.length()-1) != '\n') {
|
||||
program += "\n";
|
||||
//}
|
||||
|
||||
// if the program ends with an unterminated multi-line comment,
|
||||
// if the program ends with an unterminated multiline comment,
|
||||
// an OutOfMemoryError or NullPointerException will happen.
|
||||
// again, not gonna bother tracking this down, but here's a hack.
|
||||
// http://dev.processing.org/bugs/show_bug.cgi?id=16
|
||||
@ -234,187 +268,66 @@ public class PdePreprocessor {
|
||||
program = new String(p2, 0, index);
|
||||
}
|
||||
}
|
||||
|
||||
// These may change in-between (if the prefs panel adds this option)
|
||||
// so grab them here on construction.
|
||||
String prefsLine = Preferences.get("preproc.imports");
|
||||
defaultImports = PApplet.splitTokens(prefsLine, ", ");
|
||||
|
||||
//String importRegexp = "(?:^|\\s|;)(import\\s+)(\\S+)(\\s*;)";
|
||||
String importRegexp = "(?:^|;)\\s*(import\\s+)(\\S+)(\\s*;)";
|
||||
|
||||
// if this guy has his own imports, need to remove them
|
||||
// just in case it's not an advanced mode sketch
|
||||
PatternMatcher matcher = new Perl5Matcher();
|
||||
PatternCompiler compiler = new Perl5Compiler();
|
||||
//String mess = "^\\s*(import\\s+\\S+\\s*;)";
|
||||
//String mess = "^\\s*(import\\s+)(\\S+)(\\s*;)";
|
||||
String mess = "^\\s*#include\\s+[<\"](\\S+)[\">]";
|
||||
programImports = new ArrayList<String>();
|
||||
|
||||
do {
|
||||
String[] pieces = PApplet.match(program, importRegexp);
|
||||
// Stop the loop if we've removed all the importy lines
|
||||
if (pieces == null) break;
|
||||
|
||||
String piece = pieces[1] + pieces[2] + pieces[3];
|
||||
int len = piece.length(); // how much to trim out
|
||||
|
||||
programImports.add(pieces[2]); // the package name
|
||||
int idx = program.indexOf(piece);
|
||||
// just remove altogether?
|
||||
program = program.substring(0, idx) + program.substring(idx + len);
|
||||
|
||||
} while (true);
|
||||
|
||||
codeFolderImports = new ArrayList<String>();
|
||||
if (codeFolderPackages != null) {
|
||||
for (String item : codeFolderPackages) {
|
||||
codeFolderImports.add(item + ".*");
|
||||
}
|
||||
Pattern pattern = null;
|
||||
try {
|
||||
pattern = compiler.compile(mess);
|
||||
} catch (MalformedPatternException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
|
||||
PatternMatcherInput input = new PatternMatcherInput(program);
|
||||
while (matcher.contains(input, pattern)) {
|
||||
programImports.add(matcher.getMatch().group(1));
|
||||
}
|
||||
|
||||
// do this after the program gets re-combobulated
|
||||
this.programReader = new StringReader(program);
|
||||
|
||||
File streamFile = new File(buildPath, name + ".java");
|
||||
stream = new PrintStream(new FileOutputStream(streamFile));
|
||||
int importsLength = writeImports(stream);
|
||||
|
||||
// return the length of the imports plus the extra lines for declarations
|
||||
return importsLength + 2;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* preprocesses a pde file and write out a java file
|
||||
* @return the classname of the exported Java
|
||||
*/
|
||||
//public String write(String program, String buildPath, String name,
|
||||
// String extraImports[]) throws java.lang.Exception {
|
||||
public String write() throws java.lang.Exception {
|
||||
// create a lexer with the stream reader, and tell it to handle
|
||||
// hidden tokens (eg whitespace, comments) since we want to pass these
|
||||
// through so that the line numbers when the compiler reports errors
|
||||
// match those that will be highlighted in the PDE IDE
|
||||
//
|
||||
PdeLexer lexer = new PdeLexer(programReader);
|
||||
lexer.setTokenObjectClass("antlr.CommonHiddenStreamToken");
|
||||
|
||||
// create the filter for hidden tokens and specify which tokens to
|
||||
// hide and which to copy to the hidden text
|
||||
//
|
||||
filter = new TokenStreamCopyingHiddenTokenFilter(lexer);
|
||||
filter.hide(PdeRecognizer.SL_COMMENT);
|
||||
filter.hide(PdeRecognizer.ML_COMMENT);
|
||||
filter.hide(PdeRecognizer.WS);
|
||||
filter.copy(PdeRecognizer.SEMI);
|
||||
filter.copy(PdeRecognizer.LPAREN);
|
||||
filter.copy(PdeRecognizer.RPAREN);
|
||||
filter.copy(PdeRecognizer.LCURLY);
|
||||
filter.copy(PdeRecognizer.RCURLY);
|
||||
filter.copy(PdeRecognizer.COMMA);
|
||||
filter.copy(PdeRecognizer.RBRACK);
|
||||
filter.copy(PdeRecognizer.LBRACK);
|
||||
filter.copy(PdeRecognizer.COLON);
|
||||
|
||||
// create a parser and set what sort of AST should be generated
|
||||
//
|
||||
PdeRecognizer parser = new PdeRecognizer(filter);
|
||||
|
||||
// use our extended AST class
|
||||
//
|
||||
parser.setASTNodeClass("antlr.ExtendedCommonASTWithHiddenTokens");
|
||||
|
||||
// start parsing at the compilationUnit non-terminal
|
||||
//
|
||||
parser.pdeProgram();
|
||||
|
||||
// set up the AST for traversal by PdeEmitter
|
||||
//
|
||||
ASTFactory factory = new ASTFactory();
|
||||
AST parserAST = parser.getAST();
|
||||
AST rootNode = factory.create(ROOT_ID, "AST ROOT");
|
||||
rootNode.setFirstChild(parserAST);
|
||||
|
||||
// unclear if this actually works, but it's worth a shot
|
||||
//
|
||||
//((CommonAST)parserAST).setVerboseStringConversion(
|
||||
// true, parser.getTokenNames());
|
||||
// (made to use the static version because of jikes 1.22 warning)
|
||||
CommonAST.setVerboseStringConversion(true, parser.getTokenNames());
|
||||
|
||||
// if this is an advanced program, the classname is already defined.
|
||||
//
|
||||
if (programType == JAVA) {
|
||||
name = getFirstClassName(parserAST);
|
||||
}
|
||||
|
||||
// if 'null' was passed in for the name, but this isn't
|
||||
// a 'java' mode class, then there's a problem, so punt.
|
||||
//
|
||||
this.buildPath = buildPath;
|
||||
|
||||
List prototypes = prototypes(program);
|
||||
|
||||
// store # of prototypes so that line number reporting can be adjusted
|
||||
prototypeCount = prototypes.size();
|
||||
|
||||
if (name == null) return null;
|
||||
|
||||
// output the code
|
||||
//
|
||||
PdeEmitter emitter = new PdeEmitter();
|
||||
//writeHeader(stream, extraImports, name);
|
||||
writeDeclaration(stream, name);
|
||||
File streamFile = new File(buildPath, name + ".cpp");
|
||||
PrintStream stream = new PrintStream(new FileOutputStream(streamFile));
|
||||
|
||||
emitter.setOut(stream);
|
||||
emitter.print(rootNode);
|
||||
|
||||
writeFooter(stream, name);
|
||||
writeHeader(stream);
|
||||
//added to write the pde code to the cpp file
|
||||
writeProgram(stream, program, prototypes);
|
||||
writeFooter(stream, target);
|
||||
stream.close();
|
||||
|
||||
// if desired, serialize the parse tree to an XML file. can
|
||||
// be viewed usefully with Mozilla or IE
|
||||
|
||||
if (Preferences.getBoolean("preproc.output_parse_tree")) {
|
||||
writeParseTree("parseTree.xml", parserAST);
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
protected void writeParseTree(String filename, AST ast) {
|
||||
try {
|
||||
PrintStream stream = new PrintStream(new FileOutputStream(filename));
|
||||
stream.println("<?xml version=\"1.0\"?>");
|
||||
stream.println("<document>");
|
||||
OutputStreamWriter writer = new OutputStreamWriter(stream);
|
||||
if (ast != null) {
|
||||
((CommonAST) ast).xmlSerialize(writer);
|
||||
// Write the pde program to the cpp file
|
||||
void writeProgram(PrintStream out, String program, List prototypes) {
|
||||
int prototypeInsertionPoint = firstStatement(program);
|
||||
|
||||
out.print(program.substring(0, prototypeInsertionPoint));
|
||||
out.print("#include \"WProgram.h\"\n");
|
||||
|
||||
// print user defined prototypes
|
||||
for (int i = 0; i < prototypes.size(); i++) {
|
||||
out.print(prototypes.get(i) + "\n");
|
||||
}
|
||||
writer.flush();
|
||||
stream.println("</document>");
|
||||
writer.close();
|
||||
} catch (IOException e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
int writeImports(PrintStream out) {
|
||||
out.println("import processing.core.*; ");
|
||||
out.println("import processing.xml.*; ");
|
||||
out.println();
|
||||
int count = 3;
|
||||
|
||||
if (programImports.size() != 0) {
|
||||
for (String item : programImports) {
|
||||
out.println("import " + item + "; ");
|
||||
}
|
||||
out.println();
|
||||
count += programImports.size() + 1;
|
||||
}
|
||||
|
||||
if (codeFolderImports.size() != 0) {
|
||||
for (String item : codeFolderImports) {
|
||||
out.println("import " + item + "; ");
|
||||
}
|
||||
out.println();
|
||||
count += codeFolderImports.size() + 1;
|
||||
}
|
||||
|
||||
for (String item : defaultImports) {
|
||||
out.println("import " + item + ".*; ");
|
||||
}
|
||||
out.println();
|
||||
count += defaultImports.length + 1;
|
||||
|
||||
return count;
|
||||
|
||||
out.print(program.substring(prototypeInsertionPoint));
|
||||
}
|
||||
|
||||
|
||||
@ -422,70 +335,30 @@ public class PdePreprocessor {
|
||||
* Write any required header material (eg imports, class decl stuff)
|
||||
*
|
||||
* @param out PrintStream to write it to.
|
||||
* @param exporting Is this being exported from PDE?
|
||||
* @param name Name of the class being created.
|
||||
*/
|
||||
void writeDeclaration(PrintStream out, String className) {
|
||||
|
||||
String indent = " ";
|
||||
|
||||
if (programType == JAVA) {
|
||||
// Print two blank lines so that the offset doesn't change
|
||||
out.println();
|
||||
out.println();
|
||||
|
||||
} else if (programType == ACTIVE) {
|
||||
// Print an extra blank line so the offset is identical to the others
|
||||
out.println("public class " + className + " extends PApplet {");
|
||||
out.println();
|
||||
|
||||
} else if (programType == STATIC) {
|
||||
out.println("public class " + className + " extends PApplet {");
|
||||
out.print(indent + "public void setup() {");
|
||||
}
|
||||
}
|
||||
void writeHeader(PrintStream out) throws IOException {}
|
||||
|
||||
/**
|
||||
* Write any necessary closing text.
|
||||
*
|
||||
* @param out PrintStream to write it to.
|
||||
* @param out PrintStream to write it to.
|
||||
*/
|
||||
void writeFooter(PrintStream out, String className) {
|
||||
void writeFooter(PrintStream out, Target target) throws java.lang.Exception {
|
||||
// Open the file main.cxx and copy its entire contents to the bottom of the
|
||||
// generated sketch .cpp file...
|
||||
|
||||
if (programType == STATIC) {
|
||||
// close off draw() definition
|
||||
out.println(indent + "noLoop();");
|
||||
out.println("} ");
|
||||
String mainFileName = target.getPath() + File.separator + "main.cxx";
|
||||
FileReader reader = null;
|
||||
reader = new FileReader(mainFileName);
|
||||
|
||||
LineNumberReader mainfile = new LineNumberReader(reader);
|
||||
|
||||
String line;
|
||||
while ((line = mainfile.readLine()) != null) {
|
||||
out.print(line + "\n");
|
||||
}
|
||||
|
||||
if ((programType == STATIC) || (programType == ACTIVE)) {
|
||||
if (!PdePreprocessor.foundMain) {
|
||||
out.println(indent + "static public void main(String args[]) {");
|
||||
out.print(indent + indent + "PApplet.main(new String[] { ");
|
||||
|
||||
if (Preferences.getBoolean("export.application.fullscreen")) {
|
||||
out.print("\"" + PApplet.ARGS_PRESENT + "\", ");
|
||||
|
||||
String farbe = Preferences.get("run.present.bgcolor");
|
||||
out.print("\"" + PApplet.ARGS_BGCOLOR + "=" + farbe + "\", ");
|
||||
|
||||
if (Preferences.getBoolean("export.application.stop")) {
|
||||
farbe = Preferences.get("run.present.stop.color");
|
||||
out.print("\"" + PApplet.ARGS_STOP_COLOR + "=" + farbe + "\", ");
|
||||
} else {
|
||||
out.print("\"" + PApplet.ARGS_HIDE_STOP + "\", ");
|
||||
}
|
||||
} else {
|
||||
String farbe = Preferences.get("run.window.bgcolor");
|
||||
out.print("\"" + PApplet.ARGS_BGCOLOR + "=" + farbe + "\", ");
|
||||
}
|
||||
out.println("\"" + className + "\" });");
|
||||
out.println(indent + "}");
|
||||
}
|
||||
|
||||
// close off the class definition
|
||||
out.println("}");
|
||||
}
|
||||
mainfile.close();
|
||||
}
|
||||
|
||||
|
||||
@ -494,11 +367,13 @@ public class PdePreprocessor {
|
||||
}
|
||||
|
||||
|
||||
static String advClassName = "";
|
||||
|
||||
/**
|
||||
* Find the first CLASS_DEF node in the tree, and return the name of the
|
||||
* class in question.
|
||||
*
|
||||
* TODO [dmose] right now, we're using a little hack to the grammar to get
|
||||
* XXXdmose right now, we're using a little hack to the grammar to get
|
||||
* this info. In fact, we should be descending the AST passed in.
|
||||
*/
|
||||
String getFirstClassName(AST ast) {
|
||||
@ -508,4 +383,5 @@ public class PdePreprocessor {
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,11 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
rm -f *Lexer.java
|
||||
rm -f *Recognizer.java
|
||||
rm -f *TokenTypes.java
|
||||
rm -f *TokenTypes.txt
|
||||
rm -f *TreeParser.java
|
||||
rm -f *TreeParserTokenTypes.java
|
||||
rm -f *TreeParserTokenTypes.txt
|
||||
rm -f expanded*.g
|
||||
|
@ -1,3 +0,0 @@
|
||||
java -cp ../../build/macosx/work/lib/antlr.jar antlr.Tool java.g
|
||||
# now build the pde stuff that extends the java classes
|
||||
java -cp ../../build/macosx/work/lib/antlr.jar antlr.Tool -glib java.g pde.g
|
@ -1,304 +0,0 @@
|
||||
/* -*- mode: antlr; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
header {
|
||||
package processing.app.preproc;
|
||||
|
||||
import processing.app.*;
|
||||
}
|
||||
|
||||
class PdeRecognizer extends JavaRecognizer;
|
||||
|
||||
options {
|
||||
importVocab = Java;
|
||||
exportVocab = PdePartial;
|
||||
|
||||
codeGenMakeSwitchThreshold=10; // this is set high for debugging
|
||||
codeGenBitsetTestThreshold=10; // this is set high for debugging
|
||||
|
||||
// developers may to want to set this to true for better
|
||||
// debugging messages, however, doing so disables highlighting errors
|
||||
// in the editor.
|
||||
defaultErrorHandler = false; //true;
|
||||
}
|
||||
|
||||
tokens {
|
||||
CONSTRUCTOR_CAST; EMPTY_FIELD;
|
||||
}
|
||||
|
||||
pdeProgram
|
||||
// only java mode programs will have their own public classes or
|
||||
// imports (and they must have at least one)
|
||||
: ( "public" "class" | "import" ) => javaProgram
|
||||
{ PdePreprocessor.programType = PdePreprocessor.JAVA; }
|
||||
|
||||
// the syntactic predicate here looks for any minimal (thus
|
||||
// the non-greedy qualifier) number of fields, followed by
|
||||
// the tokens that represent the definition of loop() or
|
||||
// some other member function. java mode programs may have such
|
||||
// definitions, but they won't reach this point, having already been
|
||||
// selected in the previous alternative. static mode programs
|
||||
// don't have member functions.
|
||||
//
|
||||
| ( ( options {greedy=false;}: possiblyEmptyField)* "void" IDENT LPAREN )
|
||||
=> activeProgram
|
||||
{ PdePreprocessor.programType = PdePreprocessor.ACTIVE; }
|
||||
|
||||
| staticProgram
|
||||
{ PdePreprocessor.programType = PdePreprocessor.STATIC; }
|
||||
;
|
||||
|
||||
// advanced mode is really just a normal java file
|
||||
javaProgram
|
||||
: compilationUnit
|
||||
;
|
||||
|
||||
activeProgram
|
||||
: (possiblyEmptyField)+
|
||||
;
|
||||
|
||||
staticProgram
|
||||
: (statement)*
|
||||
;
|
||||
|
||||
// copy of the java.g rule with WEBCOLOR_LITERAL added
|
||||
constant
|
||||
: NUM_INT
|
||||
| CHAR_LITERAL
|
||||
| STRING_LITERAL
|
||||
| NUM_FLOAT
|
||||
| NUM_LONG
|
||||
| NUM_DOUBLE
|
||||
| webcolor_literal
|
||||
;
|
||||
|
||||
// of the form #cc008f in PDE
|
||||
webcolor_literal
|
||||
: w:WEBCOLOR_LITERAL
|
||||
{ Preferences.getBoolean("preproc.web_colors") &&
|
||||
w.getText().length() == 6 }? // must be exactly 6 hex digits
|
||||
;
|
||||
|
||||
// copy of the java.g builtInType rule
|
||||
builtInConsCastType
|
||||
: "void"
|
||||
| "boolean"
|
||||
| "byte"
|
||||
| "char"
|
||||
| "short"
|
||||
| "int"
|
||||
| "float"
|
||||
| "long"
|
||||
| "double"
|
||||
;
|
||||
|
||||
// our types include the java types and "color". this is separated into two
|
||||
// rules so that constructor casts can just use the original typelist, since
|
||||
// we don't want to support the color type as a constructor cast.
|
||||
//
|
||||
builtInType
|
||||
: builtInConsCastType
|
||||
| "color" // aliased to an int in PDE
|
||||
{ Preferences.getBoolean("preproc.color_datatype") }?
|
||||
;
|
||||
|
||||
// constructor style casts.
|
||||
constructorCast!
|
||||
: t:consCastTypeSpec[true]
|
||||
LPAREN!
|
||||
e:expression
|
||||
RPAREN!
|
||||
// if this is a string literal, make sure the type we're trying to cast
|
||||
// to is one of the supported ones
|
||||
//
|
||||
{ #e.getType() != STRING_LITERAL ||
|
||||
( #t.getType() == LITERAL_byte ||
|
||||
#t.getType() == LITERAL_double ||
|
||||
#t.getType() == LITERAL_float ||
|
||||
#t.getType() == LITERAL_int ||
|
||||
#t.getType() == LITERAL_long ||
|
||||
#t.getType() == LITERAL_short ) }?
|
||||
// create the node
|
||||
//
|
||||
{#constructorCast = #(#[CONSTRUCTOR_CAST,"CONSTRUCTOR_CAST"], t, e);}
|
||||
;
|
||||
|
||||
// A list of types that be used as the destination type in a constructor-style
|
||||
// cast. Ideally, this would include all class types, not just "String".
|
||||
// Unfortunately, it's not possible to tell whether Foo(5) is supposed to be
|
||||
// a method call or a constructor cast without have a table of all valid
|
||||
// types or methods, which requires semantic analysis (eg processing of import
|
||||
// statements). So we accept the set of built-in types plus "String".
|
||||
//
|
||||
consCastTypeSpec[boolean addImagNode]
|
||||
// : stringTypeSpec[addImagNode]
|
||||
// | builtInConsCastTypeSpec[addImagNode]
|
||||
: builtInConsCastTypeSpec[addImagNode]
|
||||
// trying to remove String() cast [fry]
|
||||
;
|
||||
|
||||
//stringTypeSpec[boolean addImagNode]
|
||||
// : id:IDENT { #id.getText().equals("String") }?
|
||||
// {
|
||||
// if ( addImagNode ) {
|
||||
// #stringTypeSpec = #(#[TYPE,"TYPE"],
|
||||
// #stringTypeSpec);
|
||||
// }
|
||||
// }
|
||||
// ;
|
||||
|
||||
builtInConsCastTypeSpec[boolean addImagNode]
|
||||
: builtInConsCastType
|
||||
{
|
||||
if ( addImagNode ) {
|
||||
#builtInConsCastTypeSpec = #(#[TYPE,"TYPE"],
|
||||
#builtInConsCastTypeSpec);
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
// Since "color" tokens are lexed as LITERAL_color now, we need to have a rule
|
||||
// that can generate a method call from an expression that starts with this
|
||||
// token
|
||||
//
|
||||
colorMethodCall
|
||||
: c:"color" {#c.setType(IDENT);} // this would default to LITERAL_color
|
||||
lp:LPAREN^ {#lp.setType(METHOD_CALL);}
|
||||
argList
|
||||
RPAREN!
|
||||
;
|
||||
|
||||
// copy of the java.g rule with added constructorCast and colorMethodCall
|
||||
// alternatives
|
||||
primaryExpression
|
||||
: (consCastTypeSpec[false] LPAREN) => constructorCast
|
||||
{ Preferences.getBoolean("preproc.enhanced_casting") }?
|
||||
| identPrimary ( options {greedy=true;} : DOT^ "class" )?
|
||||
| constant
|
||||
| "true"
|
||||
| "false"
|
||||
| "null"
|
||||
| newExpression
|
||||
| "this"
|
||||
| "super"
|
||||
| LPAREN! assignmentExpression RPAREN!
|
||||
| colorMethodCall
|
||||
// look for int.class and int[].class
|
||||
| builtInType
|
||||
( lbt:LBRACK^ {#lbt.setType(ARRAY_DECLARATOR);} RBRACK! )*
|
||||
DOT^ "class"
|
||||
;
|
||||
|
||||
// the below variable rule hacks are needed so that it's possible for the
|
||||
// emitter to correctly output variable declarations of the form "float a, b"
|
||||
// from the AST. This means that our AST has a somewhat different form in
|
||||
// these rules than the java one does, and this new form may have its own
|
||||
// semantic issues. But it seems to fix the comma declaration issues.
|
||||
//
|
||||
variableDefinitions![AST mods, AST t]
|
||||
: vd:variableDeclarator[getASTFactory().dupTree(mods),
|
||||
getASTFactory().dupTree(t)]
|
||||
{#variableDefinitions = #(#[VARIABLE_DEF,"VARIABLE_DEF"], mods,
|
||||
t, vd);}
|
||||
;
|
||||
variableDeclarator[AST mods, AST t]
|
||||
: ( id:IDENT (lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!)*
|
||||
v:varInitializer (COMMA!)? )+
|
||||
;
|
||||
|
||||
// java.g builds syntax trees with an inconsistent structure. override one of
|
||||
// the rules there to fix this.
|
||||
//
|
||||
explicitConstructorInvocation!
|
||||
: t:"this" LPAREN a1:argList RPAREN SEMI
|
||||
{#explicitConstructorInvocation = #(#[CTOR_CALL, "CTOR_CALL"],
|
||||
#t, #a1);}
|
||||
| s:"super" LPAREN a2:argList RPAREN SEMI
|
||||
{#explicitConstructorInvocation = #(#[SUPER_CTOR_CALL,
|
||||
"SUPER_CTOR_CALL"],
|
||||
#s, #a2);}
|
||||
;
|
||||
|
||||
// quick-n-dirty hack to the get the advanced class name. we should
|
||||
// really be getting it from the AST and not forking this rule from
|
||||
// the java.g copy at all. Since this is a recursive descent parser, we get
|
||||
// the last class name in the file so that we don't end up with the classname
|
||||
// of an inner class. If there is more than one "outer" class in a file,
|
||||
// this heuristic will fail.
|
||||
//
|
||||
classDefinition![AST modifiers]
|
||||
: "class" i:IDENT
|
||||
// it _might_ have a superclass...
|
||||
sc:superClassClause
|
||||
// it might implement some interfaces...
|
||||
ic:implementsClause
|
||||
// now parse the body of the class
|
||||
cb:classBlock
|
||||
{#classDefinition = #(#[CLASS_DEF,"CLASS_DEF"],
|
||||
modifiers,i,sc,ic,cb);
|
||||
PdePreprocessor.advClassName = i.getText();}
|
||||
;
|
||||
|
||||
possiblyEmptyField
|
||||
: field
|
||||
| s:SEMI {#s.setType(EMPTY_FIELD);}
|
||||
;
|
||||
|
||||
class PdeLexer extends JavaLexer;
|
||||
|
||||
options {
|
||||
importVocab=PdePartial;
|
||||
exportVocab=Pde;
|
||||
}
|
||||
|
||||
// We need to preserve whitespace and commentary instead of ignoring
|
||||
// like the supergrammar does. Otherwise Jikes won't be able to give
|
||||
// us error messages that point to the equivalent PDE code.
|
||||
|
||||
// WS, SL_COMMENT, ML_COMMENT are copies of the original productions,
|
||||
// but with the SKIP assigment removed.
|
||||
|
||||
WS : ( ' '
|
||||
| '\t'
|
||||
| '\f'
|
||||
// handle newlines
|
||||
| ( options {generateAmbigWarnings=false;}
|
||||
: "\r\n" // Evil DOS
|
||||
| '\r' // Macintosh
|
||||
| '\n' // Unix (the right way)
|
||||
)
|
||||
{ newline(); }
|
||||
)+
|
||||
;
|
||||
|
||||
// Single-line comments
|
||||
SL_COMMENT
|
||||
: "//"
|
||||
(~('\n'|'\r'))* ('\n'|'\r'('\n')?)
|
||||
{newline();}
|
||||
;
|
||||
|
||||
// multiple-line comments
|
||||
ML_COMMENT
|
||||
: "/*"
|
||||
( /* '\r' '\n' can be matched in one alternative or by matching
|
||||
'\r' in one iteration and '\n' in another. I am trying to
|
||||
handle any flavor of newline that comes in, but the language
|
||||
that allows both "\r\n" and "\r" and "\n" to all be valid
|
||||
newline is ambiguous. Consequently, the resulting grammar
|
||||
must be ambiguous. I'm shutting this warning off.
|
||||
*/
|
||||
options {
|
||||
generateAmbigWarnings=false;
|
||||
}
|
||||
:
|
||||
{ LA(2)!='/' }? '*'
|
||||
| '\r' '\n' {newline();}
|
||||
| '\r' {newline();}
|
||||
| '\n' {newline();}
|
||||
| ~('*'|'\n'|'\r')
|
||||
)*
|
||||
"*/"
|
||||
;
|
||||
|
||||
WEBCOLOR_LITERAL
|
||||
: '#'! (HEX_DIGIT)+
|
||||
;
|
@ -1,150 +0,0 @@
|
||||
// this is a whitespace and other invisible token torture test for the ANTLR-based
|
||||
// preprocessor. edit pde.properties and set "editor.save_build_files" to true.
|
||||
// then, build this in processing. next, use
|
||||
//
|
||||
// diff -u --strip-trailing-cr \
|
||||
// work/sketchbook/default/whitespace_test/whitespace_test.pde \
|
||||
// work/lib/build/MyDemo.java
|
||||
//
|
||||
// to compare the files before and after preprocessing. There should not be
|
||||
// any differences.
|
||||
|
||||
import // comment test
|
||||
java.io.*;
|
||||
|
||||
// comment 1
|
||||
public class // post-class comment
|
||||
|
||||
// comment2
|
||||
|
||||
MyDemo extends BApplet implements // foo
|
||||
java.lang. // bar
|
||||
Cloneable {
|
||||
|
||||
//argh
|
||||
|
||||
public // foo
|
||||
String // bar
|
||||
fff = /*rheet */ "stuff";
|
||||
|
||||
static /*a*/ {
|
||||
/*foo*/
|
||||
/*bar*/
|
||||
six = 6;
|
||||
} /* b*/
|
||||
|
||||
static /*a*/ final /*b*/ int six;
|
||||
|
||||
void setup()
|
||||
{
|
||||
size(200, 200);
|
||||
background(255);
|
||||
|
||||
this . fff = /* ook */ (String)/*foo*/"yo";
|
||||
rectMode(CENTER_DIAMETER); // comment 1a
|
||||
noStroke();
|
||||
fill(255, 204, 0);
|
||||
|
||||
int q = /*a*/ - /*b*/ 1;
|
||||
|
||||
boolean c = /*a*/ ! /*b*/ true;
|
||||
}
|
||||
|
||||
int foo() /*a*/ throws /*b*/ java.lang.Exception /*c*/
|
||||
{
|
||||
int b = 7;
|
||||
switch /*a*/ ( /*b*/ b /*c*/ ) {
|
||||
case /*d*/ 1 /*e*/: /*f*/
|
||||
int c=9;
|
||||
/*g*/
|
||||
break; /*h*/
|
||||
default /*i*/ :
|
||||
int d=9;
|
||||
break;
|
||||
}
|
||||
|
||||
try { /* qq */
|
||||
loop(); /* rr */
|
||||
} catch /*ss*/ (java.lang.Exception ex) /*tt*/ {
|
||||
b = 8; /*tut*/
|
||||
throw /*utu*/ ex;
|
||||
} /*uu*/ finally /*vv*/ {
|
||||
b = 9;
|
||||
} /*ww*/
|
||||
|
||||
b /*aaa*/ = /*bbb*/ true /*ccc*/ ? /*ddd*/ 0 /*eee*/
|
||||
: /* fff*/ 1 /*ggg*/;
|
||||
return /*a*/ 5 /*b*/;
|
||||
}
|
||||
|
||||
// comment 2
|
||||
void loop()
|
||||
{
|
||||
|
||||
int arr1 /* VVV */ [ /* XXX */] /*YYY*/ ;
|
||||
int[] arr2 = { /*a*/ 2, 3 /*b*/ } /*c*/ ;
|
||||
|
||||
for /*a*/ (/*b*/ int j=0 /*c*/; /*d*/ j<2/*e*/ ; /*f*/ j++ /*g*/)
|
||||
/*h*/
|
||||
arr2[1] = 6;
|
||||
|
||||
/*foo*/
|
||||
;
|
||||
/*bar*/
|
||||
rect(width-mouseX, height-mouseY, 50, 50);
|
||||
rect(mouseX, mouseY, 50, 50);
|
||||
|
||||
if (/*a*/ arr2[1] == 6/*b*/) {
|
||||
/*c*/
|
||||
int d=7;
|
||||
} /*d*/else /*e*/{
|
||||
int e=8;
|
||||
/*f*/
|
||||
}
|
||||
|
||||
int f;
|
||||
if (/*aa*/ arr2[1] ==6 /*bb*/ )
|
||||
/*cc*/
|
||||
f=8; /*dd*/
|
||||
else /*ee*/
|
||||
f=10; /*ff*/
|
||||
|
||||
while ( /*aaa*/ f < 15) /*bbb*/ {
|
||||
f ++;
|
||||
} /*ggg*/
|
||||
|
||||
do /* aaaa */ {
|
||||
f++;
|
||||
} /*bbbb*/ while /*cccc*/ ( /*a*/ - /*b*/ 20 > f) /*dddd*/;
|
||||
|
||||
f = 2 * 3 + 4;
|
||||
|
||||
f = ( 2 * 3 ) + 4 + /*aa*/ -/*bb*/1;
|
||||
|
||||
f = 2 * ( 3 + 4 ) ;
|
||||
|
||||
fff = /*a*/ new /*b*/ String(/*c*/"foo"/*d*/) /*e*/;
|
||||
|
||||
int arr3[] = /*a*/ new /*b*/ int/*c*/[/*d*/] /*e*/ {1/*f*/,2};
|
||||
int arr4[][] = new /*a*/int/*b*/[1][2]/*c*/;
|
||||
|
||||
}
|
||||
|
||||
class Shoe
|
||||
{
|
||||
Shoe(String brand)
|
||||
{
|
||||
println(brand);
|
||||
}
|
||||
}
|
||||
|
||||
class NikeAir extends Shoe
|
||||
{
|
||||
NikeAir()
|
||||
{
|
||||
/*a*/ super /*b*/ ( /*c*/ "Nike" /*d*/ ) /*e*/ ;
|
||||
|
||||
/*aa*/ ( /*bb*/ new /*cc*/ MyDemo /*dd*/ (/*ee*/)/*ff*/)/*gg*/./*hh*/super/*ii*/(/*jj*/5/*kk*/);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user