From cfdd9ff32441ba428b25361dfdfad868b2223f3b Mon Sep 17 00:00:00 2001
From: rschoene <rene.schoene@tu-dresden.de>
Date: Fri, 29 Nov 2019 19:13:24 +0100
Subject: [PATCH] Split statemachine in task and solution.

---
 settings.gradle                               |   3 +-
 statemachine.drast/build.gradle               |   4 +-
 .../inf/st/statemachine/DrAstRunner.java      |   2 +-
 .../.gitignore                                |   0
 .../build.gradle                              |   0
 .../src/main/jastadd/Analysis.jrag            |   0
 .../src/main/jastadd/ConnectedComponents.jrag |   0
 .../src/main/jastadd/NameAnalysis.jrag        |   0
 .../src/main/jastadd/Navigation.jrag          |   0
 .../src/main/jastadd/Printing.jrag            |   0
 .../src/main/jastadd/SMtoDotG.jrag            |   0
 .../main/jastadd/StateMachineParser.parser    |   0
 .../src/main/jastadd/StateMachineScanner.flex |   0
 .../src/main/jastadd/Util.jadd                |   0
 .../src/main/jastadd/Util.jrag                |   0
 .../tudresden/inf/st/statemachine/Main.java   |   0
 .../inf/st/statemachine/ParserUtils.java      |   0
 .../src/main/resources/StateMachine.ecore     |   0
 .../src/main/resources/log4j2.xml             |   0
 .../inf/st/statemachine/AnalysisTest.java     |   0
 .../inf/st/statemachine/ParserTest.java       |   0
 .../src/test/resources/empty.sm               |   0
 .../src/test/resources/machine_one.sm         |   0
 .../src/test/resources/telephone.sm           |   0
 statemachine.task/.gitignore                  |   7 +
 statemachine.task/build.gradle                | 143 ++++++++++++++++++
 .../src/main/jastadd/Analysis.jrag            |  77 ++++++++++
 .../src/main/jastadd/ConnectedComponents.jrag |  67 ++++++++
 .../src/main/jastadd/NameAnalysis.jrag        |  25 +++
 .../src/main/jastadd/Navigation.jrag          |  47 ++++++
 .../src/main/jastadd/Printing.jrag            |  12 ++
 .../src/main/jastadd/SMtoDotG.jrag            |  18 +++
 .../main/jastadd/StateMachineParser.parser    |  65 ++++++++
 .../src/main/jastadd/StateMachineScanner.flex |  46 ++++++
 statemachine.task/src/main/jastadd/Util.jadd  |  39 +++++
 statemachine.task/src/main/jastadd/Util.jrag  |   3 +
 .../tudresden/inf/st/statemachine/Main.java   |  96 ++++++++++++
 .../inf/st/statemachine/ParserUtils.java      |  27 ++++
 .../src/main/resources/StateMachine.ecore     |  27 ++++
 .../src/main/resources/log4j2.xml             |  22 +++
 .../inf/st/statemachine/AnalysisTest.java     | 116 ++++++++++++++
 .../inf/st/statemachine/ParserTest.java       |  85 +++++++++++
 statemachine.task/src/test/resources/empty.sm |   7 +
 .../src/test/resources/machine_one.sm         |   6 +
 .../src/test/resources/telephone.sm           |  25 +++
 45 files changed, 965 insertions(+), 4 deletions(-)
 rename {statemachine.base => statemachine.solution}/.gitignore (100%)
 rename {statemachine.base => statemachine.solution}/build.gradle (100%)
 rename {statemachine.base => statemachine.solution}/src/main/jastadd/Analysis.jrag (100%)
 rename {statemachine.base => statemachine.solution}/src/main/jastadd/ConnectedComponents.jrag (100%)
 rename {statemachine.base => statemachine.solution}/src/main/jastadd/NameAnalysis.jrag (100%)
 rename {statemachine.base => statemachine.solution}/src/main/jastadd/Navigation.jrag (100%)
 rename {statemachine.base => statemachine.solution}/src/main/jastadd/Printing.jrag (100%)
 rename {statemachine.base => statemachine.solution}/src/main/jastadd/SMtoDotG.jrag (100%)
 rename {statemachine.base => statemachine.solution}/src/main/jastadd/StateMachineParser.parser (100%)
 rename {statemachine.base => statemachine.solution}/src/main/jastadd/StateMachineScanner.flex (100%)
 rename {statemachine.base => statemachine.solution}/src/main/jastadd/Util.jadd (100%)
 rename {statemachine.base => statemachine.solution}/src/main/jastadd/Util.jrag (100%)
 rename {statemachine.base => statemachine.solution}/src/main/java/de/tudresden/inf/st/statemachine/Main.java (100%)
 rename {statemachine.base => statemachine.solution}/src/main/java/de/tudresden/inf/st/statemachine/ParserUtils.java (100%)
 rename {statemachine.base => statemachine.solution}/src/main/resources/StateMachine.ecore (100%)
 rename {statemachine.base => statemachine.solution}/src/main/resources/log4j2.xml (100%)
 rename {statemachine.base => statemachine.solution}/src/test/java/de/tudresden/inf/st/statemachine/AnalysisTest.java (100%)
 rename {statemachine.base => statemachine.solution}/src/test/java/de/tudresden/inf/st/statemachine/ParserTest.java (100%)
 rename {statemachine.base => statemachine.solution}/src/test/resources/empty.sm (100%)
 rename {statemachine.base => statemachine.solution}/src/test/resources/machine_one.sm (100%)
 rename {statemachine.base => statemachine.solution}/src/test/resources/telephone.sm (100%)
 create mode 100644 statemachine.task/.gitignore
 create mode 100644 statemachine.task/build.gradle
 create mode 100644 statemachine.task/src/main/jastadd/Analysis.jrag
 create mode 100644 statemachine.task/src/main/jastadd/ConnectedComponents.jrag
 create mode 100644 statemachine.task/src/main/jastadd/NameAnalysis.jrag
 create mode 100644 statemachine.task/src/main/jastadd/Navigation.jrag
 create mode 100644 statemachine.task/src/main/jastadd/Printing.jrag
 create mode 100644 statemachine.task/src/main/jastadd/SMtoDotG.jrag
 create mode 100644 statemachine.task/src/main/jastadd/StateMachineParser.parser
 create mode 100644 statemachine.task/src/main/jastadd/StateMachineScanner.flex
 create mode 100644 statemachine.task/src/main/jastadd/Util.jadd
 create mode 100644 statemachine.task/src/main/jastadd/Util.jrag
 create mode 100644 statemachine.task/src/main/java/de/tudresden/inf/st/statemachine/Main.java
 create mode 100644 statemachine.task/src/main/java/de/tudresden/inf/st/statemachine/ParserUtils.java
 create mode 100644 statemachine.task/src/main/resources/StateMachine.ecore
 create mode 100644 statemachine.task/src/main/resources/log4j2.xml
 create mode 100644 statemachine.task/src/test/java/de/tudresden/inf/st/statemachine/AnalysisTest.java
 create mode 100644 statemachine.task/src/test/java/de/tudresden/inf/st/statemachine/ParserTest.java
 create mode 100644 statemachine.task/src/test/resources/empty.sm
 create mode 100644 statemachine.task/src/test/resources/machine_one.sm
 create mode 100644 statemachine.task/src/test/resources/telephone.sm

