diff --git a/preprocessor/DynamicModel.cc b/preprocessor/DynamicModel.cc
index 46b4d5856cb95e8233828d37e17a2a074015b5e7..fb22c354b835df515540a2e59c6644d6df672a61 100644
--- a/preprocessor/DynamicModel.cc
+++ b/preprocessor/DynamicModel.cc
@@ -2831,37 +2831,25 @@ DynamicModel::hessianHelper(ostream &output, int row_nb, int col_nb, ExprNodeOut
 }
 
 void
-DynamicModel::substituteLeadGreaterThanTwo()
+DynamicModel::substituteEndoLeadGreaterThanTwo()
 {
-  ExprNode::subst_table_t subst_table;
-  vector<BinaryOpNode *> neweqs;
-
-  // Substitute in model local variables
-  for(map<int, NodeID>::iterator it = local_variables_table.begin();
-      it != local_variables_table.end(); it++)
-    it->second = it->second->substituteLeadGreaterThanTwo(subst_table, neweqs);
-
-  // Substitute in equations
-  for(int i = 0; i < (int) equations.size(); i++)
-    {
-      BinaryOpNode *substeq = dynamic_cast<BinaryOpNode *>(equations[i]->substituteLeadGreaterThanTwo(subst_table, neweqs));
-      assert(substeq != NULL);
-      equations[i] = substeq;
-    }
-
-  // Add new equations
-  for(int i = 0; i < (int) neweqs.size(); i++)
-    addEquation(neweqs[i]);
+  substituteLeadLagInternal(0);
+}
 
-  // Add the new set of equations at the *beginning* of aux_equations
-  copy(neweqs.rbegin(), neweqs.rend(), front_inserter(aux_equations));
+void
+DynamicModel::substituteEndoLagGreaterThanTwo()
+{
+  substituteLeadLagInternal(1);
+}
 
-  if (neweqs.size() > 0)
-    cout << "Substitution of leads >= 2: added " << neweqs.size() << " auxiliary variables and equations." << endl;
+void
+DynamicModel::substituteExoLeadLag()
+{
+  substituteLeadLagInternal(2);
 }
 
 void
-DynamicModel::substituteLagGreaterThanTwo()
+DynamicModel::substituteLeadLagInternal(int vars)
 {
   ExprNode::subst_table_t subst_table;
   vector<BinaryOpNode *> neweqs;
@@ -2869,25 +2857,68 @@ DynamicModel::substituteLagGreaterThanTwo()
   // Substitute in model local variables
   for(map<int, NodeID>::iterator it = local_variables_table.begin();
       it != local_variables_table.end(); it++)
-    it->second = it->second->substituteLagGreaterThanTwo(subst_table, neweqs);
+    {
+      NodeID subst;
+      switch(vars)
+        {
+        case 0:
+          subst = it->second->substituteEndoLeadGreaterThanTwo(subst_table, neweqs);
+          break;
+        case 1:
+          subst = it->second->substituteEndoLagGreaterThanTwo(subst_table, neweqs);
+          break;
+        case 2:
+          subst = it->second->substituteExoLeadLag(subst_table, neweqs);
+          break;
+        }
+      it->second = subst;
+    }
 
   // Substitute in equations
   for(int i = 0; i < (int) equations.size(); i++)
     {
-      BinaryOpNode *substeq = dynamic_cast<BinaryOpNode *>(equations[i]->substituteLagGreaterThanTwo(subst_table, neweqs));
+      NodeID subst;
+      switch(vars)
+        {
+        case 0:
+          subst = equations[i]->substituteEndoLeadGreaterThanTwo(subst_table, neweqs);
+          break;
+        case 1:
+          subst = equations[i]->substituteEndoLagGreaterThanTwo(subst_table, neweqs);
+          break;
+        case 2:
+          subst = equations[i]->substituteExoLeadLag(subst_table, neweqs);
+          break;
+        }
+      BinaryOpNode *substeq = dynamic_cast<BinaryOpNode *>(subst);
       assert(substeq != NULL);
       equations[i] = substeq;
     }
 
   // Add new equations
   for(int i = 0; i < (int) neweqs.size(); i++)
-      addEquation(neweqs[i]);
+    addEquation(neweqs[i]);
 
   // Add the new set of equations at the *beginning* of aux_equations
   copy(neweqs.rbegin(), neweqs.rend(), front_inserter(aux_equations));
 
   if (neweqs.size() > 0)
-    cout << "Substitution of lags >= 2: added " << neweqs.size() << " auxiliary variables and equations." << endl;
+    {
+      cout << "Substitution of ";
+      switch(vars)
+        {
+        case 0:
+          cout << "endo leads >= 2";
+          break;
+        case 1:
+          cout << "endo lags >= 2";
+          break;
+        case 2:
+          cout << "exo leads/lags >= 2";
+          break;
+        }
+      cout << ": added " << neweqs.size() << " auxiliary variables and equations." << endl;
+    }
 }
 
 void
