diff --git a/build.gradle b/build.gradle
index 310849df7b39c3f77c3f4733980ea679ce595793..c3081b53c889988208ce063fe68051a069953ebd 100644
--- a/build.gradle
+++ b/build.gradle
@@ -4,17 +4,19 @@ apply plugin: 'eclipse'
 apply plugin: 'maven-publish'
 apply plugin: 'signing'
 
+allprojects {
+  project.group = 'de.hhu.stups'
+  project.version = '3.3.0'
+  project.ext.isSnapshot = project.version.endsWith("-SNAPSHOT")
 
-project.version = '3.2.14'
-project.group = 'de.hhu.stups'
+  ext."signing.secretKeyRingFile" = rootProject.file("secring.gpg").absolutePath
+}
 
 wrapper {
   gradleVersion = "6.3"
   distributionType = Wrapper.DistributionType.ALL
 }
 
-final isSnapshot = project.version.endsWith("-SNAPSHOT")
-
 sourceCompatibility = 7
 targetCompatibility = 7
 
@@ -38,7 +40,10 @@ processResources {
 
 jar {
   manifest {
-    attributes 'Main-Class': mainClassName
+    attributes([
+      'Main-Class': mainClassName,
+      'Automatic-Module-Name': 'org.sablecc.sablecc',
+    ])
   }
 }
 
diff --git a/gradle.properties.enc b/gradle.properties.enc
index 6f9a4bbdb53a7ebd2f58e4f2057bc168906e2026..83e084509404a88a304c64f23a26e07bf592c44d 100644
--- a/gradle.properties.enc
+++ b/gradle.properties.enc
@@ -1,6 +1,5 @@
-U2FsdGVkX1+772WWsEs8y4Z+vdhQLZyW24cH/04lX8CxgZ4JycDLZWPBAc70ZGyT
-w1lgwUF18NmTGDpjwyDkUQmXdYUHYRGUCLTeNays57gOaxEVQQz0zm0kKAISdnNW
-9IgD8BI/lbftz7Y8dqxMUBxfcUTijzJfXz+uEK53jwBoxKYVznzzCCfwEv+1KMR9
-oypMpm9HRBMEZyDkPRPJ2DKOFhW6YCdcszCjTNKmeJkOwVjfyltC43WXzcrzYKR/
-S2pGjR+7mcBg9zq0yMI+1DgMWwmrAaLP9pKnyDqDgXK1yJIKKE80C4NkJN6XVhHc
-qjWQ8xnLXRorA7j0lkWAhw==
+U2FsdGVkX18nOHLNyyzYk3lwSF0IGgXp8ubFJuMWOPaMbTBmgRPWS/jQT4LO17HP
+W5yqIb+NzcYqzLBohg9s9r4XFyoS5ic3TIyPp87IXzgWNh3gKV+F+DfbggwMjiyJ
+0gZI+90cmkWXBDW7c3JijLOX2f0NATwuiwHFPau3FCKC0cp7uOArtqkbfZau2how
+oP8hzzAue50fahPuBfg8h3OtofJW9x9UCUxxD/NXzD8VZFQabICUjI8mcjEcvaea
+MqQn9JuoekIRPDUsUwZ9Er07OkzKXHB5c968S3DUP3w=
diff --git a/sablecc-runtime/build.gradle b/sablecc-runtime/build.gradle
new file mode 100644
index 0000000000000000000000000000000000000000..9fb2145f1fd89f80b1a0c1299dfaf5b4843e3a06
--- /dev/null
+++ b/sablecc-runtime/build.gradle
@@ -0,0 +1,72 @@
+plugins {
+  id "java-library"
+  id "maven-publish"
+  id "signing"
+}
+
+java {
+  sourceCompatibility = JavaVersion.VERSION_1_7
+  withSourcesJar()
+  withJavadocJar()
+}
+
+jar {
+  manifest {
+    attributes([
+      "Automatic-Module-Name": "de.hhu.stups.sablecc.patch",
+    ])
+  }
+}
+
+publishing {
+  publications {
+    mavenJava(MavenPublication) {
+      from components.java
+      
+      pom {
+        name = 'SableCC - Stups fork (runtime library)'
+        description = 'This is the runtime support library for the Stups fork of SableCC. It provides common classes and interfaces used by the generated parsers at runtime.'
+        url = 'https://gitlab.cs.uni-duesseldorf.de/general/stups/sablecc-stups'
+        
+        licenses {
+          license {
+            name = 'GNU Lesser General Public License, Version 2.1'
+            url = 'http://www.gnu.org/licenses/lgpl-2.1.html'
+          }
+        }
+        
+        scm {
+          connection = 'scm:git:https://gitlab.cs.uni-duesseldorf.de/general/stups/sablecc-stups.git'
+          developerConnection = 'scm:git:git@gitlab.cs.uni-duesseldorf.de:general/stups/sablecc-stups.git'
+          url = 'https://gitlab.cs.uni-duesseldorf.de/general/stups/sablecc-stups'
+        }
+        
+        developers {
+          developer {
+            id = 'bendisposto'
+            name = 'Jens Bendisposto'
+            email = 'jens@bendisposto.de'
+          }
+        }
+      }
+    }
+  }
+  
+  repositories {
+    maven {
+      final releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2"
+      final snapshotsRepoUrl = "https://oss.sonatype.org/content/repositories/snapshots"
+      url isSnapshot ? snapshotsRepoUrl : releasesRepoUrl
+      if (project.hasProperty('ossrhUsername') && project.hasProperty('ossrhPassword')) {
+        credentials {
+          username project.ossrhUsername
+          password project.ossrhPassword
+        }
+      }
+    }
+  }
+}
+
+signing {
+  sign publishing.publications.mavenJava
+}
diff --git a/src/main/resources/patchfiles/IParser.txt b/sablecc-runtime/src/main/java/de/hhu/stups/sablecc/patch/IParser.java
similarity index 100%
rename from src/main/resources/patchfiles/IParser.txt
rename to sablecc-runtime/src/main/java/de/hhu/stups/sablecc/patch/IParser.java
diff --git a/src/main/resources/patchfiles/IToken.txt b/sablecc-runtime/src/main/java/de/hhu/stups/sablecc/patch/IToken.java
similarity index 100%
rename from src/main/resources/patchfiles/IToken.txt
rename to sablecc-runtime/src/main/java/de/hhu/stups/sablecc/patch/IToken.java
diff --git a/src/main/resources/patchfiles/ITokenListContainer.txt b/sablecc-runtime/src/main/java/de/hhu/stups/sablecc/patch/ITokenListContainer.java
similarity index 100%
rename from src/main/resources/patchfiles/ITokenListContainer.txt
rename to sablecc-runtime/src/main/java/de/hhu/stups/sablecc/patch/ITokenListContainer.java
diff --git a/src/main/resources/patchfiles/PositionedNode.txt b/sablecc-runtime/src/main/java/de/hhu/stups/sablecc/patch/PositionedNode.java
similarity index 100%
rename from src/main/resources/patchfiles/PositionedNode.txt
rename to sablecc-runtime/src/main/java/de/hhu/stups/sablecc/patch/PositionedNode.java
diff --git a/src/main/resources/patchfiles/SourcePosition.txt b/sablecc-runtime/src/main/java/de/hhu/stups/sablecc/patch/SourcePosition.java
similarity index 100%
rename from src/main/resources/patchfiles/SourcePosition.txt
rename to sablecc-runtime/src/main/java/de/hhu/stups/sablecc/patch/SourcePosition.java
diff --git a/src/main/resources/patchfiles/SourcePositions.txt b/sablecc-runtime/src/main/java/de/hhu/stups/sablecc/patch/SourcePositions.java
similarity index 100%
rename from src/main/resources/patchfiles/SourcePositions.txt
rename to sablecc-runtime/src/main/java/de/hhu/stups/sablecc/patch/SourcePositions.java
diff --git a/src/main/resources/patchfiles/SourcecodeRange.txt b/sablecc-runtime/src/main/java/de/hhu/stups/sablecc/patch/SourcecodeRange.java
similarity index 100%
rename from src/main/resources/patchfiles/SourcecodeRange.txt
rename to sablecc-runtime/src/main/java/de/hhu/stups/sablecc/patch/SourcecodeRange.java
diff --git a/settings.gradle b/settings.gradle
index f8e1a304f02217429bc099f8761a639e7dc3a25a..00be2ad78605ef76b81c9b00234e736f7affc882 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1,2 @@
 rootProject.name = "sablecc"
+include "sablecc-runtime"
diff --git a/src/main/java/org/sablecc/sablecc/SableCC.java b/src/main/java/org/sablecc/sablecc/SableCC.java
index 235a92e466bff7e91e4ae178064897a5602fba6d..3c80cb626ed821872cef3501ce4e949035dba5a5 100644
--- a/src/main/java/org/sablecc/sablecc/SableCC.java
+++ b/src/main/java/org/sablecc/sablecc/SableCC.java
@@ -113,33 +113,6 @@ public class SableCC {
 			}
 		}
 
