diff --git a/.gitignore b/.gitignore
index 87b4cdd3d7c6a41502ca98703abeeb69a1d536fb..6dbaade2d929c7a425eca520d34b28c2a3a30369 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,5 @@
 build
 src/gen-res/
 src/gen/
-out/
+out*/
 *.class
diff --git a/src/main/java/org/jastadd/JastAddConfiguration.java b/src/main/java/org/jastadd/JastAddConfiguration.java
index 0620a16ee7862dc9da15af4b8c16b5babec7b94b..30774005356c0eb30354b7fb76e1bafe67d00873 100644
--- a/src/main/java/org/jastadd/JastAddConfiguration.java
+++ b/src/main/java/org/jastadd/JastAddConfiguration.java
@@ -31,8 +31,8 @@ import org.jastadd.option.ArgumentParser;
 import org.jastadd.option.Option;
 
 import java.io.PrintStream;
-import java.util.Collection;
-import java.util.LinkedList;
+import java.util.*;
+import java.util.stream.Collectors;
 
 /**
  * Tracks JastAdd configuration options.
@@ -46,22 +46,52 @@ public class JastAddConfiguration extends org.jastadd.Configuration {
    */
   final boolean unknownOptions;
 
+  private boolean isJastAddCompliant;
+
+  public boolean isJastAddCompliant() {
+    return isJastAddCompliant;
+  }
+
   /**
    * Parse options from an argument list.
    *
    * @param args Command-line arguments to build configuration from
    * @param err  output stream to print configuration warnings to
    */
