Index: /ModelExtender/src/de/uni_hildesheim/sse/model_extender/Main.java
===================================================================
--- /ModelExtender/src/de/uni_hildesheim/sse/model_extender/Main.java	(revision 193)
+++ /ModelExtender/src/de/uni_hildesheim/sse/model_extender/Main.java	(revision 194)
@@ -7,6 +7,8 @@
 
 import de.uni_hildesheim.sse.model.varModel.Project;
+import de.uni_hildesheim.sse.model_extender.convert.ModelExtender;
 import de.uni_hildesheim.sse.model_extender.in.DimacsReader;
 import de.uni_hildesheim.sse.model_extender.in.MalformedFileException;
+import de.uni_hildesheim.sse.trans.in.ParserException;
 import de.uni_hildesheim.sse.trans.out.DimacsWriter;
 
@@ -59,5 +61,11 @@
         }
         
-        // TODO: add constraint to model
+        ModelExtender extender = new ModelExtender(model);
+        try {
+            extender.addConstraint(args[1]);
+            
+        } catch (ParserException e) {
+            e.printStackTrace(System.err);
+        }
         
         File writeModelFile = new File(args[2]);
Index: /ModelExtender/src/de/uni_hildesheim/sse/model_extender/convert/ListMaxTermConverter.java
===================================================================
--- /ModelExtender/src/de/uni_hildesheim/sse/model_extender/convert/ListMaxTermConverter.java	(revision 194)
+++ /ModelExtender/src/de/uni_hildesheim/sse/model_extender/convert/ListMaxTermConverter.java	(revision 194)
@@ -0,0 +1,41 @@
+package de.uni_hildesheim.sse.model_extender.convert;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import de.uni_hildesheim.sse.model.cst.ConstraintSyntaxTree;
+import de.uni_hildesheim.sse.trans.convert.MaxTermConverter2;
+
+/**
+ * A {@link MaxTermConverter} that instead of adding the constraints to a project
+ * just stores them in a {@link List}.
+ * 
+ * @author Adam Krafczyk
+ */
+public class ListMaxTermConverter extends MaxTermConverter2 {
+
+    private List<ConstraintSyntaxTree> trees;
+    
+    /**
+     * Creates a new {@link ListMaxTermConverter}.
+     */
+    public ListMaxTermConverter() {
+        trees = new ArrayList<ConstraintSyntaxTree>();
+    }
+    
+    @Override
+    protected void addConstraint(ConstraintSyntaxTree cst) {
+        trees.add(cst);
+    }
+    
+    /**
+     * Getter for the List of created CSTs.
+     * 
+     * @return An unmodifieable List of CSTs.
+     */
+    public List<ConstraintSyntaxTree> getCSTs() {
+        return Collections.unmodifiableList(trees);
+    }
+    
+}
Index: /ModelExtender/src/de/uni_hildesheim/sse/model_extender/convert/ModelExtender.java
===================================================================
--- /ModelExtender/src/de/uni_hildesheim/sse/model_extender/convert/ModelExtender.java	(revision 194)
+++ /ModelExtender/src/de/uni_hildesheim/sse/model_extender/convert/ModelExtender.java	(revision 194)
@@ -0,0 +1,267 @@
+package de.uni_hildesheim.sse.model_extender.convert;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import de.uni_hildesheim.sse.model.cst.CSTSemanticException;
+import de.uni_hildesheim.sse.model.cst.ConstraintSyntaxTree;
+import de.uni_hildesheim.sse.model.cst.OCLFeatureCall;
+import de.uni_hildesheim.sse.model.cst.Variable;
+import de.uni_hildesheim.sse.model.cst.VariablePool;
+import de.uni_hildesheim.sse.model.varModel.AbstractVariable;
+import de.uni_hildesheim.sse.model.varModel.Constraint;
+import de.uni_hildesheim.sse.model.varModel.DecisionVariableDeclaration;
+import de.uni_hildesheim.sse.model.varModel.Project;
+import de.uni_hildesheim.sse.model.varModel.datatypes.BooleanType;
+import de.uni_hildesheim.sse.model.varModel.datatypes.OclKeyWords;
+import de.uni_hildesheim.sse.model.varModel.filter.DeclarationFinder;
+import de.uni_hildesheim.sse.model.varModel.filter.DeclarationFinder.VisibilityType;
+import de.uni_hildesheim.sse.model.varModel.filter.FilterType;
+import de.uni_hildesheim.sse.trans.in.ParserException;
+import de.uni_hildesheim.sse.trans.in.ParserException.ParserExceptionType;
+
+/**
+ * Extends existing models in CNF with additional constraints.
+ * 
+ * @author Adam Krafczyk
+ */
+public class ModelExtender {
+
+    private Project model;
+    
+    private Map<String, AbstractVariable> variables;
+    
+    private VariablePool varPool;
+    
+    /**
+     * Creates a {@link ModelExtender} for the given model.
+     * 
+     * @param model The model where new constraints will be added to.
+     */
+    public ModelExtender(Project model) {
+        this.model = model;
+        this.varPool = new VariablePool();
+        this.variables = new HashMap<String, AbstractVariable>();
+        
+        DeclarationFinder declarationFinder = new DeclarationFinder(model, FilterType.ALL, null);
+        List<AbstractVariable> variableDeclarations = declarationFinder.getVariableDeclarations(VisibilityType.ALL);
+        
+        for (AbstractVariable var : variableDeclarations) {
+            variables.put(var.getName(), var);
+        }
+    }
+    
+    /**
+     * Adds the given constraint to the model.
+     * 
+     * @param constraint The constraint to add to the model.
+     * @throws ParserException If the constraint is not correctly formatted.
+     */
+    public void addConstraint(String constraint) throws ParserException {
+        ConstraintSyntaxTree tree = toCST(constraint);
+        
+        Constraint tmp = new Constraint(null);
+        try {
+            tmp.setConsSyntax(tree);
+        } catch (CSTSemanticException e) {
+            e.printStackTrace(); // TODO
+        }
+        ListMaxTermConverter converter = new ListMaxTermConverter();
+        converter.convert(tmp);
+        
+        for (ConstraintSyntaxTree cst : converter.getCSTs()) {
+            Constraint constr = new Constraint(model);
+            try {
+                constr.setConsSyntax(cst);
+            } catch (CSTSemanticException e) {
+                e.printStackTrace(); // TODO
+            }
+            model.add(constr);
+        }
+        
+        // TODO handle =, <=, >=, < and >
+    }
+    
+    /**
+     * Converts the given String into a {@link ConstraintSyntaxTree}.
+     * 
+     * @param constraint The String that contains the constraint.
+     * @return A {@link ConstraintSyntaxTree} representing the constraint.
+     * @throws ParserException If the constraint is not correctly formatted.
+     */
+    private ConstraintSyntaxTree toCST(String constraint) throws ParserException {
+        constraint = constraint.replace(" ", "");
+        
+        // We assume that ! can only be in front of variables
+        
+        String highestOperand = null;
+        int highestOperandLevel = Integer.MAX_VALUE;
+        int highestOperandPos = -1;
+        int currentLevel = 0;
+        
+        for (int i = 0; i < constraint.length(); i++) {
+            char c = constraint.charAt(i);
+            switch (c) {
+            case '(':
+                currentLevel++;
+                break;
+            case ')':
+                currentLevel--;
+                break;
+                
+            case '&':
+                if (constraint.charAt(i + 1) != '&') {
+                    throw new ParserException(ParserExceptionType.NOT_SUPPORTED_FIELD);
+                }
+                if (highestOperandLevel > currentLevel) {
+                    highestOperand = OclKeyWords.AND;
+                    highestOperandPos = i;
+                    highestOperandLevel = currentLevel;
+                }
+                i++;
+                break;
+            
+            case '|':
+                if (constraint.charAt(i + 1) != '|') {
+                    throw new ParserException(ParserExceptionType.NOT_SUPPORTED_FIELD);
+                }
+                if (highestOperandLevel > currentLevel) {
+                    highestOperand = OclKeyWords.OR;
+                    highestOperandPos = i;
+                    highestOperandLevel = currentLevel;
+                }
+                i++;
+                break;
+            
+            default:
+                break;
+            }
+        }
+        
+        ConstraintSyntaxTree result = null;
+        
+        if (highestOperandPos == -1) {
+            if (!constraint.equals("y")) {
+                // we only have a variable
+                result = getVariable(constraint);
+            }
+            // result = null if condition is "y"
+        } else {
+            StringBuffer left = new StringBuffer();
+            StringBuffer right = new StringBuffer();
+            split(constraint, highestOperandPos, highestOperandLevel, left, right);
+            result = new OCLFeatureCall(toCST(left.toString()),
+                    highestOperand, toCST(right.toString()));
+        }
+        
+        return result;
+    }
+    
+    /**
+     * Splits the given line at the given operand position into a left and right part.
+     * @param line The whole line
+     * @param operandPos The position of the operand in the line
+     * @param operandLevel The logic level of the operand (by counting brackets)
+     * @param left A {@link StringBuffer} where the left side of the operand will be written to
+     * @param right A {@link StringBuffer} where the right side of the operand will be written to
+     */
+    private void split(String line, int operandPos, int operandLevel, StringBuffer left, StringBuffer right) {
+        left.append(line.substring(0, operandPos));
+        right.append(line.substring(operandPos + 2, line.length()));
+        int currentLevel = 0;
+        for (int i = 0; i < left.length(); i++) {
+            char c = left.charAt(i);
+            if ((c == '(' || c == ')') && currentLevel < operandLevel) {
+                left.replace(i, i + 1, "");
+            }
+            if (c == '(') {
+                currentLevel++;
+            }
+            if (c == ')') {
+                currentLevel--;
+            }
+        }
+        currentLevel = 0;
+        for (int i = right.length() - 1; i >= 0; i--) {
+            char c = right.charAt(i);
+            if ((c == '(' || c == ')') && currentLevel < operandLevel) {
+                right.replace(i, i + 1, "");
+            }
+            if (c == ')') {
+                currentLevel++;
+            }
+            if (c == '(') {
+                currentLevel--;
+            }
+        }
+    }
+    
+    /**
+     * Converts the given variable from a string to a {@link ConstraintSyntaxTree}.
+     * A ! at the beginning will result in a {@link OCLFeatureCall} with NOT.
+     * @param var A string representing the variable.
+     * @return A {@link ConstraintSyntaxTree} representing the variable.
+     */
+    private ConstraintSyntaxTree getVariable(String var) {
+        ConstraintSyntaxTree result = null;
+        
+        // Remove parenthesis around variable names
+        if (var.startsWith("(")) {
+            var = var.substring(1);
+            if (var.endsWith(")")) {
+                var = var.substring(0, var.length() - 1);
+            }
+        }
+        
+        if (var.startsWith("!")) {
+            var = var.substring(1);
+            ConstraintSyntaxTree variable = getVariable(var);
+            result = new OCLFeatureCall(variable, OclKeyWords.NOT);
+        }
+        
+//        TODO: is this needed?
+//        if (result == null) {
+//            result = handleConstantInVariable(var);
+//        }
+//        
+//        if (result == null) {
+//            result = handleModuleInVariable(var);
+//        }
+//        
+//        if (result == null) {
+//            result = handleStringInVariable(var);
+//        }
+        
+        if (result == null) {
+            // Remove ' around variable names
+            if (var.startsWith("'")) {
+                var = var.substring(1);
+            }
+            if (var.endsWith("'")) {
+                var = var.substring(0, var.length() - 1);
+            }
+            
+            Variable variable = varPool.obtainVariable(getVariableFromProject(var));
+            result = variable;
+        }
+        return result;
+    }
+    
+    /**
+     * Gets or creates the variable for the given name in the model.
+     * 
+     * @param name The name of the variable.
+     * @return The variable.
+     */
+    private AbstractVariable getVariableFromProject(String name) {
+        AbstractVariable var = variables.get(name);
+        if (var == null) {
+            var = new DecisionVariableDeclaration(name, BooleanType.TYPE, model);
+            model.add(var);
+            variables.put(name, var);
+        }
+        return var;
+    }
+    
+}
Index: /ModelExtender/src/de/uni_hildesheim/sse/model_extender/convert/package-info.java
===================================================================
--- /ModelExtender/src/de/uni_hildesheim/sse/model_extender/convert/package-info.java	(revision 194)
+++ /ModelExtender/src/de/uni_hildesheim/sse/model_extender/convert/package-info.java	(revision 194)
@@ -0,0 +1,4 @@
+/**
+ * Contains classes for extending models with additional constraints.
+ */
+package de.uni_hildesheim.sse.model_extender.convert;