-		/*
-		 * extract additional stups-classes from .jar-file
-		 */
-		String generated = ".";
-		boolean found = false;
-		for (String p : arguments) {
-			if (found) {
-				generated = p;
-				break;
-			}
-
-			if ("-d".equals(p)) {
-				found = true;
-			}
-		}
-
-		String patchFolder = generated + "/de/hhu/stups/sablecc/patch";
-		String[] patchFiles = { "IParser", "IToken", "ITokenListContainer",
-				"PositionedNode", "SourcePosition", "SourcePositions",
-				"SourcecodeRange" };
-
-		new File(patchFolder).mkdirs();
-
-		for (String f : patchFiles) {
-			extractPatchFile(patchFolder, f);
-		}
-
 		try {
 			for (int i = 0; i < filename.size(); i++) {
 				processGrammar((String) filename.elementAt(i), d_option);
@@ -151,74 +124,6 @@ public class SableCC {
 		System.exit(0);
 	}
 
-	private static void extractPatchFile(String patchFolder, String patchFile) {
-
-		ClassLoader loader = SableCC.class.getClassLoader();
-		InputStream input = loader.getResourceAsStream("patchfiles/"
-				+ patchFile + ".txt");
-		String output = "";
-
-		String outputFile = patchFolder + "/" + patchFile + ".java";
-		try {
-			output = convertStreamToString(input);
-		} catch (IOException e) {
-			e.printStackTrace();
-			System.exit(1);
-		}
-
-		Writer writer = null;
-		try {
-			File file = new File(outputFile);
-			writer = new BufferedWriter(new FileWriter(file));
-			writer.write(output);
-		} catch (FileNotFoundException e) {
-			e.printStackTrace();
-			System.exit(1);
-		} catch (IOException e) {
-			e.printStackTrace();
-			System.exit(1);
-		} finally {
-			try {
-				if (writer != null) {
-					writer.close();
-				}
-			} catch (IOException e) {
-				e.printStackTrace();
-				System.exit(1);
-			}
-		}
-	}
-
-	private static String convertStreamToString(InputStream is)
-			throws IOException {
-		/*
-		 * To convert the InputStream to String we use the Reader.read(char[]
-		 * buffer) method. We iterate until the Reader return -1 which means
-		 * there's no more data to read. We use the StringWriter class to
-		 * produce the string.
-		 */
-
-		if (is != null) {
-			Writer writer = new StringWriter();
-
-			char[] buffer = new char[1024];
-			try {
-				Reader reader = new BufferedReader(new InputStreamReader(is,
-						"UTF-8"));
-				int n;
-				while ((n = reader.read(buffer)) != -1) {
-					writer.write(buffer, 0, n);
-				}
-			} finally {
-				is.close();
-			}
-			return writer.toString();
-		} else {
-			return "";
-		}
-
-	}
-
 	/**
 	 * The main method for processing grammar file and generating the
 	 * parser/lexer.