diff --git a/preprocessor/DynamicModel.hh b/preprocessor/DynamicModel.hh
index d9fa77dfdf27977f96491aa8406fefb998b12d25..04bf98b5d195ac7608309efaa442925e6088cf13 100644
--- a/preprocessor/DynamicModel.hh
+++ b/preprocessor/DynamicModel.hh
@@ -144,6 +144,9 @@ private:
   //! Write chain rule derivative of a recursive equation w.r. to a variable
   void writeChainRuleDerivative(ostream &output, int eq, int var, int lag, ExprNodeOutputType output_type, const temporary_terms_type &temporary_terms) const;
 
+  //! Factorized code for substitutions of leads/lags
+  /*! \param[in] vars 0 for endo leads, 1 for endo lags, 2 for exo */
+  void substituteLeadLagInternal(int vars);
 
 public:
   DynamicModel(SymbolTable &symbol_table_arg, NumericalConstants &num_constants);
@@ -199,11 +202,14 @@ public:
   //! Returns true indicating that this is a dynamic model
   virtual bool isDynamic() const { return true; };
 
-  //! Transforms the model by removing all leads greater or equal than 2
-  void substituteLeadGreaterThanTwo();
+  //! Transforms the model by removing all leads greater or equal than 2 on endos
+  void substituteEndoLeadGreaterThanTwo();
 
-  //! Transforms the model by removing all lags greater or equal than 2
-  void substituteLagGreaterThanTwo();
+  //! Transforms the model by removing all lags greater or equal than 2 on endos
+  void substituteEndoLagGreaterThanTwo();
+
+  //! Transforms the model by removing all leads and lags on exos
+  void substituteExoLeadLag();
 
   //! Fills eval context with values of model local variables and auxiliary variables
   void fillEvalContext(eval_context_type &eval_context) const;
diff --git a/preprocessor/ExprNode.cc b/preprocessor/ExprNode.cc
index e1329f5dc3a4853fad025c5b52c022c63e6e7b92..089502e316d247d74ae39dbbc598cfda30761433 100644
--- a/preprocessor/ExprNode.cc
+++ b/preprocessor/ExprNode.cc
@@ -148,7 +148,7 @@ ExprNode::writeOutput(ostream &output)
 }
 
 VariableNode *
