From 29baba3b6eb9b323c9adfac05ce3d5c9dd52ff23 Mon Sep 17 00:00:00 2001
From: Michael Zangl <michael.zangl@student.kit.edu>
Date: Wed, 1 Jul 2015 15:10:08 +0200
Subject: [PATCH 8/8] Moved global SOM management out of NavigationComponent to
 SystemOfMeasurement class

---
 .../josm/actions/mapmode/ParallelWayAction.java    |    3 +-
 .../josm/data/SystemOfMeasurement.java             |   74 +
 src/org/openstreetmap/josm/gui/MapStatus.java      |    8 +-
 .../josm/gui/NavigatableComponent.java             |   79 +-
 src/org/openstreetmap/josm/gui/layer/GpxLayer.java |    5 +-
 .../gui/layer/gpx/ChooseTrackVisibilityAction.java |    4 +-
 .../mappaint/mapcss/parsergen/MapCSSParser.java    | 3650 ++++++++++++++++++++
 .../mapcss/parsergen/MapCSSParserConstants.java    |  195 ++
 .../mapcss/parsergen/MapCSSParserTokenManager.java | 1450 ++++++++
 .../mappaint/mapcss/parsergen/ParseException.java  |  195 ++
 .../mapcss/parsergen/SimpleCharStream.java         |  474 +++
 .../josm/gui/mappaint/mapcss/parsergen/Token.java  |  131 +
 .../mappaint/mapcss/parsergen/TokenMgrError.java   |  146 +
 .../projection/ProjectionPreference.java           |    3 +-
 14 files changed, 6352 insertions(+), 65 deletions(-)
 create mode 100644 src/org/openstreetmap/josm/gui/mappaint/mapcss/parsergen/MapCSSParser.java
 create mode 100644 src/org/openstreetmap/josm/gui/mappaint/mapcss/parsergen/MapCSSParserConstants.java
 create mode 100644 src/org/openstreetmap/josm/gui/mappaint/mapcss/parsergen/MapCSSParserTokenManager.java
 create mode 100644 src/org/openstreetmap/josm/gui/mappaint/mapcss/parsergen/ParseException.java
 create mode 100644 src/org/openstreetmap/josm/gui/mappaint/mapcss/parsergen/SimpleCharStream.java
 create mode 100644 src/org/openstreetmap/josm/gui/mappaint/mapcss/parsergen/Token.java
 create mode 100644 src/org/openstreetmap/josm/gui/mappaint/mapcss/parsergen/TokenMgrError.java

diff --git a/src/org/openstreetmap/josm/actions/mapmode/ParallelWayAction.java b/src/org/openstreetmap/josm/actions/mapmode/ParallelWayAction.java
index 9f1d4d5..f09880b 100644
--- a/src/org/openstreetmap/josm/actions/mapmode/ParallelWayAction.java
+++ b/src/org/openstreetmap/josm/actions/mapmode/ParallelWayAction.java
@@ -31,7 +31,6 @@ import org.openstreetmap.josm.data.osm.WaySegment;
 import org.openstreetmap.josm.data.osm.visitor.paint.PaintColors;
 import org.openstreetmap.josm.gui.MapFrame;
 import org.openstreetmap.josm.gui.MapView;
-import org.openstreetmap.josm.gui.NavigatableComponent;
 import org.openstreetmap.josm.gui.layer.Layer;
 import org.openstreetmap.josm.gui.layer.MapViewPaintable;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
@@ -423,7 +422,7 @@ public class ParallelWayAction extends MapMode implements ModifierListener, MapV
             // TODO: Very simple snapping
             // - Snap steps relative to the distance?
             double snapDistance;
-            SystemOfMeasurement som = NavigatableComponent.getSystemOfMeasurement();
+            SystemOfMeasurement som = SystemOfMeasurement.getSystemOfMeasurement();
             if (som.equals(SystemOfMeasurement.CHINESE)) {
                 snapDistance = snapDistanceChinese * SystemOfMeasurement.CHINESE.aValue;
             } else if (som.equals(SystemOfMeasurement.IMPERIAL)) {
diff --git a/src/org/openstreetmap/josm/data/SystemOfMeasurement.java b/src/org/openstreetmap/josm/data/SystemOfMeasurement.java
index ba694b3..1a3bb86 100644
--- a/src/org/openstreetmap/josm/data/SystemOfMeasurement.java
+++ b/src/org/openstreetmap/josm/data/SystemOfMeasurement.java
@@ -7,17 +7,33 @@ import java.text.NumberFormat;
 import java.util.LinkedHashMap;
 import java.util.Locale;
 import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.preferences.projection.ProjectionPreference;
 
 /**
  * A system of units used to express length and area measurements.
+ * <p>
+ * This class also manages one globally set system of measurement stored in the {@link ProjectionPreference}
  * @since 3406 (creation)
  * @since 6992 (extraction in this package)
  */
 public class SystemOfMeasurement {
 
     /**
+     * Interface to notify listeners of the change of the system of measurement.
+     */
+    public interface SoMChangeListener {
+        /**
+         * The current SoM has changed.
+         * @param oldSoM The old system of measurement
+         * @param newSoM The new (current) system of measurement
+         */
+        void systemOfMeasurementChanged(String oldSoM, String newSoM);
+    }
+
+    /**
      * Metric system (international standard).
      * @since 3406
      */
@@ -54,6 +70,64 @@ public class SystemOfMeasurement {
         ALL_SYSTEMS.put(marktr("Nautical Mile"), NAUTICAL_MILE);
     }
 
+    private static final CopyOnWriteArrayList<SoMChangeListener> somChangeListeners = new CopyOnWriteArrayList<>();
+
+    /**
+     * Removes a global SoM change listener
+     *
+     * @param listener the listener. Ignored if null or already absent
+     * @since 6056
+     */
+    public static void removeSoMChangeListener(SoMChangeListener listener) {
+        somChangeListeners.remove(listener);
+    }
+
+    /**
+     * Adds a SoM change listener
+     *
+     * @param listener the listener. Ignored if null or already registered.
+     * @since 6056
+     */
+    public static void addSoMChangeListener(SoMChangeListener listener) {
+        if (listener != null) {
+            somChangeListeners.addIfAbsent(listener);
+        }
+    }
+
+    protected static void fireSoMChanged(String oldSoM, String newSoM) {
+        for (SoMChangeListener l : somChangeListeners) {
+            l.systemOfMeasurementChanged(oldSoM, newSoM);
+        }
+    }
+
+    /**
+     * Returns the current global system of measurement.
+     * @return The current system of measurement (metric system by default).
+     * @since 3490
+     */
+    public static SystemOfMeasurement getSystemOfMeasurement() {
+        SystemOfMeasurement som = SystemOfMeasurement.ALL_SYSTEMS.get(ProjectionPreference.PROP_SYSTEM_OF_MEASUREMENT.get());
+        if (som == null)
+            return SystemOfMeasurement.METRIC;
+        return som;
+    }
+
+    /**
+     * Sets the current global system of measurement.
+     * @param somKey The system of measurement key. Must be defined in {@link SystemOfMeasurement#ALL_SYSTEMS}.
+     * @throws IllegalArgumentException if {@code somKey} is not known
+     * @since 6056
+     */
+    public static void setSystemOfMeasurement(String somKey) {
+        if (!SystemOfMeasurement.ALL_SYSTEMS.containsKey(somKey)) {
+            throw new IllegalArgumentException("Invalid system of measurement: "+somKey);
+        }
+        String oldKey = ProjectionPreference.PROP_SYSTEM_OF_MEASUREMENT.get();
+        if (ProjectionPreference.PROP_SYSTEM_OF_MEASUREMENT.put(somKey)) {
+            fireSoMChanged(oldKey, somKey);
+        }
+    }
+
     /** First value, in meters, used to translate unit according to above formula. */
     public final double aValue;
     /** Second value, in meters, used to translate unit according to above formula. */
diff --git a/src/org/openstreetmap/josm/gui/MapStatus.java b/src/org/openstreetmap/josm/gui/MapStatus.java
index 61f1604..51e87e2 100644
--- a/src/org/openstreetmap/josm/gui/MapStatus.java
+++ b/src/org/openstreetmap/josm/gui/MapStatus.java
@@ -53,13 +53,13 @@ import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.Preferences.PreferenceChangeEvent;
 import org.openstreetmap.josm.data.Preferences.PreferenceChangedListener;
 import org.openstreetmap.josm.data.SystemOfMeasurement;
+import org.openstreetmap.josm.data.SystemOfMeasurement.SoMChangeListener;
 import org.openstreetmap.josm.data.coor.CoordinateFormat;
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.data.preferences.ColorProperty;
-import org.openstreetmap.josm.gui.NavigatableComponent.SoMChangeListener;
 import org.openstreetmap.josm.gui.help.Helpful;
 import org.openstreetmap.josm.gui.preferences.projection.ProjectionPreference;
 import org.openstreetmap.josm.gui.progress.PleaseWaitProgressMonitor;
@@ -864,7 +864,7 @@ public class MapStatus extends JPanel implements Helpful, Destroyable, Preferenc
             });
         }
 
