diff --git a/ConfigFile.cc b/ConfigFile.cc
new file mode 100644
index 0000000000000000000000000000000000000000..34972660e1194200afd7758fbdab2109aab10674
--- /dev/null
+++ b/ConfigFile.cc
@@ -0,0 +1,482 @@
+/*
+ * Copyright (C) 2010 Dynare Team
+ *
+ * This file is part of Dynare.
+ *
+ * Dynare is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dynare is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dynare.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <cstdlib>
+#include <iostream>
+#include <fstream>
+#include <vector>
+
+#include "ConfigFile.hh"
+#include <boost/algorithm/string/trim.hpp>
+#include <boost/algorithm/string/split.hpp>
+#include <boost/lexical_cast.hpp>
+using namespace std;
+
+SlaveNode::SlaveNode(string &computerName_arg, int minCpuNbr_arg, int maxCpuNbr_arg, string &userName_arg,
+                     string &password_arg, string &remoteDrive_arg, string &remoteDirectory_arg,
+                     string &dynarePath_arg,  string &matlabOctavePath_arg, bool singleCompThread_arg) :
+  computerName(computerName_arg), minCpuNbr(minCpuNbr_arg), maxCpuNbr(maxCpuNbr_arg), userName(userName_arg),
+  password(password_arg), remoteDrive(remoteDrive_arg), remoteDirectory(remoteDirectory_arg), dynarePath(dynarePath_arg),
+  matlabOctavePath(matlabOctavePath_arg), singleCompThread(singleCompThread_arg)
+{
+  if (computerName.empty())
+    {
+      cerr << "ERROR: The node must have a ComputerName." << endl;
+      exit(EXIT_FAILURE);
+    }
+}
+
+Cluster::Cluster(vector<string> member_nodes_arg) : member_nodes(member_nodes_arg)
+{
+  if (member_nodes.empty())
+    {
+      cerr << "ERROR: The cluster must have at least one member node." << endl;
+      exit(EXIT_FAILURE);
+    }
+}
+
+ConfigFile::ConfigFile(bool parallel_arg, bool parallel_test_arg,
+                       bool parallel_slave_open_mode_arg, const string &cluster_name_arg) :
+  parallel(parallel_arg), parallel_test(parallel_test_arg),
+  parallel_slave_open_mode(parallel_slave_open_mode_arg), cluster_name(cluster_name_arg)
+{
+}
+
+ConfigFile::~ConfigFile()
+{
+}
+
+void
+ConfigFile::getConfigFileInfo(const string &parallel_config_file)
+{
+  if (!parallel && !parallel_test)
+    return;
+
+  ifstream *configFile;
+  if (parallel_config_file.empty())
+    {
+      // Test OS and try to open default file
+#if defined(_WIN32) || defined(__CYGWIN32__)
+      string defaultConfigFile (getenv("APPDATA"));
+      if (&defaultConfigFile==NULL)
+        {
+          cerr << "ERROR: APPDATA environment variable not found." << endl;
+          exit(EXIT_FAILURE);
+        }
+      defaultConfigFile += "\\dynare.ini";
+#else
+      string defaultConfigFile (getenv("HOME"));
+      if (&defaultConfigFile==NULL)
+        {
+          cerr << "ERROR: HOME environment variable not found." << endl;
+          exit(EXIT_FAILURE);
+        }
+      defaultConfigFile += "/.dynare";
+#endif
+      configFile = new ifstream(defaultConfigFile.c_str(), fstream::in);
+      if (!configFile->is_open())
+        {
+          cerr << "ERROR: Could not open the default config file" << endl;
+          exit(EXIT_FAILURE);
+        }
+    }
+  else
+    {
+      configFile = new ifstream(parallel_config_file.c_str(), fstream::in);
+      if (!configFile->is_open())
+        {
+          cerr << "ERROR: Couldn't open file " << parallel_config_file << endl;;
+          exit(EXIT_FAILURE);
+        }
+    }
+
+  string name, computerName, userName, password, remoteDrive,
+    remoteDirectory, dynarePath, matlabOctavePath;
+  int minCpuNbr = 0, maxCpuNbr = 0;
+  bool singleCompThread = true;
+  vector<string> member_nodes;
+
+  bool inNode = false;
+  bool inCluster = false;
+  while (configFile->good())
+    {
+      string line;
+      getline(*configFile, line);
+      boost::trim(line);
+      if (line.empty())
+        continue;
+
+      if (!line.compare("[node]") || !line.compare("[cluster]"))
+        {
+          addConfFileElement(inNode, inCluster, member_nodes, name,
+                 computerName, minCpuNbr, maxCpuNbr, userName,
+                 password, remoteDrive, remoteDirectory,
+                 dynarePath,  matlabOctavePath, singleCompThread);
+
+          //! Reset communication vars / option defaults
+          if (!line.compare("[node]"))
+            {
+              inNode = true;
+              inCluster = false;
+            }
+          else
+            {
+              inNode = false;
+              inCluster = true;
+            }
+
+          name = userName = computerName = password = remoteDrive =
+            remoteDirectory = dynarePath = matlabOctavePath = "";
+          minCpuNbr = maxCpuNbr = 0;
+          singleCompThread = true;
+          member_nodes.clear();
+        }
+      else
+        {
+          vector<string> tokenizedLine;
+          boost::split(tokenizedLine, line, boost::is_any_of("="));
+          if (tokenizedLine.size() != 2)
+            {
+              cerr << "ERROR (in config file): Options should be formatted as 'option = value'." << endl;
+              exit(EXIT_FAILURE);
+            }
+          boost::trim(tokenizedLine.front());
+          boost::trim(tokenizedLine.back());
+
+          if (!tokenizedLine.front().compare("Name"))
+            name = tokenizedLine.back();
+          else if (!tokenizedLine.front().compare("CPUnbr"))
+            {
+              vector<string> tokenizedCpuNbr;
+              boost::split(tokenizedCpuNbr, tokenizedLine.back(), boost::is_any_of(":"));
+              try
+                {
+                  if (tokenizedCpuNbr.size() == 1)
+                    {
+                      minCpuNbr = 1;
+                      maxCpuNbr = boost::lexical_cast< int >(tokenizedCpuNbr.front());
+                    }
+                  else if (tokenizedCpuNbr.size() == 2 &&
+                           tokenizedCpuNbr[0].at(0) == '[' &&
+                           tokenizedCpuNbr[1].at(tokenizedCpuNbr[1].size()-1) == ']')
+                    {
+                      tokenizedCpuNbr[0].erase(0,1);
+                      tokenizedCpuNbr[1].erase(tokenizedCpuNbr[1].size()-1,1);
+                      minCpuNbr = boost::lexical_cast< int >(tokenizedCpuNbr[0]);
+                      maxCpuNbr = boost::lexical_cast< int >(tokenizedCpuNbr[1]);
+                    }
+                }
+              catch( const boost::bad_lexical_cast & )
+                {
+                  cerr << "ERROR: Could not convert value to integer for CPUnbr." << endl;
+                  exit(EXIT_FAILURE);
+                }
+
+              if (minCpuNbr <= 0 || maxCpuNbr <= 0)
+                {
+                  cerr << "ERROR: Syntax for the CPUnbr option is as follows:" << endl
+                       << "       1) CPUnbr = <int>" << endl
+                       << "    or 2) CPUnbr = [<int>:<int>]" << endl
+                       << "       where <int> is an Integer > 0." << endl;
+                  exit(EXIT_FAILURE);
+                }
+
+              minCpuNbr--;
+              maxCpuNbr--;
+              if (minCpuNbr > maxCpuNbr)
+                {
+                  int tmp = maxCpuNbr;
+                  maxCpuNbr = minCpuNbr;
+                  minCpuNbr = tmp;
+                }
+            }
+          else if (!tokenizedLine.front().compare("ComputerName"))
+            computerName = tokenizedLine.back();
+          else if (!tokenizedLine.front().compare("UserName"))
+            userName = tokenizedLine.back();
+          else if (!tokenizedLine.front().compare("Password"))
+            password = tokenizedLine.back();
+          else if (!tokenizedLine.front().compare("RemoteDrive"))
+            remoteDrive = tokenizedLine.back();
+          else if (!tokenizedLine.front().compare("RemoteDirectory"))
+            remoteDirectory = tokenizedLine.back();
+          else if (!tokenizedLine.front().compare("DynarePath"))
+            dynarePath = tokenizedLine.back();
+          else if (!tokenizedLine.front().compare("MatlabOctavePath"))
+            matlabOctavePath = tokenizedLine.back();
+          else if (!tokenizedLine.front().compare("SingleCompThread"))
+            if (tokenizedLine.back().compare("true"))
+              singleCompThread = true;
+            else if (tokenizedLine.back().compare("false"))
+              singleCompThread = false;
+            else
+              {
+                cerr << "ERROR (in config file): The value passed to SingleCompThread may only be 'true' or 'false'." << endl;
+                exit(EXIT_FAILURE);
+              }
+          else if (!tokenizedLine.front().compare("Members"))
+            {
+              vector<string> tmp_member_nodes;
+              boost::split(tmp_member_nodes, tokenizedLine.back(), boost::is_any_of(";, "));
+              for ( vector<string>::iterator it = tmp_member_nodes.begin();
+                    it < tmp_member_nodes.end(); it++ )
+                {
+                  boost::trim(*it);
+                  if (!it->empty())
+                    member_nodes.push_back(*it);
+                }
+            }
+          else
+            {
+              cerr << "ERROR (in config file): Option " << tokenizedLine.front() << " is invalid." << endl;
+              exit(EXIT_FAILURE);
+            }
+        }
+    }
+
+  addConfFileElement(inNode, inCluster, member_nodes, name,
+                     computerName, minCpuNbr, maxCpuNbr, userName,
+                     password, remoteDrive, remoteDirectory,
+                     dynarePath,  matlabOctavePath, singleCompThread);
+  configFile->close();
+  delete configFile;
+}
+
+void
+ConfigFile::addConfFileElement(bool inNode, bool inCluster, vector<string> member_nodes, string &name,
+                               string &computerName, int minCpuNbr, int maxCpuNbr, string &userName,
+                               string &password, string &remoteDrive, string &remoteDirectory,
+                               string &dynarePath,  string &matlabOctavePath, bool singleCompThread)
+{
+  //! ADD NODE
+  if (inNode)
+    if (!member_nodes.empty())
+      {
+        cerr << "Invalid option passed to [node]." << endl;
+        exit(EXIT_FAILURE);
+      }
+    else
+      if (name.empty() || slave_nodes.find(name) != slave_nodes.end())
+        {
+          cerr << "ERROR: Every node must be assigned a unique name." << endl;
+          exit(EXIT_FAILURE);
+        }
+      else
+        slave_nodes[name] = new SlaveNode(computerName, minCpuNbr, maxCpuNbr, userName,
+                                          password, remoteDrive, remoteDirectory, dynarePath,
+                                          matlabOctavePath, singleCompThread);
+  //! ADD CLUSTER
+  else if (inCluster)
+    if ( minCpuNbr > 0 || maxCpuNbr > 0 || !userName.empty() ||
+         !password.empty() || !remoteDrive.empty() || !remoteDirectory.empty() ||
+         !dynarePath.empty() || !matlabOctavePath.empty())
+      {
+        cerr << "Invalid option passed to [cluster]." << endl;
+        exit(EXIT_FAILURE);
+      }
+    else
+      if (name.empty() || clusters.find(name) != clusters.end())
+        {
+          cerr << "ERROR: The cluster must be assigned a unique name." << endl;
+          exit(EXIT_FAILURE);
+        }
+      else
+        {
+          if (clusters.empty())
+            firstClusterName = name;
+          clusters[name] = new Cluster(member_nodes);
+        }
+}
+
+void
+ConfigFile::checkPass() const
+{
+  if (!parallel && !parallel_test)
+    return;
+
+  //! Check Slave Nodes
+  if (slave_nodes.empty())
+    {
+      cerr << "ERROR: At least one node must be defined in the config file." << endl;
+      exit(EXIT_FAILURE);
+    }
+
+  for (map<string, SlaveNode *>::const_iterator it = slave_nodes.begin();
+       it != slave_nodes.end(); it++)
+    {
+#if !defined(_WIN32) && !defined(__CYGWIN32__)
+      //For Linux/Mac, check that cpuNbr starts at 0
+      if (it->second->minCpuNbr != 0)
+        cout << "WARNING: On Unix-based operating systems, you cannot specify the CPU that is used "
+             << "in parallel processing. This will be adjusted for you such that the same number of CPUs "
+             << "are used." << endl;
+#endif
+      if (!it->second->computerName.compare("localhost")) // We are working locally
+        {
+          if (!it->second->remoteDrive.empty())
+            {
+              cerr << "ERROR (node " << it->first << "): the RemoteDrive option may not be passed for a local node." << endl;
+              exit(EXIT_FAILURE);
+            }
+          if (!it->second->remoteDirectory.empty())
+            {
+              cerr << "ERROR (node " << it->first << "): the RemoteDirectory option may not be passed for a local node." << endl;
+              exit(EXIT_FAILURE);
+            }
+        }
+      else
+        {
+          if (it->second->userName.empty())
+            {
+              cerr << "ERROR (node " << it->first << "): the UserName option must be passed for every remote node." << endl;
+              exit(EXIT_FAILURE);
+            }
+#if defined(_WIN32) || defined(__CYGWIN32__)
+          if (it->second->userName.empty() || it->second->password.empty())
+            {
+              cerr << "ERROR (node " << it->first << "): the Password option must be passed under Windows for every remote node." << endl;
+              exit(EXIT_FAILURE);
+            }
+          if (it->second->remoteDrive.empty())
+            {
+              cerr << "ERROR (node " << it->first << "): the RemoteDrive option must be passed under Windows for every remote node." << endl;
+              exit(EXIT_FAILURE);
+            }
+#endif
+          if (it->second->remoteDirectory.empty())
+            {
+              cerr << "ERROR (node " << it->first << "): the RemoteDirectory must be specified for every remote node." << endl;
+              exit(EXIT_FAILURE);
+            }
+        }
+    }
+
+  //! Check Clusters
+  if (clusters.empty())
+    {
+      cerr << "ERROR: At least one cluster must be defined in the config file." << endl;
+      exit(EXIT_FAILURE);
+    }
+
+  if (!cluster_name.empty() && clusters.find(cluster_name) == clusters.end())
+    {
+      cerr << "ERROR: Cluster Name " << cluster_name << " was not found in the config file." << endl;
+      exit(EXIT_FAILURE);
+    }
+
+  for (map<string, Cluster *>::const_iterator it = clusters.begin();
+       it != clusters.end(); it++)
+    for (vector<string>::const_iterator itmn = it->second->member_nodes.begin();
+         itmn < it->second->member_nodes.end(); itmn++)
+      if (slave_nodes.find(*itmn) == slave_nodes.end())
+        {
+          cerr << "Error: node " << *itmn << " specified in cluster " << it->first << " was not found" << endl;
+          exit(EXIT_FAILURE);
+        }
+}
+
+void
+ConfigFile::transformPass()
+{
+  if (!parallel && !parallel_test)
+    return;
+
+#if !defined(_WIN32) && !defined(__CYGWIN32__)
+  //For Linux/Mac, check that cpuNbr starts at 0
+  for (map<string, SlaveNode *>::const_iterator it = slave_nodes.begin();
+       it != slave_nodes.end(); it++)
+    if (it->second->minCpuNbr != 0)
+      {
+        it->second->maxCpuNbr = it->second->maxCpuNbr - it->second->minCpuNbr;
+        it->second->minCpuNbr = 0;
+      }
+#endif
+}
+
+void
+ConfigFile::writeCluster(ostream &output) const
+{
+  if (!parallel && !parallel_test)
+    return;
+
+  map<string, Cluster *>::const_iterator cluster_it ;
+  if (cluster_name.empty())
+    cluster_it = clusters.find(firstClusterName);
+  else
+    cluster_it = clusters.find(cluster_name);
+
+  int i = 1;
+  for (map<string, SlaveNode *>::const_iterator it = slave_nodes.begin();
+       it != slave_nodes.end(); it++)
+    {
+      bool slave_node_in_member_nodes = false;
+      for (vector<string>::const_iterator itmn = cluster_it->second->member_nodes.begin();
+           itmn < cluster_it->second->member_nodes.end(); itmn++)
+        if (!it->first.compare(*itmn))
+          slave_node_in_member_nodes = true;
+
+      if (!slave_node_in_member_nodes)
+        continue;
+
+      output << "options_.parallel";
+      if (i > 1)
+        output << "(" << i << ")";
+      i++;
+      output << " = struct('Local', ";
+      if (it->second->computerName.compare("localhost"))
+        output << "0, ";
+      else
+        output << "1, ";
+
+      output << "'ComputerName', '" << it->second->computerName << "', "
+             << "'CPUnbr', [" << it->second->minCpuNbr << ":" << it->second->maxCpuNbr << "], "
+             << "'UserName', '" << it->second->userName << "', "
+             << "'Password', '" << it->second->password << "', "
+             << "'RemoteDrive', '" << it->second->remoteDrive << "', "
+             << "'RemoteDirectory', '" << it->second->remoteDirectory << "', "
+             << "'DynarePath', '" << it->second->dynarePath << "', "
+             << "'MatlabOctavePath', '" << it->second->matlabOctavePath << "', ";
+
+      if (it->second->singleCompThread)
+        output << "'SingleCompThread', 'true');" << endl;
+      else
+        output << "'SingleCompThread', 'false');" << endl;
+    }
+
+  if (parallel_slave_open_mode)
+    output << "options_.parallel_info.leaveSlaveOpen = 1;" << endl;
+
+  output << "InitializeComputationalEnvironment();" << endl;
+  if (parallel_test)
+    output  << "ErrorCode = AnalyseComputationalEnvironment(options_.parallel, options_.parallel_info);" << endl
+            << "disp(['AnalyseComputationalEnvironment returned with Error Code: ' num2str(ErrorCode)]);" << endl
+            << "diary off;" << endl
+            << "return;" << endl;
+}
+
+void
+ConfigFile::writeEndParallel(ostream &output) const
+{
+  if ((!parallel && !parallel_test) || !parallel_slave_open_mode)
+    return;
+
+  output << "if options_.parallel_info.leaveSlaveOpen == 1" << endl
+         << "     closeSlave(options_.parallel,options_.parallel_info.RemoteTmpFolder);" << endl
+         << "end" << endl;
+}
diff --git a/ConfigFile.hh b/ConfigFile.hh
new file mode 100644
index 0000000000000000000000000000000000000000..1a5eb9974c4f4dec77c8126e1ddb0c9c97ba4f9e
--- /dev/null
+++ b/ConfigFile.hh
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2010 Dynare Team
+ *
+ * This file is part of Dynare.
+ *
+ * Dynare is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dynare is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dynare.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _CONFIG_FILE_HH
+#define _CONFIG_FILE_HH
+
+#include <map>
+#include <vector>
+using namespace std;
+
+class SlaveNode
+{
+  friend class ConfigFile;
+public:
+  SlaveNode(string &computerName_arg, int minCpuNbr_arg, int maxCpuNbr_arg, string &userName_arg,
+            string &password_arg, string &remoteDrive_arg, string &remoteDirectory_arg,
+            string &dynarePath_arg, string &matlabOctavePath_arg, bool singleCompThread_arg);
+  ~SlaveNode();
+
+protected:
+  const string computerName;
+  int minCpuNbr;
+  int maxCpuNbr;
+  const string userName;
+  const string password;
+  const string remoteDrive;
+  const string remoteDirectory;
+  const string dynarePath;
+  const string matlabOctavePath;
+  const bool singleCompThread;
+};
+
+class Cluster
+{
+  friend class ConfigFile;
+public:
+  Cluster(vector<string> member_nodes_arg);
+  ~Cluster();
+
+protected:
+  const vector<string> member_nodes;
+};
+
+//! The abstract representation of a "config" file
+class ConfigFile
+{
+public:
+  ConfigFile(bool parallel_arg, bool parallel_test_arg, bool parallel_slave_open_mode_arg, const string &cluster_name);
+  ~ConfigFile();
+
+private:
+  const bool parallel;
+  const bool parallel_test;
+  const bool parallel_slave_open_mode;
+  const string cluster_name;
+  string firstClusterName;
+  //! Cluster Table
+  map<string, Cluster *> clusters;
+  //! Node Map
+  map<string, SlaveNode *> slave_nodes;
+  //! Add a SlaveNode or a Cluster object
+  void addConfFileElement(bool inNode, bool inCluster, vector<string> member_nodes, string &name,
+                          string &computerName, int minCpuNbr, int maxCpuNbr, string &userName,
+                          string &password, string &remoteDrive, string &remoteDirectory,
+                          string &dynarePath,  string &matlabOctavePath, bool singleCompThread);
+public:
+  //! Parse config file
+  void getConfigFileInfo(const string &parallel_config_file);
+  //! Check Pass
+  void checkPass() const;
+  //! Check Pass
+  void transformPass();
+  //! Create options_.parallel structure, write options
+  void writeCluster(ostream &output) const;
+  //! Close slave nodes if needed
+  void writeEndParallel(ostream &output) const;
+};
+
+#endif // ! CONFIG_FILE_HH
diff --git a/DynareMain.cc b/DynareMain.cc
index 8969aaadf0768b7b331d84471f3b4fd6eabe80f4..27225bfa61be20c64a7fdde053c63d9eebdf679a 100644
--- a/DynareMain.cc
+++ b/DynareMain.cc
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2003-2009 Dynare Team
+ * Copyright (C) 2003-2010 Dynare Team
  *
  * This file is part of Dynare.
  *
@@ -34,7 +34,9 @@ using namespace std;
    Splitting main() in two parts was necessary because ParsingDriver.h and MacroDriver.h can't be
    included simultaneously (because of Bison limitations).
 */