-  public JastAddConfiguration(String[] args, PrintStream err, Collection<Option<?>> extraOptions) {
+  public JastAddConfiguration(String[] args, PrintStream err, boolean isJastAddCompliant, Collection<Option<?>> extraOptions) {
     ArgumentParser argParser = new ArgumentParser();
-    argParser.addOptions(allJastAddOptions());
-    argParser.addOptions(extraOptions);
+    this.isJastAddCompliant = isJastAddCompliant;
+    if (isJastAddCompliant) {
+      Collection<Option<?>> jastAddOptions = allJastAddOptions();
+      argParser.addOptions(jastAddOptions);
+
+      // if the JastAdd options are supported, we have to check for duplicates!
+      Set<String> jastAddOptionNames = jastAddOptions.stream().map(o -> o.name()).collect(Collectors.toSet());
+      for (Option option : extraOptions) {
+        if (jastAddOptionNames.contains(option.name())) {
+          System.err.println("Unable to add option '" + option.name() + "', because there is a JastAdd option with the same name.");
+        } else {
+          argParser.addOption(option);
+        }
+      }
+    } else {
+      argParser.addOptions(extraOptions);
+    }
+
     unknownOptions = !argParser.parseArgs(args, err);
     filenames = argParser.getFilenames();
   }
 
+  /**
+   * @return all files
+   */
+  @Override
+  public Collection<String> getFiles() {
+    return Collections.unmodifiableCollection(filenames);
+  }
+
   private Collection<Option<?>> allJastAddOptions() {
-    Collection<Option<?>> allOptions = new LinkedList<Option<?>>();
+    Collection<Option<?>> allOptions = new LinkedList<>();
     allOptions.add(ASTNodeOption);
     allOptions.add(ListOption);
     allOptions.add(OptOption);
diff --git a/src/main/java/org/jastadd/relast/compiler/AbstractCompiler.java b/src/main/java/org/jastadd/relast/compiler/AbstractCompiler.java
index cb4a8399b790fd2b9d44321def104c46f6d20246..1330ebe284b62a90480959eb35eb23dbda831540 100644
--- a/src/main/java/org/jastadd/relast/compiler/AbstractCompiler.java
+++ b/src/main/java/org/jastadd/relast/compiler/AbstractCompiler.java
@@ -31,13 +31,8 @@ public abstract class AbstractCompiler {
 
     options = new ArrayList<>();
     initOptions();
-    if (jastAddCompliant) {
-      configuration = new JastAddConfiguration(args, System.err, options);
-    } else {
-      commandLine = new ArgumentParser();
-      commandLine.addOptions(options);
-      commandLine.parseArgs(args, System.err);
-    }
+    configuration = new JastAddConfiguration(args, System.err, jastAddCompliant, options);
+
     return compile();
   }
 
diff --git a/src/main/java/org/jastadd/relast/compiler/RelastSourceToSourceCompiler.java b/src/main/java/org/jastadd/relast/compiler/RelastSourceToSourceCompiler.java
index e8f86a0079ea10b4f177a61342a8d7e9ac6c7593..7d6949f5ff7ec74d2e1963e564bff9d633d4fbec 100644
--- a/src/main/java/org/jastadd/relast/compiler/RelastSourceToSourceCompiler.java
+++ b/src/main/java/org/jastadd/relast/compiler/RelastSourceToSourceCompiler.java
@@ -10,16 +10,18 @@ import org.jastadd.relast.scanner.RelAstScanner;
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.nio.file.DirectoryStream;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Optional;
 
 public class RelastSourceToSourceCompiler extends AbstractCompiler {
 
 
-  protected ValueOption optionOutputDir;
-  protected ValueOption optionInputDir;
+  protected ValueOption optionOutputBaseDir;
+  protected ValueOption optionInputBaseDir;
 
   public RelastSourceToSourceCompiler(String name, boolean jastAddCompliant) {
     super(name, jastAddCompliant);
@@ -34,96 +36,109 @@ public class RelastSourceToSourceCompiler extends AbstractCompiler {
     }
   }
 
+  protected static boolean isGrammarFile(String fileName) {
+    String extension = fileName.subSequence(fileName.lastIndexOf("."), fileName.length()).toString();
+    return extension.equals(".relast") || extension.equals(".ast");
+  }
+
   @Override
   protected void initOptions() {
-    optionOutputDir = addOption(new ValueOption("outputDir", "target directory for the generated files."));
-    optionInputDir = addOption(new ValueOption("inputDir", "input directory."));
+    optionOutputBaseDir = addOption(new ValueOption("outputBaseDir", "base directory for generated files"));
+    optionInputBaseDir = addOption(new ValueOption("inputBaseDir", "base directory for input files"));
   }
 
   @Override
   protected int compile() throws CompilerException {
-    Path inputPath;
-    if (optionInputDir.isMatched()) {
-      inputPath = Paths.get(optionInputDir.value());
+    final Path inputBasePath;
+    if (optionInputBaseDir.isMatched()) {
+      inputBasePath = Paths.get(optionInputBaseDir.value()).toAbsolutePath();
     } else {
-      inputPath = Paths.get(".");
-      printMessage("No input dir is set. Assuming current directory '" + inputPath.toAbsolutePath().toString() + "'.");
+      inputBasePath = Paths.get(".").toAbsolutePath();
+      printMessage("No input base dir is set. Assuming current directory '" + inputBasePath.toAbsolutePath().toString() + "'.");
     }
 
-    if (!inputPath.toFile().exists()) {
-      printMessage("Input path '" + inputPath.toAbsolutePath().toString() + "' does not exist. Exiting...");
+    if (!inputBasePath.toFile().exists()) {
+      printMessage("Input path '" + inputBasePath.toAbsolutePath().toString() + "' does not exist. Exiting...");
       System.exit(-1);
-    } else if (!inputPath.toFile().isDirectory()) {
-      printMessage("Input path '" + inputPath.toAbsolutePath().toString() + "' is not a directory. Exiting...");
+    } else if (!inputBasePath.toFile().isDirectory()) {
+      printMessage("Input path '" + inputBasePath.toAbsolutePath().toString() + "' is not a directory. Exiting...");
       System.exit(-1);
     }
 
-    Path outputPath;
-    if (optionOutputDir.isMatched()) {
-      outputPath = Paths.get(optionOutputDir.value());
+    final Path outputBasePath;
+    if (optionOutputBaseDir.isMatched()) {
+      outputBasePath = Paths.get(optionOutputBaseDir.value()).toAbsolutePath();
     } else {
-      outputPath = Paths.get("./gen/");
-      printMessage("No output dir is set. Assuming '" + outputPath.toAbsolutePath().toString() + "'.");
+      throw new CompilerException("No output base dir is set.");
     }
 
-    if (outputPath.toFile().exists() && !outputPath.toFile().isDirectory()) {
-      printMessage("Output path '" + inputPath.toAbsolutePath().toString() + "' exists, but is not a directory. Exiting...");
+    if (outputBasePath.toFile().exists() && !outputBasePath.toFile().isDirectory()) {
+      printMessage("Output path '" + inputBasePath.toAbsolutePath().toString() + "' exists, but is not a directory. Exiting...");
     }
 
     printMessage("Running RelAST Preprocessor");
 
-    Program program = parseProgram(inputPath);
+    // gather all files
+    Collection<Path> inputFiles = new ArrayList<>();
+    getConfiguration().getFiles().forEach(name -> relativizeFileName(inputBasePath, Paths.get(name)).ifPresent(path -> inputFiles.add(path)));
+
+
+    Program program = parseProgram(inputFiles);
 
     printMessage("Writing output files");
 
     for (GrammarFile grammarFile : program.getGrammarFileList()) {
       // TODO decide and document what the file name should be, the full path or a simple name?
-      writeToFile(outputPath + grammarFile.getFileName() + "/Grammar.relast", grammarFile.generateAbstractGrammar());
+      writeToFile(outputBasePath.resolve(inputBasePath.relativize(Paths.get(grammarFile.getFileName()))), grammarFile.generateAbstractGrammar());
     }
-
-    writeToFile(outputPath + "/Grammar.relast", program.generateAbstractGrammar());
     return 0;
   }
 
+  private Optional<Path> relativizeFileName(Path inputBasePath, Path filePath) {
+    if (filePath.isAbsolute()) {
+      if (filePath.startsWith(inputBasePath)) {
+        return Optional.of(filePath.relativize(inputBasePath));
+      } else {
+        printMessage("Path '" + filePath + "' is not contained in the base path '" + inputBasePath + "'.");
+        return Optional.empty();
+      }
+    } else {
+      return Optional.of(inputBasePath.resolve(filePath));
+    }
+  }
+
   private void printMessage(String message) {
     System.out.println(message);
   }
 
-  private void writeToFile(String filename, String str) throws CompilerException {
-    try {
-      PrintWriter writer = new PrintWriter(filename);
+  private void writeToFile(Path path, String str) throws CompilerException {
+    try (PrintWriter writer = new PrintWriter(path.toFile())) {
       writer.print(str);
-      writer.close();
     } catch (Exception e) {
-      throw new CompilerException("Could not write to file " + filename, e);
+      throw new CompilerException("Could not write to file " + path, e);
     }
   }
 
-  private Program parseProgram(Path inputPath) throws CompilerException {
+  private Program parseProgram(Collection<Path> inputFiles) throws CompilerException {
     Program program = new Program();
 
-    try (DirectoryStream<Path> stream = Files.newDirectoryStream(inputPath, "*.relast")) {
-      RelAstParser parser = new RelAstParser();
-      stream.forEach(path -> {
-        try (BufferedReader reader = Files.newBufferedReader(path)) {
-          RelAstScanner scanner = new RelAstScanner(reader);
-          GrammarFile inputGrammar = (GrammarFile) parser.parse(scanner);
-          inputGrammar.dumpTree(System.out);
-          program.addGrammarFile(inputGrammar);
-          inputGrammar.treeResolveAll();
-        } catch (IOException | Parser.Exception e) {
-          printMessage("Could not parse grammar file " + path);
-          e.printStackTrace();
+    RelAstParser parser = new RelAstParser();
+    inputFiles.stream().filter(path -> isGrammarFile(path.toString())).forEach(
+        path -> {
+          try (BufferedReader reader = Files.newBufferedReader(path)) {
+            RelAstScanner scanner = new RelAstScanner(reader);
+            GrammarFile inputGrammar = (GrammarFile) parser.parse(scanner);
+            inputGrammar.setFileName(path.toString());
+            program.addGrammarFile(inputGrammar);
+            inputGrammar.treeResolveAll();
+          } catch (IOException | Parser.Exception e) {
+            printMessage("Could not parse grammar file " + path);
+            e.printStackTrace();
+          }
         }
-      });
-    } catch (IOException e) {
-      printMessage("Unable to iterate over input path '" + inputPath.toAbsolutePath().toString() + "'. Exiting...");
-      e.printStackTrace();
-      System.exit(-1);
-    }
-
+    );
 
     return program;
-  }
+}
 }
 
diff --git a/src/test/java/org/jastadd/ros2rag/tests/RelAstTest.java b/src/test/java/org/jastadd/ros2rag/tests/RelAstTest.java
index fdc383d8efc181dfb27e17a7bc41a3c64c19bf58..c87e51f7dbc70644b621998548d4f942160e0ea9 100644
--- a/src/test/java/org/jastadd/ros2rag/tests/RelAstTest.java
+++ b/src/test/java/org/jastadd/ros2rag/tests/RelAstTest.java
@@ -29,8 +29,9 @@ public class RelAstTest {
     }
 
     String[] args = {
-        "--outputDir=" + outputDir,
-        "--inputDir=" + inputDir
+        "--outputBaseDir=" + outputDir,
+        "--inputBaseDir=" + inputDir,
+        "Example.relast"
     };
 
     new RelastSourceToSourceCompiler("testCompiler", jastAddCompliant).run(args);
@@ -38,7 +39,7 @@ public class RelAstTest {
 
   @Test
   void transformMinimalExample() throws CompilerException {
-    transform(false,"src/test/resources/in", "src/test/resources/out");
-    transform(true,"src/test/resources/in", "src/test/resources/out");
+    transform(false,"src/test/resources/in", "src/test/resources/out-simple");
+    transform(true,"src/test/resources/in", "src/test/resources/out-compliant");
   }
 }