towards better error handling
diff --git a/src/main/antlr/CollectionQuery.g4 b/src/main/antlr/CollectionQuery.g4
index f46bbbf..da73081 100644
--- a/src/main/antlr/CollectionQuery.g4
+++ b/src/main/antlr/CollectionQuery.g4
@@ -38,6 +38,7 @@
 COLON				: ':';
 DASH				: '-';
 TILDE				: '~';
+NEGTILDE			: '!~';
 SINCE				: 'since';
 UNTIL				: 'until';
 IN					: 'in';
@@ -97,7 +98,7 @@
 ;
 
 operator
-:	(NEG? EQ) | LT | GT | LEQ | GEQ | TILDE;
+:	(NEG? EQ) | LT | GT | LEQ | GEQ | TILDE | NEGTILDE;
 
 expr
 : constraint
diff --git a/src/main/java/de/ids_mannheim/korap/query/serialize/AbstractSyntaxTree.java b/src/main/java/de/ids_mannheim/korap/query/serialize/AbstractSyntaxTree.java
index eee2507..ffdceae 100644
--- a/src/main/java/de/ids_mannheim/korap/query/serialize/AbstractSyntaxTree.java
+++ b/src/main/java/de/ids_mannheim/korap/query/serialize/AbstractSyntaxTree.java
@@ -11,6 +11,7 @@
 import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 
+import de.ids_mannheim.korap.query.serialize.util.StatusCodes;
 import de.ids_mannheim.korap.util.QueryException;
 
 public abstract class AbstractSyntaxTree {
@@ -209,7 +210,7 @@
 			frame = "frame:contains";
 		}
 		group.put("frame", frame);
-		addMessage(303, "Deprecated 2014-09-22: 'frame' only to be supported until 3 months from deprecation date. " +
+		addMessage(StatusCodes.DEPRECATED_QUERY_ELEMENT, "Deprecated 2014-09-22: 'frame' only to be supported until 3 months from deprecation date. " +
 				"Position frames are now expressed through 'frames'.");
 		return group;
 	}
@@ -231,7 +232,7 @@
 			group.put("class", classCount);
 			group.put("classOut", classCount);
 		}
-		addMessage(303, "Deprecated 2014-10-07: 'class' only to be supported until 3 months from deprecation date. " +
+		addMessage(StatusCodes.DEPRECATED_QUERY_ELEMENT, "Deprecated 2014-10-07: 'class' only to be supported until 3 months from deprecation date. " +
 				"Classes are now defined using the 'classOut' attribute.");
 		group.put("operands", new ArrayList<Object>());
 		return group;
@@ -245,7 +246,7 @@
 		group.put("classIn", Arrays.asList(classIn));
 		group.put("classOut", classOut);
 		group.put("class", classOut);
-		addMessage(303, "Deprecated 2014-10-07: 'class' only to be supported until 3 months from deprecation date. " +
+		addMessage(StatusCodes.DEPRECATED_QUERY_ELEMENT, "Deprecated 2014-10-07: 'class' only to be supported until 3 months from deprecation date. " +
 				"Classes are now defined using the 'classOut' attribute.");
 		group.put("operands", new ArrayList<Object>());
 		return group;
@@ -299,7 +300,7 @@
 		if (max != null) {
 			group.put("max", max);
 		}
-		addMessage(303, "Deprecated 2014-07-24: 'min' and 'max' to be supported until 3 months from deprecation date.");
+		addMessage(StatusCodes.DEPRECATED_QUERY_ELEMENT, "Deprecated 2014-07-24: 'min' and 'max' to be supported until 3 months from deprecation date.");
 		return group;
 	}
 	
@@ -388,20 +389,4 @@
 		}
 		return number;
 	}
-	
-    public static void checkUnbalancedPars(String q) throws QueryException {
-        int openingPars = StringUtils.countMatches(q, "(");
-        int closingPars = StringUtils.countMatches(q, ")");
-        int openingBrkts = StringUtils.countMatches(q, "[");
-        int closingBrkts = StringUtils.countMatches(q, "]");
-        int openingBrcs = StringUtils.countMatches(q, "{");
-        int closingBrcs = StringUtils.countMatches(q, "}");
-        if (openingPars != closingPars) throw new QueryException(
-                "Your query string contains an unbalanced number of parantheses.");
-        if (openingBrkts != closingBrkts) throw new QueryException(
-                "Your query string contains an unbalanced number of brackets.");
-        if (openingBrcs != closingBrcs) throw new QueryException(
-                "Your query string contains an unbalanced number of braces.");
-    }
-
 }