-        NavigatableComponent.addSoMChangeListener(somListener = new SoMChangeListener() {
+        SystemOfMeasurement.addSoMChangeListener(somListener = new SoMChangeListener() {
             @Override
             public void systemOfMeasurementChanged(String oldSoM, String newSoM) {
                 setDist(distValue);
@@ -907,7 +907,7 @@ public class MapStatus extends JPanel implements Helpful, Destroyable, Preferenc
      * @since 6960
      */
     public void updateSystemOfMeasurement(String newsom) {
-        NavigatableComponent.setSystemOfMeasurement(newsom);
+        SystemOfMeasurement.setSystemOfMeasurement(newsom);
         if (Main.pref.getBoolean("statusbar.notify.change-system-of-measurement", true)) {
             new Notification(tr("System of measurement changed to {0}", newsom))
                 .setDuration(Notification.TIME_SHORT)
@@ -1019,7 +1019,7 @@ public class MapStatus extends JPanel implements Helpful, Destroyable, Preferenc
 
     @Override
     public void destroy() {
-        NavigatableComponent.removeSoMChangeListener(somListener);
+        SystemOfMeasurement.removeSoMChangeListener(somListener);
         Main.pref.removePreferenceChangeListener(this);
 
         // MapFrame gets destroyed when the last layer is removed, but the status line background
diff --git a/src/org/openstreetmap/josm/gui/NavigatableComponent.java b/src/org/openstreetmap/josm/gui/NavigatableComponent.java
index 03e70fe..c5505f9 100644
--- a/src/org/openstreetmap/josm/gui/NavigatableComponent.java
+++ b/src/org/openstreetmap/josm/gui/NavigatableComponent.java
@@ -51,7 +51,6 @@ import org.openstreetmap.josm.gui.download.DownloadDialog;
 import org.openstreetmap.josm.gui.help.Helpful;
 import org.openstreetmap.josm.gui.mappaint.MapPaintStyles;
 import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSStyleSource;
-import org.openstreetmap.josm.gui.preferences.projection.ProjectionPreference;
 import org.openstreetmap.josm.tools.Predicate;
 import org.openstreetmap.josm.tools.Utils;
 
@@ -78,13 +77,7 @@ public class NavigatableComponent extends JComponent implements Helpful {
      * Interface to notify listeners of the change of the system of measurement.
      * @since 6056
      */
-    public interface SoMChangeListener {
-        /**
-         * The current SoM has changed.
-         * @param oldSoM The old system of measurement
-         * @param newSoM The new (current) system of measurement
-         */
-        void systemOfMeasurementChanged(String oldSoM, String newSoM);
+    public interface SoMChangeListener extends SystemOfMeasurement.SoMChangeListener {
     }
 
     public transient Predicate<OsmPrimitive> isSelectablePredicate = new Predicate<OsmPrimitive>() {
@@ -137,7 +130,6 @@ public class NavigatableComponent extends JComponent implements Helpful {
         }
     }
 
-    private static final CopyOnWriteArrayList<SoMChangeListener> somChangeListeners = new CopyOnWriteArrayList<>();
 
     /**
      * Removes a SoM change listener
@@ -145,8 +137,9 @@ public class NavigatableComponent extends JComponent implements Helpful {
      * @param listener the listener. Ignored if null or already absent
      * @since 6056
      */
+    @Deprecated
     public static void removeSoMChangeListener(NavigatableComponent.SoMChangeListener listener) {
-        somChangeListeners.remove(listener);
+        SystemOfMeasurement.removeSoMChangeListener(listener);
     }
 
     /**
@@ -155,25 +148,33 @@ public class NavigatableComponent extends JComponent implements Helpful {
      * @param listener the listener. Ignored if null or already registered.
      * @since 6056
      */
+    @Deprecated
     public static void addSoMChangeListener(NavigatableComponent.SoMChangeListener listener) {
-        if (listener != null) {
-            somChangeListeners.addIfAbsent(listener);
-        }
+        SystemOfMeasurement.addSoMChangeListener(listener);
     }
 
-    protected static void fireSoMChanged(String oldSoM, String newSoM) {
-        for (SoMChangeListener l : somChangeListeners) {
-            l.systemOfMeasurementChanged(oldSoM, newSoM);
-        }
+    /**
+     * Returns the current system of measurement.
+     * @return The current system of measurement (metric system by default).
+     * @since 3490
+     */
+    @Deprecated
+    public static SystemOfMeasurement getSystemOfMeasurement() {
+        return SystemOfMeasurement.getSystemOfMeasurement();
     }
 
     /**
-     * The scale factor in x or y-units per pixel. This means, if scale = 10,
-     * every physical pixel on screen are 10 x or 10 y units in the
-     * northing/easting space of the projection.
+     * Sets the current system of measurement.
+     * @param somKey The system of measurement key. Must be defined in {@link SystemOfMeasurement#ALL_SYSTEMS}.
+     * @throws IllegalArgumentException if {@code somKey} is not known
+     * @since 6056
      */
-    private double scale = Main.getProjection().getDefaultZoomInPPD();
+    @Deprecated
+    public static void setSystemOfMeasurement(String somKey) {
+        SystemOfMeasurement.setSystemOfMeasurement(somKey);
+    }
 
+    private double scale = Main.getProjection().getDefaultZoomInPPD();
     /**
      * Center n/e coordinate of the desired screen center.
      */
@@ -211,7 +212,7 @@ public class NavigatableComponent extends JComponent implements Helpful {
      * @since 3406
      */
     public static String getDistText(double dist) {
-        return getSystemOfMeasurement().getDistText(dist);
+        return SystemOfMeasurement.getSystemOfMeasurement().getDistText(dist);
     }
 
     /**
@@ -223,7 +224,7 @@ public class NavigatableComponent extends JComponent implements Helpful {
      * @since 7135
      */
     public static String getDistText(final double dist, final NumberFormat format, final double threshold) {
-        return getSystemOfMeasurement().getDistText(dist, format, threshold);
+        return SystemOfMeasurement.getSystemOfMeasurement().getDistText(dist, format, threshold);
     }
 
     /**
@@ -233,7 +234,7 @@ public class NavigatableComponent extends JComponent implements Helpful {
      * @since 5560
      */
     public static String getAreaText(double area) {
-        return getSystemOfMeasurement().getAreaText(area);
+        return SystemOfMeasurement.getSystemOfMeasurement().getAreaText(area);
     }
 
     /**
@@ -245,7 +246,7 @@ public class NavigatableComponent extends JComponent implements Helpful {
      * @since 7135
      */
     public static String getAreaText(final double area, final NumberFormat format, final double threshold) {
-        return getSystemOfMeasurement().getAreaText(area, format, threshold);
+        return SystemOfMeasurement.getSystemOfMeasurement().getAreaText(area, format, threshold);
     }
 
     public String getDist100PixelText() {
@@ -1434,34 +1435,6 @@ public class NavigatableComponent extends JComponent implements Helpful {
         return (int) id.getValue();
     }
 
-    /**
-     * Returns the current system of measurement.
-     * @return The current system of measurement (metric system by default).
-     * @since 3490
-     */
-    public static SystemOfMeasurement getSystemOfMeasurement() {
-        SystemOfMeasurement som = SystemOfMeasurement.ALL_SYSTEMS.get(ProjectionPreference.PROP_SYSTEM_OF_MEASUREMENT.get());
-        if (som == null)
-            return SystemOfMeasurement.METRIC;
-        return som;
-    }
-
-    /**
-     * Sets the current system of measurement.
-     * @param somKey The system of measurement key. Must be defined in {@link SystemOfMeasurement#ALL_SYSTEMS}.
-     * @throws IllegalArgumentException if {@code somKey} is not known
-     * @since 6056
-     */
-    public static void setSystemOfMeasurement(String somKey) {
-        if (!SystemOfMeasurement.ALL_SYSTEMS.containsKey(somKey)) {
-            throw new IllegalArgumentException("Invalid system of measurement: "+somKey);
-        }
-        String oldKey = ProjectionPreference.PROP_SYSTEM_OF_MEASUREMENT.get();
-        if (ProjectionPreference.PROP_SYSTEM_OF_MEASUREMENT.put(somKey)) {
-            fireSoMChanged(oldKey, somKey);
-        }
-    }
-
     private static class CursorInfo {
         private final Cursor cursor;
         private final Object object;
diff --git a/src/org/openstreetmap/josm/gui/layer/GpxLayer.java b/src/org/openstreetmap/josm/gui/layer/GpxLayer.java
index cca96d9..9d188a4 100644
--- a/src/org/openstreetmap/josm/gui/layer/GpxLayer.java
+++ b/src/org/openstreetmap/josm/gui/layer/GpxLayer.java
@@ -25,6 +25,7 @@ import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.actions.RenameLayerAction;
 import org.openstreetmap.josm.actions.SaveActionBase;
 import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.SystemOfMeasurement;
 import org.openstreetmap.josm.data.gpx.GpxConstants;
 import org.openstreetmap.josm.data.gpx.GpxData;
 import org.openstreetmap.josm.data.gpx.GpxTrack;
@@ -149,7 +150,7 @@ public class GpxLayer extends Layer {
                 info.append("</td><td>");
                 info.append(getTimespanForTrack(trk));
                 info.append("</td><td>");
-                info.append(NavigatableComponent.getSystemOfMeasurement().getDistText(trk.length()));
+                info.append(SystemOfMeasurement.getSystemOfMeasurement().getDistText(trk.length()));
                 info.append("</td><td>");
                 if (trk.getAttributes().containsKey("url")) {
                     info.append(trk.get("url"));
@@ -221,7 +222,7 @@ public class GpxLayer extends Layer {
         info.append(trn("{0} track, ", "{0} tracks, ", data.tracks.size(), data.tracks.size()))
             .append(trn("{0} route, ", "{0} routes, ", data.routes.size(), data.routes.size()))
             .append(trn("{0} waypoint", "{0} waypoints", data.waypoints.size(), data.waypoints.size())).append("<br>")
-            .append(tr("Length: {0}", NavigatableComponent.getSystemOfMeasurement().getDistText(data.length())))
+            .append(tr("Length: {0}", SystemOfMeasurement.getSystemOfMeasurement().getDistText(data.length())))
             .append("<br></html>");
         return info.toString();
     }
diff --git a/src/org/openstreetmap/josm/gui/layer/gpx/ChooseTrackVisibilityAction.java b/src/org/openstreetmap/josm/gui/layer/gpx/ChooseTrackVisibilityAction.java
index d1b7ac1..848da50 100644
--- a/src/org/openstreetmap/josm/gui/layer/gpx/ChooseTrackVisibilityAction.java
+++ b/src/org/openstreetmap/josm/gui/layer/gpx/ChooseTrackVisibilityAction.java
@@ -32,10 +32,10 @@ import javax.swing.table.TableCellRenderer;
 import javax.swing.table.TableRowSorter;
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.SystemOfMeasurement;
 import org.openstreetmap.josm.data.gpx.GpxConstants;
 import org.openstreetmap.josm.data.gpx.GpxTrack;
 import org.openstreetmap.josm.gui.ExtendedDialog;
-import org.openstreetmap.josm.gui.NavigatableComponent;
 import org.openstreetmap.josm.gui.layer.GpxLayer;
 import org.openstreetmap.josm.tools.GBC;
 import org.openstreetmap.josm.tools.ImageProvider;
@@ -82,7 +82,7 @@ public class ChooseTrackVisibilityAction extends AbstractAction {
          */
         @Override
         public String toString() {
-            return NavigatableComponent.getSystemOfMeasurement().getDistText(value);
+            return SystemOfMeasurement.getSystemOfMeasurement().getDistText(value);
         }
     }
 
diff --git a/src/org/openstreetmap/josm/gui/mappaint/mapcss/parsergen/MapCSSParser.java b/src/org/openstreetmap/josm/gui/mappaint/mapcss/parsergen/MapCSSParser.java
new file mode 100644
index 0000000..fb4a00b
--- /dev/null
+++ b/src/org/openstreetmap/josm/gui/mappaint/mapcss/parsergen/MapCSSParser.java
@@ -0,0 +1,3650 @@
+/* MapCSSParser.java */
+/* Generated By:JavaCC: Do not edit this line. MapCSSParser.java */
+package org.openstreetmap.josm.gui.mappaint.mapcss.parsergen;
+
+import java.io.InputStream;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.mappaint.Keyword;
+import org.openstreetmap.josm.gui.mappaint.mapcss.Condition;
+import org.openstreetmap.josm.gui.mappaint.mapcss.Condition.Context;
+import org.openstreetmap.josm.gui.mappaint.mapcss.Expression;
+import org.openstreetmap.josm.gui.mappaint.mapcss.ExpressionFactory;
+import org.openstreetmap.josm.gui.mappaint.mapcss.ExpressionFactory.NullExpression;
+import org.openstreetmap.josm.gui.mappaint.mapcss.Instruction;
+import org.openstreetmap.josm.gui.mappaint.mapcss.LiteralExpression;
+import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSException;
+import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSRule;
+import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSRule.Declaration;
+import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSStyleSource;
+import org.openstreetmap.josm.gui.mappaint.mapcss.Selector;
+import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.ChildOrParentSelector;
+import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.GeneralSelector;
+import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.LinkSelector;
+import org.openstreetmap.josm.gui.mappaint.mapcss.Subpart;
+import org.openstreetmap.josm.tools.ColorHelper;
+import org.openstreetmap.josm.tools.Pair;
+import org.openstreetmap.josm.tools.Utils;
+
+/**
+ * MapCSS parser.
+ *
+ * Contains two independent grammars:
+ * (a) the preprocessor and (b) the main mapcss parser.
+ *
+ * The preprocessor handles @supports and @media syntax (@media is deprecated).
+ * Basically this allows to write one style for different versions of JOSM (or different editors).
+ * When the @supports condition is not fulfilled, it should simply skip over
+ * the whole section and not attempt to parse the possibly unknown
+ * grammar. It preserves whitespace and comments, in order to keep the
+ * line and column numbers in the error messages correct for the second pass.
+ *
+ */
+
+public class MapCSSParser implements MapCSSParserConstants {
+    MapCSSStyleSource sheet;
+    StringBuilder sb;
+    int declarationCounter;
+
+    /**
+     * Nicer way to refer to a lexical state.
+     */
+    public static enum LexicalState {
+        PREPROCESSOR(0), /* the preprocessor */
+        DEFAULT(2);      /* the main parser */
+
+        int idx; // the integer, which javacc assigns to this state
+
+        LexicalState(int idx) {
+            if (!this.name().equals(MapCSSParserTokenManager.lexStateNames[idx])) {
+                throw new RuntimeException();
+            }
+            this.idx = idx;
+        }
+    };
+
+    /**
+     * Constructor which initializes the parser with a certain lexical state.
+     */
+    public MapCSSParser(InputStream in, String encoding, LexicalState initState) {
+        this(createTokenManager(in, encoding, initState));
+        declarationCounter = 0;
+    }
+
+    protected static MapCSSParserTokenManager createTokenManager(InputStream in, String encoding, LexicalState initState) {
+        SimpleCharStream scs;
+        try {
+            scs = new SimpleCharStream(in, encoding, 1, 1);
+        } catch (java.io.UnsupportedEncodingException e) {
+            throw new RuntimeException(e);
+        }
+        return new MapCSSParserTokenManager(scs, initState.idx);
+    }
+
+    /**
+     * Constructor which initializes the parser with a certain lexical state.
+     */
+    public MapCSSParser(Reader in, LexicalState initState) {
+        this(createTokenManager(in, initState));
+        declarationCounter = 0;
+    }
+
+    protected static MapCSSParserTokenManager createTokenManager(Reader in, LexicalState initState) {
+        final SimpleCharStream scs = new SimpleCharStream(in, 1, 1);
+        return new MapCSSParserTokenManager(scs, initState.idx);
+    }
+
+/*************
+ *
+ * Preprocessor parser definitions:
+ *
+ * <pre>
+ *
+ * {@literal @media} { ... } queries are supported, following http://www.w3.org/TR/css3-mediaqueries/#syntax
+ *
+ *                               media_query
+ *         ___________________________|_______________________________
+ *        |                                                           |
+ * {@literal @media} all and (min-josm-version: 7789) and (max-josm-version: 7790), all and (user-agent: xyz) { ... }
+ *                |______________________|
+ *                          |
+ *                    media_expression
+ * </pre>
+ */
+
+
+/**
+ * root method for the preprocessor.
+ */
+  final public String pp_root(MapCSSStyleSource sheet) throws ParseException {
+sb = new StringBuilder(); this.sheet = sheet;
+    pp_black_box(true);
+    jj_consume_token(0);
+{if ("" != null) return sb.toString();}
+    throw new Error("Missing return statement in function");
+  }
+
+/**
+ * Parse any unknown grammar (black box).
+ *
+ * Only stop when "@media" is encountered and keep track of correct number of
+ * opening and closing curly brackets.
+ *
+ * @param write false if this content should be skipped (@pp_media condition is not fulfilled), true otherwise
+ */
+  final public void pp_black_box(boolean write) throws ParseException {Token t;
+    label_1:
+    while (true) {
+      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+      case PP_AND:
+      case PP_OR:
+      case PP_NOT:
+      case PP_SUPPORTS:
+      case PP_MEDIA:
+      case PP_NEWLINECHAR:
+      case PP_WHITESPACE:
+      case PP_COMMENT_START:
+      case IDENT:
+      case UINT:
+      case STRING:
+      case REGEX:
+      case LBRACE:
+      case LPAR:
+      case RPAR:
+      case COMMA:
+      case COLON:
+      case PP_SOMETHING_ELSE:{
+        ;
+        break;
+        }
+      default:
+        jj_la1[0] = jj_gen;
+        break label_1;
+      }
+      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+      case PP_AND:
+      case PP_OR:
+      case PP_NOT:
+      case IDENT:
+      case UINT:
+      case STRING:
+      case REGEX:
+      case LPAR:
+      case RPAR:
+      case COMMA:
+      case COLON:
+      case PP_SOMETHING_ELSE:{
+        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+        case PP_AND:{
+          t = jj_consume_token(PP_AND);
+          break;
+          }
+        case PP_OR:{
+          t = jj_consume_token(PP_OR);
+          break;
+          }
+        case PP_NOT:{
+          t = jj_consume_token(PP_NOT);
+          break;
+          }
+        case UINT:{
+          t = jj_consume_token(UINT);
+          break;
+          }
+        case STRING:{
+          t = jj_consume_token(STRING);
+          break;
+          }
+        case REGEX:{
+          t = jj_consume_token(REGEX);
+          break;
+          }
+        case LPAR:{
+          t = jj_consume_token(LPAR);
+          break;
+          }
+        case RPAR:{
+          t = jj_consume_token(RPAR);
+          break;
+          }
+        case COMMA:{
+          t = jj_consume_token(COMMA);
+          break;
+          }
+        case COLON:{
+          t = jj_consume_token(COLON);
+          break;
+          }
+        case IDENT:{
+          t = jj_consume_token(IDENT);
+          break;
+          }
+        case PP_SOMETHING_ELSE:{
+          t = jj_consume_token(PP_SOMETHING_ELSE);
+          break;
+          }
+        default:
+          jj_la1[1] = jj_gen;
+          jj_consume_token(-1);
+          throw new ParseException();
+        }
+if (write) sb.append(t.image);
+        break;
+        }
+      case PP_NEWLINECHAR:
+      case PP_WHITESPACE:
+      case PP_COMMENT_START:{
+        pp_w1();
+        break;
+        }
+      case PP_SUPPORTS:{
+        pp_supports(!write);
+        break;
+        }
+      case PP_MEDIA:{
+        pp_media(!write);
+        break;
+        }
+      case LBRACE:{
+        t = jj_consume_token(LBRACE);
+if (write) sb.append(t.image);
+        pp_black_box(write);
+        t = jj_consume_token(RBRACE);
+if (write) sb.append(t.image);
+        break;
+        }
+      default:
+        jj_la1[2] = jj_gen;
+        jj_consume_token(-1);
+        throw new ParseException();
+      }
+    }
+  }
+
+/**
+ * Parses an @supports rule.
+ *
+ * @param ignore if the content of this rule should be ignored
+ * (because we are already inside a @supports block that didn't pass)
+ */
+  final public void pp_supports(boolean ignore) throws ParseException {boolean pass;
+    jj_consume_token(PP_SUPPORTS);
+    pp_w();
+    pass = pp_supports_condition();
+    jj_consume_token(LBRACE);
+    pp_black_box(pass && !ignore);
+    jj_consume_token(RBRACE);
+  }
+
+/**
+ * Parses the condition of the @supports rule.
+ *
+ * Unlike other parsing rules, grabs trailing whitespace.
+ * @return true, if the condition is fulfilled
+ */
+  final public boolean pp_supports_condition() throws ParseException {boolean pass;
+    boolean q;
+    switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+    case PP_NOT:{
+      jj_consume_token(PP_NOT);
+      pp_w();
+      q = pp_supports_condition_in_parens();
+pass = !q;
+      pp_w();
+      break;
+      }
+    default:
+      jj_la1[5] = jj_gen;
+      if (jj_2_1(2147483647)) {
+        pass = pp_supports_condition_in_parens();
+        pp_w();
+        label_2:
+        while (true) {
+          jj_consume_token(PP_AND);
+          pp_w();
+          q = pp_supports_condition_in_parens();
+pass = pass && q;
+          pp_w();
+          switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+          case PP_AND:{
+            ;
+            break;
+            }
+          default:
+            jj_la1[3] = jj_gen;
+            break label_2;
+          }
+        }
+      } else if (jj_2_2(2147483647)) {
+        pass = pp_supports_condition_in_parens();
+        pp_w();
+        label_3:
+        while (true) {
+          jj_consume_token(PP_OR);
+          pp_w();
+          q = pp_supports_condition_in_parens();
+pass = pass || q;
+          pp_w();
+          switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+          case PP_OR:{
+            ;
+            break;
+            }
+          default:
+            jj_la1[4] = jj_gen;
+            break label_3;
+          }
+        }
+      } else {
+        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+        case LPAR:{
+          pass = pp_supports_condition_in_parens();
+          pp_w();
+          break;
+          }
+        default:
+          jj_la1[6] = jj_gen;
+          jj_consume_token(-1);
+          throw new ParseException();
+        }
+      }
+    }
+{if ("" != null) return pass;}
+    throw new Error("Missing return statement in function");
+  }
+
+/**
+ * Parses something in parenthesis inside the condition of the @supports rule.
+ *
+ * @return true, if the condition is fulfilled
+ */
+  final public boolean pp_supports_condition_in_parens() throws ParseException {boolean pass;
+    if (jj_2_3(2147483647)) {
+      pass = pp_supports_declaration_condition();
+    } else {
+      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+      case LPAR:{
+        jj_consume_token(LPAR);
+        pp_w();
+        pass = pp_supports_condition();
+        jj_consume_token(RPAR);
+        break;
+        }
+      default:
+        jj_la1[7] = jj_gen;
+        jj_consume_token(-1);
+        throw new ParseException();
+      }
+    }
+{if ("" != null) return pass;}
+    throw new Error("Missing return statement in function");
+  }
+
+/**
+ * Parse an @supports declaration condition, e.&nbsp;g. a single (key:value) or (key) statement.
+ *
+ * The parsing rule {@link #literal()} from the main mapcss parser is reused here.
+ *
+ * @return true if the condition is fulfilled
+ */
+  final public boolean pp_supports_declaration_condition() throws ParseException {Token t;
+    String feature;
+    Object val = null;
+    jj_consume_token(LPAR);
+    pp_w();
+    t = jj_consume_token(IDENT);
+feature = t.image;
+    pp_w();
+    switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+    case COLON:{
+      jj_consume_token(COLON);
+      pp_w();
+      val = literal();
+      break;
+      }
+    default:
+      jj_la1[8] = jj_gen;
+      ;
+    }
+    jj_consume_token(RPAR);
+{if ("" != null) return this.sheet.evalSupportsDeclCondition(feature, val);}
+    throw new Error("Missing return statement in function");
+  }
+
+// deprecated
+  final public void pp_media(boolean ignore) throws ParseException {boolean pass = false;
+    boolean q;
+    boolean empty = true;
+    jj_consume_token(PP_MEDIA);
+    pp_w();
+    switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+    case PP_NOT:
+    case IDENT:
+    case LPAR:{
+      q = pp_media_query();
+pass = pass || q; empty = false;
+      label_4:
+      while (true) {
+        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+        case COMMA:{
+          ;
+          break;
+          }
+        default:
+          jj_la1[9] = jj_gen;
+          break label_4;
+        }
+        jj_consume_token(COMMA);
+        pp_w();
+        q = pp_media_query();
+pass = pass || q;
+      }
+      break;
+      }
+    default:
+      jj_la1[10] = jj_gen;
+      ;
+    }
+    jj_consume_token(LBRACE);
+    pp_black_box((empty || pass) && !ignore);
+    jj_consume_token(RBRACE);
+  }
+
+// deprecated
+  final public boolean pp_media_query() throws ParseException {Token t;
+    String mediatype = "all";
+    boolean pass = true;
+    boolean invert = false;
+    boolean e;
+    switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+    case PP_NOT:{
+      jj_consume_token(PP_NOT);
+invert = true;
+      pp_w();
+      break;
+      }
+    default:
+      jj_la1[11] = jj_gen;
+      ;
+    }
+    switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+    case IDENT:{
+      t = jj_consume_token(IDENT);
+mediatype = t.image.toLowerCase(Locale.ENGLISH);
+      pp_w();
+      label_5:
+      while (true) {
+        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+        case PP_AND:{
+          ;
+          break;
+          }
+        default:
+          jj_la1[12] = jj_gen;
+          break label_5;
+        }
+        jj_consume_token(PP_AND);
+        pp_w();
+        e = pp_media_expression();
+pass = pass && e;
+        pp_w();
+      }
+      break;
+      }
+    case LPAR:{
+      e = pp_media_expression();
+pass = pass && e;
+      pp_w();
+      label_6:
+      while (true) {
+        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+        case PP_AND:{
+          ;
+          break;
+          }
+        default:
+          jj_la1[13] = jj_gen;
+          break label_6;
+        }
+        jj_consume_token(PP_AND);
+        pp_w();
+        e = pp_media_expression();
+pass = pass && e;
+        pp_w();
+      }
+      break;
+      }
+    default:
+      jj_la1[14] = jj_gen;
+      jj_consume_token(-1);
+      throw new ParseException();
+    }
+if (!"all".equals(mediatype)) {
+            pass = false;
+        }
+        {if ("" != null) return invert ? (!pass) : pass;}
+    throw new Error("Missing return statement in function");
+  }
+
+/**
+ * Parse an @media expression.
+ *
+ * The parsing rule {@link #literal()} from the main mapcss parser is reused here.
+ *
+ * @return true if the condition is fulfilled
+ */
+// deprecated
+  final public boolean pp_media_expression() throws ParseException {Token t;
+    String feature;
+    Object val = null;
+    jj_consume_token(LPAR);
+    pp_w();
+    t = jj_consume_token(IDENT);
+feature = t.image;
+    pp_w();
+    switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+    case COLON:{
+      jj_consume_token(COLON);
+      pp_w();
+      val = literal();
+      break;
+      }
+    default:
+      jj_la1[15] = jj_gen;
+      ;
+    }
+    jj_consume_token(RPAR);
+{if ("" != null) return this.sheet.evalSupportsDeclCondition(feature, val);}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public void pp_w1() throws ParseException {Token t;
+    switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+    case PP_NEWLINECHAR:{
+      t = jj_consume_token(PP_NEWLINECHAR);
+sb.append(t.image);
+      break;
+      }
+    case PP_WHITESPACE:{
+      t = jj_consume_token(PP_WHITESPACE);
+sb.append(t.image);
+      break;
+      }
+    case PP_COMMENT_START:{
+      t = jj_consume_token(PP_COMMENT_START);
+sb.append(t.image);
+      t = jj_consume_token(PP_COMMENT_END);
+sb.append(t.image);
+      break;
+      }
+    default:
+      jj_la1[16] = jj_gen;
+      jj_consume_token(-1);
+      throw new ParseException();
+    }
+  }
+
+  final public void pp_w() throws ParseException {
+    label_7:
+    while (true) {
+      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+      case PP_NEWLINECHAR:
+      case PP_WHITESPACE:
+      case PP_COMMENT_START:{
+        ;
+        break;
+        }
+      default:
+        jj_la1[17] = jj_gen;
+        break label_7;
+      }
+      pp_w1();
+    }
+  }
+
+/*************
+ *
+ * Parser definition for the main MapCSS parser:
+ *
+ * <pre>
+ *
+ *                       rule
+ *  _______________________|______________________________
+ * |                                                      |
+ *        selector                      declaration
+ *  _________|___________________   _________|____________
+ * |                             | |                      |
+ *
+ * way|z11-12[highway=residential] { color: red; width: 3 }
+ *
+ *    |_____||___________________|   |_________|
+ *       |            |                   |
+ *     zoom       condition          instruction
+ *
+ * more general:
+ *
+ * way|z13-[a=b][c=d]::subpart, way|z-3[u=v]:closed::subpart2 { p1 : val; p2 : val; }
+ *
+ * 'val' can be a literal, or an expression like "prop(width, default) + 0.8".
+ *
+ * </pre>
+ */
+  final public 
+int uint() throws ParseException {Token i;
+    i = jj_consume_token(UINT);
+{if ("" != null) return Integer.parseInt(i.image);}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public int int_() throws ParseException {int i;
+    switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+    case MINUS:{
+      jj_consume_token(MINUS);
+      i = uint();
+{if ("" != null) return -i;}
+      break;
+      }
+    case UINT:{
+      i = uint();
+{if ("" != null) return i;}
+      break;
+      }
+    default:
+      jj_la1[18] = jj_gen;
+      jj_consume_token(-1);
+      throw new ParseException();
+    }
+    throw new Error("Missing return statement in function");
+  }
+
+  final public float ufloat() throws ParseException {Token f;
+    switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+    case UFLOAT:{
+      f = jj_consume_token(UFLOAT);
+      break;
+      }
+    case UINT:{
+      f = jj_consume_token(UINT);
+      break;
+      }
+    default:
+      jj_la1[19] = jj_gen;
+      jj_consume_token(-1);
+      throw new ParseException();
+    }
+{if ("" != null) return Float.parseFloat(f.image);}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public float float_() throws ParseException {float f;
+    switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+    case MINUS:{
+      jj_consume_token(MINUS);
+      f = ufloat();
+{if ("" != null) return -f;}
+      break;
+      }
+    case UINT:
+    case UFLOAT:{
+      f = ufloat();
+{if ("" != null) return f;}
+      break;
+      }
+    default:
+      jj_la1[20] = jj_gen;
+      jj_consume_token(-1);
+      throw new ParseException();
+    }
+    throw new Error("Missing return statement in function");
+  }
+
+  final public String string() throws ParseException {Token t;
+    t = jj_consume_token(STRING);
+{if ("" != null) return t.image.substring(1, t.image.length() - 1).replace("\\\"", "\"").replace("\\\\", "\\");}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public String ident() throws ParseException {Token t;
+    String s;
+    switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+    case IDENT:{
+      t = jj_consume_token(IDENT);
+      break;
+      }
+    case SET:{
+      t = jj_consume_token(SET);
+      break;
+      }
+    default:
+      jj_la1[21] = jj_gen;
+      jj_consume_token(-1);
+      throw new ParseException();
+    }
+{if ("" != null) return t.image;}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public String string_or_ident() throws ParseException {Token t;
+    String s;
+    switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+    case SET:
+    case IDENT:{
+      s = ident();
+      break;
+      }
+    case STRING:{
+      s = string();
+      break;
+      }
+    default:
+      jj_la1[22] = jj_gen;
+      jj_consume_token(-1);
+      throw new ParseException();
+    }
+{if ("" != null) return s;}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public String regex() throws ParseException {Token t;
+    t = jj_consume_token(REGEX);
+{if ("" != null) return t.image.substring(1, t.image.length() - 1);}
+    throw new Error("Missing return statement in function");
+  }
+
+/**
+ * white-space
+ */
+  final public void s() throws ParseException {
+    switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+    case S:{
+      jj_consume_token(S);
+      break;
+      }
+    default:
+      jj_la1[23] = jj_gen;
+      ;
+    }
+  }
+
+/**
+ * mix of white-space and comments
+ */
+  final public void w() throws ParseException {
+    label_8:
+    while (true) {
+      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+      case S:
+      case COMMENT_START:{
+        ;
+        break;
+        }
+      default:
+        jj_la1[24] = jj_gen;
+        break label_8;
+      }
+      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+      case S:{
+        jj_consume_token(S);
+        break;
+        }
+      case COMMENT_START:{
+        jj_consume_token(COMMENT_START);
+        jj_consume_token(COMMENT_END);
+        break;
+        }
+      default:
+        jj_la1[25] = jj_gen;
+        jj_consume_token(-1);
+        throw new ParseException();
+      }
+    }
+  }
+
+/**
+ * comma delimited list of floats (at least 2, all &gt;= 0)
+ */
+  final public List<Float> float_array() throws ParseException {float f;
+    List<Float> fs = new ArrayList<Float>();
+    f = ufloat();
+fs.add(f);
+    label_9:
+    while (true) {
+      jj_consume_token(COMMA);
+      s();
+      f = ufloat();
+fs.add(f);
+      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+      case COMMA:{
+        ;
+        break;
+        }
+      default:
+        jj_la1[26] = jj_gen;
+        break label_9;
+      }
+    }
+{if ("" != null) return fs;}
+    throw new Error("Missing return statement in function");
+  }
+
+/**
+ * entry point for the main parser
+ */
+  final public void sheet(MapCSSStyleSource sheet) throws ParseException {
+this.sheet = sheet;
+    w();
+    label_10:
+    while (true) {
+      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+      case IDENT:
+      case STAR:{
+        ;
+        break;
+        }
+      default:
+        jj_la1[27] = jj_gen;
+        break label_10;
+      }
+      try {
+        rule();
+        w();
+      } catch (MapCSSException mex) {
+Main.error(mex);
+            error_skipto(RBRACE, mex);
+            w();
+      } catch (ParseException ex) {
+error_skipto(RBRACE, null);
+            w();
+      }
+    }
+    jj_consume_token(0);
+  }
+
+  final public void rule() throws ParseException {List<Selector> selectors = new ArrayList<Selector>();
+    Selector sel;
+    Declaration decl;
+    sel = child_selector();
+selectors.add(sel);
+    label_11:
+    while (true) {
+      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+      case COMMA:{
+        ;
+        break;
+        }
+      default:
+        jj_la1[28] = jj_gen;
+        break label_11;
+      }
+      jj_consume_token(COMMA);
+      w();
+      sel = child_selector();
+selectors.add(sel);
+    }
+    decl = declaration();
+for (Selector s : selectors) {
+            sheet.rules.add(new MapCSSRule(s, decl));
+        }
+  }
+
+  final public Selector child_selector() throws ParseException {Selector.ChildOrParentSelectorType type = null;
+    Condition c;
+    List<Condition> conditions = new ArrayList<Condition>();
+    Selector selLeft;
+    LinkSelector selLink = null;
+    Selector selRight = null;
+    selLeft = selector();
+    w();
+    switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+    case IDENT:
+    case STAR:
+    case GREATER:
+    case LESS:
+    case PLUS:
+    case ELEMENT_OF:
+    case CROSSING:{
+      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+      case GREATER:
+      case LESS:
+      case PLUS:
+      case ELEMENT_OF:
+      case CROSSING:{
+        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+        case GREATER:
+        case LESS:
+        case PLUS:{
+          switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+          case GREATER:{
+            jj_consume_token(GREATER);
+type = Selector.ChildOrParentSelectorType.CHILD;
+            break;
+            }
+          case LESS:{
+            jj_consume_token(LESS);
+type = Selector.ChildOrParentSelectorType.PARENT;
+            break;
+            }
+          case PLUS:{
+            jj_consume_token(PLUS);
+type = Selector.ChildOrParentSelectorType.SIBLING;
+            break;
+            }
+          default:
+            jj_la1[29] = jj_gen;
+            jj_consume_token(-1);
+            throw new ParseException();
+          }
+          label_12:
+          while (true) {
+            switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+            case COLON:
+            case LSQUARE:
+            case EXCLAMATION:
+            case FULLSTOP:{
+              ;
+              break;
+              }
+            default:
+              jj_la1[30] = jj_gen;
+              break label_12;
+            }
+            switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+            case LSQUARE:{
+              c = condition(Context.LINK);
+              break;
+              }
+            case COLON:
+            case EXCLAMATION:
+            case FULLSTOP:{
+              c = class_or_pseudoclass(Context.LINK);
+              break;
+              }
+            default:
+              jj_la1[31] = jj_gen;
+              jj_consume_token(-1);
+              throw new ParseException();
+            }
+conditions.add(c);
+          }
+          break;
+          }
+        case ELEMENT_OF:{
+          jj_consume_token(ELEMENT_OF);
+type = Selector.ChildOrParentSelectorType.ELEMENT_OF;
+          break;
+          }
+        case CROSSING:{
+          jj_consume_token(CROSSING);
+type = Selector.ChildOrParentSelectorType.CROSSING;
+          break;
+          }
+        default:
+          jj_la1[32] = jj_gen;
+          jj_consume_token(-1);
+          throw new ParseException();
+        }
+        w();
+        break;
+        }
+      default:
+        jj_la1[33] = jj_gen;
+/* <GREATER> is optional for child selector */ type = Selector.ChildOrParentSelectorType.CHILD;
+      }
+selLink = new LinkSelector(conditions);
+      selRight = selector();
+      w();
+      break;
+      }
+    default:
+      jj_la1[34] = jj_gen;
+      ;
+    }
+{if ("" != null) return selRight != null ? new ChildOrParentSelector(selLeft, selLink, selRight, type) : selLeft;}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public Selector selector() throws ParseException {Token base;
+    Condition c;
+    Pair<Integer, Integer> r = null;
+    List<Condition> conditions = new ArrayList<Condition>();
+    Subpart sub = null;
+    switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+    case IDENT:{
+      base = jj_consume_token(IDENT);
+      break;
+      }
+    case STAR:{
+      base = jj_consume_token(STAR);
+      break;
+      }
+    default:
+      jj_la1[35] = jj_gen;
+      jj_consume_token(-1);
+      throw new ParseException();
+    }
+    switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+    case PIPE_Z:{
+      r = zoom();
+      break;
+      }
+    default:
+      jj_la1[36] = jj_gen;
+      ;
+    }
+    label_13:
+    while (true) {
+      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+      case COLON:
+      case LSQUARE:
+      case EXCLAMATION:
+      case FULLSTOP:{
+        ;
+        break;
+        }
+      default:
+        jj_la1[37] = jj_gen;
+        break label_13;
+      }
+      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+      case LSQUARE:{
+        c = condition(Context.PRIMITIVE);
+        break;
+        }
+      case COLON:
+      case EXCLAMATION:
+      case FULLSTOP:{
+        c = class_or_pseudoclass(Context.PRIMITIVE);
+        break;
+        }
+      default:
+        jj_la1[38] = jj_gen;
+        jj_consume_token(-1);
+        throw new ParseException();
+      }
+conditions.add(c);
+    }
+    switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+    case DCOLON:{
+      sub = subpart();
+      break;
+      }
+    default:
+      jj_la1[39] = jj_gen;
+      ;
+    }
+{if ("" != null) return new GeneralSelector(base.image, r, conditions, sub);}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public Pair<Integer, Integer> zoom() throws ParseException {Integer min = 0;
+    Integer max = Integer.MAX_VALUE;
+    jj_consume_token(PIPE_Z);
+    switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+    case MINUS:{
+      jj_consume_token(MINUS);
+      max = uint();
+      break;
+      }
+    default:
+      jj_la1[41] = jj_gen;
+      if (jj_2_4(2)) {
+        min = uint();
+        jj_consume_token(MINUS);
+        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+        case UINT:{
+          max = uint();
+          break;
+          }
+        default:
+          jj_la1[40] = jj_gen;
+          ;
+        }
+      } else {
+        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+        case UINT:{
+          min = uint();
+max = min;
+          break;
+          }
+        default:
+          jj_la1[42] = jj_gen;
+          jj_consume_token(-1);
+          throw new ParseException();
+        }
+      }
+    }
+{if ("" != null) return new Pair<Integer, Integer>(min, max);}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public Condition condition(Context context) throws ParseException {Condition c;
+    Expression e;
+    jj_consume_token(LSQUARE);
+    s();
+    if (jj_2_5(2147483647)) {
+      c = simple_key_condition(context);
+      s();
+      jj_consume_token(RSQUARE);
+{if ("" != null) return c;}
+    } else if (jj_2_6(2147483647)) {
+      c = simple_key_value_condition(context);
+      s();
+      jj_consume_token(RSQUARE);
+{if ("" != null) return c;}
+    } else {
+      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+      case SET:
+      case IDENT:
+      case UINT:
+      case STRING:
+      case LPAR:
+      case UFLOAT:
+      case HEXCOLOR:
+      case EXCLAMATION:
+      case PLUS:
+      case MINUS:{
+        e = expression();
+        jj_consume_token(RSQUARE);
+{if ("" != null) return Condition.createExpressionCondition(e, context);}
+        break;
+        }
+      default:
+        jj_la1[43] = jj_gen;
+        jj_consume_token(-1);
+        throw new ParseException();
+      }
+    }
+    throw new Error("Missing return statement in function");
+  }
+
+  final public String tag_key() throws ParseException {String s, s2;
+    Token t;
+    switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+    case STRING:{
+      s = string();
+{if ("" != null) return s;}
+      break;
+      }
+    case SET:
+    case IDENT:{
+      s = ident();
+      label_14:
+      while (true) {
+        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+        case COLON:{
+          ;
+          break;
+          }
+        default:
+          jj_la1[44] = jj_gen;
+          break label_14;
+        }
+        jj_consume_token(COLON);
+        s2 = ident();
+s += ':' + s2;
+      }
+{if ("" != null) return s;}
+      break;
+      }
+    default:
+      jj_la1[45] = jj_gen;
+      jj_consume_token(-1);
+      throw new ParseException();
+    }
+    throw new Error("Missing return statement in function");
+  }
+
+  final public Condition simple_key_condition(Context context) throws ParseException {boolean not = false;
+    Condition.KeyMatchType matchType = null;;
+    String key;
+    switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+    case EXCLAMATION:{
+      jj_consume_token(EXCLAMATION);
+not = true;
+      break;
+      }
+    default:
+      jj_la1[46] = jj_gen;
+      ;
+    }
+    switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+    case REGEX:{
+matchType = Condition.KeyMatchType.REGEX;
+      key = regex();
+      break;
+      }
+    case SET:
+    case IDENT:
+    case STRING:{
+      key = tag_key();
+      break;
+      }
+    default:
+      jj_la1[47] = jj_gen;
+      jj_consume_token(-1);
+      throw new ParseException();
+    }
+    if (jj_2_7(2)) {
+      jj_consume_token(QUESTION);
+      jj_consume_token(EXCLAMATION);
+matchType = Condition.KeyMatchType.FALSE;
+    } else {
+      ;
+    }
+    switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+    case QUESTION:{
+      jj_consume_token(QUESTION);
+matchType = Condition.KeyMatchType.TRUE;
+      break;
+      }
+    default:
+      jj_la1[48] = jj_gen;
+      ;
+    }
+{if ("" != null) return Condition.createKeyCondition(key, not, matchType, context);}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public Condition simple_key_value_condition(Context context) throws ParseException {String key;
+    String val;
+    float f;
+    int i;
+    Condition.Op op;
+    boolean considerValAsKey = false;
+    key = tag_key();
+    s();
+    if (jj_2_9(3)) {
+      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+      case EQUAL:{
+        jj_consume_token(EQUAL);
+        jj_consume_token(TILDE);
+op=Condition.Op.REGEX;
+        break;
+        }
+      case EXCLAMATION:{
+        jj_consume_token(EXCLAMATION);
+        jj_consume_token(TILDE);
+op=Condition.Op.NREGEX;
+        break;
+        }
+      default:
+        jj_la1[49] = jj_gen;
+        jj_consume_token(-1);
+        throw new ParseException();
+      }
+      s();
+      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+      case STAR:{
+        jj_consume_token(STAR);
+considerValAsKey=true;
+        break;
+        }
+      default:
+        jj_la1[50] = jj_gen;
+        ;
+      }
+      val = regex();
+    } else {
+      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+      case STAR:
+      case EQUAL:
+      case EXCLAMATION:
+      case TILDE:
+      case DOLLAR:
+      case CARET:{
+        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+        case EXCLAMATION:{
+          jj_consume_token(EXCLAMATION);
+          jj_consume_token(EQUAL);
+op=Condition.Op.NEQ;
+          break;
+          }
+        case EQUAL:{
+          jj_consume_token(EQUAL);
+op=Condition.Op.EQ;
+          break;
+          }
+        case TILDE:{
+          jj_consume_token(TILDE);
+          jj_consume_token(EQUAL);
+op=Condition.Op.ONE_OF;
+          break;
+          }
+        case CARET:{
+          jj_consume_token(CARET);
+          jj_consume_token(EQUAL);
+op=Condition.Op.BEGINS_WITH;
+          break;
+          }
+        case DOLLAR:{
+          jj_consume_token(DOLLAR);
+          jj_consume_token(EQUAL);
+op=Condition.Op.ENDS_WITH;
+          break;
+          }
+        case STAR:{
+          jj_consume_token(STAR);
+          jj_consume_token(EQUAL);
+op=Condition.Op.CONTAINS;
+          break;
+          }
+        default:
+          jj_la1[51] = jj_gen;
+          jj_consume_token(-1);
+          throw new ParseException();
+        }
+        s();
+        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+        case STAR:{
+          jj_consume_token(STAR);
+considerValAsKey=true;
+          break;
+          }
+        default:
+          jj_la1[52] = jj_gen;
+          ;
+        }
+        if (jj_2_8(2)) {
+          i = int_();
+val=Integer.toString(i);
+        } else {
+          switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+          case UINT:
+          case UFLOAT:
+          case MINUS:{
+            f = float_();
+val=Float.toString(f);
+            break;
+            }
+          case SET:
+          case IDENT:
+          case STRING:{
+            val = string_or_ident();
+            break;
+            }
+          default:
+            jj_la1[53] = jj_gen;
+            jj_consume_token(-1);
+            throw new ParseException();
+          }
+        }
+        break;
+        }
+      case GREATER_EQUAL:
+      case LESS_EQUAL:
+      case GREATER:
+      case LESS:{
+        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+        case GREATER_EQUAL:{
+          jj_consume_token(GREATER_EQUAL);
+op=Condition.Op.GREATER_OR_EQUAL;
+          break;
+          }
+        case GREATER:{
+          jj_consume_token(GREATER);
+op=Condition.Op.GREATER;
+          break;
+          }
+        case LESS_EQUAL:{
+          jj_consume_token(LESS_EQUAL);
+op=Condition.Op.LESS_OR_EQUAL;
+          break;
+          }
+        case LESS:{
+          jj_consume_token(LESS);
+op=Condition.Op.LESS;
+          break;
+          }
+        default:
+          jj_la1[54] = jj_gen;
+          jj_consume_token(-1);
+          throw new ParseException();
+        }
+        s();
+        f = float_();
+val=Float.toString(f);
+        break;
+        }
+      default:
+        jj_la1[55] = jj_gen;
+        jj_consume_token(-1);
+        throw new ParseException();
+      }
+    }
+{if ("" != null) return Condition.createKeyValueCondition(key, val, op, context, considerValAsKey);}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public Condition class_or_pseudoclass(Context context) throws ParseException {String s;
+    boolean not = false;
+    boolean pseudo;
+    switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+    case EXCLAMATION:{
+      jj_consume_token(EXCLAMATION);
+not = true;
+      break;
+      }
+    default:
+      jj_la1[56] = jj_gen;
+      ;
+    }
+    switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+    case FULLSTOP:{
+      jj_consume_token(FULLSTOP);
+pseudo = false;
+      break;
+      }
+    case COLON:{
+      jj_consume_token(COLON);
+pseudo = true;
+      break;
+      }
+    default:
+      jj_la1[57] = jj_gen;
+      jj_consume_token(-1);
+      throw new ParseException();
+    }
+    s = ident();
+{if ("" != null) return pseudo
+        ? Condition.createPseudoClassCondition(s, not, context)
+        : Condition.createClassCondition(s, not, context);}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public Subpart subpart() throws ParseException {String s;
+    Expression e;
+    jj_consume_token(DCOLON);
+    switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+    case SET:
+    case IDENT:{
+      s = ident();
+{if ("" != null) return new Subpart.StringSubpart(s);}
+      break;
+      }
+    case STAR:{
+      jj_consume_token(STAR);
+{if ("" != null) return new Subpart.StringSubpart("*");}
+      break;
+      }
+    case LPAR:{
+      jj_consume_token(LPAR);
+      e = expression();
+      jj_consume_token(RPAR);
+{if ("" != null) return new Subpart.ExpressionSubpart(e);}
+      break;
+      }
+    default:
+      jj_la1[58] = jj_gen;
+      jj_consume_token(-1);
+      throw new ParseException();
+    }
+    throw new Error("Missing return statement in function");
+  }
+
+  final public Declaration declaration() throws ParseException {List<Instruction> ins = new ArrayList<Instruction>();
+    Instruction i;
+    Token key;
+    Object val = null;
+    jj_consume_token(LBRACE);
+    w();
+    label_15:
+    while (true) {
+      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+      case SET:
+      case IDENT:{
+        ;
+        break;
+        }
+      default:
+        jj_la1[59] = jj_gen;
+        break label_15;
+      }
+      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+      case SET:{
+        jj_consume_token(SET);
+        w();
+        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+        case FULLSTOP:{
+          jj_consume_token(FULLSTOP);
+          break;
+          }
+        default:
+          jj_la1[60] = jj_gen;
+          ;
+        }
+        // specification allows "set .class" to set "class". we also support "set class"
+                    key = jj_consume_token(IDENT);
+        w();
+        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+        case EQUAL:{
+          jj_consume_token(EQUAL);
+          val = expression();
+          break;
+          }
+        default:
+          jj_la1[61] = jj_gen;
+          ;
+        }
+ins.add(new Instruction.AssignmentInstruction(key.image, val == null ? true : val, true));
+        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+        case RBRACE:{
+          jj_consume_token(RBRACE);
+{if ("" != null) return new Declaration(ins, declarationCounter++);}
+          break;
+          }
+        case SEMICOLON:{
+          jj_consume_token(SEMICOLON);
+          w();
+          break;
+          }
+        default:
+          jj_la1[62] = jj_gen;
+          jj_consume_token(-1);
+          throw new ParseException();
+        }
+        break;
+        }
+      case IDENT:{
+        key = jj_consume_token(IDENT);
+        w();
+        jj_consume_token(COLON);
+        w();
+        if (jj_2_10(2147483647)) {
+          val = float_array();
+ins.add(new Instruction.AssignmentInstruction(key.image, val, false));
+          w();
+          switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+          case RBRACE:{
+            jj_consume_token(RBRACE);
+{if ("" != null) return new Declaration(ins, declarationCounter++);}
+            break;
+            }
+          case SEMICOLON:{
+            jj_consume_token(SEMICOLON);
+            w();
+            break;
+            }
+          default:
+            jj_la1[63] = jj_gen;
+            jj_consume_token(-1);
+            throw new ParseException();
+          }
+        } else if (jj_2_11(2147483647)) {
+          val = expression();
+ins.add(new Instruction.AssignmentInstruction(key.image, val, false));
+          switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+          case RBRACE:{
+            jj_consume_token(RBRACE);
+{if ("" != null) return new Declaration(ins, declarationCounter++);}
+            break;
+            }
+          case SEMICOLON:{
+            jj_consume_token(SEMICOLON);
+            w();
+            break;
+            }
+          default:
+            jj_la1[64] = jj_gen;
+            jj_consume_token(-1);
+            throw new ParseException();
+          }
+        } else {
+          val = readRaw();
+          w();
+ins.add(new Instruction.AssignmentInstruction(key.image, val, false));
+        }
+        break;
+        }
+      default:
+        jj_la1[65] = jj_gen;
+        jj_consume_token(-1);
+        throw new ParseException();
+      }
+    }
+    jj_consume_token(RBRACE);
+{if ("" != null) return new Declaration(ins, declarationCounter++);}
+    throw new Error("Missing return statement in function");
+  }
+
+/**
+ * General expression.
+ * Separate production rule for each level of operator precedence (recursive descent).
+ */
+  final public Expression expression() throws ParseException {Expression e;
+    e = conditional_expression();
+{if ("" != null) return e;}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public Expression conditional_expression() throws ParseException {Expression e, e1, e2;
+    String op = null;
+    e = or_expression();
+    switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+    case QUESTION:{
+      jj_consume_token(QUESTION);
+      w();
+      e1 = conditional_expression();
+      jj_consume_token(COLON);
+      w();
+      e2 = conditional_expression();
+e = ExpressionFactory.createFunctionExpression("cond", Arrays.asList(e, e1, e2));
+      break;
+      }
+    default:
+      jj_la1[66] = jj_gen;
+      ;
+    }
+{if ("" != null) return e;}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public Expression or_expression() throws ParseException {Expression e, e2;
+    String op = null;
+    e = and_expression();
+    label_16:
+    while (true) {
+      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+      case PIPE:{
+        ;
+        break;
+        }
+      default:
+        jj_la1[67] = jj_gen;
+        break label_16;
+      }
+      jj_consume_token(PIPE);
+      jj_consume_token(PIPE);
+      w();
+      e2 = and_expression();
+e = ExpressionFactory.createFunctionExpression("or", Arrays.asList(e, e2));
+    }
+{if ("" != null) return e;}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public Expression and_expression() throws ParseException {Expression e, e2;
+    String op = null;
+    e = relational_expression();
+    label_17:
+    while (true) {
+      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+      case AMPERSAND:{
+        ;
+        break;
+        }
+      default:
+        jj_la1[68] = jj_gen;
+        break label_17;
+      }
+      jj_consume_token(AMPERSAND);
+      jj_consume_token(AMPERSAND);
+      w();
+      e2 = relational_expression();
+e = ExpressionFactory.createFunctionExpression("and", Arrays.asList(e, e2));
+    }
+{if ("" != null) return e;}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public Expression relational_expression() throws ParseException {Expression e, e2;
+    String op = null;
+    e = additive_expression();
+    switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+    case GREATER_EQUAL:
+    case LESS_EQUAL:
+    case GREATER:
+    case LESS:
+    case EQUAL:
+    case EXCLAMATION:{
+      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+      case GREATER_EQUAL:{
+        jj_consume_token(GREATER_EQUAL);
+op = "greater_equal";
+        break;
+        }
+      case LESS_EQUAL:{
+        jj_consume_token(LESS_EQUAL);
+op = "less_equal";
+        break;
+        }
+      case GREATER:{
+        jj_consume_token(GREATER);
+op = "greater";
+        break;
+        }
+      case LESS:{
+        jj_consume_token(LESS);
+op = "less";
+        break;
+        }
+      case EQUAL:{
+        jj_consume_token(EQUAL);
+        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+        case EQUAL:{
+          jj_consume_token(EQUAL);
+          break;
+          }
+        default:
+          jj_la1[69] = jj_gen;
+          ;
+        }
+op = "equal";
+        break;
+        }
+      case EXCLAMATION:{
+        jj_consume_token(EXCLAMATION);
+        jj_consume_token(EQUAL);
+op = "not_equal";
+        break;
+        }
+      default:
+        jj_la1[70] = jj_gen;
+        jj_consume_token(-1);
+        throw new ParseException();
+      }
+      w();
+      e2 = additive_expression();
+e = ExpressionFactory.createFunctionExpression(op, Arrays.asList(e, e2));
+      break;
+      }
+    default:
+      jj_la1[71] = jj_gen;
+      ;
+    }
+{if ("" != null) return e;}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public Expression additive_expression() throws ParseException {Expression e, e2;
+    String op = null;
+    e = multiplicative_expression();
+    label_18:
+    while (true) {
+      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+      case PLUS:
+      case MINUS:{
+        ;
+        break;
+        }
+      default:
+        jj_la1[72] = jj_gen;
+        break label_18;
+      }
+      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+      case PLUS:{
+        jj_consume_token(PLUS);
+op = "plus";
+        break;
+        }
+      case MINUS:{
+        jj_consume_token(MINUS);
+op = "minus";
+        break;
+        }
+      default:
+        jj_la1[73] = jj_gen;
+        jj_consume_token(-1);
+        throw new ParseException();
+      }
+      w();
+      e2 = multiplicative_expression();
+e = ExpressionFactory.createFunctionExpression(op, Arrays.asList(e, e2));
+    }
+{if ("" != null) return e;}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public Expression multiplicative_expression() throws ParseException {Expression e, e2;
+    String op = null;
+    e = unary_expression();
+    label_19:
+    while (true) {
+      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+      case STAR:
+      case SLASH:{
+        ;
+        break;
+        }
+      default:
+        jj_la1[74] = jj_gen;
+        break label_19;
+      }
+      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+      case STAR:{
+        jj_consume_token(STAR);
+op = "times";
+        break;
+        }
+      case SLASH:{
+        jj_consume_token(SLASH);
+op = "divided_by";
+        break;
+        }
+      default:
+        jj_la1[75] = jj_gen;
+        jj_consume_token(-1);
+        throw new ParseException();
+      }
+      w();
+      e2 = unary_expression();
+e = ExpressionFactory.createFunctionExpression(op, Arrays.asList(e, e2));
+    }
+{if ("" != null) return e;}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public Expression unary_expression() throws ParseException {Expression e;
+    String op = null;
+    switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+    case EXCLAMATION:
+    case MINUS:{
+      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+      case MINUS:{
+        jj_consume_token(MINUS);
+op = "minus";
+        w();
+        break;
+        }
+      case EXCLAMATION:{
+        jj_consume_token(EXCLAMATION);
+op = "not";
+        w();
+        break;
+        }
+      default:
+        jj_la1[76] = jj_gen;
+        jj_consume_token(-1);
+        throw new ParseException();
+      }
+      break;
+      }
+    default:
+      jj_la1[77] = jj_gen;
+      ;
+    }
+    e = primary();
+    w();
+if (op == null)
+            {if ("" != null) return e;}
+        {if ("" != null) return ExpressionFactory.createFunctionExpression(op, Collections.singletonList(e));}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public Expression primary() throws ParseException {Expression nested;
+    Expression fn;
+    Object lit;
+    if (jj_2_12(3)) {
+      // both function and identifier start with an identifier (+ optional whitespace)
+              fn = function();
+{if ("" != null) return fn;}
+    } else {
+      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+      case SET:
+      case IDENT:
+      case UINT:
+      case STRING:
+      case UFLOAT:
+      case HEXCOLOR:
+      case PLUS:{
+        lit = literal();
+if (lit == null)
+                {if ("" != null) return NullExpression.INSTANCE;}
+            {if ("" != null) return new LiteralExpression(lit);}
+        break;
+        }
+      case LPAR:{
+        jj_consume_token(LPAR);
+        w();
+        nested = expression();
+        jj_consume_token(RPAR);
+{if ("" != null) return nested;}
+        break;
+        }
+      default:
+        jj_la1[78] = jj_gen;
+        jj_consume_token(-1);
+        throw new ParseException();
+      }
+    }
+    throw new Error("Missing return statement in function");
+  }
+
+  final public Expression function() throws ParseException {Expression arg;
+    String name;
+    List<Expression> args = new ArrayList<Expression>();
+    name = ident();
+    w();
+    jj_consume_token(LPAR);
+    w();
+    switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+    case SET:
+    case IDENT:
+    case UINT:
+    case STRING:
+    case LPAR:
+    case UFLOAT:
+    case HEXCOLOR:
+    case EXCLAMATION:
+    case PLUS:
+    case MINUS:{
+      arg = expression();
+args.add(arg);
+      label_20:
+      while (true) {
+        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+        case COMMA:{
+          ;
+          break;
+          }
+        default:
+          jj_la1[79] = jj_gen;
+          break label_20;
+        }
+        jj_consume_token(COMMA);
+        w();
+        arg = expression();
+args.add(arg);
+      }
+      break;
+      }
+    default:
+      jj_la1[80] = jj_gen;
+      ;
+    }
+    jj_consume_token(RPAR);
+{if ("" != null) return ExpressionFactory.createFunctionExpression(name, args);}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public Object literal() throws ParseException {String val, pref;
+    Token t;
+    Float f;
+    if (jj_2_13(2)) {
+      pref = ident();
+      t = jj_consume_token(HEXCOLOR);
+{if ("" != null) return Main.pref.getColor("mappaint." + (sheet == null ? "MapCSS" : sheet.title) + "." + pref, ColorHelper.html2color(t.image));}
+    } else {
+      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+      case IDENT:{
+        t = jj_consume_token(IDENT);
+{if ("" != null) return new Keyword(t.image);}
+        break;
+        }
+      case STRING:{
+        val = string();
+{if ("" != null) return val;}
+        break;
+        }
+      case PLUS:{
+        jj_consume_token(PLUS);
+        f = ufloat();
+{if ("" != null) return new Instruction.RelativeFloat(f);}
+        break;
+        }
+      default:
+        jj_la1[81] = jj_gen;
+        if (jj_2_14(2)) {
+          f = ufloat_unit();
+{if ("" != null) return f;}
+        } else {
+          switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+          case UINT:
+          case UFLOAT:{
+            f = ufloat();
+{if ("" != null) return f;}
+            break;
+            }
+          case HEXCOLOR:{
+            t = jj_consume_token(HEXCOLOR);
+{if ("" != null) return ColorHelper.html2color(t.image);}
+            break;
+            }
+          default:
+            jj_la1[82] = jj_gen;
+            jj_consume_token(-1);
+            throw new ParseException();
+          }
+        }
+      }
+    }
+    throw new Error("Missing return statement in function");
+  }
+
+/**
+ * Number followed by a unit.
+ *
+ * Returns angles in radians and lengths in pixels.
+ */
+  final public Float ufloat_unit() throws ParseException {float f;
+    String u;
+    f = ufloat();
+    switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
+    case SET:
+    case IDENT:{
+      u = ident();
+      break;
+      }
+    case DEG:{
+      jj_consume_token(DEG);
+u = "\u00b0";
+      break;
+      }
+    default:
+      jj_la1[83] = jj_gen;
+      jj_consume_token(-1);
+      throw new ParseException();
+    }
+Double m = unit_factor(u);
+        if (m == null)
+            {if ("" != null) return null;}
+        {if ("" != null) return (float) (f * m);}
+    throw new Error("Missing return statement in function");
+  }
+
+  private Double unit_factor(String unit) throws ParseException {switch (unit) {
+        case "deg":
+        case "\u00b0": return Math.PI / 180;
+        case "rad": return 1.;
+        case "grad": return Math.PI / 200;
+        case "turn": return 2 * Math.PI;
+        case "px": return 1.;
+        case "cm": return 96/2.54;
+        case "mm": return 9.6/2.54;
+        case "in": return 96.;
+        case "q": return 2.4/2.54;
+        case "pc": return 16.;
+        case "pt": return 96./72;
+        default: return null;
+    }
+  }
+
+  void error_skipto(int kind, MapCSSException me) throws ParseException {if (token.kind == EOF)
+        throw new ParseException("Reached end of file while parsing");
+
+    Exception e = null;
+    ParseException pe = generateParseException();
+
+    if (me != null) {
+        final Token token = Utils.firstNonNull(pe.currentToken.next, pe.currentToken);
+        me.setLine(token.beginLine);
+        me.setColumn(token.beginColumn);
+        e = me;
+    } else {
+        e = new ParseException(pe.getMessage()); // prevent memory leak
+    }
+
+    Main.error("Skipping to the next rule, because of an error:");
+    Main.error(e);
+    if (sheet != null) {
+        sheet.logError(e);
+    }
+    Token t;
+    do {
+        t = getNextToken();
+    } while (t.kind != kind && t.kind != EOF);
+    if (t.kind == EOF)
+        throw new ParseException("Reached end of file while parsing");
+  }
+
+/**
+ * read everything to the next semicolon
+ */
+  String readRaw() throws ParseException {Token t;
+    StringBuilder s = new StringBuilder();
+    while (true) {
+        t = getNextToken();
+        if ((t.kind == S || t.kind == STRING || t.kind == UNEXPECTED_CHAR) &&
+                t.image.contains("\n")) {
+            ParseException e = new ParseException(String.format("Warning: end of line while reading an unquoted string at line %s column %s.", t.beginLine, t.beginColumn));
+            Main.error(e);
+            if (sheet != null) {
+                sheet.logError(e);
+            }
+        }
+        if (t.kind == SEMICOLON || t.kind == EOF)
+            break;
+        s.append(t.image);
+    }
+    if (t.kind == EOF)
+        throw new ParseException("Reached end of file while parsing");
+    return s.toString();
+  }
+
+  private boolean jj_2_1(int xla)
+ {
+    jj_la = xla; jj_lastpos = jj_scanpos = token;
+    try { return !jj_3_1(); }
+    catch(LookaheadSuccess ls) { return true; }
+    finally { jj_save(0, xla); }
+  }
+
+  private boolean jj_2_2(int xla)
+ {
+    jj_la = xla; jj_lastpos = jj_scanpos = token;
+    try { return !jj_3_2(); }
+    catch(LookaheadSuccess ls) { return true; }
+    finally { jj_save(1, xla); }
+  }
+
+  private boolean jj_2_3(int xla)
+ {
+    jj_la = xla; jj_lastpos = jj_scanpos = token;
+    try { return !jj_3_3(); }
+    catch(LookaheadSuccess ls) { return true; }
+    finally { jj_save(2, xla); }
+  }
+
+  private boolean jj_2_4(int xla)
+ {
+    jj_la = xla; jj_lastpos = jj_scanpos = token;
+    try { return !jj_3_4(); }
+    catch(LookaheadSuccess ls) { return true; }
+    finally { jj_save(3, xla); }
+  }
+
+  private boolean jj_2_5(int xla)
+ {
+    jj_la = xla; jj_lastpos = jj_scanpos = token;
+    try { return !jj_3_5(); }
+    catch(LookaheadSuccess ls) { return true; }
+    finally { jj_save(4, xla); }
+  }
+
+  private boolean jj_2_6(int xla)
+ {
+    jj_la = xla; jj_lastpos = jj_scanpos = token;
+    try { return !jj_3_6(); }
+    catch(LookaheadSuccess ls) { return true; }
+    finally { jj_save(5, xla); }
+  }
+
+  private boolean jj_2_7(int xla)
+ {
+    jj_la = xla; jj_lastpos = jj_scanpos = token;
+    try { return !jj_3_7(); }
+    catch(LookaheadSuccess ls) { return true; }
+    finally { jj_save(6, xla); }
+  }
+
+  private boolean jj_2_8(int xla)
+ {
+    jj_la = xla; jj_lastpos = jj_scanpos = token;
+    try { return !jj_3_8(); }
+    catch(LookaheadSuccess ls) { return true; }
+    finally { jj_save(7, xla); }
+  }
+
+  private boolean jj_2_9(int xla)
+ {
+    jj_la = xla; jj_lastpos = jj_scanpos = token;
+    try { return !jj_3_9(); }
+    catch(LookaheadSuccess ls) { return true; }
+    finally { jj_save(8, xla); }
+  }
+
+  private boolean jj_2_10(int xla)
+ {
+    jj_la = xla; jj_lastpos = jj_scanpos = token;
+    try { return !jj_3_10(); }
+    catch(LookaheadSuccess ls) { return true; }
+    finally { jj_save(9, xla); }
+  }
+
+  private boolean jj_2_11(int xla)
+ {
+    jj_la = xla; jj_lastpos = jj_scanpos = token;
+    try { return !jj_3_11(); }
+    catch(LookaheadSuccess ls) { return true; }
+    finally { jj_save(10, xla); }
+  }
+
+  private boolean jj_2_12(int xla)
+ {
+    jj_la = xla; jj_lastpos = jj_scanpos = token;
+    try { return !jj_3_12(); }
+    catch(LookaheadSuccess ls) { return true; }
+    finally { jj_save(11, xla); }
+  }
+
+  private boolean jj_2_13(int xla)
+ {
+    jj_la = xla; jj_lastpos = jj_scanpos = token;
+    try { return !jj_3_13(); }
+    catch(LookaheadSuccess ls) { return true; }
+    finally { jj_save(12, xla); }
+  }
+
+  private boolean jj_2_14(int xla)
+ {
+    jj_la = xla; jj_lastpos = jj_scanpos = token;
+    try { return !jj_3_14(); }
+    catch(LookaheadSuccess ls) { return true; }
+    finally { jj_save(13, xla); }
+  }
+
+  private boolean jj_3_9()
+ {
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_3R_29()) {
+    jj_scanpos = xsp;
+    if (jj_3R_30()) return true;
+    }
+    if (jj_3R_26()) return true;
+    xsp = jj_scanpos;
+    if (jj_3R_31()) jj_scanpos = xsp;
+    if (jj_3R_32()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_78()
+ {
+    if (jj_scan_token(COMMENT_START)) return true;
+    if (jj_scan_token(COMMENT_END)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_58()
+ {
+    if (jj_scan_token(DEG)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_105()
+ {
+    if (jj_scan_token(AMPERSAND)) return true;
+    if (jj_scan_token(AMPERSAND)) return true;
+    if (jj_3R_34()) return true;
+    if (jj_3R_104()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_46()
+ {
+    if (jj_scan_token(QUESTION)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_27()
+ {
+    if (jj_3R_47()) return true;
+    if (jj_3R_26()) return true;
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_3_9()) {
+    jj_scanpos = xsp;
+    if (jj_3R_48()) {
+    jj_scanpos = xsp;
+    if (jj_3R_49()) return true;
+    }
+    }
+    return false;
+  }
+
+  private boolean jj_3R_54()
+ {
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_scan_token(28)) {
+    jj_scanpos = xsp;
+    if (jj_3R_78()) return true;
+    }
+    return false;
+  }
+
+  private boolean jj_3R_34()
+ {
+    Token xsp;
+    while (true) {
+      xsp = jj_scanpos;
+      if (jj_3R_54()) { jj_scanpos = xsp; break; }
+    }
+    return false;
+  }
+
+  private boolean jj_3R_98()
+ {
+    if (jj_3R_104()) return true;
+    Token xsp;
+    while (true) {
+      xsp = jj_scanpos;
+      if (jj_3R_105()) { jj_scanpos = xsp; break; }
+    }
+    return false;
+  }
+
+  private boolean jj_3R_57()
+ {
+    if (jj_3R_37()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_23()
+ {
+    if (jj_scan_token(LPAR)) return true;
+    if (jj_3R_22()) return true;
+    if (jj_scan_token(IDENT)) return true;
+    if (jj_3R_22()) return true;
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_3R_42()) jj_scanpos = xsp;
+    if (jj_scan_token(RPAR)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_26()
+ {
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_scan_token(28)) jj_scanpos = xsp;
+    return false;
+  }
+
+  private boolean jj_3_7()
+ {
+    if (jj_scan_token(QUESTION)) return true;
+    if (jj_scan_token(EXCLAMATION)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_45()
+ {
+    if (jj_3R_47()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_94()
+ {
+    if (jj_scan_token(COLON)) return true;
+    if (jj_3R_37()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_44()
+ {
+    if (jj_3R_32()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_103()
+ {
+    if (jj_3R_93()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_99()
+ {
+    if (jj_scan_token(PIPE)) return true;
+    if (jj_scan_token(PIPE)) return true;
+    if (jj_3R_34()) return true;
+    if (jj_3R_98()) return true;
+    return false;
+  }
+
+  private boolean jj_3_3()
+ {
+    if (jj_3R_23()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_43()
+ {
+    if (jj_scan_token(EXCLAMATION)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_25()
+ {
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_3R_43()) jj_scanpos = xsp;
+    xsp = jj_scanpos;
+    if (jj_3R_44()) {
+    jj_scanpos = xsp;
+    if (jj_3R_45()) return true;
+    }
+    xsp = jj_scanpos;
+    if (jj_3_7()) jj_scanpos = xsp;
+    xsp = jj_scanpos;
+    if (jj_3R_46()) jj_scanpos = xsp;
+    return false;
+  }
+
+  private boolean jj_3R_38()
+ {
+    if (jj_3R_52()) return true;
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_3R_57()) {
+    jj_scanpos = xsp;
+    if (jj_3R_58()) return true;
+    }
+    return false;
+  }
+
+  private boolean jj_3R_97()
+ {
+    if (jj_3R_52()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_79()
+ {
+    if (jj_3R_98()) return true;
+    Token xsp;
+    while (true) {
+      xsp = jj_scanpos;
+      if (jj_3R_99()) { jj_scanpos = xsp; break; }
+    }
+    return false;
+  }
+
+  private boolean jj_3R_32()
+ {
+    if (jj_scan_token(REGEX)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_40()
+ {
+    if (jj_scan_token(LPAR)) return true;
+    if (jj_3R_22()) return true;
+    if (jj_3R_59()) return true;
+    if (jj_scan_token(RPAR)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_63()
+ {
+    if (jj_3R_37()) return true;
+    Token xsp;
+    while (true) {
+      xsp = jj_scanpos;
+      if (jj_3R_94()) { jj_scanpos = xsp; break; }
+    }
+    return false;
+  }
+
+  private boolean jj_3R_39()
+ {
+    if (jj_3R_23()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_47()
+ {
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_3R_62()) {
+    jj_scanpos = xsp;
+    if (jj_3R_63()) return true;
+    }
+    return false;
+  }
+
+  private boolean jj_3R_62()
+ {
+    if (jj_3R_93()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_102()
+ {
+    if (jj_3R_37()) return true;
+    return false;
+  }
+
+  private boolean jj_3_6()
+ {
+    if (jj_3R_27()) return true;
+    if (jj_3R_26()) return true;
+    if (jj_scan_token(RSQUARE)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_95()
+ {
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_3R_102()) {
+    jj_scanpos = xsp;
+    if (jj_3R_103()) return true;
+    }
+    return false;
+  }
+
+  private boolean jj_3R_92()
+ {
+    if (jj_scan_token(HEXCOLOR)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_91()
+ {
+    if (jj_3R_52()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_21()
+ {
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_3R_39()) {
+    jj_scanpos = xsp;
+    if (jj_3R_40()) return true;
+    }
+    return false;
+  }
+
+  private boolean jj_3_5()
+ {
+    if (jj_3R_25()) return true;
+    if (jj_3R_26()) return true;
+    if (jj_scan_token(RSQUARE)) return true;
+    return false;
+  }
+
+  private boolean jj_3_14()
+ {
+    if (jj_3R_38()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_90()
+ {
+    if (jj_scan_token(PLUS)) return true;
+    if (jj_3R_52()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_80()
+ {
+    if (jj_scan_token(QUESTION)) return true;
+    if (jj_3R_34()) return true;
+    if (jj_3R_55()) return true;
+    if (jj_scan_token(COLON)) return true;
+    if (jj_3R_34()) return true;
+    if (jj_3R_55()) return true;
+    return false;
+  }
+
+  private boolean jj_3_2()
+ {
+    if (jj_3R_21()) return true;
+    if (jj_3R_22()) return true;
+    if (jj_scan_token(PP_OR)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_89()
+ {
+    if (jj_3R_93()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_37()
+ {
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_scan_token(12)) {
+    jj_scanpos = xsp;
+    if (jj_scan_token(11)) return true;
+    }
+    return false;
+  }
+
+  private boolean jj_3R_51()
+ {
+    if (jj_3R_24()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_88()
+ {
+    if (jj_scan_token(IDENT)) return true;
+    return false;
+  }
+
+  private boolean jj_3_1()
+ {
+    if (jj_3R_21()) return true;
+    if (jj_3R_22()) return true;
+    if (jj_scan_token(PP_AND)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_101()
+ {
+    if (jj_scan_token(PP_OR)) return true;
+    if (jj_3R_22()) return true;
+    if (jj_3R_21()) return true;
+    if (jj_3R_22()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_84()
+ {
+    if (jj_3R_21()) return true;
+    if (jj_3R_22()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_55()
+ {
+    if (jj_3R_79()) return true;
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_3R_80()) jj_scanpos = xsp;
+    return false;
+  }
+
+  private boolean jj_3_13()
+ {
+    if (jj_3R_37()) return true;
+    if (jj_scan_token(HEXCOLOR)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_61()
+ {
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_3_13()) {
+    jj_scanpos = xsp;
+    if (jj_3R_88()) {
+    jj_scanpos = xsp;
+    if (jj_3R_89()) {
+    jj_scanpos = xsp;
+    if (jj_3R_90()) {
+    jj_scanpos = xsp;
+    if (jj_3_14()) {
+    jj_scanpos = xsp;
+    if (jj_3R_91()) {
+    jj_scanpos = xsp;
+    if (jj_3R_92()) return true;
+    }
+    }
+    }
+    }
+    }
+    }
+    return false;
+  }
+
+  private boolean jj_3R_100()
+ {
+    if (jj_scan_token(PP_AND)) return true;
+    if (jj_3R_22()) return true;
+    if (jj_3R_21()) return true;
+    if (jj_3R_22()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_83()
+ {
+    if (jj_3R_21()) return true;
+    if (jj_3R_22()) return true;
+    Token xsp;
+    if (jj_3R_101()) return true;
+    while (true) {
+      xsp = jj_scanpos;
+      if (jj_3R_101()) { jj_scanpos = xsp; break; }
+    }
+    return false;
+  }
+
+  private boolean jj_3R_93()
+ {
+    if (jj_scan_token(STRING)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_82()
+ {
+    if (jj_3R_21()) return true;
+    if (jj_3R_22()) return true;
+    Token xsp;
+    if (jj_3R_100()) return true;
+    while (true) {
+      xsp = jj_scanpos;
+      if (jj_3R_100()) { jj_scanpos = xsp; break; }
+    }
+    return false;
+  }
+
+  private boolean jj_3R_81()
+ {
+    if (jj_scan_token(PP_NOT)) return true;
+    if (jj_3R_22()) return true;
+    if (jj_3R_21()) return true;
+    if (jj_3R_22()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_35()
+ {
+    if (jj_3R_55()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_128()
+ {
+    if (jj_scan_token(COMMA)) return true;
+    if (jj_3R_34()) return true;
+    if (jj_3R_35()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_96()
+ {
+    if (jj_scan_token(MINUS)) return true;
+    if (jj_3R_52()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_77()
+ {
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_3R_96()) {
+    jj_scanpos = xsp;
+    if (jj_3R_97()) return true;
+    }
+    return false;
+  }
+
+  private boolean jj_3_11()
+ {
+    if (jj_3R_35()) return true;
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_scan_token(41)) {
+    jj_scanpos = xsp;
+    if (jj_scan_token(19)) return true;
+    }
+    return false;
+  }
+
+  private boolean jj_3R_59()
+ {
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_3R_81()) {
+    jj_scanpos = xsp;
+    if (jj_3R_82()) {
+    jj_scanpos = xsp;
+    if (jj_3R_83()) {
+    jj_scanpos = xsp;
+    if (jj_3R_84()) return true;
+    }
+    }
+    }
+    return false;
+  }
+
+  private boolean jj_3_4()
+ {
+    if (jj_3R_24()) return true;
+    if (jj_scan_token(MINUS)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_56()
+ {
+    if (jj_3R_35()) return true;
+    Token xsp;
+    while (true) {
+      xsp = jj_scanpos;
+      if (jj_3R_128()) { jj_scanpos = xsp; break; }
+    }
+    return false;
+  }
+
+  private boolean jj_3_10()
+ {
+    if (jj_3R_33()) return true;
+    if (jj_3R_34()) return true;
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_scan_token(41)) {
+    jj_scanpos = xsp;
+    if (jj_scan_token(19)) return true;
+    }
+    return false;
+  }
+
+  private boolean jj_3R_52()
+ {
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_scan_token(25)) {
+    jj_scanpos = xsp;
+    if (jj_scan_token(13)) return true;
+    }
+    return false;
+  }
+
+  private boolean jj_3R_36()
+ {
+    if (jj_3R_37()) return true;
+    if (jj_3R_34()) return true;
+    if (jj_scan_token(LPAR)) return true;
+    if (jj_3R_34()) return true;
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_3R_56()) jj_scanpos = xsp;
+    if (jj_scan_token(RPAR)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_127()
+ {
+    if (jj_scan_token(LPAR)) return true;
+    if (jj_3R_34()) return true;
+    if (jj_3R_35()) return true;
+    if (jj_scan_token(RPAR)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_28()
+ {
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_3R_50()) {
+    jj_scanpos = xsp;
+    if (jj_3R_51()) return true;
+    }
+    return false;
+  }
+
+  private boolean jj_3R_50()
+ {
+    if (jj_scan_token(MINUS)) return true;
+    if (jj_3R_24()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_126()
+ {
+    if (jj_3R_61()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_24()
+ {
+    if (jj_scan_token(UINT)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_121()
+ {
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_3_12()) {
+    jj_scanpos = xsp;
+    if (jj_3R_126()) {
+    jj_scanpos = xsp;
+    if (jj_3R_127()) return true;
+    }
+    }
+    return false;
+  }
+
+  private boolean jj_3_12()
+ {
+    if (jj_3R_36()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_123()
+ {
+    if (jj_scan_token(SLASH)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_125()
+ {
+    if (jj_scan_token(EXCLAMATION)) return true;
+    if (jj_3R_34()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_124()
+ {
+    if (jj_scan_token(MINUS)) return true;
+    if (jj_3R_34()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_120()
+ {
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_3R_124()) {
+    jj_scanpos = xsp;
+    if (jj_3R_125()) return true;
+    }
+    return false;
+  }
+
+  private boolean jj_3R_116()
+ {
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_3R_120()) jj_scanpos = xsp;
+    if (jj_3R_121()) return true;
+    if (jj_3R_34()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_119()
+ {
+    if (jj_scan_token(MINUS)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_122()
+ {
+    if (jj_scan_token(STAR)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_117()
+ {
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_3R_122()) {
+    jj_scanpos = xsp;
+    if (jj_3R_123()) return true;
+    }
+    if (jj_3R_34()) return true;
+    if (jj_3R_116()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_41()
+ {
+    if (jj_3R_60()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_22()
+ {
+    Token xsp;
+    while (true) {
+      xsp = jj_scanpos;
+      if (jj_3R_41()) { jj_scanpos = xsp; break; }
+    }
+    return false;
+  }
+
+  private boolean jj_3R_108()
+ {
+    if (jj_3R_116()) return true;
+    Token xsp;
+    while (true) {
+      xsp = jj_scanpos;
+      if (jj_3R_117()) { jj_scanpos = xsp; break; }
+    }
+    return false;
+  }
+
+  private boolean jj_3R_87()
+ {
+    if (jj_scan_token(PP_COMMENT_START)) return true;
+    if (jj_scan_token(PP_COMMENT_END)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_86()
+ {
+    if (jj_scan_token(PP_WHITESPACE)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_85()
+ {
+    if (jj_scan_token(PP_NEWLINECHAR)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_60()
+ {
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_3R_85()) {
+    jj_scanpos = xsp;
+    if (jj_3R_86()) {
+    jj_scanpos = xsp;
+    if (jj_3R_87()) return true;
+    }
+    }
+    return false;
+  }
+
+  private boolean jj_3R_76()
+ {
+    if (jj_scan_token(LESS)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_75()
+ {
+    if (jj_scan_token(LESS_EQUAL)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_74()
+ {
+    if (jj_scan_token(GREATER)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_118()
+ {
+    if (jj_scan_token(PLUS)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_72()
+ {
+    if (jj_3R_95()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_73()
+ {
+    if (jj_scan_token(GREATER_EQUAL)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_109()
+ {
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_3R_118()) {
+    jj_scanpos = xsp;
+    if (jj_3R_119()) return true;
+    }
+    if (jj_3R_34()) return true;
+    if (jj_3R_108()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_71()
+ {
+    if (jj_3R_77()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_106()
+ {
+    if (jj_3R_108()) return true;
+    Token xsp;
+    while (true) {
+      xsp = jj_scanpos;
+      if (jj_3R_109()) { jj_scanpos = xsp; break; }
+    }
+    return false;
+  }
+
+  private boolean jj_3R_42()
+ {
+    if (jj_scan_token(COLON)) return true;
+    if (jj_3R_22()) return true;
+    if (jj_3R_61()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_49()
+ {
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_3R_73()) {
+    jj_scanpos = xsp;
+    if (jj_3R_74()) {
+    jj_scanpos = xsp;
+    if (jj_3R_75()) {
+    jj_scanpos = xsp;
+    if (jj_3R_76()) return true;
+    }
+    }
+    }
+    if (jj_3R_26()) return true;
+    if (jj_3R_77()) return true;
+    return false;
+  }
+
+  private boolean jj_3_8()
+ {
+    if (jj_3R_28()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_69()
+ {
+    if (jj_scan_token(STAR)) return true;
+    if (jj_scan_token(EQUAL)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_68()
+ {
+    if (jj_scan_token(DOLLAR)) return true;
+    if (jj_scan_token(EQUAL)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_70()
+ {
+    if (jj_scan_token(STAR)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_115()
+ {
+    if (jj_scan_token(EXCLAMATION)) return true;
+    if (jj_scan_token(EQUAL)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_67()
+ {
+    if (jj_scan_token(CARET)) return true;
+    if (jj_scan_token(EQUAL)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_114()
+ {
+    if (jj_scan_token(EQUAL)) return true;
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_scan_token(37)) jj_scanpos = xsp;
+    return false;
+  }
+
+  private boolean jj_3R_66()
+ {
+    if (jj_scan_token(TILDE)) return true;
+    if (jj_scan_token(EQUAL)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_113()
+ {
+    if (jj_scan_token(LESS)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_65()
+ {
+    if (jj_scan_token(EQUAL)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_112()
+ {
+    if (jj_scan_token(GREATER)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_64()
+ {
+    if (jj_scan_token(EXCLAMATION)) return true;
+    if (jj_scan_token(EQUAL)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_111()
+ {
+    if (jj_scan_token(LESS_EQUAL)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_110()
+ {
+    if (jj_scan_token(GREATER_EQUAL)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_30()
+ {
+    if (jj_scan_token(EXCLAMATION)) return true;
+    if (jj_scan_token(TILDE)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_107()
+ {
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_3R_110()) {
+    jj_scanpos = xsp;
+    if (jj_3R_111()) {
+    jj_scanpos = xsp;
+    if (jj_3R_112()) {
+    jj_scanpos = xsp;
+    if (jj_3R_113()) {
+    jj_scanpos = xsp;
+    if (jj_3R_114()) {
+    jj_scanpos = xsp;
+    if (jj_3R_115()) return true;
+    }
+    }
+    }
+    }
+    }
+    if (jj_3R_34()) return true;
+    if (jj_3R_106()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_29()
+ {
+    if (jj_scan_token(EQUAL)) return true;
+    if (jj_scan_token(TILDE)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_48()
+ {
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_3R_64()) {
+    jj_scanpos = xsp;
+    if (jj_3R_65()) {
+    jj_scanpos = xsp;
+    if (jj_3R_66()) {
+    jj_scanpos = xsp;
+    if (jj_3R_67()) {
+    jj_scanpos = xsp;
+    if (jj_3R_68()) {
+    jj_scanpos = xsp;
+    if (jj_3R_69()) return true;
+    }
+    }
+    }
+    }
+    }
+    if (jj_3R_26()) return true;
+    xsp = jj_scanpos;
+    if (jj_3R_70()) jj_scanpos = xsp;
+    xsp = jj_scanpos;
+    if (jj_3_8()) {
+    jj_scanpos = xsp;
+    if (jj_3R_71()) {
+    jj_scanpos = xsp;
+    if (jj_3R_72()) return true;
+    }
+    }
+    return false;
+  }
+
+  private boolean jj_3R_31()
+ {
+    if (jj_scan_token(STAR)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_53()
+ {
+    if (jj_scan_token(COMMA)) return true;
+    if (jj_3R_26()) return true;
+    if (jj_3R_52()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_104()
+ {
+    if (jj_3R_106()) return true;
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_3R_107()) jj_scanpos = xsp;
+    return false;
+  }
+
+  private boolean jj_3R_33()
+ {
+    if (jj_3R_52()) return true;
+    Token xsp;
+    if (jj_3R_53()) return true;
+    while (true) {
+      xsp = jj_scanpos;
+      if (jj_3R_53()) { jj_scanpos = xsp; break; }
+    }
+    return false;
+  }
+
+  /** Generated Token Manager. */
+  public MapCSSParserTokenManager token_source;
+  SimpleCharStream jj_input_stream;
+  /** Current token. */
+  public Token token;
+  /** Next token. */
+  public Token jj_nt;
+  private int jj_ntk;
+  private Token jj_scanpos, jj_lastpos;
+  private int jj_la;
+  private int jj_gen;
+  final private int[] jj_la1 = new int[84];
+  static private int[] jj_la1_0;
+  static private int[] jj_la1_1;
+  static {
+      jj_la1_init_0();
+      jj_la1_init_1();
+   }
+   private static void jj_la1_init_0() {
+      jj_la1_0 = new int[] {0x1f671fe,0x1f2700e,0x1f671fe,0x2,0x4,0x8,0x100000,0x100000,0x800000,0x400000,0x101008,0x8,0x2,0x2,0x101000,0x800000,0x1c0,0x1c0,0x2000,0x2002000,0x2002000,0x1800,0x5800,0x10000000,0x10000000,0x10000000,0x400000,0x20001000,0x400000,0x0,0x80800000,0x80800000,0x0,0x0,0x20001000,0x20001000,0x0,0x80800000,0x80800000,0x0,0x2000,0x0,0x2000,0xa107800,0x800000,0x5800,0x0,0x25800,0x0,0x0,0x20000000,0x20000000,0x20000000,0x2007800,0x0,0x20000000,0x0,0x800000,0x20101800,0x1800,0x0,0x0,0x80000,0x80000,0x80000,0x1800,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x60000000,0x60000000,0x0,0x0,0xa107800,0x400000,0xa107800,0x5000,0xa002000,0x1800,};
+   }
+   private static void jj_la1_init_1() {
+      jj_la1_1 = new int[] {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2000,0x0,0x2000,0x0,0x0,0x0,0x400000,0x400000,0x0,0x0,0x0,0x1018,0x40040,0x40040,0x301018,0x301018,0x301018,0x0,0x800,0x40040,0x40040,0x100,0x0,0x2000,0x0,0x3040,0x0,0x0,0x40,0x0,0x8000,0x60,0x0,0x300e0,0x0,0x2000,0x1e,0x300fe,0x40,0x40000,0x0,0x0,0x40000,0x20,0x200,0x200,0x200,0x0,0x8000,0x400,0x4000,0x20,0x7e,0x7e,0x3000,0x3000,0x0,0x0,0x2040,0x2040,0x1000,0x0,0x3040,0x1000,0x0,0x80000,};
+   }
+  final private JJCalls[] jj_2_rtns = new JJCalls[14];
+  private boolean jj_rescan = false;
+  private int jj_gc = 0;
+
+  /** Constructor with InputStream. */
+  public MapCSSParser(java.io.InputStream stream) {
+     this(stream, null);
+  }
+  /** Constructor with InputStream and supplied encoding */
+  public MapCSSParser(java.io.InputStream stream, String encoding) {
+    try { jj_input_stream = new SimpleCharStream(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); }
+    token_source = new MapCSSParserTokenManager(jj_input_stream);
+    token = new Token();
+    jj_ntk = -1;
+    jj_gen = 0;
+    for (int i = 0; i < 84; i++) jj_la1[i] = -1;
+    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
+  }
+
+  /** Reinitialise. */
+  public void ReInit(java.io.InputStream stream) {
+     ReInit(stream, null);
+  }
+  /** Reinitialise. */
+  public void ReInit(java.io.InputStream stream, String encoding) {
+    try { jj_input_stream.ReInit(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); }
+    token_source.ReInit(jj_input_stream);
+    token = new Token();
+    jj_ntk = -1;
+    jj_gen = 0;
+    for (int i = 0; i < 84; i++) jj_la1[i] = -1;
+    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
+  }
+
+  /** Constructor. */
+  public MapCSSParser(java.io.Reader stream) {
+    jj_input_stream = new SimpleCharStream(stream, 1, 1);
+    token_source = new MapCSSParserTokenManager(jj_input_stream);
+    token = new Token();
+    jj_ntk = -1;
+    jj_gen = 0;
+    for (int i = 0; i < 84; i++) jj_la1[i] = -1;
+    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
+  }
+
+  /** Reinitialise. */
+  public void ReInit(java.io.Reader stream) {
+	if (jj_input_stream == null) {
+      jj_input_stream = new SimpleCharStream(stream, 1, 1);
+   } else {
+      jj_input_stream.ReInit(stream, 1, 1);
+   }
+   if (token_source == null) {
+      token_source = new MapCSSParserTokenManager(jj_input_stream);
+   }
+
+    token_source.ReInit(jj_input_stream);
+    token = new Token();
+    jj_ntk = -1;
+    jj_gen = 0;
+    for (int i = 0; i < 84; i++) jj_la1[i] = -1;
+    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
+  }
+
+  /** Constructor with generated Token Manager. */
+  public MapCSSParser(MapCSSParserTokenManager tm) {
+    token_source = tm;
+    token = new Token();
+    jj_ntk = -1;
+    jj_gen = 0;
+    for (int i = 0; i < 84; i++) jj_la1[i] = -1;
+    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
+  }
+
+  /** Reinitialise. */
+  public void ReInit(MapCSSParserTokenManager tm) {
+    token_source = tm;
+    token = new Token();
+    jj_ntk = -1;
+    jj_gen = 0;
+    for (int i = 0; i < 84; i++) jj_la1[i] = -1;
+    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
+  }
+
+  private Token jj_consume_token(int kind) throws ParseException {
+    Token oldToken;
+    if ((oldToken = token).next != null) token = token.next;
+    else token = token.next = token_source.getNextToken();
+    jj_ntk = -1;
+    if (token.kind == kind) {
+      jj_gen++;
+      if (++jj_gc > 100) {
+        jj_gc = 0;
+        for (int i = 0; i < jj_2_rtns.length; i++) {
+          JJCalls c = jj_2_rtns[i];
+          while (c != null) {
+            if (c.gen < jj_gen) c.first = null;
+            c = c.next;
+          }
+        }
+      }
+      return token;
+    }
+    token = oldToken;
+    jj_kind = kind;
+    throw generateParseException();
+  }
+
+  @SuppressWarnings("serial")
+  static private final class LookaheadSuccess extends java.lang.Error { }
+  final private LookaheadSuccess jj_ls = new LookaheadSuccess();
+  private boolean jj_scan_token(int kind) {
+    if (jj_scanpos == jj_lastpos) {
+      jj_la--;
+      if (jj_scanpos.next == null) {
+        jj_lastpos = jj_scanpos = jj_scanpos.next = token_source.getNextToken();
+      } else {
+        jj_lastpos = jj_scanpos = jj_scanpos.next;
+      }
+    } else {
+      jj_scanpos = jj_scanpos.next;
+    }
+    if (jj_rescan) {
+      int i = 0; Token tok = token;
+      while (tok != null && tok != jj_scanpos) { i++; tok = tok.next; }
+      if (tok != null) jj_add_error_token(kind, i);
+    }
+    if (jj_scanpos.kind != kind) return true;
+    if (jj_la == 0 && jj_scanpos == jj_lastpos) throw jj_ls;
+    return false;
+  }
+
+
+/** Get the next Token. */
+  final public Token getNextToken() {
+    if (token.next != null) token = token.next;
+    else token = token.next = token_source.getNextToken();
+    jj_ntk = -1;
+    jj_gen++;
+    return token;
+  }
+
+/** Get the specific Token. */
+  final public Token getToken(int index) {
+    Token t = token;
+    for (int i = 0; i < index; i++) {
+      if (t.next != null) t = t.next;
+      else t = t.next = token_source.getNextToken();
+    }
+    return t;
+  }
+
+  private int jj_ntk_f() {
+    if ((jj_nt=token.next) == null)
+      return (jj_ntk = (token.next=token_source.getNextToken()).kind);
+    else
+      return (jj_ntk = jj_nt.kind);
+  }
+
+  private java.util.List<int[]> jj_expentries = new java.util.ArrayList<int[]>();
+  private int[] jj_expentry;
+  private int jj_kind = -1;
+  private int[] jj_lasttokens = new int[100];
+  private int jj_endpos;
+
+  private void jj_add_error_token(int kind, int pos) {
+    if (pos >= 100) {
+       return;
+    }
+
+    if (pos == jj_endpos + 1) {
+      jj_lasttokens[jj_endpos++] = kind;
+    } else if (jj_endpos != 0) {
+      jj_expentry = new int[jj_endpos];
+
+      for (int i = 0; i < jj_endpos; i++) {
+        jj_expentry[i] = jj_lasttokens[i];
+      }
+
+      for (int[] oldentry : jj_expentries) {
+        if (oldentry.length == jj_expentry.length) {
+          boolean isMatched = true;
+
+          for (int i = 0; i < jj_expentry.length; i++) {
+            if (oldentry[i] != jj_expentry[i]) {
+              isMatched = false;
+              break;
+            }
+
+          }
+          if (isMatched) {
+            jj_expentries.add(jj_expentry);
+            break;
+          }
+        }
+      }
+
+      if (pos != 0) {
+        jj_lasttokens[(jj_endpos = pos) - 1] = kind;
+      }
+    }
+  }
+
+  /** Generate ParseException. */
+  public ParseException generateParseException() {
+    jj_expentries.clear();
+    boolean[] la1tokens = new boolean[58];
+    if (jj_kind >= 0) {
+      la1tokens[jj_kind] = true;
+      jj_kind = -1;
+    }
+    for (int i = 0; i < 84; i++) {
+      if (jj_la1[i] == jj_gen) {
+        for (int j = 0; j < 32; j++) {
+          if ((jj_la1_0[i] & (1<<j)) != 0) {
+            la1tokens[j] = true;
+          }
+          if ((jj_la1_1[i] & (1<<j)) != 0) {
+            la1tokens[32+j] = true;
+          }
+        }
+      }
+    }
+    for (int i = 0; i < 58; i++) {
+      if (la1tokens[i]) {
+        jj_expentry = new int[1];
+        jj_expentry[0] = i;
+        jj_expentries.add(jj_expentry);
+      }
+    }
+    jj_endpos = 0;
+    jj_rescan_token();
+    jj_add_error_token(0, 0);
+    int[][] exptokseq = new int[jj_expentries.size()][];
+    for (int i = 0; i < jj_expentries.size(); i++) {
+      exptokseq[i] = jj_expentries.get(i);
+    }
+    return new ParseException(token, exptokseq, tokenImage);
+  }
+
+  /** Enable tracing. */
+  final public void enable_tracing() {
+  }
+
+  /** Disable tracing. */
+  final public void disable_tracing() {
+  }
+
+  private void jj_rescan_token() {
+    jj_rescan = true;
+    for (int i = 0; i < 14; i++) {
+      try {
+        JJCalls p = jj_2_rtns[i];
+
+        do {
+          if (p.gen > jj_gen) {
+            jj_la = p.arg; jj_lastpos = jj_scanpos = p.first;
+            switch (i) {
+              case 0: jj_3_1(); break;
+              case 1: jj_3_2(); break;
+              case 2: jj_3_3(); break;
+              case 3: jj_3_4(); break;
+              case 4: jj_3_5(); break;
+              case 5: jj_3_6(); break;
+              case 6: jj_3_7(); break;
+              case 7: jj_3_8(); break;
+              case 8: jj_3_9(); break;
+              case 9: jj_3_10(); break;
+              case 10: jj_3_11(); break;
+              case 11: jj_3_12(); break;
+              case 12: jj_3_13(); break;
+              case 13: jj_3_14(); break;
+            }
+          }
+          p = p.next;
+        } while (p != null);
+
+        } catch(LookaheadSuccess ls) { }
+    }
+    jj_rescan = false;
+  }
+
+  private void jj_save(int index, int xla) {
+    JJCalls p = jj_2_rtns[index];
+    while (p.gen > jj_gen) {
+      if (p.next == null) { p = p.next = new JJCalls(); break; }
+      p = p.next;
+    }
+
+    p.gen = jj_gen + xla - jj_la; 
+    p.first = token;
+    p.arg = xla;
+  }
+
+  static final class JJCalls {
+    int gen;
+    Token first;
+    int arg;
+    JJCalls next;
+  }
+
+}
diff --git a/src/org/openstreetmap/josm/gui/mappaint/mapcss/parsergen/MapCSSParserConstants.java b/src/org/openstreetmap/josm/gui/mappaint/mapcss/parsergen/MapCSSParserConstants.java
new file mode 100644
index 0000000..34b1b33
--- /dev/null
+++ b/src/org/openstreetmap/josm/gui/mappaint/mapcss/parsergen/MapCSSParserConstants.java
@@ -0,0 +1,195 @@
+/* Generated By:JavaCC: Do not edit this line. MapCSSParserConstants.java */
+package org.openstreetmap.josm.gui.mappaint.mapcss.parsergen;
+
+
+/**
+ * Token literal values and constants.
+ * Generated by org.javacc.parser.OtherFilesGen#start()
+ */
+public interface MapCSSParserConstants {
+
+  /** End of File. */
+  int EOF = 0;
+  /** RegularExpression Id. */
+  int PP_AND = 1;
+  /** RegularExpression Id. */
+  int PP_OR = 2;
+  /** RegularExpression Id. */
+  int PP_NOT = 3;
+  /** RegularExpression Id. */
+  int PP_SUPPORTS = 4;
+  /** RegularExpression Id. */
+  int PP_MEDIA = 5;
+  /** RegularExpression Id. */
+  int PP_NEWLINECHAR = 6;
+  /** RegularExpression Id. */
+  int PP_WHITESPACE = 7;
+  /** RegularExpression Id. */
+  int PP_COMMENT_START = 8;
+  /** RegularExpression Id. */
+  int PP_COMMENT_END = 9;
+  /** RegularExpression Id. */
+  int SET = 11;
+  /** RegularExpression Id. */
+  int IDENT = 12;
+  /** RegularExpression Id. */
+  int UINT = 13;
+  /** RegularExpression Id. */
+  int STRING = 14;
+  /** RegularExpression Id. */
+  int PREDEFINED = 15;
+  /** RegularExpression Id. */
+  int REGEX_CHAR_WITHOUT_STAR = 16;
+  /** RegularExpression Id. */
+  int REGEX = 17;
+  /** RegularExpression Id. */
+  int LBRACE = 18;
+  /** RegularExpression Id. */
+  int RBRACE = 19;
+  /** RegularExpression Id. */
+  int LPAR = 20;
+  /** RegularExpression Id. */
+  int RPAR = 21;
+  /** RegularExpression Id. */
+  int COMMA = 22;
+  /** RegularExpression Id. */
+  int COLON = 23;
+  /** RegularExpression Id. */
+  int PP_SOMETHING_ELSE = 24;
+  /** RegularExpression Id. */
+  int UFLOAT = 25;
+  /** RegularExpression Id. */
+  int H = 26;
+  /** RegularExpression Id. */
+  int HEXCOLOR = 27;
+  /** RegularExpression Id. */
+  int S = 28;
+  /** RegularExpression Id. */
+  int STAR = 29;
+  /** RegularExpression Id. */
+  int SLASH = 30;
+  /** RegularExpression Id. */
+  int LSQUARE = 31;
+  /** RegularExpression Id. */
+  int RSQUARE = 32;
+  /** RegularExpression Id. */
+  int GREATER_EQUAL = 33;
+  /** RegularExpression Id. */
+  int LESS_EQUAL = 34;
+  /** RegularExpression Id. */
+  int GREATER = 35;
+  /** RegularExpression Id. */
+  int LESS = 36;
+  /** RegularExpression Id. */
+  int EQUAL = 37;
+  /** RegularExpression Id. */
+  int EXCLAMATION = 38;
+  /** RegularExpression Id. */
+  int TILDE = 39;
+  /** RegularExpression Id. */
+  int DCOLON = 40;
+  /** RegularExpression Id. */
+  int SEMICOLON = 41;
+  /** RegularExpression Id. */
+  int PIPE = 42;
+  /** RegularExpression Id. */
+  int PIPE_Z = 43;
+  /** RegularExpression Id. */
+  int PLUS = 44;
+  /** RegularExpression Id. */
+  int MINUS = 45;
+  /** RegularExpression Id. */
+  int AMPERSAND = 46;
+  /** RegularExpression Id. */
+  int QUESTION = 47;
+  /** RegularExpression Id. */
+  int DOLLAR = 48;
+  /** RegularExpression Id. */
+  int CARET = 49;
+  /** RegularExpression Id. */
+  int FULLSTOP = 50;
+  /** RegularExpression Id. */
+  int DEG = 51;
+  /** RegularExpression Id. */
+  int ELEMENT_OF = 52;
+  /** RegularExpression Id. */
+  int CROSSING = 53;
+  /** RegularExpression Id. */
+  int COMMENT_START = 54;
+  /** RegularExpression Id. */
+  int UNEXPECTED_CHAR = 55;
+  /** RegularExpression Id. */
+  int COMMENT_END = 56;
+
+  /** Lexical state. */
+  int PREPROCESSOR = 0;
+  /** Lexical state. */
+  int PP_COMMENT = 1;
+  /** Lexical state. */
+  int DEFAULT = 2;
+  /** Lexical state. */
+  int COMMENT = 3;
+
+  /** Literal token values. */
+  String[] tokenImage = {
+    "<EOF>",
+    "\"and\"",
+    "\"or\"",
+    "\"not\"",
+    "\"@supports\"",
+    "\"@media\"",
+    "<PP_NEWLINECHAR>",
+    "<PP_WHITESPACE>",
+    "\"/*\"",
+    "\"*/\"",
+    "<token of kind 10>",
+    "\"set\"",
+    "<IDENT>",
+    "<UINT>",
+    "<STRING>",
+    "<PREDEFINED>",
+    "<REGEX_CHAR_WITHOUT_STAR>",
+    "<REGEX>",
+    "\"{\"",
+    "\"}\"",
+    "\"(\"",
+    "\")\"",
+    "\",\"",
+    "\":\"",
+    "<PP_SOMETHING_ELSE>",
+    "<UFLOAT>",
+    "<H>",
+    "<HEXCOLOR>",
+    "<S>",
+    "\"*\"",
+    "\"/\"",
+    "\"[\"",
+    "\"]\"",
+    "\">=\"",
+    "\"<=\"",
+    "\">\"",
+    "\"<\"",
+    "\"=\"",
+    "\"!\"",
+    "\"~\"",
+    "\"::\"",
+    "\";\"",
+    "\"|\"",
+    "\"|z\"",
+    "\"+\"",
+    "\"-\"",
+    "\"&\"",
+    "\"?\"",
+    "\"$\"",
+    "\"^\"",
+    "\".\"",
+    "\"\\u00b0\"",
+    "\"\\u2208\"",
+    "\"\\u29c9\"",
+    "\"/*\"",
+    "<UNEXPECTED_CHAR>",
+    "\"*/\"",
+    "<token of kind 57>",
+  };
+
+}
diff --git a/src/org/openstreetmap/josm/gui/mappaint/mapcss/parsergen/MapCSSParserTokenManager.java b/src/org/openstreetmap/josm/gui/mappaint/mapcss/parsergen/MapCSSParserTokenManager.java
new file mode 100644
index 0000000..8ff2c29
--- /dev/null
+++ b/src/org/openstreetmap/josm/gui/mappaint/mapcss/parsergen/MapCSSParserTokenManager.java
@@ -0,0 +1,1450 @@
+/* MapCSSParserTokenManager.java */
+/* Generated By:JavaCC: Do not edit this line. MapCSSParserTokenManager.java */
+package org.openstreetmap.josm.gui.mappaint.mapcss.parsergen;
+import java.io.InputStream;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.mappaint.Keyword;
+import org.openstreetmap.josm.gui.mappaint.mapcss.Condition;
+import org.openstreetmap.josm.gui.mappaint.mapcss.Condition.Context;
+import org.openstreetmap.josm.gui.mappaint.mapcss.Expression;
+import org.openstreetmap.josm.gui.mappaint.mapcss.ExpressionFactory;
+import org.openstreetmap.josm.gui.mappaint.mapcss.ExpressionFactory.NullExpression;
+import org.openstreetmap.josm.gui.mappaint.mapcss.Instruction;
+import org.openstreetmap.josm.gui.mappaint.mapcss.LiteralExpression;
+import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSException;
+import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSRule;
+import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSRule.Declaration;
+import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSStyleSource;
+import org.openstreetmap.josm.gui.mappaint.mapcss.Selector;
+import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.ChildOrParentSelector;
+import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.GeneralSelector;
+import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.LinkSelector;
+import org.openstreetmap.josm.gui.mappaint.mapcss.Subpart;
+import org.openstreetmap.josm.tools.ColorHelper;
+import org.openstreetmap.josm.tools.Pair;
+import org.openstreetmap.josm.tools.Utils;
+
+/** Token Manager. */
+@SuppressWarnings("unused")public class MapCSSParserTokenManager implements MapCSSParserConstants {
+
+  /** Debug output. */
+  public  java.io.PrintStream debugStream = System.out;
+  /** Set debug output. */
+  public  void setDebugStream(java.io.PrintStream ds) { debugStream = ds; }
+private int jjStopAtPos(int pos, int kind)
+{
+   jjmatchedKind = kind;
+   jjmatchedPos = pos;
+   return pos + 1;
+}
+private int jjMoveStringLiteralDfa0_2(){
+   switch(curChar)
+   {
+      case 33:
+         jjmatchedKind = 38;
+         return jjMoveNfa_2(0, 0);
+      case 36:
+         jjmatchedKind = 48;
+         return jjMoveNfa_2(0, 0);
+      case 38:
+         jjmatchedKind = 46;
+         return jjMoveNfa_2(0, 0);
+      case 40:
+         jjmatchedKind = 20;
+         return jjMoveNfa_2(0, 0);
+      case 41:
+         jjmatchedKind = 21;
+         return jjMoveNfa_2(0, 0);
+      case 42:
+         jjmatchedKind = 29;
+         return jjMoveNfa_2(0, 0);
+      case 43:
+         jjmatchedKind = 44;
+         return jjMoveNfa_2(0, 0);
+      case 44:
+         jjmatchedKind = 22;
+         return jjMoveNfa_2(0, 0);
+      case 45:
+         jjmatchedKind = 45;
+         return jjMoveNfa_2(0, 0);
+      case 46:
+         jjmatchedKind = 50;
+         return jjMoveNfa_2(0, 0);
+      case 47:
+         jjmatchedKind = 30;
+         return jjMoveStringLiteralDfa1_2(0x40000000000000L);
+      case 58:
+         jjmatchedKind = 23;
+         return jjMoveStringLiteralDfa1_2(0x10000000000L);
+      case 59:
+         jjmatchedKind = 41;
+         return jjMoveNfa_2(0, 0);
+      case 60:
+         jjmatchedKind = 36;
+         return jjMoveStringLiteralDfa1_2(0x400000000L);
+      case 61:
+         jjmatchedKind = 37;
+         return jjMoveNfa_2(0, 0);
+      case 62:
+         jjmatchedKind = 35;
+         return jjMoveStringLiteralDfa1_2(0x200000000L);
+      case 63:
+         jjmatchedKind = 47;
+         return jjMoveNfa_2(0, 0);
+      case 83:
+         return jjMoveStringLiteralDfa1_2(0x800L);
+      case 91:
+         jjmatchedKind = 31;
+         return jjMoveNfa_2(0, 0);
+      case 93:
+         jjmatchedKind = 32;
+         return jjMoveNfa_2(0, 0);
+      case 94:
+         jjmatchedKind = 49;
+         return jjMoveNfa_2(0, 0);
+      case 115:
+         return jjMoveStringLiteralDfa1_2(0x800L);
+      case 123:
+         jjmatchedKind = 18;
+         return jjMoveNfa_2(0, 0);
+      case 124:
+         jjmatchedKind = 42;
+         return jjMoveStringLiteralDfa1_2(0x80000000000L);
+      case 125:
+         jjmatchedKind = 19;
+         return jjMoveNfa_2(0, 0);
+      case 126:
+         jjmatchedKind = 39;
+         return jjMoveNfa_2(0, 0);
+      case 176:
+         jjmatchedKind = 51;
+         return jjMoveNfa_2(0, 0);
+      case 8712:
+         jjmatchedKind = 52;
+         return jjMoveNfa_2(0, 0);
+      case 10697:
+         jjmatchedKind = 53;
+         return jjMoveNfa_2(0, 0);
+      default :
+         return jjMoveNfa_2(0, 0);
+   }
+}
+private int jjMoveStringLiteralDfa1_2(long active0){
+   try { curChar = input_stream.readChar(); }
+   catch(java.io.IOException e) {
+   return jjMoveNfa_2(0, 0);
+   }
+   switch(curChar)
+   {
+      case 42:
+         if ((active0 & 0x40000000000000L) != 0L)
+         {
+            jjmatchedKind = 54;
+            jjmatchedPos = 1;
+         }
+         break;
+      case 58:
+         if ((active0 & 0x10000000000L) != 0L)
+         {
+            jjmatchedKind = 40;
+            jjmatchedPos = 1;
+         }
+         break;
+      case 61:
+         if ((active0 & 0x200000000L) != 0L)
+         {
+            jjmatchedKind = 33;
+            jjmatchedPos = 1;
+         }
+         else if ((active0 & 0x400000000L) != 0L)
+         {
+            jjmatchedKind = 34;
+            jjmatchedPos = 1;
+         }
+         break;
+      case 69:
+         return jjMoveStringLiteralDfa2_2(active0, 0x800L);
+      case 101:
+         return jjMoveStringLiteralDfa2_2(active0, 0x800L);
+      case 122:
+         if ((active0 & 0x80000000000L) != 0L)
+         {
+            jjmatchedKind = 43;
+            jjmatchedPos = 1;
+         }
+         break;
+      default :
+         break;
+   }
+   return jjMoveNfa_2(0, 1);
+}
+private int jjMoveStringLiteralDfa2_2(long old0, long active0){
+   if (((active0 &= old0)) == 0L)
+      return jjMoveNfa_2(0, 1);
+   try { curChar = input_stream.readChar(); }
+   catch(java.io.IOException e) {
+   return jjMoveNfa_2(0, 1);
+   }
+   switch(curChar)
+   {
+      case 84:
+         if ((active0 & 0x800L) != 0L)
+         {
+            jjmatchedKind = 11;
+            jjmatchedPos = 2;
+         }
+         break;
+      case 116:
+         if ((active0 & 0x800L) != 0L)
+         {
+            jjmatchedKind = 11;
+            jjmatchedPos = 2;
+         }
+         break;
+      default :
+         break;
+   }
+   return jjMoveNfa_2(0, 2);
+}
+static final long[] jjbitVec0 = {
+   0xfffffffffffffffeL, 0xffffffffffffffffL, 0xffffffffffffffffL, 0xffffffffffffffffL
+};
+static final long[] jjbitVec2 = {
+   0x0L, 0x0L, 0xffffffffffffffffL, 0xffffffffffffffffL
+};
+private int jjMoveNfa_2(int startState, int curPos)
+{
+   int strKind = jjmatchedKind;
+   int strPos = jjmatchedPos;
+   int seenUpto;
+   input_stream.backup(seenUpto = curPos + 1);
+   try { curChar = input_stream.readChar(); }
+   catch(java.io.IOException e) { throw new Error("Internal Error"); }
+   curPos = 0;
+   int startsAt = 0;
+   jjnewStateCnt = 53;
+   int i = 1;
+   jjstateSet[0] = startState;
+   int kind = 0x7fffffff;
+   for (;;)
+   {
+      if (++jjround == 0x7fffffff)
+         ReInitRounds();
+      if (curChar < 64)
+      {
+         long l = 1L << curChar;
+         do
+         {
+            switch(jjstateSet[--i])
+            {
+               case 0:
+                  if ((0x3ff000000000000L & l) != 0L)
+                  {
+                     if (kind > 25)
+                        kind = 25;
+                     { jjCheckNAddTwoStates(35, 36); }
+                  }
+                  else if ((0x100003600L & l) != 0L)
+                  {
+                     if (kind > 28)
+                        kind = 28;
+                     { jjCheckNAdd(52); }
+                  }
+                  else if (curChar == 35)
+                     jjstateSet[jjnewStateCnt++] = 39;
+                  else if (curChar == 47)
+                     { jjAddStates(0, 2); }
+                  else if (curChar == 34)
+                     { jjCheckNAddStates(3, 5); }
+                  if ((0x3fe000000000000L & l) != 0L)
+                  {
+                     if (kind > 13)
+                        kind = 13;
+                     { jjCheckNAdd(3); }
+                  }
+                  break;
+               case 1:
+                  if ((0x3ff200000000000L & l) == 0L)
+                     break;
+                  if (kind > 12)
+                     kind = 12;
+                  jjstateSet[jjnewStateCnt++] = 1;
+                  break;
+               case 2:
+                  if ((0x3fe000000000000L & l) == 0L)
+                     break;
+                  if (kind > 13)
+                     kind = 13;
+                  { jjCheckNAdd(3); }
+                  break;
+               case 3:
+                  if ((0x3ff000000000000L & l) == 0L)
+                     break;
+                  if (kind > 13)
+                     kind = 13;
+                  { jjCheckNAdd(3); }
+                  break;
+               case 4:
+               case 8:
+                  if (curChar == 34)
+                     { jjCheckNAddStates(3, 5); }
+                  break;
+               case 5:
+                  if ((0xfffffffb00000000L & l) != 0L)
+                     { jjCheckNAddStates(3, 5); }
+                  break;
+               case 6:
+                  if (curChar == 34 && kind > 14)
+                     kind = 14;
+                  break;
+               case 10:
+                  if (curChar == 47)
+                     { jjAddStates(0, 2); }
+                  break;
+               case 11:
+                  if ((0xffff7bff00000000L & l) != 0L)
+                     { jjCheckNAddStates(6, 9); }
+                  break;
+               case 12:
+                  if ((0xffff7fff00000000L & l) != 0L)
+                     { jjCheckNAddStates(6, 9); }
+                  break;
+               case 15:
+                  if (curChar == 47 && kind > 17)
+                     kind = 17;
+                  break;
+               case 17:
+                  if (curChar == 36)
+                     { jjCheckNAddStates(6, 9); }
+                  break;
+               case 19:
+                  if (curChar == 42)
+                     { jjCheckNAddStates(6, 9); }
+                  break;
+               case 20:
+                  if (curChar == 63)
+                     { jjCheckNAddStates(6, 9); }
+                  break;
+               case 23:
+                  if (curChar == 41)
+                     { jjCheckNAddStates(6, 9); }
+                  break;
+               case 24:
+                  if (curChar == 40)
+                     { jjCheckNAddStates(6, 9); }
+                  break;
+               case 25:
+                  if (curChar == 34)
+                     { jjCheckNAddStates(6, 9); }
+                  break;
+               case 26:
+                  if (curChar == 39)
+                     { jjCheckNAddStates(6, 9); }
+                  break;
+               case 27:
+                  if (curChar == 46)
+                     { jjCheckNAddStates(6, 9); }
+                  break;
+               case 28:
+                  if (curChar == 43)
+                     { jjCheckNAddStates(6, 9); }
+                  break;
+               case 32:
+                  if (curChar == 47)
+                     { jjCheckNAddStates(6, 9); }
+                  break;
+               case 35:
+                  if ((0x3ff000000000000L & l) == 0L)
+                     break;
+                  if (kind > 25)
+                     kind = 25;
+                  { jjCheckNAddTwoStates(35, 36); }
+                  break;
+               case 36:
+                  if (curChar == 46)
+                     { jjCheckNAdd(37); }
+                  break;
+               case 37:
+                  if ((0x3ff000000000000L & l) == 0L)
+                     break;
+                  if (kind > 25)
+                     kind = 25;
+                  { jjCheckNAdd(37); }
+                  break;
+               case 38:
+                  if (curChar == 35)
+                     jjstateSet[jjnewStateCnt++] = 39;
+                  break;
+               case 39:
+                  if ((0x3ff000000000000L & l) != 0L)
+                     { jjAddStates(10, 12); }
+                  break;
+               case 40:
+                  if ((0x3ff000000000000L & l) != 0L)
+                     jjstateSet[jjnewStateCnt++] = 41;
+                  break;
+               case 41:
+                  if ((0x3ff000000000000L & l) != 0L)
+                     jjstateSet[jjnewStateCnt++] = 42;
+                  break;
+               case 42:
+                  if ((0x3ff000000000000L & l) != 0L)
+                     jjstateSet[jjnewStateCnt++] = 43;
+                  break;
+               case 43:
+                  if ((0x3ff000000000000L & l) != 0L)
+                     jjstateSet[jjnewStateCnt++] = 44;
+                  break;
+               case 44:
+                  if ((0x3ff000000000000L & l) != 0L)
+                     jjstateSet[jjnewStateCnt++] = 45;
+                  break;
+               case 45:
+               case 50:
+               case 51:
+                  if ((0x3ff000000000000L & l) != 0L)
+                     { jjCheckNAdd(46); }
+                  break;
+               case 46:
+                  if ((0x3ff000000000000L & l) != 0L && kind > 27)
+                     kind = 27;
+                  break;
+               case 47:
+                  if ((0x3ff000000000000L & l) != 0L)
+                     jjstateSet[jjnewStateCnt++] = 48;
+                  break;
+               case 48:
+                  if ((0x3ff000000000000L & l) != 0L)
+                     jjstateSet[jjnewStateCnt++] = 49;
+                  break;
+               case 49:
+                  if ((0x3ff000000000000L & l) != 0L)
+                     jjstateSet[jjnewStateCnt++] = 50;
+                  break;
+               case 52:
+                  if ((0x100003600L & l) == 0L)
+                     break;
+                  if (kind > 28)
+                     kind = 28;
+                  { jjCheckNAdd(52); }
+                  break;
+               default : break;
+            }
+         } while(i != startsAt);
+      }
+      else if (curChar < 128)
+      {
+         long l = 1L << (curChar & 077);
+         do
+         {
+            switch(jjstateSet[--i])
+            {
+               case 0:
+               case 1:
+                  if ((0x7fffffe87fffffeL & l) == 0L)
+                     break;
+                  if (kind > 12)
+                     kind = 12;
+                  { jjCheckNAdd(1); }
+                  break;
+               case 5:
+                  if ((0x7fffffffefffffffL & l) != 0L)
+                     { jjCheckNAddStates(3, 5); }
+                  break;
+               case 7:
+                  if (curChar == 92)
+                     { jjAddStates(13, 14); }
+                  break;
+               case 9:
+                  if (curChar == 92)
+                     { jjCheckNAddStates(3, 5); }
+                  break;
+               case 11:
+               case 12:
+                  if ((0x7fffffffefffffffL & l) != 0L)
+                     { jjCheckNAddStates(6, 9); }
+                  break;
+               case 13:
+               case 33:
+                  if (curChar == 92)
+                     { jjCheckNAdd(14); }
+                  break;
+               case 14:
+                  if ((0x488001404880096L & l) != 0L)
+                     { jjCheckNAddStates(6, 9); }
+                  break;
+               case 16:
+                  if (curChar == 92)
+                     { jjCheckNAddStates(15, 30); }
+                  break;
+               case 18:
+                  if (curChar == 94)
+                     { jjCheckNAddStates(6, 9); }
+                  break;
+               case 21:
+                  if (curChar == 125)
+                     { jjCheckNAddStates(6, 9); }
+                  break;
+               case 22:
+                  if (curChar == 123)
+                     { jjCheckNAddStates(6, 9); }
+                  break;
+               case 29:
+                  if (curChar == 93)
+                     { jjCheckNAddStates(6, 9); }
+                  break;
+               case 30:
+                  if (curChar == 91)
+                     { jjCheckNAddStates(6, 9); }
+                  break;
+               case 31:
+                  if (curChar == 92)
+                     { jjCheckNAddStates(6, 9); }
+                  break;
+               case 34:
+                  if (curChar == 92)
+                     { jjCheckNAddStates(31, 46); }
+                  break;
+               case 39:
+                  if ((0x7e0000007eL & l) != 0L)
+                     { jjAddStates(10, 12); }
+                  break;
+               case 40:
+                  if ((0x7e0000007eL & l) != 0L)
+                     jjstateSet[jjnewStateCnt++] = 41;
+                  break;
+               case 41:
+                  if ((0x7e0000007eL & l) != 0L)
+                     jjstateSet[jjnewStateCnt++] = 42;
+                  break;
+               case 42:
+                  if ((0x7e0000007eL & l) != 0L)
+                     jjstateSet[jjnewStateCnt++] = 43;
+                  break;
+               case 43:
+                  if ((0x7e0000007eL & l) != 0L)
+                     jjstateSet[jjnewStateCnt++] = 44;
+                  break;
+               case 44:
+                  if ((0x7e0000007eL & l) != 0L)
+                     jjstateSet[jjnewStateCnt++] = 45;
+                  break;
+               case 45:
+               case 50:
+               case 51:
+                  if ((0x7e0000007eL & l) != 0L)
+                     { jjCheckNAdd(46); }
+                  break;
+               case 46:
+                  if ((0x7e0000007eL & l) != 0L && kind > 27)
+                     kind = 27;
+                  break;
+               case 47:
+                  if ((0x7e0000007eL & l) != 0L)
+                     jjstateSet[jjnewStateCnt++] = 48;
+                  break;
+               case 48:
+                  if ((0x7e0000007eL & l) != 0L)
+                     jjstateSet[jjnewStateCnt++] = 49;
+                  break;
+               case 49:
+                  if ((0x7e0000007eL & l) != 0L)
+                     jjstateSet[jjnewStateCnt++] = 50;
+                  break;
+               default : break;
+            }
+         } while(i != startsAt);
+      }
+      else
+      {
+         int hiByte = (curChar >> 8);
+         int i1 = hiByte >> 6;
+         long l1 = 1L << (hiByte & 077);
+         int i2 = (curChar & 0xff) >> 6;
+         long l2 = 1L << (curChar & 077);
+         do
+         {
+            switch(jjstateSet[--i])
+            {
+               case 5:
+                  if (jjCanMove_0(hiByte, i1, i2, l1, l2))
+                     { jjAddStates(3, 5); }
+                  break;
+               case 11:
+               case 12:
+                  if (jjCanMove_0(hiByte, i1, i2, l1, l2))
+                     { jjCheckNAddStates(6, 9); }
+                  break;
+               default : if (i1 == 0 || l1 == 0 || i2 == 0 ||  l2 == 0) break; else break;
+            }
+         } while(i != startsAt);
+      }
+      if (kind != 0x7fffffff)
+      {
+         jjmatchedKind = kind;
+         jjmatchedPos = curPos;
+         kind = 0x7fffffff;
+      }
+      ++curPos;
+      if ((i = jjnewStateCnt) == (startsAt = 53 - (jjnewStateCnt = startsAt)))
+         break;
+      try { curChar = input_stream.readChar(); }
+      catch(java.io.IOException e) { break; }
+   }
+   if (jjmatchedPos > strPos)
+      return curPos;
+
+   int toRet = Math.max(curPos, seenUpto);
+
+   if (curPos < toRet)
+      for (i = toRet - Math.min(curPos, seenUpto); i-- > 0; )
+         try { curChar = input_stream.readChar(); }
+         catch(java.io.IOException e) { throw new Error("Internal Error : Please send a bug report."); }
+
+   if (jjmatchedPos < strPos)
+   {
+      jjmatchedKind = strKind;
+      jjmatchedPos = strPos;
+   }
+   else if (jjmatchedPos == strPos && jjmatchedKind > strKind)
+      jjmatchedKind = strKind;
+
+   return toRet;
+}
+private final int jjStopStringLiteralDfa_0(int pos, long active0){
+   switch (pos)
+   {
+      case 0:
+         if ((active0 & 0xeL) != 0L)
+         {
+            jjmatchedKind = 12;
+            return 3;
+         }
+         if ((active0 & 0x100L) != 0L)
+            return 13;
+         return -1;
+      case 1:
+         if ((active0 & 0x4L) != 0L)
+            return 3;
+         if ((active0 & 0xaL) != 0L)
+         {
+            jjmatchedKind = 12;
+            jjmatchedPos = 1;
+            return 3;
+         }
+         return -1;
+      case 2:
+         if ((active0 & 0xaL) != 0L)
+            return 3;
+         return -1;
+      default :
+         return -1;
+   }
+}
+private final int jjStartNfa_0(int pos, long active0){
+   return jjMoveNfa_0(jjStopStringLiteralDfa_0(pos, active0), pos + 1);
+}
+private int jjMoveStringLiteralDfa0_0(){
+   switch(curChar)
+   {
+      case 40:
+         return jjStopAtPos(0, 20);
+      case 41:
+         return jjStopAtPos(0, 21);
+      case 44:
+         return jjStopAtPos(0, 22);
+      case 47:
+         return jjMoveStringLiteralDfa1_0(0x100L);
+      case 58:
+         return jjStopAtPos(0, 23);
+      case 64:
+         return jjMoveStringLiteralDfa1_0(0x30L);
+      case 97:
+         return jjMoveStringLiteralDfa1_0(0x2L);
+      case 110:
+         return jjMoveStringLiteralDfa1_0(0x8L);
+      case 111:
+         return jjMoveStringLiteralDfa1_0(0x4L);
+      case 123:
+         return jjStopAtPos(0, 18);
+      case 125:
+         return jjStopAtPos(0, 19);
+      default :
+         return jjMoveNfa_0(0, 0);
+   }
+}
+private int jjMoveStringLiteralDfa1_0(long active0){
+   try { curChar = input_stream.readChar(); }
+   catch(java.io.IOException e) {
+      jjStopStringLiteralDfa_0(0, active0);
+      return 1;
+   }
+   switch(curChar)
+   {
+      case 42:
+         if ((active0 & 0x100L) != 0L)
+            return jjStopAtPos(1, 8);
+         break;
+      case 109:
+         return jjMoveStringLiteralDfa2_0(active0, 0x20L);
+      case 110:
+         return jjMoveStringLiteralDfa2_0(active0, 0x2L);
+      case 111:
+         return jjMoveStringLiteralDfa2_0(active0, 0x8L);
+      case 114:
+         if ((active0 & 0x4L) != 0L)
+            return jjStartNfaWithStates_0(1, 2, 3);
+         break;
+      case 115:
+         return jjMoveStringLiteralDfa2_0(active0, 0x10L);
+      default :
+         break;
+   }
+   return jjStartNfa_0(0, active0);
+}
+private int jjMoveStringLiteralDfa2_0(long old0, long active0){
+   if (((active0 &= old0)) == 0L)
+      return jjStartNfa_0(0, old0);
+   try { curChar = input_stream.readChar(); }
+   catch(java.io.IOException e) {
+      jjStopStringLiteralDfa_0(1, active0);
+      return 2;
+   }
+   switch(curChar)
+   {
+      case 100:
+         if ((active0 & 0x2L) != 0L)
+            return jjStartNfaWithStates_0(2, 1, 3);
+         break;
+      case 101:
+         return jjMoveStringLiteralDfa3_0(active0, 0x20L);
+      case 116:
+         if ((active0 & 0x8L) != 0L)
+            return jjStartNfaWithStates_0(2, 3, 3);
+         break;
+      case 117:
+         return jjMoveStringLiteralDfa3_0(active0, 0x10L);
+      default :
+         break;
+   }
+   return jjStartNfa_0(1, active0);
+}
+private int jjMoveStringLiteralDfa3_0(long old0, long active0){
+   if (((active0 &= old0)) == 0L)
+      return jjStartNfa_0(1, old0);
+   try { curChar = input_stream.readChar(); }
+   catch(java.io.IOException e) {
+      jjStopStringLiteralDfa_0(2, active0);
+      return 3;
+   }
+   switch(curChar)
+   {
+      case 100:
+         return jjMoveStringLiteralDfa4_0(active0, 0x20L);
+      case 112:
+         return jjMoveStringLiteralDfa4_0(active0, 0x10L);
+      default :
+         break;
+   }
+   return jjStartNfa_0(2, active0);
+}
+private int jjMoveStringLiteralDfa4_0(long old0, long active0){
+   if (((active0 &= old0)) == 0L)
+      return jjStartNfa_0(2, old0);
+   try { curChar = input_stream.readChar(); }
+   catch(java.io.IOException e) {
+      jjStopStringLiteralDfa_0(3, active0);
+      return 4;
+   }
+   switch(curChar)
+   {
+      case 105:
+         return jjMoveStringLiteralDfa5_0(active0, 0x20L);
+      case 112:
+         return jjMoveStringLiteralDfa5_0(active0, 0x10L);
+      default :
+         break;
+   }
+   return jjStartNfa_0(3, active0);
+}
+private int jjMoveStringLiteralDfa5_0(long old0, long active0){
+   if (((active0 &= old0)) == 0L)
+      return jjStartNfa_0(3, old0);
+   try { curChar = input_stream.readChar(); }
+   catch(java.io.IOException e) {
+      jjStopStringLiteralDfa_0(4, active0);
+      return 5;
+   }
+   switch(curChar)
+   {
+      case 97:
+         if ((active0 & 0x20L) != 0L)
+            return jjStopAtPos(5, 5);
+         break;
+      case 111:
+         return jjMoveStringLiteralDfa6_0(active0, 0x10L);
+      default :
+         break;
+   }
+   return jjStartNfa_0(4, active0);
+}
+private int jjMoveStringLiteralDfa6_0(long old0, long active0){
+   if (((active0 &= old0)) == 0L)
+      return jjStartNfa_0(4, old0);
+   try { curChar = input_stream.readChar(); }
+   catch(java.io.IOException e) {
+      jjStopStringLiteralDfa_0(5, active0);
+      return 6;
+   }
+   switch(curChar)
+   {
+      case 114:
+         return jjMoveStringLiteralDfa7_0(active0, 0x10L);
+      default :
+         break;
+   }
+   return jjStartNfa_0(5, active0);
+}
+private int jjMoveStringLiteralDfa7_0(long old0, long active0){
+   if (((active0 &= old0)) == 0L)
+      return jjStartNfa_0(5, old0);
+   try { curChar = input_stream.readChar(); }
+   catch(java.io.IOException e) {
+      jjStopStringLiteralDfa_0(6, active0);
+      return 7;
+   }
+   switch(curChar)
+   {
+      case 116:
+         return jjMoveStringLiteralDfa8_0(active0, 0x10L);
+      default :
+         break;
+   }
+   return jjStartNfa_0(6, active0);
+}
+private int jjMoveStringLiteralDfa8_0(long old0, long active0){
+   if (((active0 &= old0)) == 0L)
+      return jjStartNfa_0(6, old0);
+   try { curChar = input_stream.readChar(); }
+   catch(java.io.IOException e) {
+      jjStopStringLiteralDfa_0(7, active0);
+      return 8;
+   }
+   switch(curChar)
+   {
+      case 115:
+         if ((active0 & 0x10L) != 0L)
+            return jjStopAtPos(8, 4);
+         break;
+      default :
+         break;
+   }
+   return jjStartNfa_0(7, active0);
+}
+private int jjStartNfaWithStates_0(int pos, int kind, int state)
+{
+   jjmatchedKind = kind;
+   jjmatchedPos = pos;
+   try { curChar = input_stream.readChar(); }
+   catch(java.io.IOException e) { return pos + 1; }
+   return jjMoveNfa_0(state, pos + 1);
+}
+private int jjMoveNfa_0(int startState, int curPos)
+{
+   int startsAt = 0;
+   jjnewStateCnt = 37;
+   int i = 1;
+   jjstateSet[0] = startState;
+   int kind = 0x7fffffff;
+   for (;;)
+   {
+      if (++jjround == 0x7fffffff)
+         ReInitRounds();
+      if (curChar < 64)
+      {
+         long l = 1L << curChar;
+         do
+         {
+            switch(jjstateSet[--i])
+            {
+               case 0:
+                  if ((0x3fe000000000000L & l) != 0L)
+                  {
+                     if (kind > 13)
+                        kind = 13;
+                     { jjCheckNAdd(5); }
+                  }
+                  else if ((0x3400L & l) != 0L)
+                  {
+                     if (kind > 6)
+                        kind = 6;
+                  }
+                  else if ((0x100000200L & l) != 0L)
+                  {
+                     if (kind > 7)
+                        kind = 7;
+                  }
+                  else if (curChar == 47)
+                     { jjAddStates(47, 49); }
+                  else if (curChar == 34)
+                     { jjCheckNAddStates(50, 52); }
+                  break;
+               case 13:
+                  if ((0xffff7bff00000000L & l) != 0L)
+                     { jjCheckNAddStates(53, 56); }
+                  break;
+               case 1:
+                  if ((0x100000200L & l) != 0L && kind > 7)
+                     kind = 7;
+                  break;
+               case 3:
+                  if ((0x3ff200000000000L & l) == 0L)
+                     break;
+                  if (kind > 12)
+                     kind = 12;
+                  jjstateSet[jjnewStateCnt++] = 3;
+                  break;
+               case 4:
+                  if ((0x3fe000000000000L & l) == 0L)
+                     break;
+                  if (kind > 13)
+                     kind = 13;
+                  { jjCheckNAdd(5); }
+                  break;
+               case 5:
+                  if ((0x3ff000000000000L & l) == 0L)
+                     break;
+                  if (kind > 13)
+                     kind = 13;
+                  { jjCheckNAdd(5); }
+                  break;
+               case 6:
+               case 10:
+                  if (curChar == 34)
+                     { jjCheckNAddStates(50, 52); }
+                  break;
+               case 7:
+                  if ((0xfffffffb00000000L & l) != 0L)
+                     { jjCheckNAddStates(50, 52); }
+                  break;
+               case 8:
+                  if (curChar == 34 && kind > 14)
+                     kind = 14;
+                  break;
+               case 12:
+                  if (curChar == 47)
+                     { jjAddStates(47, 49); }
+                  break;
+               case 14:
+                  if ((0xffff7fff00000000L & l) != 0L)
+                     { jjCheckNAddStates(53, 56); }
+                  break;
+               case 17:
+                  if (curChar == 47 && kind > 17)
+                     kind = 17;
+                  break;
+               case 19:
+                  if (curChar == 36)
+                     { jjCheckNAddStates(53, 56); }
+                  break;
+               case 21:
+                  if (curChar == 42)
+                     { jjCheckNAddStates(53, 56); }
+                  break;
+               case 22:
+                  if (curChar == 63)
+                     { jjCheckNAddStates(53, 56); }
+                  break;
+               case 25:
+                  if (curChar == 41)
+                     { jjCheckNAddStates(53, 56); }
+                  break;
+               case 26:
+                  if (curChar == 40)
+                     { jjCheckNAddStates(53, 56); }
+                  break;
+               case 27:
+                  if (curChar == 34)
+                     { jjCheckNAddStates(53, 56); }
+                  break;
+               case 28:
+                  if (curChar == 39)
+                     { jjCheckNAddStates(53, 56); }
+                  break;
+               case 29:
+                  if (curChar == 46)
+                     { jjCheckNAddStates(53, 56); }
+                  break;
+               case 30:
+                  if (curChar == 43)
+                     { jjCheckNAddStates(53, 56); }
+                  break;
+               case 34:
+                  if (curChar == 47)
+                     { jjCheckNAddStates(53, 56); }
+                  break;
+               default : break;
+            }
+         } while(i != startsAt);
+      }
+      else if (curChar < 128)
+      {
+         long l = 1L << (curChar & 077);
+         do
+         {
+            switch(jjstateSet[--i])
+            {
+               case 0:
+               case 3:
+                  if ((0x7fffffe87fffffeL & l) == 0L)
+                     break;
+                  if (kind > 12)
+                     kind = 12;
+                  { jjCheckNAdd(3); }
+                  break;
+               case 13:
+                  if ((0x7fffffffefffffffL & l) != 0L)
+                     { jjCheckNAddStates(53, 56); }
+                  else if (curChar == 92)
+                     { jjCheckNAddStates(57, 72); }
+                  if (curChar == 92)
+                     { jjCheckNAdd(16); }
+                  break;
+               case 7:
+                  if ((0x7fffffffefffffffL & l) != 0L)
+                     { jjCheckNAddStates(50, 52); }
+                  break;
+               case 9:
+                  if (curChar == 92)
+                     { jjAddStates(73, 74); }
+                  break;
+               case 11:
+                  if (curChar == 92)
+                     { jjCheckNAddStates(50, 52); }
+                  break;
+               case 14:
+                  if ((0x7fffffffefffffffL & l) != 0L)
+                     { jjCheckNAddStates(53, 56); }
+                  break;
+               case 15:
+                  if (curChar == 92)
+                     { jjCheckNAdd(16); }
+                  break;
+               case 16:
+                  if ((0x488001404880096L & l) != 0L)
+                     { jjCheckNAddStates(53, 56); }
+                  break;
+               case 18:
+                  if (curChar == 92)
+                     { jjCheckNAddStates(75, 90); }
+                  break;
+               case 20:
+                  if (curChar == 94)
+                     { jjCheckNAddStates(53, 56); }
+                  break;
+               case 23:
+                  if (curChar == 125)
+                     { jjCheckNAddStates(53, 56); }
+                  break;
+               case 24:
+                  if (curChar == 123)
+                     { jjCheckNAddStates(53, 56); }
+                  break;
+               case 31:
+                  if (curChar == 93)
+                     { jjCheckNAddStates(53, 56); }
+                  break;
+               case 32:
+                  if (curChar == 91)
+                     { jjCheckNAddStates(53, 56); }
+                  break;
+               case 33:
+                  if (curChar == 92)
+                     { jjCheckNAddStates(53, 56); }
+                  break;
+               case 35:
+                  if (curChar == 92)
+                     { jjCheckNAdd(16); }
+                  break;
+               case 36:
+                  if (curChar == 92)
+                     { jjCheckNAddStates(57, 72); }
+                  break;
+               default : break;
+            }
+         } while(i != startsAt);
+      }
+      else
+      {
+         int hiByte = (curChar >> 8);
+         int i1 = hiByte >> 6;
+         long l1 = 1L << (hiByte & 077);
+         int i2 = (curChar & 0xff) >> 6;
+         long l2 = 1L << (curChar & 077);
+         do
+         {
+            switch(jjstateSet[--i])
+            {
+               case 13:
+               case 14:
+                  if (jjCanMove_0(hiByte, i1, i2, l1, l2))
+                     { jjCheckNAddStates(53, 56); }
+                  break;
+               case 7:
+                  if (jjCanMove_0(hiByte, i1, i2, l1, l2))
+                     { jjAddStates(50, 52); }
+                  break;
+               default : if (i1 == 0 || l1 == 0 || i2 == 0 ||  l2 == 0) break; else break;
+            }
+         } while(i != startsAt);
+      }
+      if (kind != 0x7fffffff)
+      {
+         jjmatchedKind = kind;
+         jjmatchedPos = curPos;
+         kind = 0x7fffffff;
+      }
+      ++curPos;
+      if ((i = jjnewStateCnt) == (startsAt = 37 - (jjnewStateCnt = startsAt)))
+         return curPos;
+      try { curChar = input_stream.readChar(); }
+      catch(java.io.IOException e) { return curPos; }
+   }
+}
+private int jjMoveStringLiteralDfa0_1(){
+   switch(curChar)
+   {
+      case 42:
+         return jjMoveStringLiteralDfa1_1(0x200L);
+      default :
+         return 1;
+   }
+}
+private int jjMoveStringLiteralDfa1_1(long active0){
+   try { curChar = input_stream.readChar(); }
+   catch(java.io.IOException e) {
+      return 1;
+   }
+   switch(curChar)
+   {
+      case 47:
+         if ((active0 & 0x200L) != 0L)
+            return jjStopAtPos(1, 9);
+         break;
+      default :
+         return 2;
+   }
+   return 2;
+}
+private int jjMoveStringLiteralDfa0_3(){
+   switch(curChar)
+   {
+      case 42:
+         return jjMoveStringLiteralDfa1_3(0x100000000000000L);
+      default :
+         return 1;
+   }
+}
+private int jjMoveStringLiteralDfa1_3(long active0){
+   try { curChar = input_stream.readChar(); }
+   catch(java.io.IOException e) {
+      return 1;
+   }
+   switch(curChar)
+   {
+      case 47:
+         if ((active0 & 0x100000000000000L) != 0L)
+            return jjStopAtPos(1, 56);
+         break;
+      default :
+         return 2;
+   }
+   return 2;
+}
+static final int[] jjnextStates = {
+   11, 33, 34, 5, 6, 7, 12, 13, 15, 16, 40, 47, 51, 8, 9, 17, 
+   18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 32, 
+   31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 13, 
+   35, 36, 7, 8, 9, 14, 15, 17, 18, 34, 33, 32, 31, 30, 29, 28, 
+   27, 26, 25, 24, 23, 22, 21, 20, 19, 10, 11, 19, 20, 21, 22, 23, 
+   24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 
+};
+private static final boolean jjCanMove_0(int hiByte, int i1, int i2, long l1, long l2)
+{
+   switch(hiByte)
+   {
+      case 0:
+         return ((jjbitVec2[i2] & l2) != 0L);
+      default :
+         if ((jjbitVec0[i1] & l1) != 0L)
+            return true;
+         return false;
+   }
+}
+
+/** Token literal values. */
+public static final String[] jjstrLiteralImages = {
+"", "\141\156\144", "\157\162", "\156\157\164", 
+"\100\163\165\160\160\157\162\164\163", "\100\155\145\144\151\141", null, null, "\57\52", null, null, null, null, null, 
+null, null, null, null, "\173", "\175", "\50", "\51", "\54", "\72", null, null, null, 
+null, null, "\52", "\57", "\133", "\135", "\76\75", "\74\75", "\76", "\74", "\75", 
+"\41", "\176", "\72\72", "\73", "\174", "\174\172", "\53", "\55", "\46", "\77", 
+"\44", "\136", "\56", "\260", "\u2208", "\u29c9", "\57\52", null, "\52\57", null, };
+protected Token jjFillToken()
+{
+   final Token t;
+   final String curTokenImage;
+   final int beginLine;
+   final int endLine;
+   final int beginColumn;
+   final int endColumn;
+   String im = jjstrLiteralImages[jjmatchedKind];
+   curTokenImage = (im == null) ? input_stream.GetImage() : im;
+   beginLine = input_stream.getBeginLine();
+   beginColumn = input_stream.getBeginColumn();
+   endLine = input_stream.getEndLine();
+   endColumn = input_stream.getEndColumn();
+   t = Token.newToken(jjmatchedKind, curTokenImage);
+
+   t.beginLine = beginLine;
+   t.endLine = endLine;
+   t.beginColumn = beginColumn;
+   t.endColumn = endColumn;
+
+   return t;
+}
+
+int curLexState = 2;
+int defaultLexState = 2;
+int jjnewStateCnt;
+int jjround;
+int jjmatchedPos;
+int jjmatchedKind;
+
+/** Get the next Token. */
+public Token getNextToken() 
+{
+  Token matchedToken;
+  int curPos = 0;
+
+  EOFLoop :
+  for (;;)
+  {
+   try
+   {
+      curChar = input_stream.BeginToken();
+   }
+   catch(Exception e)
+   {
+      jjmatchedKind = 0;
+      jjmatchedPos = -1;
+      matchedToken = jjFillToken();
+      return matchedToken;
+   }
+
+   for (;;)
+   {
+     switch(curLexState)
+     {
+       case 0:
+         jjmatchedKind = 0x7fffffff;
+         jjmatchedPos = 0;
+         curPos = jjMoveStringLiteralDfa0_0();
+         if (jjmatchedPos == 0 && jjmatchedKind > 24)
+         {
+            jjmatchedKind = 24;
+         }
+         break;
+       case 1:
+         jjmatchedKind = 0x7fffffff;
+         jjmatchedPos = 0;
+         curPos = jjMoveStringLiteralDfa0_1();
+         if (jjmatchedPos == 0 && jjmatchedKind > 10)
+         {
+            jjmatchedKind = 10;
+         }
+         break;
+       case 2:
+         jjmatchedKind = 0x7fffffff;
+         jjmatchedPos = 0;
+         curPos = jjMoveStringLiteralDfa0_2();
+         if (jjmatchedPos == 0 && jjmatchedKind > 55)
+         {
+            jjmatchedKind = 55;
+         }
+         break;
+       case 3:
+         jjmatchedKind = 0x7fffffff;
+         jjmatchedPos = 0;
+         curPos = jjMoveStringLiteralDfa0_3();
+         if (jjmatchedPos == 0 && jjmatchedKind > 57)
+         {
+            jjmatchedKind = 57;
+         }
+         break;
+     }
+     if (jjmatchedKind != 0x7fffffff)
+     {
+        if (jjmatchedPos + 1 < curPos)
+           input_stream.backup(curPos - jjmatchedPos - 1);
+        if ((jjtoToken[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L)
+        {
+           matchedToken = jjFillToken();
+       if (jjnewLexState[jjmatchedKind] != -1)
+         curLexState = jjnewLexState[jjmatchedKind];
+           return matchedToken;
+        }
+        else if ((jjtoSkip[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L)
+        {
+         if (jjnewLexState[jjmatchedKind] != -1)
+           curLexState = jjnewLexState[jjmatchedKind];
+           continue EOFLoop;
+        }
+      if (jjnewLexState[jjmatchedKind] != -1)
+        curLexState = jjnewLexState[jjmatchedKind];
+        curPos = 0;
+        jjmatchedKind = 0x7fffffff;
+        try {
+           curChar = input_stream.readChar();
+           continue;
+        }
+        catch (java.io.IOException e1) { }
+     }
+     int error_line = input_stream.getEndLine();
+     int error_column = input_stream.getEndColumn();
+     String error_after = null;
+     boolean EOFSeen = false;
+     try { input_stream.readChar(); input_stream.backup(1); }
+     catch (java.io.IOException e1) {
+        EOFSeen = true;
+        error_after = curPos <= 1 ? "" : input_stream.GetImage();
+        if (curChar == '\n' || curChar == '\r') {
+           error_line++;
+           error_column = 0;
+        }
+        else
+           error_column++;
+     }
+     if (!EOFSeen) {
+        input_stream.backup(1);
+        error_after = curPos <= 1 ? "" : input_stream.GetImage();
+     }
+     throw new TokenMgrError(EOFSeen, curLexState, error_line, error_column, error_after, curChar, TokenMgrError.LEXICAL_ERROR);
+   }
+  }
+}
+
+private void jjCheckNAdd(int state)
+{
+   if (jjrounds[state] != jjround)
+   {
+      jjstateSet[jjnewStateCnt++] = state;
+      jjrounds[state] = jjround;
+   }
+}
+private void jjAddStates(int start, int end)
+{
+   do {
+      jjstateSet[jjnewStateCnt++] = jjnextStates[start];
+   } while (start++ != end);
+}
+private void jjCheckNAddTwoStates(int state1, int state2)
+{
+   jjCheckNAdd(state1);
+   jjCheckNAdd(state2);
+}
+
+private void jjCheckNAddStates(int start, int end)
+{
+   do {
+      jjCheckNAdd(jjnextStates[start]);
+   } while (start++ != end);
+}
+
+    /** Constructor. */
+    public MapCSSParserTokenManager(SimpleCharStream stream){
+
+      if (SimpleCharStream.staticFlag)
+            throw new Error("ERROR: Cannot use a static CharStream class with a non-static lexical analyzer.");
+
+    input_stream = stream;
+  }
+
+  /** Constructor. */
+  public MapCSSParserTokenManager (SimpleCharStream stream, int lexState){
+    ReInit(stream);
+    SwitchTo(lexState);
+  }
+
+  /** Reinitialise parser. */
+  public void ReInit(SimpleCharStream stream)
+  {
+	
+    jjmatchedPos = jjnewStateCnt = 0;
+    curLexState = defaultLexState;
+    input_stream = stream;
+    ReInitRounds();
+  }
+
+  private void ReInitRounds()
+  {
+    int i;
+    jjround = 0x80000001;
+    for (i = 53; i-- > 0;)
+      jjrounds[i] = 0x80000000;
+  }
+
+  /** Reinitialise parser. */
+  public void ReInit( SimpleCharStream stream, int lexState)
+  {
+  
+    ReInit( stream);
+    SwitchTo(lexState);
+  }
+
+  /** Switch to specified lex state. */
+  public void SwitchTo(int lexState)
+  {
+    if (lexState >= 4 || lexState < 0)
+      throw new TokenMgrError("Error: Ignoring invalid lexical state : " + lexState + ". State unchanged.", TokenMgrError.INVALID_LEXICAL_STATE);
+    else
+      curLexState = lexState;
+  }
+
+/** Lexer state names. */
+public static final String[] lexStateNames = {
+   "PREPROCESSOR",
+   "PP_COMMENT",
+   "DEFAULT",
+   "COMMENT",
+};
+
+/** Lex State array. */
+public static final int[] jjnewLexState = {
+   -1, -1, -1, -1, -1, -1, -1, -1, 1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
+   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
+   -1, -1, -1, -1, 3, -1, 2, -1, 
+};
+static final long[] jjtoToken = {
+   0x1fffffffbfe7bffL, 
+};
+static final long[] jjtoSkip = {
+   0x200000000000000L, 
+};
+static final long[] jjtoMore = {
+   0x400L, 
+};
+    protected SimpleCharStream  input_stream;
+
+    private final int[] jjrounds = new int[53];
+    private final int[] jjstateSet = new int[2 * 53];
+
+    
+    protected int curChar;
+}
diff --git a/src/org/openstreetmap/josm/gui/mappaint/mapcss/parsergen/ParseException.java b/src/org/openstreetmap/josm/gui/mappaint/mapcss/parsergen/ParseException.java
new file mode 100644
index 0000000..c86ad69
--- /dev/null
+++ b/src/org/openstreetmap/josm/gui/mappaint/mapcss/parsergen/ParseException.java
@@ -0,0 +1,195 @@
+/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 6.1 */
+/* JavaCCOptions:KEEP_LINE_COLUMN=true */
+package org.openstreetmap.josm.gui.mappaint.mapcss.parsergen;
+
+/**
+ * This exception is thrown when parse errors are encountered.
+ * You can explicitly create objects of this exception type by
+ * calling the method generateParseException in the generated
+ * parser.
+ *
+ * You can modify this class to customize your error reporting
+ * mechanisms so long as you retain the public fields.
+ */
+public class ParseException extends Exception {
+
+  /**
+   * The version identifier for this Serializable class.
+   * Increment only if the <i>serialized</i> form of the
+   * class changes.
+   */
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * The end of line string for this machine.
+   */
+  protected static String EOL = System.getProperty("line.separator", "\n");
+
+  /**
+   * This constructor is used by the method "generateParseException"
+   * in the generated parser.  Calling this constructor generates
+   * a new object of this type with the fields "currentToken",
+   * "expectedTokenSequences", and "tokenImage" set.
+   */
+  public ParseException(Token currentTokenVal,
+                        int[][] expectedTokenSequencesVal,
+                        String[] tokenImageVal
+                       )
+  {
+    super(initialise(currentTokenVal, expectedTokenSequencesVal, tokenImageVal));
+    currentToken = currentTokenVal;
+    expectedTokenSequences = expectedTokenSequencesVal;
+    tokenImage = tokenImageVal;
+  }
+
+  /**
+   * The following constructors are for use by you for whatever
+   * purpose you can think of.  Constructing the exception in this
+   * manner makes the exception behave in the normal way - i.e., as
+   * documented in the class "Throwable".  The fields "errorToken",
+   * "expectedTokenSequences", and "tokenImage" do not contain
+   * relevant information.  The JavaCC generated code does not use
+   * these constructors.
+   */
+
+  public ParseException() {
+    super();
+  }
+
+  /** Constructor with message. */
+  public ParseException(String message) {
+    super(message);
+  }
+
+
+  /**
+   * This is the last token that has been consumed successfully.  If
+   * this object has been created due to a parse error, the token
+   * followng this token will (therefore) be the first error token.
+   */
+  public Token currentToken;
+
+  /**
+   * Each entry in this array is an array of integers.  Each array
+   * of integers represents a sequence of tokens (by their ordinal
+   * values) that is expected at this point of the parse.
+   */
+  public int[][] expectedTokenSequences;
+
+  /**
+   * This is a reference to the "tokenImage" array of the generated
+   * parser within which the parse error occurred.  This array is
+   * defined in the generated ...Constants interface.
+   */
+  public String[] tokenImage;
+
+  /**
+   * It uses "currentToken" and "expectedTokenSequences" to generate a parse
+   * error message and returns it.  If this object has been created
+   * due to a parse error, and you do not catch it (it gets thrown
+   * from the parser) the correct error message
+   * gets displayed.
+   */
+  private static String initialise(Token currentToken,
+                           int[][] expectedTokenSequences,
+                           String[] tokenImage) {
+
+    StringBuffer expected = new StringBuffer();
+    int maxSize = 0;
+    for (int i = 0; i < expectedTokenSequences.length; i++) {
+      if (maxSize < expectedTokenSequences[i].length) {
+        maxSize = expectedTokenSequences[i].length;
+      }
+      for (int j = 0; j < expectedTokenSequences[i].length; j++) {
+        expected.append(tokenImage[expectedTokenSequences[i][j]]).append(' ');
+      }
+      if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) {
+        expected.append("...");
+      }
+      expected.append(EOL).append("    ");
+    }
+    String retval = "Encountered \"";
+    Token tok = currentToken.next;
+    for (int i = 0; i < maxSize; i++) {
+      if (i != 0) retval += " ";
+      if (tok.kind == 0) {
+        retval += tokenImage[0];
+        break;
+      }
+      retval += " " + tokenImage[tok.kind];
+      retval += " \"";
+      retval += add_escapes(tok.image);
+      retval += " \"";
+      tok = tok.next;
+    }
+    if (currentToken.next != null) {
+        retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn;
+    }
+    retval += "." + EOL;
+    
+    
+    if (expectedTokenSequences.length == 0) {
+        // Nothing to add here
+    } else {
+	    if (expectedTokenSequences.length == 1) {
+	      retval += "Was expecting:" + EOL + "    ";
+	    } else {
+	      retval += "Was expecting one of:" + EOL + "    ";
+	    }
+	    retval += expected.toString();
+    }
+    
+    return retval;
+  }
+
+
+  /**
+   * Used to convert raw characters to their escaped version
+   * when these raw version cannot be used as part of an ASCII
+   * string literal.
+   */
+  static String add_escapes(String str) {
+      StringBuffer retval = new StringBuffer();
+      char ch;
+      for (int i = 0; i < str.length(); i++) {
+        switch (str.charAt(i))
+        {
+           case '\b':
+              retval.append("\\b");
+              continue;
+           case '\t':
+              retval.append("\\t");
+              continue;
+           case '\n':
+              retval.append("\\n");
+              continue;
+           case '\f':
+              retval.append("\\f");
+              continue;
+           case '\r':
+              retval.append("\\r");
+              continue;
+           case '\"':
+              retval.append("\\\"");
+              continue;
+           case '\'':
+              retval.append("\\\'");
+              continue;
+           case '\\':
+              retval.append("\\\\");
+              continue;
+           default:
+              if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
+                 String s = "0000" + Integer.toString(ch, 16);
+                 retval.append("\\u" + s.substring(s.length() - 4, s.length()));
+              } else {
+                 retval.append(ch);
+              }
+              continue;
+        }
+      }
+      return retval.toString();
+   }
+
+}
+/* JavaCC - OriginalChecksum=548bceecbf58182b12388d687653c3d7 (do not edit this line) */
diff --git a/src/org/openstreetmap/josm/gui/mappaint/mapcss/parsergen/SimpleCharStream.java b/src/org/openstreetmap/josm/gui/mappaint/mapcss/parsergen/SimpleCharStream.java
new file mode 100644
index 0000000..2057b40
--- /dev/null
+++ b/src/org/openstreetmap/josm/gui/mappaint/mapcss/parsergen/SimpleCharStream.java
@@ -0,0 +1,474 @@
+/* Generated By:JavaCC: Do not edit this line. SimpleCharStream.java Version 6.1 */
+/* JavaCCOptions:STATIC=false,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
+package org.openstreetmap.josm.gui.mappaint.mapcss.parsergen;
+
+/**
+ * An implementation of interface CharStream, where the stream is assumed to
+ * contain only ASCII characters (without unicode processing).
+ */
+
+public class SimpleCharStream
+{
+/** Whether parser is static. */
+  public static final boolean staticFlag = false;
+  int bufsize;
+  int available;
+  int tokenBegin;
+/** Position in buffer. */
+  public int bufpos = -1;
+  protected int bufline[];
+  protected int bufcolumn[];
+
+  protected int column = 0;
+  protected int line = 1;
+
+  protected boolean prevCharIsCR = false;
+  protected boolean prevCharIsLF = false;
+
+  protected java.io.Reader inputStream;
+
+  protected char[] buffer;
+  protected int maxNextCharInd = 0;
+  protected int inBuf = 0;
+  protected int tabSize = 1;
+  protected boolean trackLineColumn = true;
+
+  public void setTabSize(int i) { tabSize = i; }
+  public int getTabSize() { return tabSize; }
+
+
+
+  protected void ExpandBuff(boolean wrapAround)
+  {
+    char[] newbuffer = new char[bufsize + 2048];
+    int newbufline[] = new int[bufsize + 2048];
+    int newbufcolumn[] = new int[bufsize + 2048];
+
+    try
+    {
+      if (wrapAround)
+      {
+        System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
+        System.arraycopy(buffer, 0, newbuffer, bufsize - tokenBegin, bufpos);
+        buffer = newbuffer;
+
+        System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
+        System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos);
+        bufline = newbufline;
+
+        System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
+        System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos);
+        bufcolumn = newbufcolumn;
+
+        maxNextCharInd = (bufpos += (bufsize - tokenBegin));
+      }
+      else
+      {
+        System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
+        buffer = newbuffer;
+
+        System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
+        bufline = newbufline;
+
+        System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
+        bufcolumn = newbufcolumn;
+
+        maxNextCharInd = (bufpos -= tokenBegin);
+      }
+    }
+    catch (Throwable t)
+    {
+      throw new Error(t.getMessage());
+    }
+
+
+    bufsize += 2048;
+    available = bufsize;
+    tokenBegin = 0;
+  }
+
+  protected void FillBuff() throws java.io.IOException
+  {
+    if (maxNextCharInd == available)
+    {
+      if (available == bufsize)
+      {
+        if (tokenBegin > 2048)
+        {
+          bufpos = maxNextCharInd = 0;
+          available = tokenBegin;
+        }
+        else if (tokenBegin < 0)
+          bufpos = maxNextCharInd = 0;
+        else
+          ExpandBuff(false);
+      }
+      else if (available > tokenBegin)
+        available = bufsize;
+      else if ((tokenBegin - available) < 2048)
+        ExpandBuff(true);
+      else
+        available = tokenBegin;
+    }
+
+    int i;
+    try {
+      if ((i = inputStream.read(buffer, maxNextCharInd, available - maxNextCharInd)) == -1)
+      {
+        inputStream.close();
+        throw new java.io.IOException();
+      }
+      else
+        maxNextCharInd += i;
+      return;
+    }
+    catch(java.io.IOException e) {
+      --bufpos;
+      backup(0);
+      if (tokenBegin == -1)
+        tokenBegin = bufpos;
+      throw e;
+    }
+  }
+
+/** Start. */
+  public char BeginToken() throws java.io.IOException
+  {
+    tokenBegin = -1;
+    char c = readChar();
+    tokenBegin = bufpos;
+
+    return c;
+  }
+
+  protected void UpdateLineColumn(char c)
+  {
+    column++;
+
+    if (prevCharIsLF)
+    {
+      prevCharIsLF = false;
+      line += (column = 1);
+    }
+    else if (prevCharIsCR)
+    {
+      prevCharIsCR = false;
+      if (c == '\n')
+      {
+        prevCharIsLF = true;
+      }
+      else
+        line += (column = 1);
+    }
+
+    switch (c)
+    {
+      case '\r' :
+        prevCharIsCR = true;
+        break;
+      case '\n' :
+        prevCharIsLF = true;
+        break;
+      case '\t' :
+        column--;
+        column += (tabSize - (column % tabSize));
+        break;
+      default :
+        break;
+    }
+
+    bufline[bufpos] = line;
+    bufcolumn[bufpos] = column;
+  }
+
+/** Read a character. */
+  public char readChar() throws java.io.IOException
+  {
+    if (inBuf > 0)
+    {
+      --inBuf;
+
+      if (++bufpos == bufsize)
+        bufpos = 0;
+
+      return buffer[bufpos];
+    }
+
+    if (++bufpos >= maxNextCharInd)
+      FillBuff();
+
+    char c = buffer[bufpos];
+
+    UpdateLineColumn(c);
+    return c;
+  }
+
+  @Deprecated
+  /**
+   * @deprecated
+   * @see #getEndColumn
+   */
+
+  public int getColumn() {
+    return bufcolumn[bufpos];
+  }
+
+  @Deprecated
+  /**
+   * @deprecated
+   * @see #getEndLine
+   */
+
+  public int getLine() {
+    return bufline[bufpos];
+  }
+
+  /** Get token end column number. */
+  public int getEndColumn() {
+    return bufcolumn[bufpos];
+  }
+
+  /** Get token end line number. */
+  public int getEndLine() {
+     return bufline[bufpos];
+  }
+
+  /** Get token beginning column number. */
+  public int getBeginColumn() {
+    return bufcolumn[tokenBegin];
+  }
+
+  /** Get token beginning line number. */
+  public int getBeginLine() {
+    return bufline[tokenBegin];
+  }
+
+/** Backup a number of characters. */
+  public void backup(int amount) {
+
+    inBuf += amount;
+    if ((bufpos -= amount) < 0)
+      bufpos += bufsize;
+  }
+
+  /** Constructor. */
+  public SimpleCharStream(java.io.Reader dstream, int startline,
+  int startcolumn, int buffersize)
+  {
+    inputStream = dstream;
+    line = startline;
+    column = startcolumn - 1;
+
+    available = bufsize = buffersize;
+    buffer = new char[buffersize];
+    bufline = new int[buffersize];
+    bufcolumn = new int[buffersize];
+  }
+
+  /** Constructor. */
+  public SimpleCharStream(java.io.Reader dstream, int startline,
+                          int startcolumn)
+  {
+    this(dstream, startline, startcolumn, 4096);
+  }
+
+  /** Constructor. */
+  public SimpleCharStream(java.io.Reader dstream)
+  {
+    this(dstream, 1, 1, 4096);
+  }
+
+  /** Reinitialise. */
+  public void ReInit(java.io.Reader dstream, int startline,
+  int startcolumn, int buffersize)
+  {
+    inputStream = dstream;
+    line = startline;
+    column = startcolumn - 1;
+
+    if (buffer == null || buffersize != buffer.length)
+    {
+      available = bufsize = buffersize;
+      buffer = new char[buffersize];
+      bufline = new int[buffersize];
+      bufcolumn = new int[buffersize];
+    }
+    prevCharIsLF = prevCharIsCR = false;
+    tokenBegin = inBuf = maxNextCharInd = 0;
+    bufpos = -1;
+  }
+
+  /** Reinitialise. */
+  public void ReInit(java.io.Reader dstream, int startline,
+                     int startcolumn)
+  {
+    ReInit(dstream, startline, startcolumn, 4096);
+  }
+
+  /** Reinitialise. */
+  public void ReInit(java.io.Reader dstream)
+  {
+    ReInit(dstream, 1, 1, 4096);
+  }
+  /** Constructor. */
+  public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
+  int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException
+  {
+    this(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
+  }
+
+  /** Constructor. */
+  public SimpleCharStream(java.io.InputStream dstream, int startline,
+  int startcolumn, int buffersize)
+  {
+    this(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
+  }
+
+  /** Constructor. */
+  public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
+                          int startcolumn) throws java.io.UnsupportedEncodingException
+  {
+    this(dstream, encoding, startline, startcolumn, 4096);
+  }
+
+  /** Constructor. */
+  public SimpleCharStream(java.io.InputStream dstream, int startline,
+                          int startcolumn)
+  {
+    this(dstream, startline, startcolumn, 4096);
+  }
+
+  /** Constructor. */
+  public SimpleCharStream(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException
+  {
+    this(dstream, encoding, 1, 1, 4096);
+  }
+
+  /** Constructor. */
+  public SimpleCharStream(java.io.InputStream dstream)
+  {
+    this(dstream, 1, 1, 4096);
+  }
+
+  /** Reinitialise. */
+  public void ReInit(java.io.InputStream dstream, String encoding, int startline,
+                          int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException
+  {
+    ReInit(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
+  }
+
+  /** Reinitialise. */
+  public void ReInit(java.io.InputStream dstream, int startline,
+                          int startcolumn, int buffersize)
+  {
+    ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
+  }
+
+  /** Reinitialise. */
+  public void ReInit(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException
+  {
+    ReInit(dstream, encoding, 1, 1, 4096);
+  }
+
+  /** Reinitialise. */
+  public void ReInit(java.io.InputStream dstream)
+  {
+    ReInit(dstream, 1, 1, 4096);
+  }
+  /** Reinitialise. */
+  public void ReInit(java.io.InputStream dstream, String encoding, int startline,
+                     int startcolumn) throws java.io.UnsupportedEncodingException
+  {
+    ReInit(dstream, encoding, startline, startcolumn, 4096);
+  }
+  /** Reinitialise. */
+  public void ReInit(java.io.InputStream dstream, int startline,
+                     int startcolumn)
+  {
+    ReInit(dstream, startline, startcolumn, 4096);
+  }
+  /** Get token literal value. */
+  public String GetImage()
+  {
+    if (bufpos >= tokenBegin)
+      return new String(buffer, tokenBegin, bufpos - tokenBegin + 1);
+    else
+      return new String(buffer, tokenBegin, bufsize - tokenBegin) +
+                            new String(buffer, 0, bufpos + 1);
+  }
+
+  /** Get the suffix. */
+  public char[] GetSuffix(int len)
+  {
+    char[] ret = new char[len];
+
+    if ((bufpos + 1) >= len)
+      System.arraycopy(buffer, bufpos - len + 1, ret, 0, len);
+    else
+    {
+      System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0,
+                                                        len - bufpos - 1);
+      System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1);
+    }
+
+    return ret;
+  }
+
+  /** Reset buffer when finished. */
+  public void Done()
+  {
+    buffer = null;
+    bufline = null;
+    bufcolumn = null;
+  }
+
+  /**
+   * Method to adjust line and column numbers for the start of a token.
+   */
+  public void adjustBeginLineColumn(int newLine, int newCol)
+  {
+    int start = tokenBegin;
+    int len;
+
+    if (bufpos >= tokenBegin)
+    {
+      len = bufpos - tokenBegin + inBuf + 1;
+    }
+    else
+    {
+      len = bufsize - tokenBegin + bufpos + 1 + inBuf;
+    }
+
+    int i = 0, j = 0, k = 0;
+    int nextColDiff = 0, columnDiff = 0;
+
+    while (i < len && bufline[j = start % bufsize] == bufline[k = ++start % bufsize])
+    {
+      bufline[j] = newLine;
+      nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j];
+      bufcolumn[j] = newCol + columnDiff;
+      columnDiff = nextColDiff;
+      i++;
+    }
+
+    if (i < len)
+    {
+      bufline[j] = newLine++;
+      bufcolumn[j] = newCol + columnDiff;
+
+      while (i++ < len)
+      {
+        if (bufline[j = start % bufsize] != bufline[++start % bufsize])
+          bufline[j] = newLine++;
+        else
+          bufline[j] = newLine;
+      }
+    }
+
+    line = bufline[j];
+    column = bufcolumn[j];
+  }
+  boolean getTrackLineColumn() { return trackLineColumn; }
+  void setTrackLineColumn(boolean tlc) { trackLineColumn = tlc; }
+}
+/* JavaCC - OriginalChecksum=2f6b7f39a94ff76199e633e8579cec6c (do not edit this line) */
diff --git a/src/org/openstreetmap/josm/gui/mappaint/mapcss/parsergen/Token.java b/src/org/openstreetmap/josm/gui/mappaint/mapcss/parsergen/Token.java
new file mode 100644
index 0000000..1e940cd
--- /dev/null
+++ b/src/org/openstreetmap/josm/gui/mappaint/mapcss/parsergen/Token.java
@@ -0,0 +1,131 @@
+/* Generated By:JavaCC: Do not edit this line. Token.java Version 6.1 */
+/* JavaCCOptions:TOKEN_EXTENDS=,KEEP_LINE_COLUMN=true,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
+package org.openstreetmap.josm.gui.mappaint.mapcss.parsergen;
+
+/**
+ * Describes the input token stream.
+ */
+
+public class Token implements java.io.Serializable {
+
+  /**
+   * The version identifier for this Serializable class.
+   * Increment only if the <i>serialized</i> form of the
+   * class changes.
+   */
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * An integer that describes the kind of this token.  This numbering
+   * system is determined by JavaCCParser, and a table of these numbers is
+   * stored in the file ...Constants.java.
+   */
+  public int kind;
+
+  /** The line number of the first character of this Token. */
+  public int beginLine;
+  /** The column number of the first character of this Token. */
+  public int beginColumn;
+  /** The line number of the last character of this Token. */
+  public int endLine;
+  /** The column number of the last character of this Token. */
+  public int endColumn;
+
+  /**
+   * The string image of the token.
+   */
+  public String image;
+
+  /**
+   * A reference to the next regular (non-special) token from the input
+   * stream.  If this is the last token from the input stream, or if the
+   * token manager has not read tokens beyond this one, this field is
+   * set to null.  This is true only if this token is also a regular
+   * token.  Otherwise, see below for a description of the contents of
+   * this field.
+   */
+  public Token next;
+
+  /**
+   * This field is used to access special tokens that occur prior to this
+   * token, but after the immediately preceding regular (non-special) token.
+   * If there are no such special tokens, this field is set to null.
+   * When there are more than one such special token, this field refers
+   * to the last of these special tokens, which in turn refers to the next
+   * previous special token through its specialToken field, and so on
+   * until the first special token (whose specialToken field is null).
+   * The next fields of special tokens refer to other special tokens that
+   * immediately follow it (without an intervening regular token).  If there
+   * is no such token, this field is null.
+   */
+  public Token specialToken;
+
+  /**
+   * An optional attribute value of the Token.
+   * Tokens which are not used as syntactic sugar will often contain
+   * meaningful values that will be used later on by the compiler or
+   * interpreter. This attribute value is often different from the image.
+   * Any subclass of Token that actually wants to return a non-null value can
+   * override this method as appropriate.
+   */
+  public Object getValue() {
+    return null;
+  }
+
+  /**
+   * No-argument constructor
+   */
+  public Token() {}
+
+  /**
+   * Constructs a new token for the specified Image.
+   */
+  public Token(int kind)
+  {
+    this(kind, null);
+  }
+
+  /**
+   * Constructs a new token for the specified Image and Kind.
+   */
+  public Token(int kind, String image)
+  {
+    this.kind = kind;
+    this.image = image;
+  }
+
+  /**
+   * Returns the image.
+   */
+  public String toString()
+  {
+    return image;
+  }
+
+  /**
+   * Returns a new Token object, by default. However, if you want, you
+   * can create and return subclass objects based on the value of ofKind.
+   * Simply add the cases to the switch for all those special cases.
+   * For example, if you have a subclass of Token called IDToken that
+   * you want to create if ofKind is ID, simply add something like :
+   *
+   *    case MyParserConstants.ID : return new IDToken(ofKind, image);
+   *
+   * to the following switch statement. Then you can cast matchedToken
+   * variable to the appropriate type and use sit in your lexical actions.
+   */
+  public static Token newToken(int ofKind, String image)
+  {
+    switch(ofKind)
+    {
+      default : return new Token(ofKind, image);
+    }
+  }
+
+  public static Token newToken(int ofKind)
+  {
+    return newToken(ofKind, null);
+  }
+
+}
+/* JavaCC - OriginalChecksum=9a5dc89ff6b77704ef74bd54f3677052 (do not edit this line) */
diff --git a/src/org/openstreetmap/josm/gui/mappaint/mapcss/parsergen/TokenMgrError.java b/src/org/openstreetmap/josm/gui/mappaint/mapcss/parsergen/TokenMgrError.java
new file mode 100644
index 0000000..56b083c
--- /dev/null
+++ b/src/org/openstreetmap/josm/gui/mappaint/mapcss/parsergen/TokenMgrError.java
@@ -0,0 +1,146 @@
+/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 6.1 */
+/* JavaCCOptions: */
+package org.openstreetmap.josm.gui.mappaint.mapcss.parsergen;
+
+/** Token Manager Error. */
+public class TokenMgrError extends Error
+{
+
+  /**
+   * The version identifier for this Serializable class.
+   * Increment only if the <i>serialized</i> form of the
+   * class changes.
+   */
+  private static final long serialVersionUID = 1L;
+
+  /*
+   * Ordinals for various reasons why an Error of this type can be thrown.
+   */
+
+  /**
+   * Lexical error occurred.
+   */
+  public static final int LEXICAL_ERROR = 0;
+
+  /**
+   * An attempt was made to create a second instance of a static token manager.
+   */
+  public static final int STATIC_LEXER_ERROR = 1;
+
+  /**
+   * Tried to change to an invalid lexical state.
+   */
+  public static final int INVALID_LEXICAL_STATE = 2;
+
+  /**
+   * Detected (and bailed out of) an infinite loop in the token manager.
+   */
+  public static final int LOOP_DETECTED = 3;
+
+  /**
+   * Indicates the reason why the exception is thrown. It will have
+   * one of the above 4 values.
+   */
+  int errorCode;
+
+  /**
+   * Replaces unprintable characters by their escaped (or unicode escaped)
+   * equivalents in the given string
+   */
+  protected static final String addEscapes(String str) {
+    StringBuffer retval = new StringBuffer();
+    char ch;
+    for (int i = 0; i < str.length(); i++) {
+      switch (str.charAt(i))
+      {
+        case '\b':
+          retval.append("\\b");
+          continue;
+        case '\t':
+          retval.append("\\t");
+          continue;
+        case '\n':
+          retval.append("\\n");
+          continue;
+        case '\f':
+          retval.append("\\f");
+          continue;
+        case '\r':
+          retval.append("\\r");
+          continue;
+        case '\"':
+          retval.append("\\\"");
+          continue;
+        case '\'':
+          retval.append("\\\'");
+          continue;
+        case '\\':
+          retval.append("\\\\");
+          continue;
+        default:
+          if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
+            String s = "0000" + Integer.toString(ch, 16);
+            retval.append("\\u" + s.substring(s.length() - 4, s.length()));
+          } else {
+            retval.append(ch);
+          }
+          continue;
+      }
+    }
+    return retval.toString();
+  }
+
+  /**
+   * Returns a detailed message for the Error when it is thrown by the
+   * token manager to indicate a lexical error.
+   * Parameters :
+   *    EOFSeen     : indicates if EOF caused the lexical error
+   *    curLexState : lexical state in which this error occurred
+   *    errorLine   : line number when the error occurred
+   *    errorColumn : column number when the error occurred
+   *    errorAfter  : prefix that was seen before this error occurred
+   *    curchar     : the offending character
+   * Note: You can customize the lexical error message by modifying this method.
+   */
+  protected static String LexicalErr(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, int curChar) {
+    char curChar1 = (char)curChar;
+    return("Lexical error at line " +
+          errorLine + ", column " +
+          errorColumn + ".  Encountered: " +
+          (EOFSeen ? "<EOF> " : ("\"" + addEscapes(String.valueOf(curChar1)) + "\"") + " (" + (int)curChar + "), ") +
+          "after : \"" + addEscapes(errorAfter) + "\"");
+  }
+
+  /**
+   * You can also modify the body of this method to customize your error messages.
+   * For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not
+   * of end-users concern, so you can return something like :
+   *
+   *     "Internal Error : Please file a bug report .... "
+   *
+   * from this method for such cases in the release version of your parser.
+   */
+  public String getMessage() {
+    return super.getMessage();
+  }
+
+  /*
+   * Constructors of various flavors follow.
+   */
+
+  /** No arg constructor. */
+  public TokenMgrError() {
+  }
+
+  /** Constructor with message and reason. */
+  public TokenMgrError(String message, int reason) {
+    super(message);
+    errorCode = reason;
+  }
+
+  /** Full Constructor. */
+  public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, int curChar, int reason) {
+    this(LexicalErr(EOFSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason);
+  }
+}
+/* JavaCC - OriginalChecksum=0e1a6491f37ae169ef267e06e7e99988 (do not edit this line) */
diff --git a/src/org/openstreetmap/josm/gui/preferences/projection/ProjectionPreference.java b/src/org/openstreetmap/josm/gui/preferences/projection/ProjectionPreference.java
index dacece7..3a1ec63 100644
--- a/src/org/openstreetmap/josm/gui/preferences/projection/ProjectionPreference.java
+++ b/src/org/openstreetmap/josm/gui/preferences/projection/ProjectionPreference.java
@@ -29,7 +29,6 @@ import org.openstreetmap.josm.data.preferences.CollectionProperty;
 import org.openstreetmap.josm.data.preferences.StringProperty;
 import org.openstreetmap.josm.data.projection.CustomProjection;
 import org.openstreetmap.josm.data.projection.Projection;
-import org.openstreetmap.josm.gui.NavigatableComponent;
 import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
 import org.openstreetmap.josm.gui.preferences.PreferenceSettingFactory;
 import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
@@ -383,7 +382,7 @@ public class ProjectionPreference implements SubPreferenceSetting {
         }
 
         int i = unitsCombo.getSelectedIndex();
-        NavigatableComponent.setSystemOfMeasurement(unitsValues[i]);
+        SystemOfMeasurement.setSystemOfMeasurement(unitsValues[i]);
 
         return false;
     }
-- 
1.9.1