-ExprNode::createLeadAuxiliaryVarForMyself(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
+ExprNode::createEndoLeadAuxiliaryVarForMyself(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
 {
   int n = maxEndoLead();
   assert(n >= 2);
@@ -168,7 +168,7 @@ ExprNode::createLeadAuxiliaryVarForMyself(subst_table_t &subst_table, vector<Bin
       it = subst_table.find(orig_expr);
       if (it == subst_table.end())
         {
-          int symb_id = datatree.symbol_table.addLeadAuxiliaryVar(orig_expr->idx);
+          int symb_id = datatree.symbol_table.addEndoLeadAuxiliaryVar(orig_expr->idx);
           neweqs.push_back(dynamic_cast<BinaryOpNode *>(datatree.AddEqual(datatree.AddVariable(symb_id, 0), substexpr)));
           substexpr = datatree.AddVariable(symb_id, +1);
           assert(dynamic_cast<VariableNode *>(substexpr) != NULL);
@@ -278,13 +278,19 @@ NumConstNode::decreaseLeadsLags(int n) const
 }
 
 NodeID
-NumConstNode::substituteLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
+NumConstNode::substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
 {
   return const_cast<NumConstNode *>(this);
 }
 
 NodeID
-NumConstNode::substituteLagGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
+NumConstNode::substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
+{
+  return const_cast<NumConstNode *>(this);
+}
+
+NodeID
+NumConstNode::substituteExoLeadLag(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
 {
   return const_cast<NumConstNode *>(this);
 }
@@ -766,7 +772,7 @@ VariableNode::decreaseLeadsLags(int n) const
 }
 
 NodeID
-VariableNode::substituteLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
+VariableNode::substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
 {
   NodeID value;
   switch(type)
@@ -775,20 +781,20 @@ VariableNode::substituteLeadGreaterThanTwo(subst_table_t &subst_table, vector<Bi
       if (lag <= 1)
         return const_cast<VariableNode *>(this);
       else
-        return createLeadAuxiliaryVarForMyself(subst_table, neweqs);
+        return createEndoLeadAuxiliaryVarForMyself(subst_table, neweqs);
     case eModelLocalVariable:
       value = datatree.local_variables_table[symb_id];
       if (value->maxEndoLead() <= 1)
         return const_cast<VariableNode *>(this);
       else
-        return value->substituteLeadGreaterThanTwo(subst_table, neweqs);
+        return value->substituteEndoLeadGreaterThanTwo(subst_table, neweqs);
     default:
       return const_cast<VariableNode *>(this);
     }
 }
 
 NodeID
-VariableNode::substituteLagGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
+VariableNode::substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
 {
   VariableNode *substexpr;
   subst_table_t::const_iterator it;
@@ -814,7 +820,7 @@ VariableNode::substituteLagGreaterThanTwo(subst_table_t &subst_table, vector<Bin
           it = subst_table.find(orig_expr);
           if (it == subst_table.end())
             {
-              int aux_symb_id = datatree.symbol_table.addLagAuxiliaryVar(symb_id, cur_lag+1);
+              int aux_symb_id = datatree.symbol_table.addEndoLagAuxiliaryVar(symb_id, cur_lag+1);
               neweqs.push_back(dynamic_cast<BinaryOpNode *>(datatree.AddEqual(datatree.AddVariable(aux_symb_id, 0), substexpr)));
               substexpr = datatree.AddVariable(aux_symb_id, -1);
               subst_table[orig_expr] = substexpr;
@@ -827,7 +833,81 @@ VariableNode::substituteLagGreaterThanTwo(subst_table_t &subst_table, vector<Bin
       return substexpr;
 
     case eModelLocalVariable:
-      return datatree.local_variables_table[symb_id]->substituteLagGreaterThanTwo(subst_table, neweqs);
+      return datatree.local_variables_table[symb_id]->substituteEndoLagGreaterThanTwo(subst_table, neweqs);
+    default:
+      return const_cast<VariableNode *>(this);
+    }
+}
+
+NodeID
+VariableNode::substituteExoLeadLag(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
+{
+  VariableNode *substexpr;
+  subst_table_t::const_iterator it;
+  int cur_lag;
+  switch(type)
+    {
+    case eExogenous:
+      if (lag == 0)
+        return const_cast<VariableNode *>(this);
+
+      it = subst_table.find(this);
+      if (it != subst_table.end())
+        return const_cast<VariableNode *>(it->second);
+
+      if (lag < 0)
+        {
+          substexpr = datatree.AddVariable(symb_id, 0);
+          cur_lag = -1;
+
+          // Each iteration tries to create an auxvar such that auxvar(-1)=curvar(cur_lag)
+          // At the beginning (resp. end) of each iteration, substexpr is an expression (possibly an auxvar) equivalent to curvar(cur_lag+1) (resp. curvar(cur_lag))
+          while(cur_lag >= lag)
+            {
+              VariableNode *orig_expr = datatree.AddVariable(symb_id, cur_lag);
+              it = subst_table.find(orig_expr);
+              if (it == subst_table.end())
+                {
+                  int aux_symb_id = datatree.symbol_table.addExoLagAuxiliaryVar(symb_id, cur_lag+1);
+                  neweqs.push_back(dynamic_cast<BinaryOpNode *>(datatree.AddEqual(datatree.AddVariable(aux_symb_id, 0), substexpr)));
+                  substexpr = datatree.AddVariable(aux_symb_id, -1);
+                  subst_table[orig_expr] = substexpr;
+                }
+              else
+                substexpr = const_cast<VariableNode *>(it->second);
+
+              cur_lag--;
+            }
+          return substexpr;
+        }
+      else
+        {
+          substexpr = datatree.AddVariable(symb_id, 0);
+          cur_lag = +1;
+
+          // Each iteration tries to create an auxvar such that auxvar(+1)=curvar(cur_lag)
+          // At the beginning (resp. end) of each iteration, substexpr is an expression (possibly an auxvar) equivalent to curvar(cur_lag-1) (resp. curvar(cur_lag))
+          while(cur_lag <= lag)
+            {
+              VariableNode *orig_expr = datatree.AddVariable(symb_id, cur_lag);
+              it = subst_table.find(orig_expr);
+              if (it == subst_table.end())
+                {
+                  int aux_symb_id = datatree.symbol_table.addExoLeadAuxiliaryVar(symb_id, cur_lag-1);
+                  neweqs.push_back(dynamic_cast<BinaryOpNode *>(datatree.AddEqual(datatree.AddVariable(aux_symb_id, 0), substexpr)));
+                  substexpr = datatree.AddVariable(aux_symb_id, +1);
+                  subst_table[orig_expr] = substexpr;
+                }
+              else
+                substexpr = const_cast<VariableNode *>(it->second);
+
+              cur_lag++;
+            }
+          return substexpr;
+        }
+
+    case eModelLocalVariable:
+      return datatree.local_variables_table[symb_id]->substituteExoLeadLag(subst_table, neweqs);
     default:
       return const_cast<VariableNode *>(this);
     }
@@ -1471,26 +1551,33 @@ UnaryOpNode::decreaseLeadsLags(int n) const
 }
 
 NodeID
-UnaryOpNode::substituteLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
+UnaryOpNode::substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
 {
   if (op_code == oUminus)
     {
-      NodeID argsubst = arg->substituteLeadGreaterThanTwo(subst_table, neweqs);
+      NodeID argsubst = arg->substituteEndoLeadGreaterThanTwo(subst_table, neweqs);
       return buildSimilarUnaryOpNode(argsubst, datatree);
     }
   else
     {
       if (maxEndoLead() >= 2)
-        return createLeadAuxiliaryVarForMyself(subst_table, neweqs);
+        return createEndoLeadAuxiliaryVarForMyself(subst_table, neweqs);
       else
         return const_cast<UnaryOpNode *>(this);
     }
 }
 
 NodeID
-UnaryOpNode::substituteLagGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
+UnaryOpNode::substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
+{
+  NodeID argsubst = arg->substituteEndoLagGreaterThanTwo(subst_table, neweqs);
+  return buildSimilarUnaryOpNode(argsubst, datatree);
+}
+
+NodeID
+UnaryOpNode::substituteExoLeadLag(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
 {
-  NodeID argsubst = arg->substituteLagGreaterThanTwo(subst_table, neweqs);
+  NodeID argsubst = arg->substituteExoLeadLag(subst_table, neweqs);
   return buildSimilarUnaryOpNode(argsubst, datatree);
 }
 
@@ -2365,7 +2452,7 @@ BinaryOpNode::decreaseLeadsLags(int n) const
 }
 
 NodeID
-BinaryOpNode::substituteLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
+BinaryOpNode::substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
 {
   NodeID arg1subst, arg2subst;
   int maxlead1 = arg1->maxEndoLead(), maxlead2 = arg2->maxEndoLead();
@@ -2378,32 +2465,40 @@ BinaryOpNode::substituteLeadGreaterThanTwo(subst_table_t &subst_table, vector<Bi
     case oPlus:
     case oMinus:
     case oEqual:
-      arg1subst = maxlead1 >= 2 ? arg1->substituteLeadGreaterThanTwo(subst_table, neweqs) : arg1;
-      arg2subst = maxlead2 >= 2 ? arg2->substituteLeadGreaterThanTwo(subst_table, neweqs) : arg2;
+      arg1subst = maxlead1 >= 2 ? arg1->substituteEndoLeadGreaterThanTwo(subst_table, neweqs) : arg1;
+      arg2subst = maxlead2 >= 2 ? arg2->substituteEndoLeadGreaterThanTwo(subst_table, neweqs) : arg2;
       return buildSimilarBinaryOpNode(arg1subst, arg2subst, datatree);
     case oTimes:
     case oDivide:
       if (maxlead1 >= 2 && maxlead2 == 0)
         {
-          arg1subst = arg1->substituteLeadGreaterThanTwo(subst_table, neweqs);
+          arg1subst = arg1->substituteEndoLeadGreaterThanTwo(subst_table, neweqs);
           return buildSimilarBinaryOpNode(arg1subst, arg2, datatree);
         }
       if (maxlead1 == 0 && maxlead2 >= 2 && op_code == oTimes)
         {
-          arg2subst = arg2->substituteLeadGreaterThanTwo(subst_table, neweqs);
+          arg2subst = arg2->substituteEndoLeadGreaterThanTwo(subst_table, neweqs);
           return buildSimilarBinaryOpNode(arg1, arg2subst, datatree);
         }
-      return createLeadAuxiliaryVarForMyself(subst_table, neweqs);
+      return createEndoLeadAuxiliaryVarForMyself(subst_table, neweqs);
     default:
-      return createLeadAuxiliaryVarForMyself(subst_table, neweqs);
+      return createEndoLeadAuxiliaryVarForMyself(subst_table, neweqs);
     }
 }
 
 NodeID
-BinaryOpNode::substituteLagGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
+BinaryOpNode::substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
+{
+  NodeID arg1subst = arg1->substituteEndoLagGreaterThanTwo(subst_table, neweqs);
+  NodeID arg2subst = arg2->substituteEndoLagGreaterThanTwo(subst_table, neweqs);
+  return buildSimilarBinaryOpNode(arg1subst, arg2subst, datatree);
+}
+
+NodeID
+BinaryOpNode::substituteExoLeadLag(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
 {
-  NodeID arg1subst = arg1->substituteLagGreaterThanTwo(subst_table, neweqs);
-  NodeID arg2subst = arg2->substituteLagGreaterThanTwo(subst_table, neweqs);
+  NodeID arg1subst = arg1->substituteExoLeadLag(subst_table, neweqs);
+  NodeID arg2subst = arg2->substituteExoLeadLag(subst_table, neweqs);
   return buildSimilarBinaryOpNode(arg1subst, arg2subst, datatree);
 }
 
@@ -2766,20 +2861,29 @@ TrinaryOpNode::decreaseLeadsLags(int n) const
 }
 
 NodeID
-TrinaryOpNode::substituteLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
+TrinaryOpNode::substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
 {
   if (maxEndoLead() < 2)
     return const_cast<TrinaryOpNode *>(this);
   else
-    return createLeadAuxiliaryVarForMyself(subst_table, neweqs);
+    return createEndoLeadAuxiliaryVarForMyself(subst_table, neweqs);
+}
+
+NodeID
+TrinaryOpNode::substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
+{
+  NodeID arg1subst = arg1->substituteEndoLagGreaterThanTwo(subst_table, neweqs);
+  NodeID arg2subst = arg2->substituteEndoLagGreaterThanTwo(subst_table, neweqs);
+  NodeID arg3subst = arg3->substituteEndoLagGreaterThanTwo(subst_table, neweqs);
+  return buildSimilarTrinaryOpNode(arg1subst, arg2subst, arg3subst, datatree);
 }
 
 NodeID
-TrinaryOpNode::substituteLagGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
+TrinaryOpNode::substituteExoLeadLag(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
 {
-  NodeID arg1subst = arg1->substituteLagGreaterThanTwo(subst_table, neweqs);
-  NodeID arg2subst = arg2->substituteLagGreaterThanTwo(subst_table, neweqs);
-  NodeID arg3subst = arg3->substituteLagGreaterThanTwo(subst_table, neweqs);
+  NodeID arg1subst = arg1->substituteExoLeadLag(subst_table, neweqs);
+  NodeID arg2subst = arg2->substituteExoLeadLag(subst_table, neweqs);
+  NodeID arg3subst = arg3->substituteExoLeadLag(subst_table, neweqs);
   return buildSimilarTrinaryOpNode(arg1subst, arg2subst, arg3subst, datatree);
 }
 
@@ -2932,15 +3036,22 @@ UnknownFunctionNode::decreaseLeadsLags(int n) const
 }
 
 NodeID
-UnknownFunctionNode::substituteLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
+UnknownFunctionNode::substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
+{
+  cerr << "UnknownFunctionNode::substituteEndoLeadGreaterThanTwo: not implemented!" << endl;
+  exit(EXIT_FAILURE);
+}
+
+NodeID
+UnknownFunctionNode::substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
 {
-  cerr << "UnknownFunctionNode::substituteLeadGreaterThanTwo: not implemented!" << endl;
+  cerr << "UnknownFunctionNode::substituteEndoLagGreaterThanTwo: not implemented!" << endl;
   exit(EXIT_FAILURE);
 }
 
 NodeID
-UnknownFunctionNode::substituteLagGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
+UnknownFunctionNode::substituteExoLeadLag(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
 {
-  cerr << "UnknownFunctionNode::substituteLagGreaterThanTwo: not implemented!" << endl;
+  cerr << "UnknownFunctionNode::substituteExoLeadLag: not implemented!" << endl;
   exit(EXIT_FAILURE);
 }
diff --git a/preprocessor/ExprNode.hh b/preprocessor/ExprNode.hh
index 08bafae8cfc15e8d185e48b2b103241111828d3f..a18508c0f14dcad52b9584743867517e82f18be4 100644
--- a/preprocessor/ExprNode.hh
+++ b/preprocessor/ExprNode.hh
@@ -240,14 +240,14 @@ public:
   //! Type for the substitution map used in the process of creating auxiliary vars for leads >= 2
   typedef map<const ExprNode *, const VariableNode *> subst_table_t;
 
-  //! Creates auxiliary lead variables corresponding to this expression
+  //! Creates auxiliary endo lead variables corresponding to this expression
   /*! 
     If maximum endogenous lead >= 3, this method will also create intermediary auxiliary var, and will add the equations of the form aux1 = aux2(+1) to the substitution table.
     \pre This expression is assumed to have maximum endogenous lead >= 2
     \param[in,out] subst_table The table to which new auxiliary variables and their correspondance will be added
     \return The new variable node corresponding to the current expression
   */
-  VariableNode *createLeadAuxiliaryVarForMyself(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
+  VariableNode *createEndoLeadAuxiliaryVarForMyself(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
 
   //! Constructs a new expression where sub-expressions with max endo lead >= 2 have been replaced by auxiliary variables
   /*!
@@ -260,14 +260,21 @@ public:
 
     \return A new equivalent expression where sub-expressions with max endo lead >= 2 have been replaced by auxiliary variables
     */
-  virtual NodeID substituteLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const = 0;
+  virtual NodeID substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const = 0;
 
   //! Constructs a new expression where endo variables with max endo lag >= 2 have been replaced by auxiliary variables
   /*!
     \param[in,out] subst_table Map used to store expressions that have already be substituted and their corresponding variable, in order to avoid creating two auxiliary variables for the same sub-expr.
     \param[out] neweqs Equations to be added to the model to match the creation of auxiliary variables.
   */
-  virtual NodeID substituteLagGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const = 0;
+  virtual NodeID substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const = 0;
+
+  //! Constructs a new expression where endo variables with max exo lag >= 2 or max exo lag >= 2 have been replaced by auxiliary variables
+  /*!
+    \param[in,out] subst_table Map used to store expressions that have already be substituted and their corresponding variable, in order to avoid creating two auxiliary variables for the same sub-expr.
+    \param[out] neweqs Equations to be added to the model to match the creation of auxiliary variables.
+  */
+  virtual NodeID substituteExoLeadLag(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const = 0;
 };
 
 //! Object used to compare two nodes (using their indexes)
@@ -300,8 +307,9 @@ public:
   virtual NodeID getChainRuleDerivative(int deriv_id, const map<int, NodeID> &recursive_variables);
   virtual int maxEndoLead() const;
   virtual NodeID decreaseLeadsLags(int n) const;
-  virtual NodeID substituteLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
-  virtual NodeID substituteLagGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
+  virtual NodeID substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
+  virtual NodeID substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
+  virtual NodeID substituteExoLeadLag(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
 };
 
 //! Symbol or variable node
@@ -334,8 +342,9 @@ public:
   virtual NodeID getChainRuleDerivative(int deriv_id, const map<int, NodeID> &recursive_variables);
   virtual int maxEndoLead() const;
   virtual NodeID decreaseLeadsLags(int n) const;
-  virtual NodeID substituteLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
-  virtual NodeID substituteLagGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
+  virtual NodeID substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
+  virtual NodeID substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
+  virtual NodeID substituteExoLeadLag(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
 };
 
 //! Unary operator node
@@ -374,10 +383,11 @@ public:
   virtual NodeID getChainRuleDerivative(int deriv_id, const map<int, NodeID> &recursive_variables);
   virtual int maxEndoLead() const;
   virtual NodeID decreaseLeadsLags(int n) const;
-  virtual NodeID substituteLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
+  virtual NodeID substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
   //! Creates another UnaryOpNode with the same opcode, but with a possibly different datatree and argument
   NodeID buildSimilarUnaryOpNode(NodeID alt_arg, DataTree &alt_datatree) const;
-  virtual NodeID substituteLagGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
+  virtual NodeID substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
+  virtual NodeID substituteExoLeadLag(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
 };
 
 //! Binary operator node
@@ -421,10 +431,11 @@ public:
   virtual NodeID getChainRuleDerivative(int deriv_id, const map<int, NodeID> &recursive_variables);
   virtual int maxEndoLead() const;
   virtual NodeID decreaseLeadsLags(int n) const;
-  virtual NodeID substituteLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
+  virtual NodeID substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
   //! Creates another BinaryOpNode with the same opcode, but with a possibly different datatree and arguments
   NodeID buildSimilarBinaryOpNode(NodeID alt_arg1, NodeID alt_arg2, DataTree &alt_datatree) const;
-  virtual NodeID substituteLagGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
+  virtual NodeID substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
+  virtual NodeID substituteExoLeadLag(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
 };
 
 //! Trinary operator node
@@ -462,10 +473,11 @@ public:
   virtual NodeID getChainRuleDerivative(int deriv_id, const map<int, NodeID> &recursive_variables);
   virtual int maxEndoLead() const;
   virtual NodeID decreaseLeadsLags(int n) const;
-  virtual NodeID substituteLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
+  virtual NodeID substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
   //! Creates another TrinaryOpNode with the same opcode, but with a possibly different datatree and arguments
   NodeID buildSimilarTrinaryOpNode(NodeID alt_arg1, NodeID alt_arg2, NodeID alt_arg3, DataTree &alt_datatree) const;
-  virtual NodeID substituteLagGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
+  virtual NodeID substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
+  virtual NodeID substituteExoLeadLag(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
 };
 
 //! Unknown function node
@@ -497,8 +509,9 @@ public:
   virtual NodeID getChainRuleDerivative(int deriv_id, const map<int, NodeID> &recursive_variables);
   virtual int maxEndoLead() const;
   virtual NodeID decreaseLeadsLags(int n) const;
-  virtual NodeID substituteLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
-  virtual NodeID substituteLagGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
+  virtual NodeID substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
+  virtual NodeID substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
+  virtual NodeID substituteExoLeadLag(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
 };
 
 #endif
diff --git a/preprocessor/ModFile.cc b/preprocessor/ModFile.cc
index dafba6b268d356ab39d3e562d8b761ba0b5b475f..28660a72c51c9810ac3528ee3060b31f696fe528 100644
--- a/preprocessor/ModFile.cc
+++ b/preprocessor/ModFile.cc
@@ -141,8 +141,9 @@ ModFile::transformPass()
       || mod_file_struct.osr_present
       || mod_file_struct.ramsey_policy_present)
     {
-      dynamic_model.substituteLeadGreaterThanTwo();
-      dynamic_model.substituteLagGreaterThanTwo();
+      dynamic_model.substituteEndoLeadGreaterThanTwo();
+      dynamic_model.substituteEndoLagGreaterThanTwo();
+      dynamic_model.substituteExoLeadLag();
     }
 
   // Freeze the symbol table
diff --git a/preprocessor/ParsingDriver.cc b/preprocessor/ParsingDriver.cc
index 451653d778b371d96f0b58902fbab161c18e6b0c..eafc6ae9eb1ca3b3ae979aef61fec9e5b9efd1e2 100644
--- a/preprocessor/ParsingDriver.cc
+++ b/preprocessor/ParsingDriver.cc
@@ -192,9 +192,6 @@ ParsingDriver::add_model_variable(string *name, string *olag)
   if (type == eUnknownFunction)
     error("Symbol " + *name + " is a function name unknown to Dynare. It cannot be used inside model.");
 
-  if (type == eExogenous && lag != 0 && !mod_file->block)
-    warning("Exogenous variable " + *name + " has lead/lag " + *olag);
-
   if (type == eModelLocalVariable && lag != 0)
     error("Model local variable " + *name + " cannot be given a lead or a lag.");
 
diff --git a/preprocessor/SymbolTable.cc b/preprocessor/SymbolTable.cc
index d82dc9ff051250348516237d03d8f5aeb00a79ff..ea72365e30d29ea660e787007f4204193b65c91d 100644
--- a/preprocessor/SymbolTable.cc
+++ b/preprocessor/SymbolTable.cc
@@ -208,9 +208,11 @@ SymbolTable::writeOutput(ostream &output) const throw (NotYetFrozenException)
              << "M_.aux_vars(" << i+1 << ").type = " << aux_vars[i].type << ";" << endl;
       switch(aux_vars[i].type)
         {
-        case avLead:
+        case avEndoLead:
           break;
-        case avLag:
+        case avEndoLag:
+        case avExoLead:
+        case avExoLag:
           output << "M_.aux_vars(" << i+1 << ").orig_endo_index = " << getTypeSpecificID(aux_vars[i].orig_symb_id)+1 << ";" << endl
                  << "M_.aux_vars(" << i+1 << ").orig_lag = " << aux_vars[i].orig_lag << ";" << endl;
           break;
@@ -219,10 +221,10 @@ SymbolTable::writeOutput(ostream &output) const throw (NotYetFrozenException)
 }
 
 int
-SymbolTable::addLeadAuxiliaryVar(int index) throw (FrozenException)
+SymbolTable::addEndoLeadAuxiliaryVar(int index) throw (FrozenException)
 {
   ostringstream varname;
-  varname << "AUXLEAD_" << index;
+  varname << "AUX_ENDO_LEAD_" << index;
   int symb_id;
   try
     {
@@ -236,17 +238,32 @@ SymbolTable::addLeadAuxiliaryVar(int index) throw (FrozenException)
 
   AuxVarInfo avi;
   avi.symb_id = symb_id;
-  avi.type = avLead;
+  avi.type = avEndoLead;
   aux_vars.push_back(avi);
 
   return symb_id;
 }
 
 int
-SymbolTable::addLagAuxiliaryVar(int orig_symb_id, int orig_lag) throw (FrozenException)
+SymbolTable::addLeadLagAuxiliaryVarInternal(aux_var_t type, int orig_symb_id, int orig_lag) throw (FrozenException)
 {
   ostringstream varname;
-  varname << "AUXLAG_" << orig_symb_id << "_" << -orig_lag;
+  switch(type)
+    {
+    case avEndoLag:
+      varname << "AUX_ENDO_LAG_" << orig_symb_id << "_" << -orig_lag;
+      break;
+    case avExoLead:
+      varname << "AUX_EXO_LEAD_" << orig_symb_id << "_" << orig_lag;
+      break;
+    case avExoLag:
+      varname << "AUX_EXO_LAG_" << orig_symb_id << "_" << -orig_lag;
+      break;
+    default:
+      cerr << "Impossible case!" << endl;
+      exit(EXIT_FAILURE);
+    }
+
   int symb_id;
   try
     {
@@ -260,10 +277,28 @@ SymbolTable::addLagAuxiliaryVar(int orig_symb_id, int orig_lag) throw (FrozenExc
 
   AuxVarInfo avi;
   avi.symb_id = symb_id;
-  avi.type = avLag;
+  avi.type = type;
   avi.orig_symb_id = orig_symb_id;
   avi.orig_lag = orig_lag;
   aux_vars.push_back(avi);
 
   return symb_id;
 }
+
+int
+SymbolTable::addEndoLagAuxiliaryVar(int orig_symb_id, int orig_lag) throw (FrozenException)
+{
+  return addLeadLagAuxiliaryVarInternal(avEndoLag, orig_symb_id, orig_lag);
+}
+
+int
+SymbolTable::addExoLeadAuxiliaryVar(int orig_symb_id, int orig_lag) throw (FrozenException)
+{
+  return addLeadLagAuxiliaryVarInternal(avExoLead, orig_symb_id, orig_lag);
+}
+
+int
+SymbolTable::addExoLagAuxiliaryVar(int orig_symb_id, int orig_lag) throw (FrozenException)
+{
+  return addLeadLagAuxiliaryVarInternal(avExoLag, orig_symb_id, orig_lag);
+}
diff --git a/preprocessor/SymbolTable.hh b/preprocessor/SymbolTable.hh
index baed9a6210218927b11c229012fbd25dec60f78e..071ec3a59e5a36a877d145f170830f125e133ce2 100644
--- a/preprocessor/SymbolTable.hh
+++ b/preprocessor/SymbolTable.hh
@@ -32,8 +32,10 @@ using namespace std;
 //! Types of auxiliary variables
 enum aux_var_t
   {
-    avLead = 0, //!< Substitute for leads >= 2
-    avLag = 1 //!< Substitute for lags >= 2
+    avEndoLead = 0, //!< Substitute for endo leads >= 2
+    avEndoLag = 1,  //!< Substitute for endo lags >= 2
+    avExoLead = 2,  //!< Substitute for exo leads >= 2
+    avExoLag = 3,   //!< Substitute for exo lags >= 2
   };
 
 //! Information on some auxiliary variables
@@ -41,8 +43,8 @@ struct AuxVarInfo
 {
   int symb_id; //!< Symbol ID of the auxiliary variable
   aux_var_t type; //!< Its type
-  int orig_symb_id; //!< Symbol ID of the endo of the original model represented by this aux var. Only for avLag
-  int orig_lag; //!< Lag of the endo of the original model represented by this aux var. Only for avLag
+  int orig_symb_id; //!< Symbol ID of the endo of the original model represented by this aux var. Not used for avEndoLead
+  int orig_lag; //!< Lead/lag of the endo of the original model represented by this aux var. Not used for avEndoLead
 };
 
 //! Stores the symbol table
@@ -88,6 +90,7 @@ private:
   vector<int> param_ids;
   //! Information about auxiliary variables
   vector<AuxVarInfo> aux_vars;
+
 public:
   SymbolTable();
   //! Thrown when trying to access an unknown symbol (by name)
@@ -132,17 +135,40 @@ public:
   class NotYetFrozenException
   {
   };
+
+private:
+  int addLeadLagAuxiliaryVarInternal(aux_var_t type, int orig_symb_id, int orig_lag) throw (FrozenException);
+
+public:
   //! Add a symbol
   /*! Returns the symbol ID */
   int addSymbol(const string &name, SymbolType type, const string &tex_name) throw (AlreadyDeclaredException, FrozenException);
   //! Add a symbol without its TeX name (will be equal to its name)
   /*! Returns the symbol ID */
   int addSymbol(const string &name, SymbolType type) throw (AlreadyDeclaredException, FrozenException);
-  //! Adds an auxiliary variable for leads >=2
-  /*! Uses the given argument to construct the variable name.
-    Will exit the preprocessor with an error message if the variable name already declared by the user. Returns the symbol ID. */
-  int addLeadAuxiliaryVar(int index) throw (FrozenException);
-  int addLagAuxiliaryVar(int orig_symb_id, int orig_lag) throw (FrozenException);
+  //! Adds an auxiliary variable for endogenous with lead >= 2
+  /*!
+    \param[in] index Used to construct the variable name
+    \return the symbol ID of the new symbol */
+  int addEndoLeadAuxiliaryVar(int index) throw (FrozenException);
+  //! Adds an auxiliary variable for endogenous with lag >= 2
+  /*!
+    \param[in] orig_symb_id symbol ID of the endogenous declared by the user that this new variable will represent
+    \param[in] orig_lag lag value such that this new variable will be equivalent to orig_symb_id(orig_lag)
+    \return the symbol ID of the new symbol */
+  int addEndoLagAuxiliaryVar(int orig_symb_id, int orig_lag) throw (FrozenException);
+  //! Adds an auxiliary variable for endogenous with lead >= 1
+  /*!
+    \param[in] orig_symb_id symbol ID of the exogenous declared by the user that this new variable will represent
+    \param[in] orig_lag lag value such that this new variable will be equivalent to orig_symb_id(orig_lag)
+    \return the symbol ID of the new symbol */
+  int addExoLeadAuxiliaryVar(int orig_symb_id, int orig_lag) throw (FrozenException);
+  //! Adds an auxiliary variable for exogenous with lag >= 1
+  /*!
+    \param[in] orig_symb_id symbol ID of the exogenous declared by the user that this new variable will represent
+    \param[in] orig_lag lag value such that this new variable will be equivalent to orig_symb_id(orig_lag)
+    \return the symbol ID of the new symbol */
+  int addExoLagAuxiliaryVar(int orig_symb_id, int orig_lag) throw (FrozenException);
   //! Tests if symbol already exists
   inline bool exists(const string &name) const;
   //! Get symbol name (by ID)