diff --git a/SanityCheck.jar b/SanityCheck.jar
index ae0827bf18a9d723f76089c40656eceb4da08e8c..bebdf1da3e6277f966e8fff78ea96d884fe27b0b 100644
Binary files a/SanityCheck.jar and b/SanityCheck.jar differ
diff --git a/devTools/javaSanityCheck/htmlTags b/devTools/javaSanityCheck/htmlTags
index 608a30a5ff6648b7c873d6c41f6f6d794afbc757..751b084ff5822f4162e3f79ea622b91f60c5472b 100644
--- a/devTools/javaSanityCheck/htmlTags
+++ b/devTools/javaSanityCheck/htmlTags
@@ -1,5 +1,5 @@
 #Allowed HTML tags
-#Effectively everything that is allowed in one of these statements like this:
+#Effectively everything that is allowed in a these statements like this:
 #<tag> or <tag ???>
 #when ;1 is specified it expects a matching closing tag like this: </tag>
 #Do not add Twine Tags here.
@@ -25,11 +25,11 @@ h1;1
 h2;1
 h3;1
 h4;1
-hr;1
+hr;0
 html;1
 i;1
 img;1
-input;1
+input;0
 li;1
 option;1
 script;1
diff --git a/devTools/javaSanityCheck/src/DisallowedTagException.java b/devTools/javaSanityCheck/src/DisallowedTagException.java
new file mode 100644
index 0000000000000000000000000000000000000000..f4cc75e736b162192a5f18bbc55a10edb21eaa38
--- /dev/null
+++ b/devTools/javaSanityCheck/src/DisallowedTagException.java
@@ -0,0 +1,8 @@
+package org.arkerthan.sanityCheck;
+
+public class DisallowedTagException extends RuntimeException {
+
+    public DisallowedTagException(String tag) {
+        super(tag);
+    }
+}
diff --git a/devTools/javaSanityCheck/src/Main.java b/devTools/javaSanityCheck/src/Main.java
index 6a7aee137ca63aad29d76d338f6f47a29351b3f3..eea3a4ff611203b0025cd29ce1fe431447f80e1c 100644
--- a/devTools/javaSanityCheck/src/Main.java
+++ b/devTools/javaSanityCheck/src/Main.java
@@ -1,11 +1,9 @@
 package org.arkerthan.sanityCheck;
 
 import org.arkerthan.sanityCheck.element.AngleBracketElement;
-import org.arkerthan.sanityCheck.element.AtElement;
+import org.arkerthan.sanityCheck.element.CommentElement;
 import org.arkerthan.sanityCheck.element.Element;
-import org.arkerthan.sanityCheck.element.KnownHtmlElement;
-import org.arkerthan.sanityCheck.tag.HtmlTag;
-import org.arkerthan.sanityCheck.tag.Tag;
+import org.arkerthan.sanityCheck.element.KnownElement;
 
 import java.io.*;
 import java.nio.charset.Charset;
@@ -16,7 +14,7 @@ import java.util.*;
 
 public class Main {
 
-    public static TagSearchTree<HtmlTag> htmlTags;
+    public static TagSearchTree<Tag> htmlTags, twineTags;
     private static String currentFile;
     private static int currentLine, currentPosition;
     private static Stack<Element> stack;
@@ -27,6 +25,7 @@ public class Main {
         //setup
         setupExclude();
         setupHtmlTags();
+        setupTwineTags();
         Path workingDir = Paths.get("").toAbsolutePath();
 
         //actual sanityCheck
@@ -42,7 +41,7 @@ public class Main {
 
     /**
      * Goes through the whole directory including subdirectories and runs
-     * sanitycheck() on all .tw files
+     * sanityCheck() on all .tw files
      *
      * @param dir to be checked
      */
@@ -61,7 +60,9 @@ public class Main {
                 }
             }
         } catch (NullPointerException e) {
-            System.err.println("Couldn't find directory " + dir.getPath());
+            e.printStackTrace();
+            System.err.println("Couldn't find directory " + currentFile);
+            System.exit(-1);
         }
     }
 