diff --git a/settings.gradle b/settings.gradle
index 03d6f56..70ecfb0 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,5 +1,6 @@
 rootProject.name = 'ifm-refactoring-jastadd'
 
-include 'statemachine.base'
+include 'statemachine.task'
+include 'statemachine.solution'
 include 'statemachine.drast'
 include 'ragdoc-view'
diff --git a/statemachine.drast/build.gradle b/statemachine.drast/build.gradle
index fcf3218..ee6ac3e 100644
--- a/statemachine.drast/build.gradle
+++ b/statemachine.drast/build.gradle
@@ -10,7 +10,7 @@ sourceCompatibility = 1.8
 repositories.mavenCentral()
 
 dependencies {
-	implementation project(':statemachine.base')
+	implementation project(':statemachine.solution')
     implementation files('../libs/DrAST-1.2.2.jar')
     implementation fileTree(dir: "${System.properties['java.home']}", include: '**/jfxrt.jar')
 }
@@ -21,7 +21,7 @@ run {
     mainClassName = 'de.tudresden.inf.st.statemachine.DrAstRunner'
     standardInput = System.in
 }
-run.dependsOn ':statemachine.base:jar'
+run.dependsOn ':statemachine.solution:jar'
 run.doFirst { environment 'JAVA_TOOL_OPTIONS', '-Dlog4j2.disableJmx=true' }
 
 task jarDrAst(type: Jar, dependsOn: ':statemachine.base:jar') {
diff --git a/statemachine.drast/src/main/java/de/tudresden/inf/st/statemachine/DrAstRunner.java b/statemachine.drast/src/main/java/de/tudresden/inf/st/statemachine/DrAstRunner.java
index fef307c..ecab210 100644
--- a/statemachine.drast/src/main/java/de/tudresden/inf/st/statemachine/DrAstRunner.java
+++ b/statemachine.drast/src/main/java/de/tudresden/inf/st/statemachine/DrAstRunner.java
@@ -37,7 +37,7 @@ public class DrAstRunner extends DrASTGUI {
 
   private static void openView() {
     guiHasBeenCreated = true;
-    DrASTSettings.put(DrASTSettings.PREV_JAR, "../statemachine.base/build/libs/statemachine.base-0.1.jar");
+    DrASTSettings.put(DrASTSettings.PREV_JAR, "../statemachine.solution/build/libs/statemachine.solution-0.1.jar");
     DrASTSettings.put(DrASTSettings.PREV_TAIL_ARGS, "-Dlog4j2.disable.jmx=true");
     launch();
     con.onApplicationClose();
diff --git a/statemachine.base/.gitignore b/statemachine.solution/.gitignore
similarity index 100%
rename from statemachine.base/.gitignore
rename to statemachine.solution/.gitignore
diff --git a/statemachine.base/build.gradle b/statemachine.solution/build.gradle
similarity index 100%
rename from statemachine.base/build.gradle
rename to statemachine.solution/build.gradle
diff --git a/statemachine.base/src/main/jastadd/Analysis.jrag b/statemachine.solution/src/main/jastadd/Analysis.jrag
similarity index 100%
rename from statemachine.base/src/main/jastadd/Analysis.jrag
rename to statemachine.solution/src/main/jastadd/Analysis.jrag
diff --git a/statemachine.base/src/main/jastadd/ConnectedComponents.jrag b/statemachine.solution/src/main/jastadd/ConnectedComponents.jrag
similarity index 100%
rename from statemachine.base/src/main/jastadd/ConnectedComponents.jrag
rename to statemachine.solution/src/main/jastadd/ConnectedComponents.jrag
diff --git a/statemachine.base/src/main/jastadd/NameAnalysis.jrag b/statemachine.solution/src/main/jastadd/NameAnalysis.jrag
similarity index 100%
rename from statemachine.base/src/main/jastadd/NameAnalysis.jrag
rename to statemachine.solution/src/main/jastadd/NameAnalysis.jrag
diff --git a/statemachine.base/src/main/jastadd/Navigation.jrag b/statemachine.solution/src/main/jastadd/Navigation.jrag
similarity index 100%
rename from statemachine.base/src/main/jastadd/Navigation.jrag
rename to statemachine.solution/src/main/jastadd/Navigation.jrag
diff --git a/statemachine.base/src/main/jastadd/Printing.jrag b/statemachine.solution/src/main/jastadd/Printing.jrag
similarity index 100%
rename from statemachine.base/src/main/jastadd/Printing.jrag
rename to statemachine.solution/src/main/jastadd/Printing.jrag
diff --git a/statemachine.base/src/main/jastadd/SMtoDotG.jrag b/statemachine.solution/src/main/jastadd/SMtoDotG.jrag
similarity index 100%
rename from statemachine.base/src/main/jastadd/SMtoDotG.jrag
rename to statemachine.solution/src/main/jastadd/SMtoDotG.jrag
diff --git a/statemachine.base/src/main/jastadd/StateMachineParser.parser b/statemachine.solution/src/main/jastadd/StateMachineParser.parser
similarity index 100%
rename from statemachine.base/src/main/jastadd/StateMachineParser.parser
rename to statemachine.solution/src/main/jastadd/StateMachineParser.parser
diff --git a/statemachine.base/src/main/jastadd/StateMachineScanner.flex b/statemachine.solution/src/main/jastadd/StateMachineScanner.flex
similarity index 100%
rename from statemachine.base/src/main/jastadd/StateMachineScanner.flex
rename to statemachine.solution/src/main/jastadd/StateMachineScanner.flex
diff --git a/statemachine.base/src/main/jastadd/Util.jadd b/statemachine.solution/src/main/jastadd/Util.jadd
similarity index 100%
rename from statemachine.base/src/main/jastadd/Util.jadd
rename to statemachine.solution/src/main/jastadd/Util.jadd
diff --git a/statemachine.base/src/main/jastadd/Util.jrag b/statemachine.solution/src/main/jastadd/Util.jrag
similarity index 100%
rename from statemachine.base/src/main/jastadd/Util.jrag
rename to statemachine.solution/src/main/jastadd/Util.jrag
diff --git a/statemachine.base/src/main/java/de/tudresden/inf/st/statemachine/Main.java b/statemachine.solution/src/main/java/de/tudresden/inf/st/statemachine/Main.java
similarity index 100%
rename from statemachine.base/src/main/java/de/tudresden/inf/st/statemachine/Main.java
rename to statemachine.solution/src/main/java/de/tudresden/inf/st/statemachine/Main.java
diff --git a/statemachine.base/src/main/java/de/tudresden/inf/st/statemachine/ParserUtils.java b/statemachine.solution/src/main/java/de/tudresden/inf/st/statemachine/ParserUtils.java
similarity index 100%
rename from statemachine.base/src/main/java/de/tudresden/inf/st/statemachine/ParserUtils.java
rename to statemachine.solution/src/main/java/de/tudresden/inf/st/statemachine/ParserUtils.java
diff --git a/statemachine.base/src/main/resources/StateMachine.ecore b/statemachine.solution/src/main/resources/StateMachine.ecore
similarity index 100%
rename from statemachine.base/src/main/resources/StateMachine.ecore
rename to statemachine.solution/src/main/resources/StateMachine.ecore
diff --git a/statemachine.base/src/main/resources/log4j2.xml b/statemachine.solution/src/main/resources/log4j2.xml
similarity index 100%
rename from statemachine.base/src/main/resources/log4j2.xml
rename to statemachine.solution/src/main/resources/log4j2.xml
diff --git a/statemachine.base/src/test/java/de/tudresden/inf/st/statemachine/AnalysisTest.java b/statemachine.solution/src/test/java/de/tudresden/inf/st/statemachine/AnalysisTest.java
similarity index 100%
rename from statemachine.base/src/test/java/de/tudresden/inf/st/statemachine/AnalysisTest.java
rename to statemachine.solution/src/test/java/de/tudresden/inf/st/statemachine/AnalysisTest.java
diff --git a/statemachine.base/src/test/java/de/tudresden/inf/st/statemachine/ParserTest.java b/statemachine.solution/src/test/java/de/tudresden/inf/st/statemachine/ParserTest.java
similarity index 100%
rename from statemachine.base/src/test/java/de/tudresden/inf/st/statemachine/ParserTest.java
rename to statemachine.solution/src/test/java/de/tudresden/inf/st/statemachine/ParserTest.java
diff --git a/statemachine.base/src/test/resources/empty.sm b/statemachine.solution/src/test/resources/empty.sm
similarity index 100%
rename from statemachine.base/src/test/resources/empty.sm
rename to statemachine.solution/src/test/resources/empty.sm
diff --git a/statemachine.base/src/test/resources/machine_one.sm b/statemachine.solution/src/test/resources/machine_one.sm
similarity index 100%
rename from statemachine.base/src/test/resources/machine_one.sm
rename to statemachine.solution/src/test/resources/machine_one.sm
diff --git a/statemachine.base/src/test/resources/telephone.sm b/statemachine.solution/src/test/resources/telephone.sm
similarity index 100%
rename from statemachine.base/src/test/resources/telephone.sm
rename to statemachine.solution/src/test/resources/telephone.sm
diff --git a/statemachine.task/.gitignore b/statemachine.task/.gitignore
new file mode 100644
index 0000000..19ad8f8
--- /dev/null
+++ b/statemachine.task/.gitignore
@@ -0,0 +1,7 @@
+build/
+src/gen/
+src/gen-res/
+.test-tmp
+/bin/
+logs/
+/doc/
diff --git a/statemachine.task/build.gradle b/statemachine.task/build.gradle
new file mode 100644
index 0000000..fc5b063
--- /dev/null
+++ b/statemachine.task/build.gradle
@@ -0,0 +1,143 @@
+// General configuration (plugins, settings, dependencies)
+group 'de.tudresden.inf.st'
+version '0.1'
+
+apply plugin: 'java'
+apply plugin: 'jastadd'
+apply plugin: 'application'
+apply plugin: "idea"
+
+sourceCompatibility = 1.8
+
+repositories.mavenCentral()
+
+buildscript {
+    repositories.mavenLocal()
+    repositories.mavenCentral()
+    dependencies {
+        classpath group: 'org.jastadd', name: 'jastaddgradle', version: '1.13.3'
+    }
+}
+
+idea.module.generatedSourceDirs += file('src/gen/java')
+
+configurations {
+    ragdoc
+}
+
+sourceSets.main.java.srcDir "src/gen/java"
+jar.manifest.attributes('Main-Class': 'de.tudresden.inf.st.statemachine.Main')
+
+dependencies {
+    implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: "${jackson_version}"
+    implementation group: 'net.sf.beaver', name: 'beaver-rt', version: '0.9.11'
+
+    jastadd2 "org.jastadd:jastadd:2.3.4"
+    ragdoc files('../libs/rd-builder.jar')
+}
+
+// Default run configuration
+run {
+    mainClassName = 'de.tudresden.inf.st.statemachine.Main'
+    standardInput = System.in
+}
+
+// Generated files
+def ecoreFile = "./src/main/resources/StateMachine.ecore"
+def relastFile = "./src/gen/jastadd/StateMachine.relast"
+
+// First phase: Ecore -> RelAst
+task ecoreToRelast(type: JavaExec) {
+    group = 'Build'
+    main = "-jar"
+
+
+    doFirst {
+        delete "src/gen/jastadd"
+        mkdir "src/gen/jastadd"
+    }
+
+    args "../libs/ecore2relast-0.1.jar", ecoreFile, relastFile
+
+    inputs.files file(ecoreFile)
+    outputs.files file(relastFile)
+}
+
+// Second phase: RelAst -> JastAdd
+task relastToJastAdd(type: JavaExec) {
+    group = 'Build'
+    main = "-jar"
+
+    args "../libs/relast.jar",
+            "--grammarName=./src/gen/jastadd/StateMachine",
+            "--useJastAddNames",
+            "--listClass=ArrayList",
+            "--jastAddList=JastAddList",
+            "--resolverHelper",
+            "--file",
+            relastFile
+
+    inputs.files relastFile
+    outputs.files file("./src/gen/jastadd/StateMachine.ast"), file("./src/gen/jastadd/StateMachine.jadd")
+}
+
+// Third phase: JastAdd -> Java (using JastAdd Gradle plugin)
+jastadd {
+    configureModuleBuild()
+    modules {
+        module("statemachine") {
+
+            java {
+                basedir "src/"
+                include "main/**/*.java"
+                include "gen/**/*.java"
+            }
+
+            jastadd {
+                basedir "src/"
+                include "main/jastadd/**/*.ast"
+                include "main/jastadd/**/*.jadd"
+                include "main/jastadd/**/*.jrag"
+                include "gen/jastadd/**/*.ast"
+                include "gen/jastadd/**/*.jadd"
+                include "gen/jastadd/**/*.jrag"
+            }
+
+            scanner {
+                include "src/main/jastadd/StateMachineScanner.flex"
+            }
+
+            parser {
+                include "src/main/jastadd/StateMachineParser.parser"
+            }
+        }
+    }
+
+    cleanGen.doFirst {
+        delete "src/gen/java/de"
+        delete "src/gen-res/BuildInfo.properties"
+    }
+
+    module = "statemachine"
+
+    astPackage = 'de.tudresden.inf.st.statemachine.jastadd.model'
+
+    parser.name = 'StateMachineParser'
+
+    genDir = 'src/gen/java'
+
+    buildInfoDir = 'src/gen-res'
+
+    scanner.genDir = "src/gen/java/de/tudresden/inf/st/statemachine/jastadd/scanner"
+    parser.genDir = "src/gen/java/de/tudresden/inf/st/statemachine/jastadd/parser"
+
+//  default options are: '--rewrite=cnta', '--safeLazy', '--visitCheck=false', '--cacheCycle=false'
+    extraJastAddOptions = ['--List=JastAddList', '--incremental=param']
+}
+
+// Workflow configuration for phases
+relastToJastAdd.dependsOn ecoreToRelast
+generateAst.dependsOn relastToJastAdd
+
+//// always run jastadd
+//jastadd.outputs.upToDateWhen {false}
diff --git a/statemachine.task/src/main/jastadd/Analysis.jrag b/statemachine.task/src/main/jastadd/Analysis.jrag
new file mode 100644
index 0000000..6bbcf6a
--- /dev/null
+++ b/statemachine.task/src/main/jastadd/Analysis.jrag
@@ -0,0 +1,77 @@
+aspect Analysis {
+  syn Set<State> State.reachable() circular [new HashSet<State>()] {
+    Set<State> result = new HashSet<>();
+    result.addAll(successors());
+    for (State s : successors()) {
+      result.addAll(s.reachable());
+    }
+    return result;
+  }
+
+  public void StateMachine.printSomeAnalysis() {
+    Set<Set<State>> sccs = this.SCC();
+    System.out.print("SCCs found: ");
+    for (Set<State> scc : sccs) {
+      System.out.print(scc + " ");
+    }
+    System.out.println();
+
+    for (State s : this.states()) {
+      System.out.println(s + ": successors() = " + s.successors() + ", reachable() = " + s.reachable());
+    }
+
+    for (State finalState : this.getFinalList()) {
+      System.out.println("initial state "+ this.getInitial() + " to " + finalState + " in " +
+          this.getInitial().minDistTo(finalState) + " step(s)");
+    }
+  }
+
+  syn int State.minDistTo(State other) circular [-1] {
+    if (this == other) {
+      return 0;
+    }
+    int result = -1;
+    for (Transition t : this.getOutgoingList()) {
+      int dist = t.getTo().minDistTo(other);
+      int delta = t.getLabel().isEmpty() ? 0 : 1;
+      if (dist != -1 && (result == -1 || result > dist + delta)) {
+        result = dist + delta;
+      }
+    }
+    return result;
+  }
+
+  syn boolean Transition.isEpsilon() = getLabel().isEmpty();
+
+  coll Set<Transition> StateMachine.epsilonTransitions() [new HashSet<>()];
+  Transition contributes this when isEpsilon() to StateMachine.epsilonTransitions();
+
+  public void StateMachine.removeEpsilonTransition(Transition t) {
+    if (t.isEpsilon()) {
+      State oldFrom = t.getFrom();
+      State oldTo = t.getTo();
+      if (oldFrom != oldTo) {
+        State combined = new State();
+        combined.setLabel(oldFrom.getLabel() + "+" + oldTo.getLabel());
+        if (oldFrom.isInitial() || oldTo.isInitial()) {
+          this.setInitial(combined);
+        }
+        if (oldFrom.isFinal() || oldTo.isFinal()) {
+          this.addFinal(combined);
+        }
+        new ArrayList<>(oldFrom.getIncomingList()).forEach(trans -> trans.setTo(combined));
+        new ArrayList<>(oldFrom.getOutgoingList()).forEach(trans -> trans.setFrom(combined));
+        new ArrayList<>(oldTo.getIncomingList()).forEach(trans -> trans.setTo(combined));
+        new ArrayList<>(oldTo.getOutgoingList()).forEach(trans -> trans.setFrom(combined));
+        this.removeFinal(oldFrom);
+        this.removeFinal(oldTo);
+        oldFrom.removeSelf();
+        oldTo.removeSelf();
+        this.addElement(combined);
+      }
+      t.removeSelf();
+    } else {
+      System.err.println("Won't remove non-epsilon transition " + t.getLabel());
+    }
+  }
+}
diff --git a/statemachine.task/src/main/jastadd/ConnectedComponents.jrag b/statemachine.task/src/main/jastadd/ConnectedComponents.jrag
new file mode 100644
index 0000000..406e5f5
--- /dev/null
+++ b/statemachine.task/src/main/jastadd/ConnectedComponents.jrag
@@ -0,0 +1,67 @@
+aspect ConnectedComponents {
+//  syn Set<State> State.successors() circular [new HashSet<>()] {
+//    Set<State> result = new HashSet<>();
+//    for (Transition t : getOutgoingList()) {
+//      State s = t.getTo();
+//      result.add(s);
+//      result.addAll(s.successors());
+//    }
+//    return result;
+//  }
+
+//  syn Set<State> State.predecessors() circular [new HashSet<>()] {
+//    Set<State> result = new HashSet<>();
+//    for (Transition t : getIncomingList()) {
+//      State s = t.getFrom();
+//      result.add(s);
+//      result.addAll(s.predecessors());
+//    }
+//    return result;
+//  }
+
+//  syn boolean State.hasCycle() = successors().contains(this);
+
+//  syn Set<State> State.SCC() {
+//    Set<State> result = new HashSet<>(successors());
+//    result.retainAll(predecessors());
+//    return result;
+//  }
+
+//  coll HashSet<Set<State>> StateMachine.SCC() with add root StateMachine;
+//  State contributes SCC() when SCC().size() > 0 to StateMachine.SCC();
+
+  /**
+   * Kosaraju's algorithm
+   */
+  syn Set<Set<State>> StateMachine.SCC() {
+    Map<State, Set> visited = new HashMap<>();
+    LinkedList<State> locked = new LinkedList<>();
+
+    for (State n : states())
+      if (!visited.containsKey(n))
+        n.visit(visited, locked);              // forward search
+
+    for (State n : locked)
+      if (visited.get(n) == null)
+        n.assign(visited, new HashSet());      // backward search
+
+    return new HashSet(visited.values());
+  }
+
+  void State.visit(Map<State, Set> visited, LinkedList<State> locked) {
+    visited.put(this, null);
+    for (Transition t : getOutgoingList())
+      if (!visited.containsKey(t.getTo()))
+        t.getTo().visit(visited, locked);
+    locked.addFirst(this);
+  }
+
+  void State.assign(Map<State, Set> visited, Set root) {
+    root.add(this);
+    visited.put(this, root);
+    for (Transition t : getIncomingList())
+      if (visited.get(t.getFrom()) == null)
+        t.getFrom().assign(visited, root);
+  }
+
+}
diff --git a/statemachine.task/src/main/jastadd/NameAnalysis.jrag b/statemachine.task/src/main/jastadd/NameAnalysis.jrag
new file mode 100644
index 0000000..a381d9c
--- /dev/null
+++ b/statemachine.task/src/main/jastadd/NameAnalysis.jrag
@@ -0,0 +1,25 @@
+aspect NameAnalysis {
+  syn State StateMachine.resolveState(String id) {
+    for (State s : states()) {
+      if (s.getLabel().equals(id)) {
+        return s;
+      }
+    }
+    return null;
+  }
+
+  syn Transition StateMachine.resolveTransition(String id) {
+    for (Transition t : transitions()) {
+      if (t.getLabel().equals(id)) {
+        return t;
+      }
+    }
+    return null;
+  }
+
+  eq StateMachine.globallyResolveStateByToken(String id) = resolveState(id);
+  eq Element.globallyResolveStateByToken(String id) = containingStateMachine().resolveState(id);
+
+  eq StateMachine.globallyResolveTransitionByToken(String id) = resolveTransition(id);
+  eq Element.globallyResolveTransitionByToken(String id) = containingStateMachine().resolveTransition(id);
+}
diff --git a/statemachine.task/src/main/jastadd/Navigation.jrag b/statemachine.task/src/main/jastadd/Navigation.jrag
new file mode 100644
index 0000000..f06ecb8
--- /dev/null
+++ b/statemachine.task/src/main/jastadd/Navigation.jrag
@@ -0,0 +1,47 @@
+aspect Navigation {
+
+  /** Check, whether an this element is a state */
+  syn boolean Element.isState() = false;
+  eq State.isState() = true;
+
+  /** View this element as a state */
+  syn State Element.asState() = null;
+  eq State.asState() = this;
+
+  /** Check, whether an this element is a transition */
+  syn boolean Element.isTransition() = false;
+  eq Transition.isTransition() = true;
+
+  /** View this element as a transition */
+  syn Transition Element.asTransition() = null;
+  eq Transition.asTransition() = this;
+
+  /** Get all states */
+  syn List<State> StateMachine.states() {
+    List<State> states = new ArrayList<>();
+    for (Element element: getElementList()) {
+      if (element.isState()) {
+        states.add(element.asState());
+      }
+    }
+    return states;
+  }
+
+  syn List<Transition> StateMachine.transitions() {
+    List<Transition> transitions = new ArrayList<>();
+    for (Element element: getElementList()) {
+      if (element.isTransition()) {
+        transitions.add(element.asTransition());
+      }
+    }
+    return transitions;
+  }
+
+  inh StateMachine Element.containingStateMachine();
+  eq StateMachine.getElement().containingStateMachine() = this;
+
+  syn boolean State.isInitial() = containingStateMachine().getInitial().equals(this);
+  syn boolean State.isFinal() = containingStateMachine().getFinalList().contains(this);
+
+  syn Collection<State> State.successors() = getOutgoingList().stream().map(Transition::getTo).collect(Collectors.toList());
+}
diff --git a/statemachine.task/src/main/jastadd/Printing.jrag b/statemachine.task/src/main/jastadd/Printing.jrag
new file mode 100644
index 0000000..1ac2e38
--- /dev/null
+++ b/statemachine.task/src/main/jastadd/Printing.jrag
@@ -0,0 +1,12 @@
+aspect Printing {
+  syn String StateMachine.prettyPrint() {
+    StringBuilder sb = new StringBuilder();
+    states().forEach(s -> sb.append(s.prettyPrint()));
+    transitions().forEach(t -> sb.append(t.prettyPrint()));
+    return sb.toString();
+  }
+
+  syn String Element.prettyPrint();
+  eq State.prettyPrint() = (isInitial() ? "initial " : "") + (isFinal() ? "final " : "") + "state " + getLabel() + ";\n";
+  eq Transition.prettyPrint() = "trans " + getFrom().getLabel() + " -> " + getTo().getLabel() + (isEpsilon() ? "" : " : " + getLabel()) + ";\n";
+}
diff --git a/statemachine.task/src/main/jastadd/SMtoDotG.jrag b/statemachine.task/src/main/jastadd/SMtoDotG.jrag
new file mode 100644
index 0000000..18155d5
--- /dev/null
+++ b/statemachine.task/src/main/jastadd/SMtoDotG.jrag
@@ -0,0 +1,18 @@
+aspect StateMachinetoDotG {
+  syn String StateMachine.toDot() {
+    StringBuilder b = new StringBuilder();
+    b.append("strict digraph cycles {\n");
+
+    for (State from : states()) {
+      b.append("  ").append(from.getLabel()).append("[label=\"").append(from.getLabel()).append("\"];\n");
+
+      for (Transition out : from.getOutgoingList()) {
+        b.append("  ").append(from.getLabel()).append(" -> ").append(out.getTo().getLabel())
+         .append("[label=\"").append(out.getLabel()).append("\"];\n");
+      }
+    }
+
+    b.append("}\n");
+    return b.toString();
+  }
+}
diff --git a/statemachine.task/src/main/jastadd/StateMachineParser.parser b/statemachine.task/src/main/jastadd/StateMachineParser.parser
new file mode 100644
index 0000000..e31987a
--- /dev/null
+++ b/statemachine.task/src/main/jastadd/StateMachineParser.parser
@@ -0,0 +1,65 @@
+%header {:
+// this code is inlined before the generated parser
+package de.tudresden.inf.st.statemachine.jastadd.parser;
+import de.tudresden.inf.st.statemachine.jastadd.model.*;
+import java.util.*;
+:};
+// Documentation links: http://beaver.sourceforge.net/spec.html and https://bitbucket.org/jastadd/jastaddparser
+
+%embed {:
+ // this code is inlined in the generated parser class
+ State initial;
+ List<State> finals = new ArrayList<>();
+:};
+
+%goal goal;
+
+// Productions with semantic actions building the JastAdd AST
+
+statemachine goal =
+  element_list
+    {:
+      StateMachine result = new StateMachine(element_list);
+      result.setInitial(initial);
+      finals.forEach( result::addFinal );
+      result.treeResolveAll();
+      return result;
+    :}
+  ;
+
+JastAddList element_list =
+    element                  {: return new JastAddList().add(element); :}
+  | element_list element     {: return element_list.add(element); :}
+  ;
+
+Element element =
+    INITIAL state_body.sb SEMI  {: initial = sb; return sb; :}
+  | FINAL state_body.sb SEMI    {: finals.add(sb); return sb; :}
+  | INITIAL FINAL state_body.sb SEMI  {: initial = sb; finals.add(sb); return sb; :}
+  | state_body.sb SEMI    {: return sb; :}
+  | TRANS NAME.from ARROW NAME.to COLON NAME.label SEMI
+    {:
+      Transition result = new Transition();
+      result.setLabel(label);
+      result.setFrom(State.createRef(from));
+      result.setTo(State.createRef(to));
+      return result;
+    :}
+  | TRANS NAME.from ARROW NAME.to SEMI
+    {:
+      Transition result = new Transition();
+      result.setLabel(""); // epsilon transition
+      result.setFrom(State.createRef(from));
+      result.setTo(State.createRef(to));
+      return result;
+    :}
+  ;
+
+State state_body =
+    STATE NAME.name
+    {:
+      State result = new State();
+      result.setLabel(name);
+      return result;
+    :}
+  ;
diff --git a/statemachine.task/src/main/jastadd/StateMachineScanner.flex b/statemachine.task/src/main/jastadd/StateMachineScanner.flex
new file mode 100644
index 0000000..547fb1a
--- /dev/null
+++ b/statemachine.task/src/main/jastadd/StateMachineScanner.flex
@@ -0,0 +1,46 @@
+package de.tudresden.inf.st.statemachine.jastadd.scanner;
+
+import de.tudresden.inf.st.statemachine.jastadd.parser.StateMachineParser.Terminals; // The terminals are implicitly defined in the parser
+%%
+// Documentation links: https://www.jflex.de/manual.html and http://beaver.sourceforge.net/scanners.html
+
+// define the signature for the generated scanner
+%public
+%final
+%class StateMachineScanner
+%extends beaver.Scanner
+
+// the interface between the scanner and the parser is the nextToken() method
+%type beaver.Symbol
+%function nextToken
+%yylexthrow beaver.Scanner.Exception
+
+// store line and column information in the tokens
+%line
+%column
+
+// this code will be inlined in the body of the generated scanner class
+%{
+  private beaver.Symbol sym(short id) {
+    return new beaver.Symbol(id, yyline + 1, yycolumn + 1, yylength(), yytext());
+  }
+%}
+
+WhiteSpace = [ ] | \t | \f | \n | \r | \r\n
+Identifier = [:jletter:][:jletterdigit:]*
+
+%%
+
+// discard whitespace information
+{WhiteSpace}  { }
+
+// token definitions
+"initial"     { return sym(Terminals.INITIAL); }
+"final"       { return sym(Terminals.FINAL); }
+"state"       { return sym(Terminals.STATE); }
+"trans"       { return sym(Terminals.TRANS); }
+{Identifier}  { return sym(Terminals.NAME); }
+";"           { return sym(Terminals.SEMI); }
+":"           { return sym(Terminals.COLON); }
+"->"          { return sym(Terminals.ARROW); }
+<<EOF>>       { return sym(Terminals.EOF); }
diff --git a/statemachine.task/src/main/jastadd/Util.jadd b/statemachine.task/src/main/jastadd/Util.jadd
new file mode 100644
index 0000000..517b6a5
--- /dev/null
+++ b/statemachine.task/src/main/jastadd/Util.jadd
@@ -0,0 +1,39 @@
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import java.util.*;
+import java.util.stream.Collectors;
+
+aspect Logging {
+  static Logger ASTNode.logger = LogManager.getLogger(ASTNode.class);
+}
+
+aspect JastAddAPIExtension {
+
+  /**
+   * removes the object from the AST, i.e. removes the reference from its parent to the object
+   *
+   * Please note that any intrinsic non-containment relations to the object are not removed.
+   * @return true, if the object had a parent.
+   */
+  public boolean ASTNode.removeSelf() {
+    if (getParent() == null) {
+      return false;
+    } else {
+      for (int childIndex = 0; childIndex < getParent().numChildren(); childIndex++) {
+        if (getParent().getChild(childIndex) == this) {
+          getParent().removeChild(childIndex);
+          return true;
+        }
+      }
+    }
+    throw new RuntimeException("unable to remove child, because it was not contained in its parent!");
+  }
+
+  public String Element.customID() {
+    return getLabel();
+  }
+
+  public String Element.toString() {
+    return getLabel();
+  }
+}
diff --git a/statemachine.task/src/main/jastadd/Util.jrag b/statemachine.task/src/main/jastadd/Util.jrag
new file mode 100644
index 0000000..37592dd
--- /dev/null
+++ b/statemachine.task/src/main/jastadd/Util.jrag
@@ -0,0 +1,3 @@
+aspect Util {
+
+}
diff --git a/statemachine.task/src/main/java/de/tudresden/inf/st/statemachine/Main.java b/statemachine.task/src/main/java/de/tudresden/inf/st/statemachine/Main.java
new file mode 100644
index 0000000..d38b8ac
--- /dev/null
+++ b/statemachine.task/src/main/java/de/tudresden/inf/st/statemachine/Main.java
@@ -0,0 +1,96 @@
+package de.tudresden.inf.st.statemachine;
+
+import beaver.Parser;
+import de.tudresden.inf.st.statemachine.jastadd.model.State;
+import de.tudresden.inf.st.statemachine.jastadd.model.StateMachine;
+import de.tudresden.inf.st.statemachine.jastadd.model.Transition;
+
+import java.io.IOException;
+import java.nio.file.Paths;
+import java.util.Set;
+
+public class Main {
+
+  @SuppressWarnings("WeakerAccess")
+  public static Object DrAST_root_node;
+
+  public static void main(String[] args) throws IOException, Parser.Exception {
+    StateMachine stateMachine;
+    if (args.length == 0) {
+      stateMachine = createExample();
+    } else {
+      // load the file given as first argument
+      stateMachine = ParserUtils.load(Paths.get(args[0]));
+    }
+    printHeading("Initial statemachine");
+    System.out.println(stateMachine.prettyPrint());
+
+    stateMachine.printSomeAnalysis();
+
+    Set<Transition> epsilons = stateMachine.epsilonTransitions();
+
+    for (Transition eps : epsilons) {
+      printHeading("Removing epsilon transition " + eps.prettyPrint().trim());
+      System.out.println("Minimal distances before:");
+      initialToFinalDistances(stateMachine);
+      stateMachine.removeEpsilonTransition(eps);
+      System.out.println("Minimal distances after:");
+      initialToFinalDistances(stateMachine);
+      printHeading("StateMachine after");
+      System.out.println(stateMachine.prettyPrint());
+    }
+    printHeading("DotGraph");
+    System.out.println(stateMachine.toDot());
+    DrAST_root_node = stateMachine;
+  }
+
+  private static void printHeading(String s) {
+    System.out.println();
+    System.out.println("========================================");
+    System.out.println("== " + s);
+    System.out.println("========================================");
+  }
+
+  private static StateMachine createExample() {
+    // manual construction of a simple statemachine
+    // (S) -- e --> (B) -- 1 --> (E)
+    //  ^            |
+    //  \            /
+    //  `---- 2 ----*
+    StateMachine stateMachine = new StateMachine();
+    State start = new State();
+    start.setLabel("S");
+    State stateB = new State();
+    stateB.setLabel("B");
+    State end = new State();
+    end.setLabel("E");
+    Transition eps = new Transition();
+    Transition t2 = new Transition();
+    t2.setLabel("2");
+    Transition t1 = new Transition();
+    t1.setLabel("1");
+    eps.setFrom(start);
+    eps.setTo(stateB);
+    t2.setFrom(stateB);
+    t2.setTo(start);
+    t1.setFrom(stateB);
+    t1.setTo(end);
+    stateMachine.addElement(start);
+    stateMachine.addElement(stateB);
+    stateMachine.addElement(end);
+    stateMachine.addElement(eps);
+    stateMachine.addElement(t2);
+    stateMachine.addElement(t1);
+    stateMachine.setInitial(start);
+    stateMachine.addFinal(end);
+    return stateMachine;
+  }
+
+  private static void initialToFinalDistances(StateMachine stateMachine) {
+    for (State finalState : stateMachine.getFinalList()) {
+      System.out.println("initial state "+ stateMachine.getInitial() + " to " + finalState + " in " +
+          stateMachine.getInitial().minDistTo(finalState) + " step(s)");
+    }
+  }
+
+}
diff --git a/statemachine.task/src/main/java/de/tudresden/inf/st/statemachine/ParserUtils.java b/statemachine.task/src/main/java/de/tudresden/inf/st/statemachine/ParserUtils.java
new file mode 100644
index 0000000..ef4e501
--- /dev/null
+++ b/statemachine.task/src/main/java/de/tudresden/inf/st/statemachine/ParserUtils.java
@@ -0,0 +1,27 @@
+package de.tudresden.inf.st.statemachine;
+
+import beaver.Parser;
+import de.tudresden.inf.st.statemachine.jastadd.model.StateMachine;
+import de.tudresden.inf.st.statemachine.jastadd.parser.StateMachineParser;
+import de.tudresden.inf.st.statemachine.jastadd.scanner.StateMachineScanner;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+/**
+ * Utility methods for loading statemachine files.
+ *
+ * @author rschoene - Initial contribution
+ */
+public class ParserUtils {
+  static StateMachine load(Path path) throws IOException, Parser.Exception {
+    Reader reader = Files.newBufferedReader(path);
+    StateMachineScanner scanner = new StateMachineScanner(reader);
+    StateMachineParser parser = new StateMachineParser();
+    StateMachine result = (StateMachine) parser.parse(scanner);
+    reader.close();
+    return result;
+  }
+}
diff --git a/statemachine.task/src/main/resources/StateMachine.ecore b/statemachine.task/src/main/resources/StateMachine.ecore
new file mode 100644
index 0000000..d2f3afe
--- /dev/null
+++ b/statemachine.task/src/main/resources/StateMachine.ecore
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="statemachine" nsURI="http://www.example.org/statemachine" nsPrefix="statemachine">
+  <eClassifiers xsi:type="ecore:EClass" name="StateMachine">
+    <eStructuralFeatures xsi:type="ecore:EReference" name="element" upperBound="-1"
+        eType="#//Element" containment="true"/>
+    <eStructuralFeatures xsi:type="ecore:EReference" name="initial" lowerBound="1"
+        eType="#//State"/>
+    <eStructuralFeatures xsi:type="ecore:EReference" name="final" upperBound="-1"
+        eType="#//State"/>
+  </eClassifiers>
+  <eClassifiers xsi:type="ecore:EClass" name="Element" abstract="true">
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="label" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+  </eClassifiers>
+  <eClassifiers xsi:type="ecore:EClass" name="State" eSuperTypes="#//Element">
+    <eStructuralFeatures xsi:type="ecore:EReference" name="outgoing" upperBound="-1"
+        eType="#//Transition" eOpposite="#//Transition/from"/>
+    <eStructuralFeatures xsi:type="ecore:EReference" name="incoming" upperBound="-1"
+        eType="#//Transition" eOpposite="#//Transition/to"/>
+  </eClassifiers>
+  <eClassifiers xsi:type="ecore:EClass" name="Transition" eSuperTypes="#//Element">
+    <eStructuralFeatures xsi:type="ecore:EReference" name="from" lowerBound="1" eType="#//State"
+        eOpposite="#//State/outgoing"/>
+    <eStructuralFeatures xsi:type="ecore:EReference" name="to" lowerBound="1" eType="#//State"
+        eOpposite="#//State/incoming"/>
+  </eClassifiers>
+</ecore:EPackage>
diff --git a/statemachine.task/src/main/resources/log4j2.xml b/statemachine.task/src/main/resources/log4j2.xml
new file mode 100644
index 0000000..e4e4e60
--- /dev/null
+++ b/statemachine.task/src/main/resources/log4j2.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Configuration>
+    <Appenders>
+        <Console name="Console">
+            <PatternLayout pattern="%highlight{%d{HH:mm:ss.SSS} %-5level} %c{1.} - %msg%n"/>
+        </Console>
+        <RollingFile name="RollingFile" fileName="logs/statemachine.log"
+                    filePattern="logs/statemachine-%i.log">
+            <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n"/>
+            <Policies>
+                <OnStartupTriggeringPolicy/>
+            </Policies>
+            <DefaultRolloverStrategy max="20"/>
+        </RollingFile>
+    </Appenders>
+    <Loggers>
+        <Root level="info">
+            <AppenderRef ref="Console"/>
+            <AppenderRef ref="RollingFile"/>
+        </Root>
+    </Loggers>
+</Configuration>
diff --git a/statemachine.task/src/test/java/de/tudresden/inf/st/statemachine/AnalysisTest.java b/statemachine.task/src/test/java/de/tudresden/inf/st/statemachine/AnalysisTest.java
new file mode 100644
index 0000000..28969a5
--- /dev/null
+++ b/statemachine.task/src/test/java/de/tudresden/inf/st/statemachine/AnalysisTest.java
@@ -0,0 +1,116 @@
+package de.tudresden.inf.st.statemachine;
+
+import beaver.Parser;
+import de.tudresden.inf.st.statemachine.jastadd.model.State;
+import de.tudresden.inf.st.statemachine.jastadd.model.StateMachine;
+import de.tudresden.inf.st.statemachine.jastadd.model.Transition;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.nio.file.Paths;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Testing analysis attributes.
+ *
+ * @author rschoene - Initial contribution
+ */
+public class AnalysisTest {
+
+  @Test
+  public void test1() throws IOException, Parser.Exception {
+    StateMachine stateMachine = ParserUtils.load(Paths.get("src", "test", "resources", "machine_one.sm"));
+    State s = stateMachine.globallyResolveStateByToken("S");
+    State a = stateMachine.globallyResolveStateByToken("A");
+    State e = stateMachine.globallyResolveStateByToken("E");
+
+    assertEquals(0, s.minDistTo(s));
+    assertEquals(1, s.minDistTo(a));
+    assertEquals(2, s.minDistTo(e));
+    assertEquals(1, a.minDistTo(e));
+    assertEquals(1, a.minDistTo(s));
+    assertEquals(0, a.minDistTo(a));
+    assertEquals(-1, e.minDistTo(s));
+    assertEquals(-1, e.minDistTo(a));
+    assertEquals(0, e.minDistTo(e));
+  }
+
+  @Test
+  public void testEmpty() throws IOException, Parser.Exception {
+    StateMachine stateMachine = ParserUtils.load(Paths.get("src", "test", "resources", "empty.sm"));
+
+    State s = stateMachine.globallyResolveStateByToken("S");
+    State a = stateMachine.globallyResolveStateByToken("A");
+    State e = stateMachine.globallyResolveStateByToken("E");
+
+    assertEquals(0, s.minDistTo(s));
+    assertEquals(1, s.minDistTo(a));
+    assertEquals(2, s.minDistTo(e));
+    assertEquals(1, a.minDistTo(e));
+    assertEquals(1, a.minDistTo(s));
+    assertEquals(0, a.minDistTo(a));
+    assertEquals(-1, e.minDistTo(s));
+    assertEquals(-1, e.minDistTo(a));
+    assertEquals(0, e.minDistTo(e));
+
+    // change some things
+    Transition t5 = new Transition();
+    t5.setFrom(a);
+    t5.setTo(e);
+    stateMachine.addElement(t5);
+
+    System.out.println(stateMachine.prettyPrint());
+
+    assertEquals(0, s.minDistTo(s));
+    assertEquals(1, s.minDistTo(a));
+    assertEquals(1, s.minDistTo(e));
+    assertEquals(0, a.minDistTo(e));
+    assertEquals(1, a.minDistTo(s));
+    assertEquals(0, a.minDistTo(a));
+    assertEquals(-1, e.minDistTo(s));
+    assertEquals(-1, e.minDistTo(a));
+    assertEquals(0, e.minDistTo(e));
+
+    Set<Transition> epsilons = stateMachine.epsilonTransitions();
+    assertEquals(2, epsilons.size());
+
+    for (Transition eps : epsilons) {
+      removeEpsilonTransition(stateMachine, eps);
+    }
+
+    State ae = stateMachine.globallyResolveStateByToken("A+E");
+    Transition t6 = new Transition();
+    t6.setFrom(s);
+    t6.setTo(ae);
+    stateMachine.addElement(t6);
+
+    System.out.println(stateMachine.prettyPrint());
+
+    epsilons = stateMachine.epsilonTransitions();
+    assertEquals(1, epsilons.size());
+
+    for (Transition eps : epsilons) {
+      removeEpsilonTransition(stateMachine, eps);
+    }
+  }
+
+  private void removeEpsilonTransition(StateMachine stateMachine, Transition eps) {
+    System.out.print("removing epsilon transition " + eps.prettyPrint());
+    System.out.println("Minimal distances before:");
+    initialToFinalDists(stateMachine);
+    stateMachine.removeEpsilonTransition(eps);
+    System.out.println("Minimal distances after:");
+    initialToFinalDists(stateMachine);
+    System.out.println("StateMachine after");
+    System.out.println(stateMachine.prettyPrint());
+  }
+
+  private void initialToFinalDists(StateMachine stateMachine) {
+    for (State finalState : stateMachine.getFinalList()) {
+      System.out.println("initial state "+ stateMachine.getInitial() + " to " + finalState + " in " +
+          stateMachine.getInitial().minDistTo(finalState) + " step(s)");
+    }
+  }
+}
diff --git a/statemachine.task/src/test/java/de/tudresden/inf/st/statemachine/ParserTest.java b/statemachine.task/src/test/java/de/tudresden/inf/st/statemachine/ParserTest.java
new file mode 100644
index 0000000..16a6344
--- /dev/null
+++ b/statemachine.task/src/test/java/de/tudresden/inf/st/statemachine/ParserTest.java
@@ -0,0 +1,85 @@
+package de.tudresden.inf.st.statemachine;
+
+import beaver.Parser;
+import de.tudresden.inf.st.statemachine.jastadd.model.State;
+import de.tudresden.inf.st.statemachine.jastadd.model.StateMachine;
+import de.tudresden.inf.st.statemachine.jastadd.model.Transition;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.nio.file.Paths;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.hamcrest.CoreMatchers.*;
+import static org.hamcrest.collection.IsEmptyCollection.empty;
+import static org.junit.Assert.*;
+
+/**
+ * Testing the statemachine parser.
+ *
+ * @author rschoene - Initial contribution
+ */
+public class ParserTest {
+
+  @Test
+  public void test1() throws IOException, Parser.Exception {
+    StateMachine stateMachine = ParserUtils.load(Paths.get("src", "test", "resources", "machine_one.sm"));
+
+    assertEquals(6, stateMachine.getNumElement());
+    assertEquals(3, stateMachine.states().size());
+    assertEquals(3, stateMachine.transitions().size());
+
+    State s = stateMachine.globallyResolveStateByToken("S");
+    State a = stateMachine.globallyResolveStateByToken("A");
+    State e = stateMachine.globallyResolveStateByToken("E");
+    Transition t1 = stateMachine.globallyResolveTransitionByToken("t1");
+    Transition t2 = stateMachine.globallyResolveTransitionByToken("t2");
+    Transition t3 = stateMachine.globallyResolveTransitionByToken("t3");
+
+    assertNotNull(s);
+    assertNotNull(a);
+    assertNotNull(e);
+
+    assertEquals(s, stateMachine.getInitial());
+    assertEquals(1, stateMachine.getFinalList().size());
+    assertThat("E is not final", stateMachine.getFinalList(), hasItem(e));
+
+    assertNotNull(t1);
+    assertNotNull(t2);
+    assertNotNull(t3);
+
+    // t1: s -> a
+    assertEquals(s, t1.getFrom());
+    assertEquals(a, t1.getTo());
+    // t2: a -> s
+    assertEquals(a, t2.getFrom());
+    assertEquals(s, t2.getTo());
+    // t3: a -> e
+    assertEquals(a, t3.getFrom());
+    assertEquals(e, t3.getTo());
+
+    List<State> outgoingFromS = outgoingConnectedStates(s);
+    List<State> outgoingFromA = outgoingConnectedStates(a);
+    assertThat(outgoingFromS, not(empty()));
+    assertThat(outgoingFromA, not(empty()));
+    assertEquals(1, outgoingFromS.size());
+    assertThat("Transition S -> A missing", outgoingFromS, hasItem(a));
+    assertEquals(2, outgoingFromA.size());
+    assertThat("Transitions A -> S or A -> E missing", outgoingFromA, hasItems(s, e));
+    assertThat(outgoingConnectedStates(e), empty());
+
+    String printedForm = "initial state S;\n" +
+        "state A;\n" +
+        "final state E;\n" +
+        "trans S -> A : t1;\n" +
+        "trans A -> S : t2;\n" +
+        "trans A -> E : t3;\n";
+    assertEquals(printedForm, stateMachine.prettyPrint());
+  }
+
+  private List<State> outgoingConnectedStates(State s) {
+    return s.getOutgoingList().stream().map(Transition::getTo).collect(Collectors.toList());
+  }
+
+}
diff --git a/statemachine.task/src/test/resources/empty.sm b/statemachine.task/src/test/resources/empty.sm
new file mode 100644
index 0000000..1bbcce6
--- /dev/null
+++ b/statemachine.task/src/test/resources/empty.sm
@@ -0,0 +1,7 @@
+initial state S;
+state A;
+final state E;
+trans S -> A : t1;
+trans A -> S : t2;
+trans A -> A;
+trans A -> E : t3;
diff --git a/statemachine.task/src/test/resources/machine_one.sm b/statemachine.task/src/test/resources/machine_one.sm
new file mode 100644
index 0000000..897ccba
--- /dev/null
+++ b/statemachine.task/src/test/resources/machine_one.sm
@@ -0,0 +1,6 @@
+initial state S;
+state A;
+final state E;
+trans S -> A : t1;
+trans A -> S : t2;
+trans A -> E : t3;
diff --git a/statemachine.task/src/test/resources/telephone.sm b/statemachine.task/src/test/resources/telephone.sm
new file mode 100644
index 0000000..655e5bb
--- /dev/null
+++ b/statemachine.task/src/test/resources/telephone.sm
@@ -0,0 +1,25 @@
+initial state start;
+state onHook;
+state dialing;
+state ringing;
+state waitingForConnection;
+state communicating;
+state onHold;
+final state end;
+
+trans start -> onHook : start ;
+trans onHook -> dialing : startDialing ;
+trans dialing -> onHook : hangUp ;
+trans onHook -> ringing : incomingCall ;
+trans ringing -> onHook : otherPartyHangUp ;
+trans dialing -> waitingForConnection : completeNumber ;
+trans waitingForConnection -> onHook : hangUp ;
+trans waitingForConnection -> onHook : timeOut ;
+trans waitingForConnection -> communicating : otherPartyPickUp ;
+trans ringing -> communicating : pickUp ;
+trans communicating -> onHook : hangUp ;
+trans communicating -> onHold : putOnHold ;
+trans onHold -> communicating : takeOffHold ;
+trans communicating -> end : otherPartyHangUp ;
+trans onHold -> end : otherPartyHangUp ;
+trans onHold -> end : hangUp ;
-- 
GitLab