diff --git a/build.gradle b/build.gradle
index 21370e02d04408a00c85681827b0e913da8df782..aff97ea032eb35353c0e1c547483b5fea7c29faa 100644
--- a/build.gradle
+++ b/build.gradle
@@ -107,12 +107,18 @@ jastadd {
             }
 
             scanner {
-                include "src/main/jastadd/RelAst.flex"
+                include "src/main/jastadd/scanner/Header.flex",         [-4]
+                include "src/main/jastadd/scanner/Preamble.flex",       [-3]
+                include "src/main/jastadd/scanner/Macros.flex",         [-2]
+                include "src/main/jastadd/scanner/RulesPreamble.flex",  [-1]
+                include "src/main/jastadd/scanner/Keywords.flex",       [0]
+                include "src/main/jastadd/scanner/Symbols.flex",        [1]
+                include "src/main/jastadd/scanner/RulesPostamble.flex", [2]
             }
 
             parser {
-                include "src/main/jastadd/Preamble.parser"
-                include "src/main/jastadd/RelAst.parser"
+                include "src/main/jastadd/parser/Preamble.parser"
+                include "src/main/jastadd/parser/RelAst.parser"
             }
         }
     }
diff --git a/src/main/jastadd/RelAst.flex b/src/main/jastadd/RelAst.flex
deleted file mode 100644
index f9595e97eb97245cf1c500c46c135996a33b918c..0000000000000000000000000000000000000000
--- a/src/main/jastadd/RelAst.flex
+++ /dev/null
@@ -1,72 +0,0 @@
-package org.jastadd.relast.scanner;
-
-import org.jastadd.relast.parser.RelAstParser.Terminals;
-
-%%
-
-%public
-%final
-%class RelAstScanner
-%extends beaver.Scanner
-
-%type beaver.Symbol
-%function nextToken
-%yylexthrow beaver.Scanner.Exception
-%scanerror RelAstScanner.ScannerError
-
-%line
-%column
-%{
-  private StringBuilder stringLitSb = new StringBuilder();
-
-  private beaver.Symbol sym(short id) {
-    return new beaver.Symbol(id, yyline + 1, yycolumn + 1, yylength(), yytext());
-  }
-
-  private beaver.Symbol sym(short id, String text) {
-    return new beaver.Symbol(id, yyline + 1, yycolumn + 1, yylength(), text);
-  }
-
-
-  public static class ScannerError extends Error {
-    public ScannerError(String message) {
-      super(message);
-    }
-  }
-%}
-
-WhiteSpace = [ ] | \t | \f | \n | \r | \r\n
-TraditionalComment   = [/][*][^*]*[*]+([^*/][^*]*[*]+)*[/]
-EndOfLineComment = "//" [^\n\r]*
-Comment = {TraditionalComment} | {EndOfLineComment}
-
-ID = [a-zA-Z$_][a-zA-Z0-9$_]*
-
-%%
-{WhiteSpace} { /* ignore */ }
-{Comment}    { return sym(Terminals.COMMENT); }
-
-"abstract"   { return sym(Terminals.ABSTRACT); }
-"rel"        { return sym(Terminals.RELATION); }
-
-";"          { return sym(Terminals.SCOL); }
-":"          { return sym(Terminals.COL); }
-"::="        { return sym(Terminals.ASSIGN); }
-"*"          { return sym(Terminals.STAR); }
-"."          { return sym(Terminals.DOT); }
-","          { return sym(Terminals.COMMA); }
-"<"          { return sym(Terminals.LT); }
-">"          { return sym(Terminals.GT); }
-"["          { return sym(Terminals.LBRACKET); }
-"]"          { return sym(Terminals.RBRACKET); }
-"/"          { return sym(Terminals.SLASH); }
-"?"          { return sym(Terminals.QUESTION_MARK); }
-"->"         { return sym(Terminals.RIGHT); }
-"<-"         { return sym(Terminals.LEFT); }
-"<->"        { return sym(Terminals.BIDIRECTIONAL); }
-
-// ID
-{ID}         { return sym(Terminals.ID); }
-<<EOF>>      { return sym(Terminals.EOF); }
-
-[^]            { throw new ScannerError((yyline+1) +"," + (yycolumn+1) + ": Illegal character <"+yytext()+">"); }
diff --git a/src/main/jastadd/Preamble.parser b/src/main/jastadd/parser/Preamble.parser
similarity index 100%
rename from src/main/jastadd/Preamble.parser
rename to src/main/jastadd/parser/Preamble.parser
diff --git a/src/main/jastadd/RelAst.parser b/src/main/jastadd/parser/RelAst.parser
similarity index 100%
rename from src/main/jastadd/RelAst.parser
rename to src/main/jastadd/parser/RelAst.parser
diff --git a/src/main/jastadd/scanner/Header.flex b/src/main/jastadd/scanner/Header.flex
new file mode 100644
index 0000000000000000000000000000000000000000..73120659873e1498b07be82eb29d82fe3d1b5112
--- /dev/null
+++ b/src/main/jastadd/scanner/Header.flex
@@ -0,0 +1,17 @@
+package org.jastadd.relast.scanner;
+
+import org.jastadd.relast.parser.RelAstParser.Terminals;
+%%
+
+%public
+%final
+%class RelAstScanner
+%extends beaver.Scanner
+
+%type beaver.Symbol
+%function nextToken
+%yylexthrow beaver.Scanner.Exception
+%scanerror RelAstScanner.ScannerError
+
+%line
+%column
diff --git a/src/main/jastadd/scanner/Keywords.flex b/src/main/jastadd/scanner/Keywords.flex
new file mode 100644
index 0000000000000000000000000000000000000000..76e6359ae9967bd16220eb09d5dac4a7ed5389cc
--- /dev/null
+++ b/src/main/jastadd/scanner/Keywords.flex
@@ -0,0 +1,2 @@
+"abstract"   { return sym(Terminals.ABSTRACT); }
+"rel"        { return sym(Terminals.RELATION); }
diff --git a/src/main/jastadd/scanner/Macros.flex b/src/main/jastadd/scanner/Macros.flex
new file mode 100644
index 0000000000000000000000000000000000000000..167f51b882cfce44a1d225503589b76ad38012b9
--- /dev/null
+++ b/src/main/jastadd/scanner/Macros.flex
@@ -0,0 +1,5 @@
+WhiteSpace = [ ] | \t | \f | \n | \r | \r\n
+ID = [a-zA-Z$_][a-zA-Z0-9$_]*
+TraditionalComment   = [/][*][^*]*[*]+([^*/][^*]*[*]+)*[/]
+EndOfLineComment = "//" [^\n\r]*
+Comment = {TraditionalComment} | {EndOfLineComment}
diff --git a/src/main/jastadd/scanner/Preamble.flex b/src/main/jastadd/scanner/Preamble.flex
new file mode 100644
index 0000000000000000000000000000000000000000..03847ade1bc46c80dfd3193424fc7ff2cd457a5f
--- /dev/null
+++ b/src/main/jastadd/scanner/Preamble.flex
@@ -0,0 +1,18 @@
+%{
+  private StringBuilder stringLitSb = new StringBuilder();
+
+  private beaver.Symbol sym(short id) {
+    return new beaver.Symbol(id, yyline + 1, yycolumn + 1, yylength(), yytext());
+  }
+
+  private beaver.Symbol sym(short id, String text) {
+    return new beaver.Symbol(id, yyline + 1, yycolumn + 1, yylength(), text);
+  }
+
+
+  public static class ScannerError extends Error {
+    public ScannerError(String message) {
+      super(message);
+    }
+  }
+%}
diff --git a/src/main/jastadd/scanner/RulesPostamble.flex b/src/main/jastadd/scanner/RulesPostamble.flex
new file mode 100644
index 0000000000000000000000000000000000000000..1ae39c6244e39c6f2bd2b0c6de41f088b3a51cde
--- /dev/null
+++ b/src/main/jastadd/scanner/RulesPostamble.flex
@@ -0,0 +1,4 @@
+{ID}         { return sym(Terminals.ID); }
+<<EOF>>      { return sym(Terminals.EOF); }
+
+[^]            { throw new ScannerError((yyline+1) +"," + (yycolumn+1) + ": Illegal character <"+yytext()+">"); }
diff --git a/src/main/jastadd/scanner/RulesPreamble.flex b/src/main/jastadd/scanner/RulesPreamble.flex
new file mode 100644
index 0000000000000000000000000000000000000000..a55876d60989c0f6640ad62e9478cdca48c0573d
--- /dev/null
+++ b/src/main/jastadd/scanner/RulesPreamble.flex
@@ -0,0 +1,5 @@
+
+%%
+
+{WhiteSpace} { /* ignore */ }
+{Comment}    { return sym(Terminals.COMMENT); }
diff --git a/src/main/jastadd/scanner/Symbols.flex b/src/main/jastadd/scanner/Symbols.flex
new file mode 100644
index 0000000000000000000000000000000000000000..2990e998f9373f259b0346d2ae3c24bb6a781452
--- /dev/null
+++ b/src/main/jastadd/scanner/Symbols.flex
@@ -0,0 +1,15 @@
+";"          { return sym(Terminals.SCOL); }
+":"          { return sym(Terminals.COL); }
+"::="        { return sym(Terminals.ASSIGN); }
+"*"          { return sym(Terminals.STAR); }
+"."          { return sym(Terminals.DOT); }
+","          { return sym(Terminals.COMMA); }
+"<"          { return sym(Terminals.LT); }
+">"          { return sym(Terminals.GT); }
+"["          { return sym(Terminals.LBRACKET); }
+"]"          { return sym(Terminals.RBRACKET); }
+"/"          { return sym(Terminals.SLASH); }
+"?"          { return sym(Terminals.QUESTION_MARK); }
+"->"         { return sym(Terminals.RIGHT); }
+"<-"         { return sym(Terminals.LEFT); }
+"<->"        { return sym(Terminals.BIDIRECTIONAL); }