summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <LukeShu@sbcglobal.net>2014-06-06 15:43:28 -0400
committerLuke Shumaker <LukeShu@sbcglobal.net>2014-06-06 15:43:28 -0400
commit8d8befb89e68217a61ce63399bb58d930332c1a4 (patch)
tree022d631d384a2a03536af2b28f90f0f49fd379b9
parentd5902fc1e3c8b9cf8574b4cf61dc5a8ceae7fefc (diff)
add jflex
-rw-r--r--conf/dependencies.mk6
-rw-r--r--conf/sources.mk3
l---------rules/jflex-bootstrap/0001-build.xml-fix-clean-target.patch1
l---------rules/jflex-bootstrap/0002-stable-cup.patch1
-rw-r--r--rules/jflex-bootstrap/0003-jlex.patch305
l---------rules/jflex-bootstrap/Makefile1
l---------rules/jflex-bootstrap/delete.list1
-rw-r--r--rules/jflex/0001-build.xml-fix-clean-target.patch24
-rw-r--r--rules/jflex/0002-stable-cup.patch147
-rw-r--r--rules/jflex/Makefile63
-rw-r--r--rules/jflex/delete.list1
11 files changed, 553 insertions, 0 deletions
diff --git a/conf/dependencies.mk b/conf/dependencies.mk
index b4f4b20..76d0ea8 100644
--- a/conf/dependencies.mk
+++ b/conf/dependencies.mk
@@ -80,3 +80,9 @@ build/packages/jaxen-bootstrap: \
build/packages/jdom1-bootstrap
build/packages/jdom1-bootstrap: \
$(dep-xerces2)
+
+build/packages/jflex: \
+ build/packages/jflex-bootstrap \
+ /usr/share/java/junit.jar
+build/packages/jflex-bootstrap: \
+ /usr/share/java/junit.jar
diff --git a/conf/sources.mk b/conf/sources.mk
index 9ceebc4..0c75153 100644
--- a/conf/sources.mk
+++ b/conf/sources.mk
@@ -29,6 +29,9 @@ jaxen-bootstrap = tar|http://dist.codehaus.org/jaxe
jdom1 = git|git://github.com/hunterhacker/jdom.git|jdom-1.1.3
jdom1-bootstrap = $(jdom1)
+jflex = tar|http://jflex.de/jflex-1.5.1.tar.gz
+jflex-bootstrap = $(jflex)
+
# Any other implementation of JSR-305 would probably be fine too.
jsr305 = svn|http://jsr-305.googlecode.com/svn|trunk/ri
diff --git a/rules/jflex-bootstrap/0001-build.xml-fix-clean-target.patch b/rules/jflex-bootstrap/0001-build.xml-fix-clean-target.patch
new file mode 120000
index 0000000..eff23a9
--- /dev/null
+++ b/rules/jflex-bootstrap/0001-build.xml-fix-clean-target.patch
@@ -0,0 +1 @@
+../jflex/0001-build.xml-fix-clean-target.patch \ No newline at end of file
diff --git a/rules/jflex-bootstrap/0002-stable-cup.patch b/rules/jflex-bootstrap/0002-stable-cup.patch
new file mode 120000
index 0000000..db2d1f9
--- /dev/null
+++ b/rules/jflex-bootstrap/0002-stable-cup.patch
@@ -0,0 +1 @@
+../jflex/0002-stable-cup.patch \ No newline at end of file
diff --git a/rules/jflex-bootstrap/0003-jlex.patch b/rules/jflex-bootstrap/0003-jlex.patch
new file mode 100644
index 0000000..96ca444
--- /dev/null
+++ b/rules/jflex-bootstrap/0003-jlex.patch
@@ -0,0 +1,305 @@
+From 61505fb5919b72f2b300508e3e64896946fa24ab Mon Sep 17 00:00:00 2001
+From: Luke Shumaker <LukeShu@sbcglobal.net>
+Date: Fri, 6 Jun 2014 15:37:50 -0400
+Subject: [PATCH 3/3] Use JLex to bootstrap the lexer.
+
+---
+ build.xml | 32 ++++++++++------
+ jflex2jlex.patch | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ jflex2jlex.sed | 97 ++++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 228 insertions(+), 11 deletions(-)
+ create mode 100644 jflex2jlex.patch
+ create mode 100644 jflex2jlex.sed
+
+diff --git a/build.xml b/build.xml
+index 334d439..dea8a54 100644
+--- a/build.xml
++++ b/build.xml
+@@ -2,7 +2,6 @@
+ <project name="JFlex" default="help">
+
+ <property name="version" value="1.5.1-SNAPSHOT" />
+- <property name="bootstrap.version" value="1.5.0" />
+ <property name="junit.version" value="4.11" />
+ <property name="java.source.version" value="1.5" />
+
+@@ -14,14 +13,13 @@
+ <property name="lib.dir" value="lib"/>
+
+ <!-- override these if you want to use your own versions -->
+- <property name="bootstrap.jflex.jar" value="${lib.dir}/jflex-${bootstrap.version}.jar" />
++ <property name="sed.exe" value="sed" />
++ <property name="jlex.exe" value="jlex" />
+ <property name="cup.exe" value="java-cup" />
+ <property name="junit.jar" value="${lib.dir}/junit-${junit.version}.jar" />
+
+ <!-- where to get tool jars from -->
+ <property name="maven.central.url" value="http://central.maven.org/maven2" />
+- <property name="bootstrap.jflex.jar.url"
+- value="${maven.central.url}/de/jflex/jflex/${bootstrap.version}/jflex-${bootstrap.version}.jar" />
+ <property name="junit.jar.url"
+ value="${maven.central.url}/junit/junit/${junit.version}/junit-${junit.version}.jar" />
+
+@@ -50,7 +48,6 @@
+ </target>
+
+ <target name="gettools" description="download development tools">
+- <get src="${bootstrap.jflex.jar.url}" dest="${bootstrap.jflex.jar}"/>
+ <get src="${junit.jar.url}" dest="${junit.jar}"/>
+ </target>
+
+@@ -114,13 +111,26 @@
+ </target>
+
+ <target name="-generate-scanner">
+- <taskdef classname="jflex.anttask.JFlexTask"
+- name="jflex" classpath="${bootstrap.jflex.jar}"/>
+ <mkdir dir="${generated.sources.dir}/jflex"/>
+- <jflex file="src/main/jflex/LexScan.flex"
+- outdir="${generated.sources.dir}/jflex"
+- skeleton="src/main/jflex/skeleton.nested"
+- nobak="on"/>
++ <exec executable="${sed.exe}"
++ input="src/main/jflex/LexScan.flex"
++ output="${generated.sources.dir}/jflex/LexScan.lex"
++ failonerror="true">
++ <arg value="-rnf"/>
++ <arg value="jflex2jlex.sed"/>
++ </exec>
++ <patch patchfile="jflex2jlex.patch"
++ originalfile="${generated.sources.dir}/jflex/LexScan.lex"
++ failonerror="true"/>
++ <exec executable="${jlex.exe}" failonerror="true">
++ <arg value="${generated.sources.dir}/jflex/LexScan.lex"/>
++ </exec>
++ <replaceregexp file="${generated.sources.dir}/jflex/LexScan.lex.java"
++ match="^public class LexScan .*\{$"
++ replace="public class LexScan implements sym, java_cup.runtime.Scanner {"
++ byline="true"/>
++ <move file="${generated.sources.dir}/jflex/LexScan.lex.java"
++ tofile="${generated.sources.dir}/jflex/LexScan.java"/>
+ </target>
+
+ <target name="-generate-parser">
+diff --git a/jflex2jlex.patch b/jflex2jlex.patch
+new file mode 100644
+index 0000000..5b2113b
+--- /dev/null
++++ b/jflex2jlex.patch
+@@ -0,0 +1,110 @@
++--- LexScan.lex 2014-06-06 13:46:02.242828126 -0400
+++++ src/main/jflex/LexScan.flex 2014-06-06 13:07:58.611333045 -0400
++@@ -203,28 +203,57 @@
++ throw new ScannerException(file,ErrorMessages.NOT_READABLE, yyline);
++ }
++ }
+++
+++ int yycolumn = -1;
+++
+++ private static final String ZZ_PUSHBACK_2BIG = "Error: pushback value was too large";
+++ private static final String ZZ_UNIMPLEMENTED = "Error: unimplemented feature";
+++ private void zzScanError(String message) {
+++ System.out.println(message);
+++ System.out.flush();
+++ throw new Error("Fatal Error.\n");
+++ }
+++
+++ private boolean yymoreStreams() { return false; }
+++ private void yypushStream(java.io.Reader reader) { zzScanError(ZZ_UNIMPLEMENTED); }
+++ private void yypopStream() { zzScanError(ZZ_UNIMPLEMENTED); }
+++
+++ private void yypushback(int number) {
+++ if ( number > yylength() )
+++ zzScanError(ZZ_PUSHBACK_2BIG);
+++ yy_buffer_end -= number;
+++ yy_buffer_index = yy_buffer_end;
+++ }
++ %}
++
++ %init{
++ states.insert("YYINITIAL", true);
++ %init}
++
+++%eofval{
+++ if ( yymoreStreams() ) {
+++ file = (File) files.pop();
+++ yypopStream();
+++ }
+++ else
+++ return symbol(EOF);
+++%eofval}
++
++ Digit = ([0-9])
++ HexDigit = ([0-9a-fA-F])
++ OctDigit = ([0-7])
++
++ Number = ({Digit}+)
++-HexNumber = (\\x{HexDigit}{2})
++-OctNumber = (\\[0-3]?{OctDigit}{1,2})
+++HexNumber = (\\x{HexDigit}{HexDigit})
+++OctNumber = (\\[0-3]?{OctDigit}{OctDigit}?)
++
++-Unicode4 = (\\u{HexDigit}{1,4})
+++Unicode4 = (\\u{HexDigit}({HexDigit}({HexDigit}{HexDigit}?)?)?)
++
++-Unicode6 = (\\U{HexDigit}{1,6})
+++Unicode6 = (\\U{HexDigit}({HexDigit}({HexDigit}({HexDigit}({HexDigit}{HexDigit}?)?)?)?)?)
++
++ WSP = ([ \t\b])
++ WSPNL = ([\u2028\u2029\u000A\u000B\u000C\u000D\u0085\t\b\ ])
++-NWSPNL = ([^\u2028\u2029\u000A\u000B\u000C\u000D\u0085\t\b\ ])
+++NWSPNL = ([^\u2028\u2029\u000A\u000B\u000C\u000D\u0085\t\b\ <}])
++ NL = ([\u2028\u2029\u000A\u000B\u000C\u000D\u0085]|\u000D\u000A)
++ NNL = ([^\u2028\u2029\u000A\u000B\u000C\u000D\u0085])
++
++@@ -255,13 +284,13 @@
++ CharLiteral = (\'([^\u2028\u2029\u000A\u000B\u000C\u000D\u0085\'\\]|{EscapeSequence})\')
++ StringLiteral = (\"({StringCharacter}|{EscapeSequence})*\")
++
++-EscapeSequence = (\\[^\u2028\u2029\u000A\u000B\u000C\u000D\u0085]|\\+u{HexDigit}{4}|\\[0-3]?{OctDigit}{1,2})
+++EscapeSequence = (\\[^\u2028\u2029\u000A\u000B\u000C\u000D\u0085]|\\+u{HexDigit}{HexDigit}{HexDigit}{HexDigit}|\\[0-3]?{OctDigit}{OctDigit}?)
++
++
++ JavaRest = ([^\{\}\"\'/]|"/"[^*/])
++ JavaCode = (({JavaRest}|{StringLiteral}|{CharLiteral}|{JavaComment})+)
++
++-DottedVersion = ([1-9][0-9]*(\.[0-9]+){0,2})
+++DottedVersion = ([1-9][0-9]*(\.[0-9]+(\.[0-9]+)?)?)
++
++ %%
++
++@@ -441,7 +470,7 @@
++ return s;
++ }
++ <REGEXPSTART> ^{WSP}*{NWSPNL} { yypushback(yylength()); yybegin(REGEXP); }
++-<REGEXPSTART> {WSP}|{NL} { }
+++<REGEXPSTART> ({WSP}|{NL}) { }
++
++ <STATES> {Ident} { return symbol(IDENT, yytext()); }
++ <STATES> "," { return symbol(COMMA); }
++@@ -491,7 +520,7 @@
++ }
++
++ <REGEXP> {WSPNL}+"{" { actionText.setLength(0); yybegin(JAVA_CODE); action_line = yyline+1; return symbol(REGEXPEND); }
++-<REGEXP> {NL}{if(macroDefinition) { yybegin(MACROS); } return symbol(REGEXPEND); }
+++<REGEXP> {NL} { if (macroDefinition) { yybegin(MACROS); } return symbol(REGEXPEND); }
++
++ <REGEXP> {WSPNL}*"/*" { nextState = REGEXP; yybegin(COMMENT); }
++
++@@ -627,10 +656,3 @@
++
++ . { throw new ScannerException(file,ErrorMessages.UNEXPECTED_CHAR, yyline, yycolumn); }
++ \n { throw new ScannerException(file,ErrorMessages.UNEXPECTED_NL, yyline, yycolumn); }
++-
++-<<EOF>> { if ( yymoreStreams() ) {
++- file = (File) files.pop();
++- yypopStream();
++- }
++- else
++- return symbol(EOF); }
+diff --git a/jflex2jlex.sed b/jflex2jlex.sed
+new file mode 100644
+index 0000000..064452a
+--- /dev/null
++++ b/jflex2jlex.sed
+@@ -0,0 +1,97 @@
++#!/usr/bin/sed -rnf
++# (Mostly) transforms a JFlex file into a JLex file
++
++:usercode
++ # Don't make any changes
++ /^%%$/ { p; n; b macros; }
++ p; n; b usercode
++
++:macros
++ /^%%$/ { p; n; b regex; }
++
++ # Preserve code blocks verbatim
++ /^%(|init)\{\s*$/ { p; n; b macros_codeblock; }
++
++ # Get rid of %-symbols not supported
++ /^%(final|column|eofclose|inputstreamctor)/ { n; b macros; }
++
++ # Get rid of comments
++ /^\s*\/\// { n; b macros; }
++ /^\s*\/*.*\*\/$/ { n; b macros; }
++
++ /^[A-Z].*=/ {
++ # Parenthesize macros
++ s:^([^=]*=\s*)(\S.*):\1(\2):
++ # Remove whitespace
++ :macros_again
++ s:(= .*[^\[]) :\1:
++ t macros_again
++ s:(= .*\\\\) :\1:
++ t macros_again
++ }
++
++ # (Rough) character class conversion
++ s/\[:jletter:\]/[A-Za-z$_]/
++ s/\[:jletterdigit:\]/[A-Za-z0-9$_]/
++
++ p; n; b macros
++:macros_codeblock
++ /^%(|init)\}\s*$/ { p; n; b macros; }
++ p; n; b macros_codeblock
++
++# De-shorthand nested state-prefixed patterns
++# Only supports nesting 2 levels deep
++:regex
++ s: <<EOF>> : ,,EOF,, :g
++ /^\s*\/\// { n; b regex; }
++ /^<[^>]*>\s*\{\s*$/ {
++ s:\s*\{.*::
++ h
++ n; b regex_stateblock
++ }
++ :regex_again
++ s:^([^>]+>\s+.*[^ \[]) (.*\S\s+\{ ):\1\2: ; t regex_again
++ p; n; b regex
++:regex_stateblock
++ s: <<EOF>> : ,,EOF,, :g
++ /^\s*\/\// { n; b regex_stateblock; }
++ /^ [^ <]/ {
++ x
++ G
++ s:\n : :
++ :regex_stateblock_again
++ s:^([^>]+>\s+.*[^ \[]) (.*\S\s+\{ ):\1\2: ; t regex_stateblock_again
++ p
++ s:>.*:>:
++ x
++ n; b regex_stateblock
++ }
++ /^ <[^>]*>\s*\{\s*$/ {
++ x
++ G
++ s:>\s*\n\s*<:, :
++ s:\s*\{.*::
++ h
++ n; b regex_stateblock2
++ }
++ /^\}/ { n; b regex; }
++ p; n; b regex_stateblock
++:regex_stateblock2
++ s: <<EOF>> : ,,EOF,, :g
++ /^\s*\/\// { n; b regex_stateblock2; }
++ /^ [^ <]/ {
++ x
++ G
++ s:\n : :
++ p
++ s:>.*:>:
++ x
++ n; b regex_stateblock2
++ }
++ /^ \}/ {
++ x
++ s:,.*:>:
++ h
++ n; b regex_stateblock
++ }
++ p; n; b regex_stateblock2
+--
+2.0.0
+
diff --git a/rules/jflex-bootstrap/Makefile b/rules/jflex-bootstrap/Makefile
new file mode 120000
index 0000000..68b95e9
--- /dev/null
+++ b/rules/jflex-bootstrap/Makefile
@@ -0,0 +1 @@
+../jflex/Makefile \ No newline at end of file
diff --git a/rules/jflex-bootstrap/delete.list b/rules/jflex-bootstrap/delete.list
new file mode 120000
index 0000000..2eb2ba5
--- /dev/null
+++ b/rules/jflex-bootstrap/delete.list
@@ -0,0 +1 @@
+../jflex/delete.list \ No newline at end of file
diff --git a/rules/jflex/0001-build.xml-fix-clean-target.patch b/rules/jflex/0001-build.xml-fix-clean-target.patch
new file mode 100644
index 0000000..f1ccf20
--- /dev/null
+++ b/rules/jflex/0001-build.xml-fix-clean-target.patch
@@ -0,0 +1,24 @@
+From e703449d06c591338a9d5b21249295e3adb3e43c Mon Sep 17 00:00:00 2001
+From: Luke Shumaker <LukeShu@sbcglobal.net>
+Date: Wed, 4 Jun 2014 22:35:35 -0400
+Subject: [PATCH 1/3] build.xml: fix 'clean' target
+
+---
+ build.xml | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/build.xml b/build.xml
+index 6e829ed..b4a5124 100644
+--- a/build.xml
++++ b/build.xml
+@@ -59,6 +59,7 @@
+ description="complete build from scratch (clean jar)"/>
+
+ <target name="clean" description="remove all generated and compiled files">
++ <mkdir dir="${build.dir}"/>
+ <delete includeemptydirs="true">
+ <fileset dir="${build.dir}" includes="**/*"/>
+ </delete>
+--
+2.0.0
+
diff --git a/rules/jflex/0002-stable-cup.patch b/rules/jflex/0002-stable-cup.patch
new file mode 100644
index 0000000..6af8bda
--- /dev/null
+++ b/rules/jflex/0002-stable-cup.patch
@@ -0,0 +1,147 @@
+From 4031b30c23cf27936c217047191f419eeac1a257 Mon Sep 17 00:00:00 2001
+From: Luke Shumaker <LukeShu@sbcglobal.net>
+Date: Thu, 5 Jun 2014 21:58:03 -0400
+Subject: [PATCH 2/3] Support the last stable release of CUP, instead of
+ requiring a beta.
+
+Unfortunately, the last stable release (0.10k) predates Java 5, and
+thus does not support generics. This requires some clever
+work-arounds.
+---
+ build.xml | 25 ++++++++++++++++---------
+ src/main/java/jflex/IntCharSet.java | 8 ++++----
+ src/main/java/jflex/IntegerList.java | 14 ++++++++++++++
+ src/main/java/jflex/IntervalList.java | 14 ++++++++++++++
+ 4 files changed, 48 insertions(+), 13 deletions(-)
+ create mode 100644 src/main/java/jflex/IntegerList.java
+ create mode 100644 src/main/java/jflex/IntervalList.java
+
+diff --git a/build.xml b/build.xml
+index b4a5124..334d439 100644
+--- a/build.xml
++++ b/build.xml
+@@ -4,7 +4,6 @@
+ <property name="version" value="1.5.1-SNAPSHOT" />
+ <property name="bootstrap.version" value="1.5.0" />
+ <property name="junit.version" value="4.11" />
+- <property name="cup.version" value="11a" />
+ <property name="java.source.version" value="1.5" />
+
+ <!-- use any of these files to override properties -->
+@@ -16,7 +15,7 @@
+
+ <!-- override these if you want to use your own versions -->
+ <property name="bootstrap.jflex.jar" value="${lib.dir}/jflex-${bootstrap.version}.jar" />
+- <property name="cup.jar" value="${lib.dir}/java-cup-${cup.version}.jar" />
++ <property name="cup.exe" value="java-cup" />
+ <property name="junit.jar" value="${lib.dir}/junit-${junit.version}.jar" />
+
+ <!-- where to get tool jars from -->
+@@ -125,13 +124,21 @@
+ </target>
+
+ <target name="-generate-parser">
+- <taskdef classname="java_cup.anttask.CUPTask"
+- name="cup" classpath="${cup.jar}"/>
+- <mkdir dir="${generated.sources.dir}"/>
+- <cup srcfile="src/main/cup/LexParse.cup"
+- destdir="${generated.sources.dir}"
+- interface="true"
+- parser="LexParse"/>
++ <mkdir dir="${generated.sources.dir}/jflex"/>
++ <copy file="src/main/cup/LexParse.cup"
++ tofile="${generated.sources.dir}/jflex/LexParse.cup"/>
++ <replaceregexp file="${generated.sources.dir}/jflex/LexParse.cup"
++ match="(Array)?List&lt;([^&gt;]*)&gt;"
++ replace="\2List"
++ flags="g"/>
++ <exec executable="${cup.exe}"
++ input="${generated.sources.dir}/jflex/LexParse.cup"
++ dir="${generated.sources.dir}/jflex"
++ failonerror="true">
++ <arg value="-interface"/>
++ <arg value="-parser"/>
++ <arg value="LexParse"/>
++ </exec>
+ </target>
+
+ <target name="-compile-test" depends="compile">
+diff --git a/src/main/java/jflex/IntCharSet.java b/src/main/java/jflex/IntCharSet.java
+index 570c0cb..0f3a7cb 100644
+--- a/src/main/java/jflex/IntCharSet.java
++++ b/src/main/java/jflex/IntCharSet.java
+@@ -26,11 +26,11 @@ public final class IntCharSet {
+ private final static boolean DEBUG = false;
+
+ /* invariant: all intervals are disjoint, ordered */
+- private List<Interval> intervals;
++ private IntervalList intervals;
+ private int pos;
+
+ public IntCharSet() {
+- this.intervals = new ArrayList<Interval>();
++ this.intervals = new IntervalList();
+ }
+
+ public IntCharSet(char c) {
+@@ -44,7 +44,7 @@ public final class IntCharSet {
+
+ public IntCharSet(List<Interval> chars) {
+ int size = chars.size();
+- intervals = new ArrayList<Interval>(size);
++ intervals = new IntervalList(size);
+
+ for (Interval interval : chars)
+ add(interval);
+@@ -329,7 +329,7 @@ public final class IntCharSet {
+ return intervals.size();
+ }
+
+- public List<Interval> getIntervals() {
++ public IntervalList getIntervals() {
+ return intervals;
+ }
+
+diff --git a/src/main/java/jflex/IntegerList.java b/src/main/java/jflex/IntegerList.java
+new file mode 100644
+index 0000000..c793ef9
+--- /dev/null
++++ b/src/main/java/jflex/IntegerList.java
+@@ -0,0 +1,14 @@
++package jflex;
++import java.util.ArrayList;
++import java.util.Collection;
++public class IntegerList extends ArrayList<Integer> {
++ public IntegerList() {
++ super();
++ }
++ public IntegerList(Collection<? extends Integer> c) {
++ super(c);
++ }
++ public IntegerList(int initialCapacity) {
++ super(initialCapacity);
++ }
++}
+diff --git a/src/main/java/jflex/IntervalList.java b/src/main/java/jflex/IntervalList.java
+new file mode 100644
+index 0000000..4731832
+--- /dev/null
++++ b/src/main/java/jflex/IntervalList.java
+@@ -0,0 +1,14 @@
++package jflex;
++import java.util.ArrayList;
++import java.util.Collection;
++public class IntervalList extends ArrayList<Interval> {
++ public IntervalList() {
++ super();
++ }
++ public IntervalList(Collection<? extends Interval> c) {
++ super(c);
++ }
++ public IntervalList(int initialCapacity) {
++ super(initialCapacity);
++ }
++}
+--
+2.0.0
+
diff --git a/rules/jflex/Makefile b/rules/jflex/Makefile
new file mode 100644
index 0000000..dcac8b2
--- /dev/null
+++ b/rules/jflex/Makefile
@@ -0,0 +1,63 @@
+DESTDIR ?=
+MAVEN_LOCAL_REPO ?= ~/.m2
+VIMDIR ?= /usr/share/vim/syntax
+EMACSDIR ?= /usr/share/emacs/site-lisp
+
+ANT = ant
+EXISTS = test -e
+FIND = find
+INSTALL = install
+RM = rm -f
+SED = sed
+TOUCH = touch
+XMLSTARLET = xml
+JLEX = jlex
+JAVA_CUP = java-cup
+
+artifactIds := jflex jflex-parent
+version := $(shell $(XMLSTARLET) sel -T -t -c /_:project/_:version -n parent.xml)
+groupId := $(shell $(XMLSTARLET) sel -T -t -c /_:project/_:groupId -n parent.xml)
+
+jarfind = $(firstword $(foreach path,$(subst :, ,$(CLASSPATH)),$(if $(findstring $1,$(path)),$(path))))
+junit_jar := $(call jarfind,junit)
+jflex_jar := $(call jarfind,jflex)
+export CLASSPATH :=
+
+antflags = -Dversion='$(version)'
+antflags += -Dsed.exe='$(SED)'
+antflags += -Djlex.exe='$(JLEX)'
+antflags += -Dcup.exe='$(JAVA_CUP)'
+antflags += -Dbootstrap.jflex.jar='$(jflex_jar)'
+antflags += -Djunit.jar='$(junit_jar)'
+
+all: PHONY build
+
+build: $(shell $(FIND) src/main) $(wildcard jflex2jlex.*) build.xml
+ $(ANT) $(antflags) build || { $(RM) -r $@; exit 1; }
+ $(TOUCH) $@
+
+install-base = $(DESTDIR)$(MAVEN_LOCAL_REPO)/$(subst .,/,$(groupId))/$(artifactId)/$(version)/$(artifactId)-$(version)
+
+install-jflex = $(foreach artifactId,jflex,$(install-base).pom $(install-base).jar)
+install-jflex-parent = $(foreach artifactId,jflex-parent,$(install-base).pom)
+install: PHONY $(install-jflex) $(install-jflex-parent) $(DESTDIR)$(VIMDIR)/jflex.vim $(DESTDIR)$(EMACSDIR)/jflex-mode.el
+
+$(filter %.jar,$(install-jflex)): build/jflex-$(version).jar
+ $(INSTALL) -Dm644 $< $@
+$(filter %.pom,$(install-jflex)): pom.xml
+ $(INSTALL) -Dm644 $< $@
+$(install-jflex-parent): parent.xml
+ $(INSTALL) -Dm644 $< $@
+$(DESTDIR)$(VIMDIR)/jflex.vim: lib/jflex.vim
+ $(INSTALL) -Dm644 $< $@
+$(DESTDIR)$(EMACSDIR)/jflex-mode.el: lib/jflex-mode.el
+ $(INSTALL) -Dm644 $< $@
+
+build/jflex-$(version).jar: build
+ $(EXISTS) $@
+ $(TOUCH) $@
+
+clean: PHONY
+ $(RM) -r build
+
+.PHONY: PHONY
diff --git a/rules/jflex/delete.list b/rules/jflex/delete.list
new file mode 100644
index 0000000..8c5987b
--- /dev/null
+++ b/rules/jflex/delete.list
@@ -0,0 +1 @@
+lib/*.jar