diff --git a/src/main/java/de/ids_mannheim/korap/query/serialize/AqlTree.java b/src/main/java/de/ids_mannheim/korap/query/serialize/AqlTree.java
index fdda503..f23d200 100644
--- a/src/main/java/de/ids_mannheim/korap/query/serialize/AqlTree.java
+++ b/src/main/java/de/ids_mannheim/korap/query/serialize/AqlTree.java
@@ -22,6 +22,7 @@
 
 import de.ids_mannheim.korap.query.annis.AqlLexer;
 import de.ids_mannheim.korap.query.annis.AqlParser;
+import de.ids_mannheim.korap.query.serialize.util.Antlr4DescriptiveErrorListener;
 import de.ids_mannheim.korap.util.QueryException;
 
 /**
@@ -708,21 +709,25 @@
 		}
 	}
 
-	private ParserRuleContext parseAnnisQuery (String p) throws QueryException {
-		Lexer poliqarpLexer = new AqlLexer((CharStream)null);
+	private ParserRuleContext parseAnnisQuery (String query) throws QueryException {
+		Lexer lexer = new AqlLexer((CharStream)null);
 		ParserRuleContext tree = null;
+		Antlr4DescriptiveErrorListener errorListener = new Antlr4DescriptiveErrorListener(query);
 		// Like p. 111
 		try {
 
 			// Tokenize input data
-			ANTLRInputStream input = new ANTLRInputStream(p);
-			poliqarpLexer.setInputStream(input);
-			CommonTokenStream tokens = new CommonTokenStream(poliqarpLexer);
+			ANTLRInputStream input = new ANTLRInputStream(query);
+			lexer.setInputStream(input);
+			CommonTokenStream tokens = new CommonTokenStream(lexer);
 			parser = new AqlParser(tokens);
 
 			// Don't throw out erroneous stuff
 			parser.setErrorHandler(new BailErrorStrategy());
-			parser.removeErrorListeners();
+			lexer.removeErrorListeners();
+            lexer.addErrorListener(errorListener);
+            parser.removeErrorListeners();
+            parser.addErrorListener(errorListener);
 
 			// Get starting rule from parser
 			Method startRule = AqlParser.class.getMethod("start"); 
@@ -731,8 +736,8 @@
 
 		// Some things went wrong ...
 		catch (Exception e) {
+			System.err.println("ERROR: "+errorListener.generateFullErrorMsg());
 			log.error(e.getMessage());
-			System.err.println( e.getMessage() );
 		}
 
 		if (tree == null) {
@@ -752,6 +757,7 @@
 				"cat=\"S\" & cat=/NP/ & cat=/PP/ > #2",
 				"pos & tok & #1 . node",
 				"cat=/S/ & cat=/NP/ & cat=/PP/ > #1",
+				"(cat=\"a\" | cat=\"b\") & tok"
 		};
 		//		AqlTree.verbose=true;
 		for (String q : queries) {
diff --git a/src/main/java/de/ids_mannheim/korap/query/serialize/CollectionQueryTree.java b/src/main/java/de/ids_mannheim/korap/query/serialize/CollectionQueryTree.java
index d237e74..5b0b0df 100644
--- a/src/main/java/de/ids_mannheim/korap/query/serialize/CollectionQueryTree.java
+++ b/src/main/java/de/ids_mannheim/korap/query/serialize/CollectionQueryTree.java
@@ -1,7 +1,9 @@
 package de.ids_mannheim.korap.query.serialize;
 
+import de.ids_mannheim.korap.query.serialize.util.Antlr4DescriptiveErrorListener;
 import de.ids_mannheim.korap.query.serialize.util.CollectionQueryLexer;
 import de.ids_mannheim.korap.query.serialize.util.CollectionQueryParser;
+import de.ids_mannheim.korap.query.serialize.util.StatusCodes;
 import de.ids_mannheim.korap.util.QueryException;
 
 import org.antlr.v4.runtime.*;
@@ -212,7 +214,7 @@
 		String type = (String) term.get("type");
 		if (type == null || type.equals("type:regex")) {
 			if (!(match.equals("match:eq") || match.equals("match:ne") || match.equals("match:contains") || match.equals("match:containsnot"))) {
-				addError(302, "You used an inequation operator with a string value.");
+				addError(StatusCodes.INCOMPATIBLE_OPERATOR_AND_OPERAND, "You used an inequation operator with a string value.");
 				return false;
 			}
 		}
@@ -306,7 +308,7 @@
                 break;
             default:
             	out = match;
-            	addError(302, "Unknown operator '"+match+"'.");
+            	addError(StatusCodes.UNKNOWN_QUERY_ELEMENT, "Unknown operator '"+match+"'.");
             	break;
         }
         return out;
@@ -440,27 +442,32 @@
 		}
 	}
     
-    private ParserRuleContext parseCollectionQuery(String p) throws QueryException {
-        Lexer collectionQueryLexer = new CollectionQueryLexer((CharStream) null);
+    private ParserRuleContext parseCollectionQuery(String query) throws QueryException {
+        Lexer lexer = new CollectionQueryLexer((CharStream) null);
         ParserRuleContext tree = null;
+        Antlr4DescriptiveErrorListener errorListener = new Antlr4DescriptiveErrorListener(query);
         // Like p. 111
         try {
 
             // Tokenize input data
-            ANTLRInputStream input = new ANTLRInputStream(p);
-            collectionQueryLexer.setInputStream(input);
-            CommonTokenStream tokens = new CommonTokenStream(collectionQueryLexer);
+            ANTLRInputStream input = new ANTLRInputStream(query);
+            lexer.setInputStream(input);
+            CommonTokenStream tokens = new CommonTokenStream(lexer);
             parser = new CollectionQueryParser(tokens);
 
             // Don't throw out erroneous stuff
             parser.setErrorHandler(new BailErrorStrategy());
+            lexer.removeErrorListeners();
+            lexer.addErrorListener(errorListener);
             parser.removeErrorListeners();
+            parser.addErrorListener(errorListener);
             // Get starting rule from parser
             Method startRule = CollectionQueryParser.class.getMethod("start");
             tree = (ParserRuleContext) startRule.invoke(parser, (Object[]) null);
         }
         // Some things went wrong ...
         catch (Exception e) {
+        	System.err.println("ERROR: "+errorListener.generateFullErrorMsg());
             System.err.println("Parsing exception message: " + e);
         }
         if (tree == null) {
@@ -476,12 +483,11 @@
         query = "(textClass=wissenschaft & textClass=politik) | textClass=ausland";
         query = "textClass=Sport & year=2014";
         query = "title!~mannheim";
-        query = "title=1984-14";
+        query = "title = /ada\\)ad/";
         CollectionQueryTree.verbose = true;
         CollectionQueryTree filter = null;
         try {
         	 filter = new CollectionQueryTree(query);
-        	 filter.verbose = true;
         } catch (QueryException e) {
             e.printStackTrace();
         }
diff --git a/src/main/java/de/ids_mannheim/korap/query/serialize/CosmasTree.java b/src/main/java/de/ids_mannheim/korap/query/serialize/CosmasTree.java
index 1dfb430..ae0397e 100644
--- a/src/main/java/de/ids_mannheim/korap/query/serialize/CosmasTree.java
+++ b/src/main/java/de/ids_mannheim/korap/query/serialize/CosmasTree.java
@@ -4,6 +4,7 @@
 import de.ids_mannheim.korap.query.cosmas2.c2psParser;
 import de.ids_mannheim.korap.query.serialize.util.CosmasCondition;
 import de.ids_mannheim.korap.query.serialize.util.ResourceMapper;
+import de.ids_mannheim.korap.query.serialize.util.StatusCodes;
 import de.ids_mannheim.korap.util.QueryException;
 
 import org.antlr.runtime.ANTLRStringStream;
@@ -877,7 +878,7 @@
 		posOptions.put("frames", positions);
 		posOptions.put("classRefCheck", classRefCheck);
 		posOptions.put("frame", "frame:"+frame);
-		addMessage(303, "Deprecated 2014-09-22: 'frame' only to be supported until 3 months from deprecation date. " +
+		addMessage(StatusCodes.DEPRECATED_QUERY_ELEMENT, "Deprecated 2014-09-22: 'frame' only to be supported until 3 months from deprecation date. " +
 				"Position frames are now expressed through 'frames' and 'sharedClasses'");
 
 		if (exclnode != null) {
@@ -964,7 +965,7 @@
 		posOptions.put("frames", positions);
 		posOptions.put("classRefCheck", classRefCheck);
 		posOptions.put("frame", "frame:"+frame);
-		addMessage(303, "Deprecated 2014-09-22: 'frame' only to be supported until 3 months from deprecation date. " +
+		addMessage(StatusCodes.DEPRECATED_QUERY_ELEMENT, "Deprecated 2014-09-22: 'frame' only to be supported until 3 months from deprecation date. " +
 				"Position frames are now expressed through 'frames' and 'sharedClasses'");
 
 		if (exclnode != null) {
diff --git a/src/main/java/de/ids_mannheim/korap/query/serialize/PoliqarpPlusTree.java b/src/main/java/de/ids_mannheim/korap/query/serialize/PoliqarpPlusTree.java
index 32f5918..3117220 100644
--- a/src/main/java/de/ids_mannheim/korap/query/serialize/PoliqarpPlusTree.java
+++ b/src/main/java/de/ids_mannheim/korap/query/serialize/PoliqarpPlusTree.java
@@ -2,7 +2,10 @@
 
 import de.ids_mannheim.korap.query.poliqarp.PoliqarpPlusLexer;
 import de.ids_mannheim.korap.query.poliqarp.PoliqarpPlusParser;
+import de.ids_mannheim.korap.query.serialize.util.Antlr4DescriptiveErrorListener;
+import de.ids_mannheim.korap.query.serialize.util.StatusCodes;
 import de.ids_mannheim.korap.util.QueryException;
+
 import org.antlr.v4.runtime.*;
 import org.antlr.v4.runtime.tree.ParseTree;
 import org.slf4j.Logger;
@@ -10,12 +13,11 @@
 
 import java.lang.reflect.Method;
 import java.util.*;
-import java.util.regex.Pattern;
 
 /**
  * Map representation of Poliqarp syntax tree as returned by ANTLR
  *
- * @author joachim
+ * @author Joachim Bingel (bingel@ids-mannheim.de)
  */
 public class PoliqarpPlusTree extends Antlr4AbstractSyntaxTree {
 
@@ -91,7 +93,7 @@
 				quantGroup.put("boundary", makeBoundary(minmax[0], minmax[1]));
 				if (minmax[0] != null) quantGroup.put("min", minmax[0]);
 				if (minmax[1] != null) quantGroup.put("max", minmax[1]);
-				addMessage(303, "Deprecated 2014-07-24: 'min' and 'max' to be " +
+				addMessage(StatusCodes.DEPRECATED_QUERY_ELEMENT, "Deprecated 2014-07-24: 'min' and 'max' to be " +
 						"supported until 3 months from deprecation date.");
 				putIntoSuperObject(quantGroup);
 				objectStack.push(quantGroup);
@@ -219,7 +221,6 @@
 		if (nodeCat.equals("span")) {
 			List<ParseTree> negations = getChildrenWithCat(node, "!");
 			boolean negated = false;
-			boolean isRegex = false;
 			if (negations.size() % 2 == 1) negated = true;
 			LinkedHashMap<String,Object> span = makeSpan();
 			ParseTree keyNode = getFirstChildWithCat(node, "key");
@@ -344,8 +345,7 @@
 						} catch (NumberFormatException e) {
 							String err = "The specified class reference in the " +
 									"shrink/split-Operator is not a number.";
-							addError(302, err);
-							throw new QueryException(err);
+							addError(StatusCodes.UNDEFINED_CLASS_REFERENCE, err);
 						}
 					}
 				}