@@ -96,23 +97,23 @@ public class Main {
     }
 
     /**
-     * sets up the alphabetical search tree for fast access later
+     * sets up the alphabetical search tree for fast access of HTML tags later
      */
     private static void setupHtmlTags() {
         //load HTML tags into a list
-        List<Tag> htmlTagsList = new LinkedList<>();
+        List<Tag> TagsList = new LinkedList<>();
         try {
 
             Files.lines(new File("devTools/javaSanityCheck/htmlTags").toPath()).map(String::trim)
                     .filter(s -> !s.startsWith("#"))
-                    .forEach(s -> htmlTagsList.add(parseTag(s)));
+                    .forEach(s -> TagsList.add(parseTag(s)));
         } catch (IOException e) {
             System.err.println("Couldn't read devTools/javaSanityCheck/htmlTags");
         }
 
         //turn List into alphabetical search tree
         try {
-            htmlTags = new TagSearchTree(htmlTagsList);
+            htmlTags = new TagSearchTree(TagsList);
         } catch (ArrayIndexOutOfBoundsException e) {
             System.err.println("Illegal Character in devTools/javaSanityCheck/htmlTags");
             System.exit(-1);
@@ -120,18 +121,42 @@ public class Main {
     }
 
     /**
-     * Turns a string into a HtmlTag
+     * sets up the alphabetical search tree for fast access of twine tags later
+     */
+    private static void setupTwineTags() {
+        //load twine tags into a list
+        List<Tag> TagsList = new LinkedList<>();
+        try {
+
+            Files.lines(new File("devTools/javaSanityCheck/twineTags").toPath()).map(String::trim)
+                    .filter(s -> !s.startsWith("#"))
+                    .forEach(s -> TagsList.add(parseTag(s)));
+        } catch (IOException e) {
+            System.err.println("Couldn't read devTools/javaSanityCheck/twineTags");
+        }
+
+        //turn List into alphabetical search tree
+        try {
+            twineTags = new TagSearchTree(TagsList);
+        } catch (ArrayIndexOutOfBoundsException e) {
+            System.err.println("Illegal Character in devTools/javaSanityCheck/twineTags");
+            System.exit(-1);
+        }
+    }
+
+    /**
+     * Turns a string into a Tag
      * ";1" at the end of the String indicates that the tag needs to be closed later
      *
      * @param s tag as String
-     * @return tag as HtmlTag
+     * @return tag as Tag
      */
-    private static HtmlTag parseTag(String s) {
+    private static Tag parseTag(String s) {
         String[] st = s.split(";");
         if (st.length > 1 && st[1].equals("1")) {
-            return new HtmlTag(st[0], false);
+            return new Tag(st[0], false);
         }
-        return new HtmlTag(st[0], true);
+        return new Tag(st[0], true);
     }
 
     /**
@@ -225,45 +250,64 @@ public class Main {
                 if (change == 2) {
                     //remove the topmost element from stack since it is complete
                     stack.pop();
+                    return;
                 }
                 //3 means the Element is complete and part of a two tag system
                 if (change == 3) {
                     //remove the topmost element from stack since it is complete
-                    KnownHtmlElement k = stack.pop().getKnownElement();
-                    if (k.isOpening()) {
+                    KnownElement k = stack.pop().getKnownElement();
+                    /*if (k.isOpening()) {
                         stack.push(k);
-                    } else if (stack.empty()) {
-                        addError(new SyntaxError("Closed HTML tag \"" + k.getStatement() + "\" without having any open tags.", -1));
-                    } else if (stack.peek() instanceof KnownHtmlElement) {
-                        KnownHtmlElement kFirst = (KnownHtmlElement) stack.peek();
-                        if (!kFirst.isMatchingElement(k)) {
-                            addError(new SyntaxError("Opening HTML tag \"" + kFirst.getStatement() +
-                                    "\" does not match closing tag \"" + k.getStatement() + "\".", -1));
+                    } else */
+                    if (k.isClosing()) {
+                        if (stack.empty()) {
+                            addError(new SyntaxError("Closed tag " + k.getShortDescription() + " without having any open tags.", -2));
+                        } else if (stack.peek() instanceof KnownElement) {
+                            KnownElement kFirst = (KnownElement) stack.pop();
+                            if (!kFirst.isMatchingElement(k)) {
+                                addError(new SyntaxError("Opening tag " + kFirst.getShortDescription() +
+                                        " does not match closing tag " + k.getShortDescription() + ".", -2));
+                            }
+                            //stack.pop();
+                        } else {
+                            addError(new SyntaxError("Closing tag " + k.getShortDescription() + " inside " +
+                                    "another tag: " + stack.peek().getShortDescription(), -2, true));
                         }
-                        stack.pop();
-                    } else {
-                        addError(new SyntaxError("Closing HTML tag \"" + k.getStatement() + "\" inside " +
-                                "another tag: " + stack.peek().getShortDescription(), -1, true));
                     }
+                    if (k.isOpening()) {
+                        stack.push(k);
+                    }
+                    return;
+                }
+                if (change == 4) {
+                    stack.pop();
+                } else {
+                    return;
                 }
-                return;
             }
         }
 
 
         //innermost element was uninterested, trying to find matching element
         switch (c) {
-            case '@':
-                stack.push(new AtElement(currentLine, currentPosition));
-                break;
+            //case '@':
+            //  stack.push(new AtElement(currentLine, currentPosition));
+            //break;
             case '<':
                 stack.push(new AngleBracketElement(currentLine, currentPosition));
                 break;
+            //case '>':
+            //addError(new SyntaxError("Dangling \">\", current innermost: " + (stack.empty() ? "null" : stack.peek().getShortDescription()), -2));
+            //break;
+            case '/':
+                stack.push(new CommentElement(currentLine, currentPosition));
+                break;
         }
     }
 
     /**
      * add an error to the error list
+     *
      * @param e new error
      */
     private static void addError(SyntaxError e) {
diff --git a/devTools/javaSanityCheck/src/SyntaxError.java b/devTools/javaSanityCheck/src/SyntaxError.java
index 90d9db7333c3b82728fc1c21dad4591e2c9d16bf..150f2bd449b8c318b5a05884868a71538554ec67 100644
--- a/devTools/javaSanityCheck/src/SyntaxError.java
+++ b/devTools/javaSanityCheck/src/SyntaxError.java
@@ -4,7 +4,7 @@ public class SyntaxError extends Exception {
     private String file;
     private int line, position;
     private String description;
-    private int change; //see Element for values; -1 means not thrown
+    private int change; //see Element for values; -2 means not thrown
     private boolean warning = false;
 
     public SyntaxError(String description, int change) {
diff --git a/devTools/javaSanityCheck/src/tag/Tag.java b/devTools/javaSanityCheck/src/Tag.java
similarity index 52%
rename from devTools/javaSanityCheck/src/tag/Tag.java
rename to devTools/javaSanityCheck/src/Tag.java
index 386292b48eb43f2eeec4721addc62f5fbc328159..8a13ee4f7a178399db3eaf626b693e8a12ae71df 100644
--- a/devTools/javaSanityCheck/src/tag/Tag.java
+++ b/devTools/javaSanityCheck/src/Tag.java
@@ -1,10 +1,10 @@
-package org.arkerthan.sanityCheck.tag;
+package org.arkerthan.sanityCheck;
 
-public abstract class Tag {
+public class Tag {
     public final String tag;
     public final boolean single;
 
-    protected Tag(String tag, boolean single) {
+    public Tag(String tag, boolean single) {
         this.tag = tag;
         this.single = single;
     }
diff --git a/devTools/javaSanityCheck/src/TagSearchTree.java b/devTools/javaSanityCheck/src/TagSearchTree.java
index 567f33f35d7d4aef7bd2b2db70f5b49c0ea6b01a..dde49df879a346f124d15647cfeb821d0e0735fb 100644
--- a/devTools/javaSanityCheck/src/TagSearchTree.java
+++ b/devTools/javaSanityCheck/src/TagSearchTree.java
@@ -1,32 +1,52 @@
 package org.arkerthan.sanityCheck;
 
-import org.arkerthan.sanityCheck.tag.Tag;
-
 import java.util.List;
 
+/**
+ * Tag SearchTree stores Tags in an alphabetical search tree.
+ * Once created the search tree can't be changed anymore.
+ *
+ * @param <E> Tag class to be stored
+ */
 public class TagSearchTree<E extends Tag> {
     private static final int SIZE = 128;
+    private final TagSearchTree<E>[] branches;
     private E element = null;
-    private TagSearchTree<E>[] branches;
     private String path;
 
+    /**
+     * creates a new empty TagSearchTree
+     */
     private TagSearchTree() {
         branches = new TagSearchTree[SIZE];
     }
 
+    /**
+     * Creates a new filled TagSearchTree
+     *
+     * @param list Tags to be inserted
+     */
     public TagSearchTree(List<E> list) {
         this();
-        for (E e :
-                list) {
+        for (E e : list) {
             this.add(e, 0);
         }
     }
 
+    /**
+     * adds a new Tag to the TagSearchTree
+     *
+     * @param e     Tag to be stored
+     * @param index index of relevant char for adding in tag
+     */
     private void add(E e, int index) {
-        path = e.tag.substring(0,index);
+        //set the path to here
+        path = e.tag.substring(0, index);
+        //checks if tag has to be stored here or further down
         if (e.tag.length() == index) {
             element = e;
         } else {
+            //store tag in correct branch
             char c = e.tag.charAt(index);
             if (branches[c] == null) {
                 branches[c] = new TagSearchTree<>();
@@ -35,15 +55,25 @@ public class TagSearchTree<E extends Tag> {
         }
     }
 
+    /**
+     * @param c character of branch needed
+     * @return branch or null if branch doesn't exist
+     */
     public TagSearchTree<E> getBranch(char c) {
         if (c >= SIZE) return null;
         return branches[c];
     }
 
+    /**
+     * @return stored Tag, null if empty
+     */
     public E getElement() {
         return element;
     }
 
+    /**
+     * @return path inside full tree to get to this Branch
+     */
     public String getPath() {
         return path;
     }
diff --git a/devTools/javaSanityCheck/src/element/AngleBracketElement.java b/devTools/javaSanityCheck/src/element/AngleBracketElement.java
index 35877dec434f5795fa0b81be43847b0a4e061104..e4819ba37ea48e4924dc944827d651fa14e02ad1 100644
--- a/devTools/javaSanityCheck/src/element/AngleBracketElement.java
+++ b/devTools/javaSanityCheck/src/element/AngleBracketElement.java
@@ -1,28 +1,39 @@
 package org.arkerthan.sanityCheck.element;
 
-import org.arkerthan.sanityCheck.Main;
-import org.arkerthan.sanityCheck.SyntaxError;
-import org.arkerthan.sanityCheck.TagSearchTree;
-import org.arkerthan.sanityCheck.UnknownStateException;
-import org.arkerthan.sanityCheck.tag.HtmlTag;
+import org.arkerthan.sanityCheck.*;
+
+import java.util.Arrays;
+import java.util.List;
 
 public class AngleBracketElement extends Element {
+    private static final List<String> logicTags = Arrays.asList("if", "elseif", "else", "switch", "case", "default");
     private int state = 0;
     /*
-    -1 - </
      0 - initial: <
+     TWINE
      1 - <<
-     2 - <<abc
-     3 - <<abc>
-
-     4 - trying to complete HTML tag: <tag ???>
-    -4 - trying to complete HTML tag: </tag>
-     5 - waiting for >
+    -1 - <</
+     2 - trying to complete twine tag: <<tag ???>>
+    -2 - trying to complete twine tag: <</tag>>
+     3 - waiting for >>
+    -3 - expecting > from 3
+     4 - waiting for >> with KnownElement
+    -4 - expecting > from 4
+     5 - expecting >>
     -5 - expecting >
-     6 - waiting for > with KnownHtmlElement
+     6 - expecting > with KnownElement opening; comparison?
+    -6 - expecting > with KnownElement closing
+
+     HTML
+    -9 - </
+    10 - trying to complete HTML tag: <tag ???>
+   -10 - trying to complete HTML tag: </tag>
+    11 - waiting for >
+   -11 - expecting >
+    12 - waiting for > with KnownElement
      */
 
-    private TagSearchTree<HtmlTag> htmlTree;
+    private TagSearchTree<Tag> tree;
 
     public AngleBracketElement(int line, int pos) {
         super(line, pos);
@@ -39,7 +50,7 @@ public class AngleBracketElement extends Element {
                     case '>':
                         throw new SyntaxError("Empty Statement?", 2);
                     case '/':
-                        state = -1;
+                        state = -9;
                         return 1;
                     case ' ':// assume comparison
                     case '=':// "
@@ -48,63 +59,118 @@ public class AngleBracketElement extends Element {
                         return 2;
                     default:
                         try {
-                            state = 4;
-                            htmlTree = Main.htmlTags;
+                            state = 10;
+                            tree = Main.htmlTags;
                             return handleOpeningHTML(c);
                         } catch (SyntaxError e) {
                             state = 1;
                             throw new SyntaxError("Opening \"<\" missing, found " + c + " [debug:initialCase]", 1);
                         }
                 }
-            case -1:
-                if (c == '>') {
-                    throw new SyntaxError("Empty Statement?", 2, true);
-                }
-                state = -4;
-                htmlTree = Main.htmlTags;
-                return handleClosingHTML(c);
             case 1:
                 if (c == '<') {
                     throw new SyntaxError("Too many \"<\".", 1);
                 } else if (c == '>') {
                     state = 3;
                     throw new SyntaxError("Empty Statement?", 1);
-                } else {
-                    state = 2;
+                } else if (c == '/') {
+                    state = -1;
                     return 1;
                 }
+                state = 2;
+                tree = Main.twineTags;
+                return handleOpeningTwine(c);
+            case -1:
+                if (c == '>') {
+                    throw new SyntaxError("Empty Statement?", 2, true);
+                }
+                state = -2;
+                tree = Main.twineTags;
+                return handleClosingTwine(c);
+
             case 2:
-                //TODO finding special Twine statements: IF, ELSE...
+                return handleOpeningTwine(c);
+            case -2:
+                return handleClosingTwine(c);
+            case 3:
                 if (c == '>') {
-                    state = 3;
+                    state = -3;
                     return 1;
                 }
                 break;
-            case 3:
+            case -3:
                 if (c == '>') {
                     return 2;
                 } else if (c == ' ' || c == '=') { // assuming comparison
-                    state = 2;
+                    state = 3;
+                    return 1;
                 } else {
-                    throw new SyntaxError("Closing \">\" missing [1]", 2);
+                    throw new SyntaxError("Closing \">\" missing, opened [" + line + ":" + pos + "]", 2);
+                }
+            case 4:
+                if (c == '>') {
+                    state = -4;
+                    return 1;
                 }
                 break;
+            case -4:
+                if (c == '>') {
+                    return 3;
+                } else if (c == ' ' || c == '=') { // assuming comparison
+                    state = 4;
+                    return 1;
+                } else {
+                    throw new SyntaxError("Closing \">\" missing, opened [" + line + ":" + pos + "]", 2);
+                }
+            case 5:
+                if (c == '>') {
+                    state = -5;
+                    return 1;
+                } else {
+                    throw new SyntaxError("Closing \">\" missing, opened [" + line + ":" + pos + "]", 2);
+                }
+            case -5:
+                if (c == '>') {
+                    return 2;
+                }
+                throw new SyntaxError("Closing \">\" missing, opened [" + line + ":" + pos + "]", 2);
+            case 6:
+                if (c == '>') {
+                    return 3;
+                } else if (c == ' ' || c == '=') {
+                    state = 3;
+                    return 1;
+                } else {
+                    throw new SyntaxError("Closing \">\" missing, opened [" + line + ":" + pos + "]", 3);
+                }
+            case -6:
+                if (c == '>') {
+                    return 3;
+                }
+                throw new SyntaxError("Closing \">\" missing, opened [" + line + ":" + pos + "]", 3);
 
-            case 4:
+            case -9:
+                if (c == '>') {
+                    throw new SyntaxError("Empty Statement?", 2, true);
+                }
+                state = -10;
+                tree = Main.htmlTags;
+                return handleClosingHTML(c);
+            case 10:
                 return handleOpeningHTML(c);
-            case -4:
+            case -10:
                 return handleClosingHTML(c);
-            case 5:
+            case 11:
                 if (c == '>')
                     return 2;
                 if (c == '@') //@ inside HTML tags is allowed
                     return 1;
                 break;
-            case -5:
+            case -11:
                 if (c == '>')
                     return 2;
                 throw new SyntaxError("Closing \">\" missing [2]", 2);
-            case 6:
+            case 12:
                 if (c == '>')
                     return 3;
                 if (c == '@') //@ inside HTML tags is allowed
@@ -118,31 +184,31 @@ public class AngleBracketElement extends Element {
 
     private int handleOpeningHTML(char c) throws SyntaxError {
         if (c == ' ') {
-            state = 5;
-            if (htmlTree.getElement() == null) {
+            state = 11;
+            if (tree.getElement() == null) {
                 throw new SyntaxError("Unknown HTML tag", 1);
             }
-            if (!htmlTree.getElement().single) {
-                k = new KnownHtmlElement(line, pos, true, htmlTree.getElement().tag);
-                state = 6;
+            if (!tree.getElement().single) {
+                k = new KnownHtmlElement(line, pos, true, tree.getElement().tag);
+                state = 12;
                 return 1;
             }
             return 1;
         }
         if (c == '>') {
-            if (htmlTree.getElement() == null) {
+            if (tree.getElement() == null) {
                 throw new SyntaxError("Unknown HTML tag", 2);
             }
-            if (!htmlTree.getElement().single) {
-                k = new KnownHtmlElement(line, pos, true, htmlTree.getElement().tag);
+            if (!tree.getElement().single) {
+                k = new KnownHtmlElement(line, pos, true, tree.getElement().tag);
                 return 3;
             }
             return 2;
         }
 
-        htmlTree = htmlTree.getBranch(c);
-        if (htmlTree == null) {
-            state = 5;
+        tree = tree.getBranch(c);
+        if (tree == null) {
+            state = 11;
             throw new SyntaxError("Unknown HTML tag or closing \">\" missing, found " + c, 1);
         }
 
@@ -151,29 +217,104 @@ public class AngleBracketElement extends Element {
 
     private int handleClosingHTML(char c) throws SyntaxError {
         if (c == '>') {
-            if (htmlTree.getElement() == null) {
+            if (tree.getElement() == null) {
                 throw new SyntaxError("Unknown HTML tag", 2);
             }
-            if (htmlTree.getElement().single) {
-                throw new SyntaxError("Single HTML tag used as closing Tag: " + htmlTree.getElement().tag, 2);
+            if (tree.getElement().single) {
+                throw new SyntaxError("Single HTML tag used as closing Tag: " + tree.getElement().tag, 2);
             }
-            k = new KnownHtmlElement(line, pos, false, htmlTree.getElement().tag);
+            k = new KnownHtmlElement(line, pos, false, tree.getElement().tag);
             return 3;
         }
 
-        htmlTree = htmlTree.getBranch(c);
-        if (htmlTree == null) {
-            state = -5;
+        tree = tree.getBranch(c);
+        if (tree == null) {
+            state = -11;
             throw new SyntaxError("Unknown HTML tag or closing \">\" missing, found " + c, 1);
         }
 
         return 1;
     }
 
+
+    private int handleOpeningTwine(char c) throws SyntaxError {
+        if (c == ' ') {
+            state = 3;
+            if (tree.getElement() == null) {
+                //assuming not listed means widget until better solution
+                return 1;
+                //throw new SyntaxError("Unknown Twine tag or closing \">>\" missing, found " + tree.getPath(), 1);
+            }
+            if (!tree.getElement().single) {
+                if (logicTags.contains(tree.getElement().tag)) {
+                    k = new KnownLogicElement(line, pos, tree.getElement().tag, false);
+                } else {
+                    k = new KnownTwineElement(line, pos, true, tree.getElement().tag);
+                }
+                state = 4;
+                return 1;
+            }
+            return 1;
+        }
+        if (c == '>') {
+            state = -5;
+            if (tree.getElement() == null) {
+                //assuming not listed means widget until better solution
+                //throw new SyntaxError("Unknown Twine tag or closing \">>\" missing, found " + tree.getPath(), 1);
+                return 1;
+            }
+            if (!tree.getElement().single) {
+                if (logicTags.contains(tree.getElement().tag)) {
+                    k = new KnownLogicElement(line, pos, tree.getElement().tag, false);
+                } else {
+                    k = new KnownTwineElement(line, pos, true, tree.getElement().tag);
+                }
+                state = 6;
+                return 1;
+            }
+            return 2;
+        }
+
+        tree = tree.getBranch(c);
+        if (tree == null) {
+            //assuming not listed means widget until better solution
+            state = 3;
+            //throw new SyntaxError("Unknown Twine tag or closing \">>\" missing, found " + c, 1);
+        }
+
+        return 1;
+    }
+
+    private int handleClosingTwine(char c) throws SyntaxError {
+        if (c == '>') {
+            if (tree.getElement() == null) {
+                throw new SyntaxError("Unknown Twine tag", 2);
+            }
+            if (tree.getElement().single) {
+                throw new SyntaxError("Single Twine tag used as closing Tag: " + tree.getElement().tag, 2);
+            }
+            if (logicTags.contains(tree.getElement().tag)) {
+                k = new KnownLogicElement(line, pos, tree.getElement().tag, true);
+            } else {
+                k = new KnownTwineElement(line, pos, false, tree.getElement().tag);
+            }
+            state = -6;
+            return 1;
+        }
+
+        tree = tree.getBranch(c);
+        if (tree == null) {
+            state = 3;
+            throw new SyntaxError("Unknown Twine closing tag or closing \">>\" missing, found " + c, 1);
+        }
+
+        return 1;
+    }
+
     @Override
     public String getShortDescription() {
         StringBuilder builder = new StringBuilder();
-        builder.append(line).append(":").append(pos).append(" ");
+        builder.append('[').append(line).append(":").append(pos).append("] ");
         switch (state) {
             case 0:
                 builder.append("<");
@@ -182,31 +323,37 @@ public class AngleBracketElement extends Element {
                 builder.append("<<");
                 break;
             case -1:
-                builder.append("</");
+                builder.append("<</");
                 break;
             case 2:
-                builder.append("<<???");
+                builder.append("<<").append(tree.getPath());
+                break;
+            case -2:
+                builder.append("<</").append(tree.getPath());
                 break;
             case 3:
-                builder.append("<<???>");
+                builder.append("<<??? ???");
                 break;
             case 4:
-                builder.append("<").append(htmlTree.getPath());
+                builder.append("<<?").append(tree.getPath()).append(" ???");
+                break;
+            case -3:
+                builder.append("<<??? ???>");
                 break;
             case -4:
-                builder.append("</").append(htmlTree.getPath());
+                builder.append("<<?").append(tree.getPath()).append(" ???>");
                 break;
             case 5:
-                builder.append("<").append(htmlTree.getPath()).append(" ???");
+                builder.append("<").append(tree.getPath()).append(" ???");
                 break;
             case -5:
-                builder.append("</").append(htmlTree.getPath());
+                builder.append("</").append(tree.getPath());
                 break;
             case 6:
-                builder.append("<").append(htmlTree.getPath()).append(" ???");
+                builder.append("<").append(tree.getPath()).append(" ???");
                 break;
             default:
-                throw new UnknownStateException(state);
+                //throw new UnknownStateException(state);
         }
         return builder.toString();
     }
diff --git a/devTools/javaSanityCheck/src/element/CommentElement.java b/devTools/javaSanityCheck/src/element/CommentElement.java
new file mode 100644
index 0000000000000000000000000000000000000000..3a3cc12aff9f3c2e4b06cc7240d14824575cc96e
--- /dev/null
+++ b/devTools/javaSanityCheck/src/element/CommentElement.java
@@ -0,0 +1,66 @@
+package org.arkerthan.sanityCheck.element;
+
+import org.arkerthan.sanityCheck.SyntaxError;
+import org.arkerthan.sanityCheck.UnknownStateException;
+
+public class CommentElement extends Element {
+    int state = 0;
+    /*
+    0 - /
+    1 - /*???
+    2 - /*???*
+    3 - /%???
+    4 - /%???%
+     */
+
+    public CommentElement(int line, int pos) {
+        super(line, pos);
+    }
+
+    @Override
+    public int handleChar(char c) throws SyntaxError {
+        switch (state) {
+            case 0:
+                if (c == '*') {
+                    state = 1;
+                } else if (c == '%') {
+                    state = 3;
+                } else if (c == '>') {
+                    throw new SyntaxError("XHTML style closure", 4, true);
+                } else {
+                    return 4;
+                }
+                break;
+            case 1:
+                if (c == '*') {
+                    state = 2;
+                }
+                break;
+            case 2:
+                if (c == '/') {
+                    return 2;
+                }
+                state = 1;
+                break;
+            case 3:
+                if (c == '%') {
+                    state = 4;
+                }
+                break;
+            case 4:
+                if (c == '/') {
+                    return 2;
+                }
+                state = 3;
+                break;
+            default:
+                throw new UnknownStateException(state);
+        }
+        return 1;
+    }
+
+    @Override
+    public String getShortDescription() {
+        return null;
+    }
+}
diff --git a/devTools/javaSanityCheck/src/element/Element.java b/devTools/javaSanityCheck/src/element/Element.java
index 5393426861853b5397f67fdb6cd85926d8481c72..b0f99fa904f66a6a9ebcecb5ffdfb7040493b08b 100644
--- a/devTools/javaSanityCheck/src/element/Element.java
+++ b/devTools/javaSanityCheck/src/element/Element.java
@@ -3,13 +3,12 @@ package org.arkerthan.sanityCheck.element;
 import org.arkerthan.sanityCheck.SyntaxError;
 
 public abstract class Element {
-    protected KnownHtmlElement k;
+    protected KnownElement k;
     protected int line, pos;
 
     /**
-     *
      * @param line Line the instance was created
-     * @param pos Position in line the instance was created
+     * @param pos  Position in line the instance was created
      */
     protected Element(int line, int pos) {
         this.line = line;
@@ -22,6 +21,7 @@ public abstract class Element {
      * 1 - the Element changed state
      * 2 - the Element is finished
      * 3 - the Element is finished and a KnownHtmlElement was generated
+     * 4 - the Element is finished and the char is still open for use
      *
      * @param c
      * @return
@@ -29,12 +29,11 @@ public abstract class Element {
      */
     public abstract int handleChar(char c) throws SyntaxError;
 
-    public KnownHtmlElement getKnownElement() {
+    public KnownElement getKnownElement() {
         return k;
     }
 
     /**
-     *
      * @return a short description usually based on state and position of the Element
      */
     public abstract String getShortDescription();
diff --git a/devTools/javaSanityCheck/src/element/KnownElement.java b/devTools/javaSanityCheck/src/element/KnownElement.java
new file mode 100644
index 0000000000000000000000000000000000000000..305be2fe65210b191d96ead352487b35e448ce39
--- /dev/null
+++ b/devTools/javaSanityCheck/src/element/KnownElement.java
@@ -0,0 +1,31 @@
+package org.arkerthan.sanityCheck.element;
+
+import org.arkerthan.sanityCheck.SyntaxError;
+
+public abstract class KnownElement extends Element {
+
+    public KnownElement(int line, int pos) {
+        super(line, pos);
+    }
+
+    /**
+     * @return true, if it needs another Known Element to close it.
+     */
+    public abstract boolean isOpening();
+
+    /**
+     * @return true if it closes another Element.
+     */
+    public abstract boolean isClosing();
+
+    /**
+     * @param k Element to be checked
+     * @return true if given Element closes Element
+     */
+    public abstract boolean isMatchingElement(KnownElement k);
+
+    @Override
+    public int handleChar(char c) throws SyntaxError {
+        return 0;
+    }
+}
diff --git a/devTools/javaSanityCheck/src/element/KnownHtmlElement.java b/devTools/javaSanityCheck/src/element/KnownHtmlElement.java
index b3b136733787bcea1261e15684fac14770e8ea66..d086a74bc547a0aa90520e50c4398f5cf6dc365e 100644
--- a/devTools/javaSanityCheck/src/element/KnownHtmlElement.java
+++ b/devTools/javaSanityCheck/src/element/KnownHtmlElement.java
@@ -1,6 +1,6 @@
 package org.arkerthan.sanityCheck.element;
 
-public class KnownHtmlElement extends Element {
+public class KnownHtmlElement extends KnownElement {
 
     private boolean opening;
     private String statement;
@@ -11,43 +11,31 @@ public class KnownHtmlElement extends Element {
         this.statement = statement;
     }
 
-    @Override
-    public int handleChar(char c) {
-        return 0;
-    }
-
     @Override
     public String getShortDescription() {
         StringBuilder builder = new StringBuilder();
-        builder.append(line).append(":").append(pos).append(" <");
-        if(!opening){
+        builder.append('[').append(line).append(":").append(pos).append("] <");
+        if (!opening) {
             builder.append("/");
         }
-        return builder.append(statement).toString();
+        return builder.append(statement).append(">").toString();
     }
 
-    /**
-     * @return true, if it needs another Known Element to close it, false if it closes another element.
-     */
+    @Override
     public boolean isOpening() {
         return opening;
     }
 
-    /**
-     * @param k Element to be checked
-     * @return true if given Element closes Element
-     */
-    public boolean isMatchingElement(KnownHtmlElement k) {
-        return k.statement.equals(this.statement);
+    @Override
+    public boolean isClosing() {
+        return !opening;
     }
 
-    /**
-     * Returns, if isOpening is true, the needed statement for closing,
-     * otherwise the statement that generated it.
-     *
-     * @return statement
-     */
-    public String getStatement() {
-        return statement;
+    @Override
+    public boolean isMatchingElement(KnownElement k) {
+        if (k instanceof KnownHtmlElement) {
+            return ((KnownHtmlElement) k).statement.equals(this.statement);
+        }
+        return false;
     }
 }
diff --git a/devTools/javaSanityCheck/src/element/KnownLogicElement.java b/devTools/javaSanityCheck/src/element/KnownLogicElement.java
new file mode 100644
index 0000000000000000000000000000000000000000..502abde93a296c3dffb2391b75b08893aeecd2c5
--- /dev/null
+++ b/devTools/javaSanityCheck/src/element/KnownLogicElement.java
@@ -0,0 +1,117 @@
+package org.arkerthan.sanityCheck.element;
+
+import org.arkerthan.sanityCheck.DisallowedTagException;
+import org.arkerthan.sanityCheck.UnknownStateException;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class KnownLogicElement extends KnownElement {
+    private static final List<String> allowedTags = Arrays.asList("if", "elseif", "else");
+    private final int state;
+    private boolean last;
+    /*
+    0 - if
+    1 - elseif
+    2 - else
+    3 - switch
+    4 - case
+    5 - default
+     */
+
+    public KnownLogicElement(int line, int pos, String tag, boolean last) {
+        this(line, pos, tag);
+        this.last = last;
+    }
+
+    public KnownLogicElement(int line, int pos, String tag) {
+        super(line, pos);
+        switch (tag) {
+            case "if":
+                state = 0;
+                break;
+            case "elseif":
+                state = 1;
+                break;
+            case "else":
+                state = 2;
+                break;
+            case "switch":
+                state = 3;
+                break;
+            case "case":
+                state = 4;
+                break;
+            case "default":
+                state = 5;
+                break;
+            default:
+                throw new DisallowedTagException(tag);
+        }
+        last = false;
+    }
+
+    @Override
+    public boolean isOpening() {
+        return !last;
+    }
+
+    @Override
+    public boolean isClosing() {
+        return (state != 0 && state != 3) || last;
+    }
+
+    @Override
+    public boolean isMatchingElement(KnownElement k) {
+        if (!(k instanceof KnownLogicElement)) {
+            return false;
+        }
+        KnownLogicElement l = (KnownLogicElement) k;
+        switch (state) {
+            case 0:
+            case 1:
+                return l.state == 1 || l.state == 2 || (l.state == 0 && l.last);
+            case 2:
+                return l.state == 0 && l.last;
+            case 3:
+            case 4:
+                return l.state == 3 || l.state == 4;
+            case 5:
+                return l.state == 3 && l.last;
+            default:
+                throw new UnknownStateException(state);
+        }
+    }
+
+    @Override
+    public String getShortDescription() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("[").append(line).append(":").append(pos).append("] <<");
+        if (last) {
+            builder.append('/');
+        }
+        switch (state) {
+            case 0:
+                builder.append("if");
+                break;
+            case 1:
+                builder.append("elseif");
+                break;
+            case 2:
+                builder.append("else");
+                break;
+            case 3:
+                builder.append("switch");
+                break;
+            case 4:
+                builder.append("case");
+                break;
+            case 5:
+                builder.append("default");
+                break;
+            default:
+                throw new UnknownStateException(state);
+        }
+        return builder.append(">>").toString();
+    }
+}
diff --git a/devTools/javaSanityCheck/src/element/KnownTwineElement.java b/devTools/javaSanityCheck/src/element/KnownTwineElement.java
new file mode 100644
index 0000000000000000000000000000000000000000..24003fd00be0bb79aa6a01b2fbd2d9a91439ac6a
--- /dev/null
+++ b/devTools/javaSanityCheck/src/element/KnownTwineElement.java
@@ -0,0 +1,41 @@
+package org.arkerthan.sanityCheck.element;
+
+public class KnownTwineElement extends KnownElement {
+
+    private boolean opening;
+    private String statement;
+
+    public KnownTwineElement(int line, int pos, boolean opening, String statement) {
+        super(line, pos);
+        this.opening = opening;
+        this.statement = statement;
+    }
+
+    @Override
+    public String getShortDescription() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("[").append(line).append(":").append(pos).append("] <<");
+        if (!opening) {
+            builder.append("/");
+        }
+        return builder.append(statement).append(">>").toString();
+    }
+
+    @Override
+    public boolean isOpening() {
+        return opening;
+    }
+
+    @Override
+    public boolean isClosing() {
+        return !opening;
+    }
+
+    @Override
+    public boolean isMatchingElement(KnownElement k) {
+        if (k instanceof KnownTwineElement) {
+            return ((KnownTwineElement) k).statement.equals(this.statement);
+        }
+        return false;
+    }
+}
diff --git a/devTools/javaSanityCheck/src/tag/HtmlTag.java b/devTools/javaSanityCheck/src/tag/HtmlTag.java
deleted file mode 100644
index 70bff2c5a32d27804cb2e95839eddf595fb4693c..0000000000000000000000000000000000000000
--- a/devTools/javaSanityCheck/src/tag/HtmlTag.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package org.arkerthan.sanityCheck.tag;
-
-public class HtmlTag extends Tag {
-    public HtmlTag(String tag, boolean single) {
-        super(tag, single);
-    }
-}
diff --git a/devTools/javaSanityCheck/twineTags b/devTools/javaSanityCheck/twineTags
index d8df5639a52b55b94f020884713f15d510f4a782..e1dea71621bd818041d6aad43d7b3053b2c78132 100644
--- a/devTools/javaSanityCheck/twineTags
+++ b/devTools/javaSanityCheck/twineTags
@@ -7,123 +7,17 @@
 #Do not add HTML Tags here.
 #Characters outside of ASCII scope are not supported.
 #
-#widgets
-amputeeDescription;0
-assignmentFilter;0
-resetAssignmentFilter;0
-accentDescription;0
-collarDescription;0
-AnusDescription;0
-armsTatDescription;0
-BoobsDescription;0
-boobBrandDescription;0
-BellyInflationDescription;0
-BellyImplantDescription;0
-BellyDescription;0
-ButtDescription;0
-showallAssignmentFilter;0
-boobsShapeDescription;0
-boobsExtraDescription;0
-boobsTatDescription;0
-shouldersDescription;0
-nipplesDescription;0
-crotchDescription;0
-listOfSlavesWithParent;0
-redisplayFamily;0
-parentName;0
-listOfSlavesWithSameParent;0
-nurseryAssignmentFilter;0
-dickDescription;0
-vaginaDescription;0
-SlaveInteractImpreg;0
-SlaveInteractFertility;0
-SlaveInteractSexOption;0
-SlaveInteractAnalSexOption;0
-SlaveInteractGropeOption;0
-SlaveInteractDickGropeOption;0
-SlaveInteractAnalGropeOption;0
-SlaveInteractDrugs;0
-nipplesPiercingDescription;0
-areolaeDescription;0
-nailsDescription;0
-backTatDescription;0
-pregnancyDescription;0
-ClothingDescription;0
-InscripDesc;0
-clothingCorsetDescription;0
-SlaveArt;0
-SlaveSort;0
-shouldersTatDescription;0
-earDescription;0
-upperFaceDescription;0
-HairDescription;0
-earPiercingDescription;0
-nosePiercingDescription;0
-eyebrowPiercingDescription;0
-customTatDescription;0
-faceDescription;0
-mouthDescription;0
-setLocalPronouns;0
-eyeDescription;0
-brandDescription;0
-Family;0
-chastityPiercingDescription;0
-footwearDescription;0
-HairClothingDescription;0
-FlowerDesc;0
-ImageDesc;0
-waistDescription;0
-heightImplantDescription;0
-BodyguardWeapon;0
-CorsetPiercingDescription;0
-heelDescription;0
-FarmyardStatistics;0
-skinDescription;0
-Master;0
-setPlayerPronouns;0
-farmyardAssignmentFilter;0
-setAssistantPronouns;0
-OptionAbbreviateDevotion;0
-OptionAbbreviateDiet;0
-OptionAbbreviateDrugs;0
-OptionAbbreviateHormoneBalance;0
-OptionAbbreviateGenitalia;0
-OptionAbbreviatePhysicals;0
-OptionAbbreviateOrigins;0
-OptionAbbreviateRulesets;0
-OptionAbbreviateSidebar;0
-OptionAbbreviateMissing;0
-OptionAbbreviateSkills;0
-OptionAbbreviateMental;0
-OptionAbbreviateNationality;0
-OptionAbbreviateClothes;0
-OptionAbbreviateRace;0
-OptionAbbreviateRules;0
-OptionAbbreviateHealth;0
-OptionLineSeparations;0
-OptionSortBy;0
-OptionRulesAssistantMain;0
-OptionDisplayAssignments;0
-OptionSortOrder;0
-OptionSortMain;0
-OptionSummaryStats;0
-s;0
-c;0
-ss;0
-S;0
-x;0
-z;0
-say;0
-Sh;0
-#
 #twine tags
 capture;1
 continue;0
 for;1
+#does foreach really exist?
+foreach;1
 goto;0
 htag;1
 include;0
 link;1
+nobr;1
 print;0
 replace;1
 run;0
@@ -134,7 +28,7 @@ textbox;0
 timed;1
 unset;0
 widget;1
-=;
+=;0
 #
 # Twine logic ### DO NOT TOUCH ###
 if;1