-void main2(stringstream &in, string &basename, bool debug, bool clear_all, bool no_tmp_terms, bool warn_uninit
+void main2(stringstream &in, string &basename, bool debug, bool clear_all, bool no_tmp_terms, bool warn_uninit,
+           bool parallel, const string &parallel_config_file, const string &cluster_name, bool parallel_slave_open_mode,
+           bool parallel_test
 #if defined(_WIN32) || defined(__CYGWIN32__)
            , bool cygwin, bool msvc
 #endif
@@ -44,6 +46,7 @@ void
 usage()
 {
   cerr << "Dynare usage: dynare mod_file [debug] [noclearall] [savemacro[=macro_file]] [onlymacro] [nolinemacro] [notmpterms] [warn_uninit]"
+       << " [parallel[=cluster_name]] [conffile=parallel_config_path_and_filename] [parallel_slave_open_mode] [parallel_test]"
 #if defined(_WIN32) || defined(__CYGWIN32__)
        << " [cygwin] [msvc]"
 #endif
@@ -72,6 +75,11 @@ main(int argc, char **argv)
   bool cygwin = false;
   bool msvc = false;
 #endif
+  string parallel_config_file;
+  bool parallel = false;
+  string cluster_name;
+  bool parallel_slave_open_mode = false;
+  bool parallel_test = false;
 
   // Parse options
   for (int arg = 2; arg < argc; arg++)
@@ -107,6 +115,32 @@ main(int argc, char **argv)
       else if (!strcmp(argv[arg], "msvc"))
         msvc = true;
 #endif
+      else if (strlen(argv[arg]) >= 8 && !strncmp(argv[arg], "conffile", 8))
+        {
+          if (strlen(argv[arg]) <= 9 || argv[arg][8] != '=')
+            {
+              cerr << "Incorrect syntax for conffile option" << endl;
+              usage();
+            }
+          parallel_config_file = string(argv[arg] + 9);
+        }
+      else if (!strcmp(argv[arg], "parallel_slave_open_mode"))
+        parallel_slave_open_mode = true;
+      else if (!strcmp(argv[arg], "parallel_test"))
+        parallel_test = true;
+      else if (strlen(argv[arg]) >= 8 && !strncmp(argv[arg], "parallel", 8))
+        {
+          parallel = true;
+          if (strlen(argv[arg]) > 8)
+            {
+              if (strlen(argv[arg]) == 9 || argv[arg][8] != '=')
+                {
+                  cerr << "Incorrect syntax for parallel option" << endl;
+                  usage();
+                }
+              cluster_name = string(argv[arg] + 9);
+            }
+        }
       else
         {
           cerr << "Unknown option: " << argv[arg] << endl;
@@ -146,7 +180,8 @@ main(int argc, char **argv)
     return EXIT_SUCCESS;
 
   // Do the rest
-  main2(macro_output, basename, debug, clear_all, no_tmp_terms, warn_uninit
+  main2(macro_output, basename, debug, clear_all, no_tmp_terms, warn_uninit,
+        parallel, parallel_config_file, cluster_name, parallel_slave_open_mode, parallel_test
 #if defined(_WIN32) || defined(__CYGWIN32__)
         , cygwin, msvc
 #endif
diff --git a/DynareMain2.cc b/DynareMain2.cc
index 1090685139ea76676d36850a49397f452531776c..5b944a4ace5fa38dc9cd805ec99721b054619246 100644
--- a/DynareMain2.cc
+++ b/DynareMain2.cc
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 Dynare Team
+ * Copyright (C) 2008-2010 Dynare Team
  *
  * This file is part of Dynare.
  *
@@ -23,9 +23,12 @@ using namespace std;
 
 #include "ParsingDriver.hh"
 #include "ModFile.hh"
+#include "ConfigFile.hh"
 
 void
-main2(stringstream &in, string &basename, bool debug, bool clear_all, bool no_tmp_terms, bool warn_uninit
+main2(stringstream &in, string &basename, bool debug, bool clear_all, bool no_tmp_terms, bool warn_uninit,
+      bool parallel, const string &parallel_config_file, const string &cluster_name, bool parallel_slave_open_mode,
+      bool parallel_test
 #if defined(_WIN32) || defined(__CYGWIN32__)
       , bool cygwin, bool msvc
 #endif
@@ -35,12 +38,16 @@ main2(stringstream &in, string &basename, bool debug, bool clear_all, bool no_tm
 
   // Do parsing and construct internal representation of mod file
   ModFile *mod_file = p.parse(in, debug);
+  ConfigFile config_file (parallel, parallel_test, parallel_slave_open_mode, cluster_name);
+  config_file.getConfigFileInfo(parallel_config_file);
 
   // Run checking pass
   mod_file->checkPass();
+  config_file.checkPass();
 
   // Perform transformations on the model (creation of auxiliary vars and equations)
   mod_file->transformPass();
+  config_file.transformPass();
 
   // Evaluate parameters initialization, initval, endval and pounds
   mod_file->evalAllExpressions(warn_uninit);
@@ -49,7 +56,7 @@ main2(stringstream &in, string &basename, bool debug, bool clear_all, bool no_tm
   mod_file->computingPass(no_tmp_terms);
 
   // Write outputs
-  mod_file->writeOutputFiles(basename, clear_all
+  mod_file->writeOutputFiles(basename, clear_all, config_file
 #if defined(_WIN32) || defined(__CYGWIN32__)
                              , cygwin, msvc
 #endif
diff --git a/Makefile.am b/Makefile.am
index 8c80d0d806fdf5de167276819cc41f6276f49961..d1f6b272a0bf3cf22dae62fdd00653189e4ff973 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -36,6 +36,8 @@ dynare_m_SOURCES = \
 	DataTree.hh \
 	ModFile.cc \
 	ModFile.hh \
+	ConfigFile.cc \
+	ConfigFile.hh \
 	Statement.cc \
 	Statement.hh \
 	ExprNode.cc \
diff --git a/ModFile.cc b/ModFile.cc
index e97f5ff51c8fe9e78bd9475beaecb45c176adcbe..bf6b9130fa2990271a5babf0c03552e21f8b168b 100644
--- a/ModFile.cc
+++ b/ModFile.cc
@@ -22,6 +22,7 @@
 #include <fstream>
 #include <typeinfo>
 #include "ModFile.hh"
+#include "ConfigFile.hh"
 
 ModFile::ModFile() : expressions_tree(symbol_table, num_constants, external_functions_table),
                      dynamic_model(symbol_table, num_constants, external_functions_table),
@@ -344,7 +345,7 @@ ModFile::computingPass(bool no_tmp_terms)
 }
 
 void
-ModFile::writeOutputFiles(const string &basename, bool clear_all
+ModFile::writeOutputFiles(const string &basename, bool clear_all, const ConfigFile &config_file
 #if defined(_WIN32) || defined(__CYGWIN32__)
                           , bool cygwin, bool msvc
 #endif
@@ -419,6 +420,8 @@ ModFile::writeOutputFiles(const string &basename, bool clear_all
               << "options_.bytecode=" << byte_code << ";" << endl
               << "options_.use_dll=" << use_dll << ";" << endl;
 
+  config_file.writeCluster(mOutputFile);
+
   if (byte_code)
     mOutputFile << "if exist('bytecode') ~= 3" << endl
                 << "  error('DYNARE: Can''t find bytecode DLL. Please compile it or remove the ''bytecode'' option.')" << endl
@@ -530,8 +533,11 @@ ModFile::writeOutputFiles(const string &basename, bool clear_all
   if (block && !byte_code)
     mOutputFile << "rmpath " << basename << ";" << endl;
 
-  mOutputFile << "save('" << basename << "_results.mat', 'oo_', 'M_', 'options_');" << endl
-              << "diary off" << endl
+  mOutputFile << "save('" << basename << "_results.mat', 'oo_', 'M_', 'options_');" << endl;
+
+  config_file.writeEndParallel(mOutputFile);
+
+  mOutputFile << "diary off" << endl
               << endl << "disp(['Total computing time : ' dynsec2hms(toc) ]);" << endl;
 
   mOutputFile.close();
diff --git a/ModFile.hh b/ModFile.hh
index a9f354dbfd98936a02e6e06c656dc249f62b4552..71d363167aaee70a5df65797193be64dfa24e69f 100644
--- a/ModFile.hh
+++ b/ModFile.hh
@@ -33,6 +33,7 @@ using namespace std;
 #include "SteadyStateModel.hh"
 #include "Statement.hh"
 #include "ExternalFunctionsTable.hh"
+#include "ConfigFile.hh"
 
 //! The abstract representation of a "mod" file
 class ModFile
@@ -106,7 +107,7 @@ public:
     \param clear_all Should a "clear all" instruction be written to output ?
     \param msvc Should the MEX command of use_dll be adapted for MSVC?
   */
-  void writeOutputFiles(const string &basename, bool clear_all
+  void writeOutputFiles(const string &basename, bool clear_all, const ConfigFile &config_file
 #if defined(_WIN32) || defined(__CYGWIN32__)
                         , bool cygwin, bool msvc
 #endif