@@ -361,8 +361,7 @@
 				String warning = "Deprecated 2014-07-24: "+type + "() as a match reducer " +
 						"to a specific class is deprecated in favor of focus() and will " +
 						"only be supported for 3 months after deprecation date.";
-				log.warn(warning);
-				requestMap.put("warning", warning);
+				addMessage(StatusCodes.DEPRECATED_QUERY_ELEMENT, warning);
 			}
 			if (classRefOp != null) {
 				referenceGroup.put("classRefOp", "classRefOp:" + classRefOp);
@@ -673,20 +672,23 @@
 
 
 	private ParserRuleContext parsePoliqarpQuery(String p) throws QueryException {
-		checkUnbalancedPars(p);
-		Lexer poliqarpLexer = new PoliqarpPlusLexer((CharStream) null);
+		Lexer lexer = new PoliqarpPlusLexer((CharStream) null);
 		ParserRuleContext tree = null;
+		Antlr4DescriptiveErrorListener errorListener = new Antlr4DescriptiveErrorListener(query);
 		// Like p. 111
 		try {
 			// Tokenize input data
 			ANTLRInputStream input = new ANTLRInputStream(p);
-			poliqarpLexer.setInputStream(input);
-			CommonTokenStream tokens = new CommonTokenStream(poliqarpLexer);
+			lexer.setInputStream(input);
+			CommonTokenStream tokens = new CommonTokenStream(lexer);
 			parser = new PoliqarpPlusParser(tokens);
 
 			// Don't throw out erroneous stuff
 			parser.setErrorHandler(new BailErrorStrategy());
-			parser.removeErrorListeners();
+			lexer.removeErrorListeners();
+            lexer.addErrorListener(errorListener);
+            parser.removeErrorListeners();
+            parser.addErrorListener(errorListener);
 
 			// Get starting rule from parser
 			Method startRule = PoliqarpPlusParser.class.getMethod("request");
diff --git a/src/main/java/de/ids_mannheim/korap/query/serialize/QuerySerializer.java b/src/main/java/de/ids_mannheim/korap/query/serialize/QuerySerializer.java
index ef47d2f..a34f7c2 100644
--- a/src/main/java/de/ids_mannheim/korap/query/serialize/QuerySerializer.java
+++ b/src/main/java/de/ids_mannheim/korap/query/serialize/QuerySerializer.java
@@ -3,6 +3,7 @@
 import com.fasterxml.jackson.core.JsonGenerationException;
 import com.fasterxml.jackson.databind.JsonMappingException;
 
+import de.ids_mannheim.korap.query.poliqarp.PoliqarpPlusParser;
 import de.ids_mannheim.korap.util.QueryException;
 import de.ids_mannheim.korap.utils.JsonUtils;
 import de.ids_mannheim.korap.utils.KorAPLogger;
@@ -19,7 +20,22 @@
  * @author bingel, hanl
  */
 public class QuerySerializer {
+	
+	public enum QueryLanguage {
+		POLIQARPPLUS, ANNIS, COSMAS2, CQL, CQP
+	}
+	
+	static HashMap<String, Class<? extends AbstractSyntaxTree>> qlProcessorAssignment;
 
+	static {
+		qlProcessorAssignment  = new HashMap<String, Class<? extends AbstractSyntaxTree>>();
+		qlProcessorAssignment.put("poliqarpplus", PoliqarpPlusTree.class);
+		qlProcessorAssignment.put("cosmas2", CosmasTree.class);
+		qlProcessorAssignment.put("annis", AqlTree.class);
+		qlProcessorAssignment.put("cql", CQLTree.class);
+	}
+	
+	
     private Logger qllogger = KorAPLogger.initiate("ql");
     public static String queryLanguageVersion;
 
@@ -32,7 +48,6 @@
     private org.slf4j.Logger log = LoggerFactory
             .getLogger(QuerySerializer.class);
 
-
     /**
      * @param args
      * @throws QueryException
@@ -46,7 +61,6 @@
         String[] queries;
         if (args.length == 0) {
             queries = new String[]{
-            		"foo"
             };
         } else
             queries = new String[]{args[0]};
@@ -100,9 +114,6 @@
             throw new QueryException(queryLanguage + " is not a supported query language!");
         }
         toJSON();
-        Map<String, Object> requestMap = ast.getRequestMap();
-        System.out.println(requestMap);
-//        mapper.writeValue(new File(outFile), requestMap);
     }
 
     public QuerySerializer setQuery(String query, String ql, String version)