diff --git a/ComputingTasks.cc b/ComputingTasks.cc
index 287da9cafd97b8c96aed2c1ae66c1f159ce5bde8..7cbf05faa0cbc3573dcb3f933596fd88808832b4 100644
--- a/ComputingTasks.cc
+++ b/ComputingTasks.cc
@@ -50,6 +50,18 @@ SteadyStatement::writeOutput(ostream &output, const string &basename, bool minim
   output << "steady;" << endl;
 }
 
+void
+SteadyStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"steady\"";
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+  output << "}";
+}
+
 CheckStatement::CheckStatement(const OptionsList &options_list_arg) :
   options_list(options_list_arg)
 {
@@ -68,6 +80,18 @@ CheckStatement::checkPass(ModFileStructure &mod_file_struct, WarningConsolidatio
   mod_file_struct.check_present = true;
 }
 
+void
+CheckStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"check\"";
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+  output << "}";
+}
+
 ModelInfoStatement::ModelInfoStatement(const OptionsList &options_list_arg) :
   options_list(options_list_arg)
 {
@@ -86,6 +110,18 @@ ModelInfoStatement::writeOutput(ostream &output, const string &basename, bool mi
   output << "model_info();" << endl;
 }
 
+void
+ModelInfoStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"model_info\"";
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+  output << "}";
+}
+
 SimulStatement::SimulStatement(const OptionsList &options_list_arg) :
   options_list(options_list_arg)
 {
@@ -105,6 +141,18 @@ SimulStatement::writeOutput(ostream &output, const string &basename, bool minima
          << "perfect_foresight_solver;" << endl;
 }
 
+void
+SimulStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"simul\"";
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+  output << "}";
+}
+
 PerfectForesightSetupStatement::PerfectForesightSetupStatement(const OptionsList &options_list_arg) :
   options_list(options_list_arg)
 {
@@ -117,6 +165,18 @@ PerfectForesightSetupStatement::writeOutput(ostream &output, const string &basen
   output << "perfect_foresight_setup;" << endl;
 }
 
+void
+PerfectForesightSetupStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"perfect_foresight_setup\"";
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+  output << "}";
+}
+
 PerfectForesightSolverStatement::PerfectForesightSolverStatement(const OptionsList &options_list_arg) :
   options_list(options_list_arg)
 {
@@ -138,6 +198,18 @@ PerfectForesightSolverStatement::writeOutput(ostream &output, const string &base
   output << "perfect_foresight_solver;" << endl;
 }
 
+void
+PerfectForesightSolverStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"perfect_foresight_solver\"";
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+  output << "}";
+}
+
 PriorPosteriorFunctionStatement::PriorPosteriorFunctionStatement(const bool prior_func_arg,
                                                                  const OptionsList &options_list_arg) :
   prior_func(prior_func_arg),
@@ -171,6 +243,21 @@ PriorPosteriorFunctionStatement::writeOutput(ostream &output, const string &base
          << "'" << type << "');" << endl;
 }
 
+void
+PriorPosteriorFunctionStatement::writeJsonOutput(ostream &output) const
+{
+  string type = "posterior";
+  if (prior_func)
+    type = "prior";
+  output << "{\"statementName\": \"prior_posterior_function\", \"type\": \"" << type << "\"";
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+  output << "}";
+}
+
 VarModelStatement::VarModelStatement(const SymbolList &symbol_list_arg,
                                      const OptionsList &options_list_arg,
                                      const string &name_arg) :
@@ -490,6 +577,23 @@ StochSimulStatement::writeOutput(ostream &output, const string &basename, bool m
   output << "info = stoch_simul(var_list_);" << endl;
 }
 
+void
+StochSimulStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"stoch_simul\"";
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+  if (!symbol_list.empty())
+    {
+      output << ", ";
+      symbol_list.writeJsonOutput(output);
+    }
+  output << "}";
+}
+
 ForecastStatement::ForecastStatement(const SymbolList &symbol_list_arg,
                                      const OptionsList &options_list_arg) :
   symbol_list(symbol_list_arg),
@@ -505,6 +609,23 @@ ForecastStatement::writeOutput(ostream &output, const string &basename, bool min
   output << "[oo_.forecast,info] = dyn_forecast(var_list_,M_,options_,oo_,'simul');" << endl;
 }
 
+void
+ForecastStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"forecast\"";
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+  if (!symbol_list.empty())
+    {
+      output << ", ";
+      symbol_list.writeJsonOutput(output);
+    }
+  output << "}";
+}
+
 RamseyModelStatement::RamseyModelStatement(const SymbolList &symbol_list_arg,
                                            const OptionsList &options_list_arg) :
   symbol_list(symbol_list_arg),
@@ -562,7 +683,20 @@ RamseyModelStatement::writeOutput(ostream &output, const string &basename, bool
   options_list.writeOutput(output);
 }
 
-RamseyConstraintsStatement::RamseyConstraintsStatement(const constraints_t &constraints_arg) :
+void
+RamseyModelStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"ramsey_model\"";
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+  output << "}";
+}
+
+RamseyConstraintsStatement::RamseyConstraintsStatement(const SymbolTable &symbol_table_arg, const constraints_t &constraints_arg) :
+  symbol_table(symbol_table_arg),
   constraints(constraints_arg)
 {
 }
@@ -608,6 +742,43 @@ RamseyConstraintsStatement::writeOutput(ostream &output, const string &basename,
   output << "};" << endl;
 }
 
+void
+RamseyConstraintsStatement::writeJsonOutput(ostream &output) const
+{
+  deriv_node_temp_terms_t tef_terms;
+  output << "{\"statementName\": \"ramsey_constraints\""
+         << ", \"ramsey_model_constraints\": [" << endl;
+  for (RamseyConstraintsStatement::constraints_t::const_iterator it = constraints.begin(); it != constraints.end(); ++it)
+    {
+      if (it != constraints.begin())
+        output << ", ";
+      output << "{\"constraint\": \"" << symbol_table.getName(it->endo) << " ";
+      switch (it->code)
+        {
+        case oLess:
+          output << '<';
+          break;
+        case oGreater:
+          output << '>';
+          break;
+        case oLessEqual:
+          output << "<=";
+          break;
+        case oGreaterEqual:
+          output << ">=";
+          break;
+        default:
+          cerr << "Ramsey constraints: this shouldn't happen." << endl;
+          exit(1);
+        }
+      output << " ";
+      it->expression->writeJsonOutput(output, temporary_terms_t(), tef_terms);
+      output << "\"}" << endl;
+    }
+  output << "]" << endl;
+  output << "}";
+}
+
 // Statement *
 // RamseyConstraintsStatement::cloneAndReindexSymbIds(DataTree &dynamic_datatree, SymbolTable &orig_symbol_table)
 // {
@@ -752,6 +923,27 @@ RamseyPolicyStatement::writeOutput(ostream &output, const string &basename, bool
          << "ramsey_policy(var_list_);" << endl;
 }
 
+void
+RamseyPolicyStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"ramsey_policy\"";
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+  output << ", \"ramsey_policy_list\": [";
+  for (vector<string>::const_iterator it = ramsey_policy_list.begin();
+       it != ramsey_policy_list.end(); ++it)
+    {
+      if (it != ramsey_policy_list.begin())
+        output << ",";
+      output << "\"" << *it << "\"";
+    }
+  output << "]"
+         << "}";
+}
+
 DiscretionaryPolicyStatement::DiscretionaryPolicyStatement(const SymbolList &symbol_list_arg,
                                                            const OptionsList &options_list_arg) :
   symbol_list(symbol_list_arg),
@@ -812,6 +1004,23 @@ DiscretionaryPolicyStatement::writeOutput(ostream &output, const string &basenam
   output << "discretionary_policy(var_list_);" << endl;
 }
 
+void
+DiscretionaryPolicyStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"discretionary_policy\"";
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+  if (!symbol_list.empty())
+    {
+      output << ", ";
+      symbol_list.writeJsonOutput(output);
+    }
+  output << "}";
+}
+
 EstimationStatement::EstimationStatement(const SymbolList &symbol_list_arg,
                                          const OptionsList &options_list_arg) :
   symbol_list(symbol_list_arg),
@@ -917,6 +1126,23 @@ EstimationStatement::writeOutput(ostream &output, const string &basename, bool m
   output << "oo_recursive_=dynare_estimation(var_list_);" << endl;
 }
 
+void
+EstimationStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"estimation\"";
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+  if (!symbol_list.empty())
+    {
+      output << ", ";
+      symbol_list.writeJsonOutput(output);
+    }
+  output << "}";
+}
+
 DynareSensitivityStatement::DynareSensitivityStatement(const OptionsList &options_list_arg) :
   options_list(options_list_arg)
 {
@@ -953,6 +1179,18 @@ DynareSensitivityStatement::writeOutput(ostream &output, const string &basename,
   output << "dynare_sensitivity(options_gsa);" << endl;
 }
 
+void
+DynareSensitivityStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"dynare_sensitivity\"";
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+  output << "}";
+}
+
 RplotStatement::RplotStatement(const SymbolList &symbol_list_arg) :
   symbol_list(symbol_list_arg)
 {
@@ -965,6 +1203,18 @@ RplotStatement::writeOutput(ostream &output, const string &basename, bool minima
   output << "rplot(var_list_);" << endl;
 }
 
+void
+RplotStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"rplot\"";
+  if (!symbol_list.empty())
+    {
+      output << ", ";
+      symbol_list.writeJsonOutput(output);
+    }
+  output << "}";
+}
+
 UnitRootVarsStatement::UnitRootVarsStatement(void)
 {
 }
@@ -976,6 +1226,14 @@ UnitRootVarsStatement::writeOutput(ostream &output, const string &basename, bool
          << "options_.steadystate.nocheck = 1;" << endl;
 }
 
+void
+UnitRootVarsStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"unit_root_vars\", "
+         << "\"diffuse_filter\": 1, "
+         << "\"steady_state.nocheck\": 1}";
+}
+
 PeriodsStatement::PeriodsStatement(int periods_arg) : periods(periods_arg)
 {
 }
@@ -986,6 +1244,13 @@ PeriodsStatement::writeOutput(ostream &output, const string &basename, bool mini
   output << "options_.periods = " << periods << ";" << endl;
 }
 
+void
+PeriodsStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"periods\", "
+         << "\"periods\": " << periods << "}";
+}
+
 DsampleStatement::DsampleStatement(int val1_arg) : val1(val1_arg), val2(-1)
 {
 }
@@ -1003,6 +1268,14 @@ DsampleStatement::writeOutput(ostream &output, const string &basename, bool mini
     output << "dsample(" << val1 << ", " << val2 << ");" << endl;
 }
 
+void
+DsampleStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"dsample\", "
+         << "\"value1\": " << val1 << ", "
+         << "\"value2\": " << val2 << "}";
+}
+
 EstimatedParamsStatement::EstimatedParamsStatement(const vector<EstimationParams> &estim_params_list_arg,
                                                    const SymbolTable &symbol_table_arg) :
   estim_params_list(estim_params_list_arg),
@@ -1131,6 +1404,55 @@ EstimatedParamsStatement::writeOutput(ostream &output, const string &basename, b
     }
 }
 
+void
+EstimatedParamsStatement::writeJsonOutput(ostream &output) const
+{
+  deriv_node_temp_terms_t tef_terms;
+  output << "{\"statementName\": \"estimated_params\", "
+         << "\"params\": [";
+  for (vector<EstimationParams>::const_iterator it = estim_params_list.begin(); it != estim_params_list.end(); it++)
+    {
+      if (it != estim_params_list.begin())
+        output << ", ";
+      output << "{";
+      switch (it->type)
+        {
+        case 1:
+          output << "\"var\": \"" << it->name << "\"";
+          break;
+        case 2:
+          output << "\"param\": \"" << it->name << "\"";
+          break;
+        case 3:
+          output << "\"var1\": \"" << it->name << "\","
+                 << "\"var2\": \"" << it->name2 << "\"";
+          break;
+        }
+
+      output << ", \"init_val\": \"";
+      it->init_val->writeJsonOutput(output, temporary_terms_t(), tef_terms);
+      output << "\", \"lower_bound\": \"";
+      it->low_bound->writeJsonOutput(output, temporary_terms_t(), tef_terms);
+      output << "\", \"upper_bound\": \"";
+      it->up_bound->writeJsonOutput(output, temporary_terms_t(), tef_terms);
+      output << "\", \"prior_distribution\": "
+             << it->prior
+             << ", \"mean\": \"";
+      it->mean->writeJsonOutput(output, temporary_terms_t(), tef_terms);
+      output << "\", \"std\": \"";
+      it->std->writeJsonOutput(output, temporary_terms_t(), tef_terms);
+      output << "\", \"p3\": \"";
+      it->p3->writeJsonOutput(output, temporary_terms_t(), tef_terms);
+      output << "\", \"p4\": \"";
+      it->p4->writeJsonOutput(output, temporary_terms_t(), tef_terms);
+      output << "\", \"jscale\": \"";
+      it->jscale->writeJsonOutput(output, temporary_terms_t(), tef_terms);
+      output << "\"}" << endl;
+    }
+  output << "]"
+         << "}";
+}
+
 EstimatedParamsInitStatement::EstimatedParamsInitStatement(const vector<EstimationParams> &estim_params_list_arg,
                                                            const SymbolTable &symbol_table_arg,
                                                            const bool use_calibration_arg) :
@@ -1204,6 +1526,42 @@ EstimatedParamsInitStatement::writeOutput(ostream &output, const string &basenam
     }
 }
 
+void
+EstimatedParamsInitStatement::writeJsonOutput(ostream &output) const
+{
+  deriv_node_temp_terms_t tef_terms;
+  output << "{\"statementName\": \"estimated_params_init\"";
+
+  if (use_calibration)
+    output << ", \"use_calibration_initialization\": 1";
+
+  output << ", \"params\": [";
+  for (vector<EstimationParams>::const_iterator it = estim_params_list.begin(); it != estim_params_list.end(); it++)
+    {
+      if (it != estim_params_list.begin())
+        output << ", ";
+      output << "{";
+      switch (it->type)
+        {
+        case 1:
+          output << "\"var\": \"" << it->name << "\"";
+          break;
+        case 2:
+          output << "\"param\": \"" << it->name << "\"";
+          break;
+        case 3:
+          output << "\"var1\": \"" << it->name << "\","
+                 << "\"var2\": \"" << it->name2 << "\"";
+          break;
+        }
+      output << ", \"init_val\": \"";
+      it->init_val->writeJsonOutput(output, temporary_terms_t(), tef_terms);
+      output << "\"}";
+    }
+  output << "]"
+         << "}";
+}
+
 EstimatedParamsBoundsStatement::EstimatedParamsBoundsStatement(const vector<EstimationParams> &estim_params_list_arg,
                                                                const SymbolTable &symbol_table_arg) :
   estim_params_list(estim_params_list_arg),
@@ -1290,6 +1648,40 @@ EstimatedParamsBoundsStatement::writeOutput(ostream &output, const string &basen
     }
 }
 
+void
+EstimatedParamsBoundsStatement::writeJsonOutput(ostream &output) const
+{
+  deriv_node_temp_terms_t tef_terms;
+  output << "{\"statementName\": \"estimated_params_bounds\", "
+         << "\"params\": [";
+
+  for (vector<EstimationParams>::const_iterator it = estim_params_list.begin(); it != estim_params_list.end(); it++)
+    {
+      if (it != estim_params_list.begin())
+        output << ", ";
+      output << "{";
+      switch (it->type)
+        {
+        case 1:
+          output << "\"var\": \"" << it->name << "\"";
+        case 2:
+          output << "\"param\": \"" << it->name << "\"";
+          break;
+        case 3:
+          output << "\"var1\": \"" << it->name << "\","
+                 << "\"var2\": \"" << it->name2 << "\"";
+          break;
+        }
+      output << ", \"lower_bound\": ";
+      it->low_bound->writeJsonOutput(output, temporary_terms_t(), tef_terms);
+      output << ", \"upper_bound\": ";
+      it->up_bound->writeJsonOutput(output, temporary_terms_t(), tef_terms);
+      output << "}";
+    }
+  output << "]"
+         << "}";
+}
+
 ObservationTrendsStatement::ObservationTrendsStatement(const trend_elements_t &trend_elements_arg,
                                                        const SymbolTable &symbol_table_arg) :
   trend_elements(trend_elements_arg),
@@ -1316,6 +1708,32 @@ ObservationTrendsStatement::writeOutput(ostream &output, const string &basename,
     }
 }
 
+void
+ObservationTrendsStatement::writeJsonOutput(ostream &output) const
+{
+  deriv_node_temp_terms_t tef_terms;
+  output << "{\"statementName\": \"observation_trends\", "
+         << "\"trends\" : {";
+  bool printed = false;
+  for (trend_elements_t::const_iterator it = trend_elements.begin();
+       it != trend_elements.end(); it++)
+    {
+      if (symbol_table.getType(it->first) == eEndogenous)
+        {
+          if (printed)
+            output << ", ";
+          output << "\"" << it->first << "\": \"";
+          it->second->writeJsonOutput(output, temporary_terms_t(), tef_terms);
+          output << "\"" << endl;
+          printed = true;
+        }
+      else
+        cerr << "Warning : Non-variable symbol used in observation_trends: " << it->first << endl;
+    }
+  output << "}"
+         << "}";
+}
+
 OsrParamsStatement::OsrParamsStatement(const SymbolList &symbol_list_arg, const SymbolTable &symbol_table_arg) :
   symbol_list(symbol_list_arg),
   symbol_table(symbol_table_arg)
@@ -1342,6 +1760,18 @@ OsrParamsStatement::writeOutput(ostream &output, const string &basename, bool mi
     output << "M_.osr.param_indices(" << ++i <<") = " << symbol_table.getTypeSpecificID(*it) + 1 << ";" << endl;
 }
 
+void
+OsrParamsStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"osr_params\"";
+  if (!symbol_list.empty())
+    {
+      output << ", ";
+      symbol_list.writeJsonOutput(output);
+    }
+  output << "}";
+}
+
 OsrStatement::OsrStatement(const SymbolList &symbol_list_arg,
                            const OptionsList &options_list_arg) :
   symbol_list(symbol_list_arg),
@@ -1381,6 +1811,29 @@ OsrParamsBoundsStatement::writeOutput(ostream &output, const string &basename, b
     }
 }
 
+void
+OsrParamsBoundsStatement::writeJsonOutput(ostream &output) const
+{
+  deriv_node_temp_terms_t tef_terms;
+  output << "{\"statementName\": \"osr_params_bounds\""
+         << ", \"bounds\": [";
+  for (vector<OsrParams>::const_iterator it = osr_params_list.begin();
+       it != osr_params_list.end(); it++)
+    {
+      if (it != osr_params_list.begin())
+        output << ", ";
+      output << "{\"parameter\": \"" << it->name << "\","
+             << "\"bounds\": [\"";
+      it->low_bound->writeJsonOutput(output, temporary_terms_t(), tef_terms);
+      output << "\", \"";
+      it->up_bound->writeJsonOutput(output, temporary_terms_t(), tef_terms);
+      output << "\"]"
+             << "}";
+    }
+  output << "]"
+         << "}";
+}
+
 void
 OsrStatement::checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings)
 {
@@ -1418,6 +1871,23 @@ OsrStatement::writeOutput(ostream &output, const string &basename, bool minimal_
   output << "oo_.osr = osr(var_list_,M_.osr.param_names,M_.osr.variable_indices,M_.osr.variable_weights);" << endl;
 }
 
+void
+OsrStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"osr\"";
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+  if (!symbol_list.empty())
+    {
+      output << ", ";
+      symbol_list.writeJsonOutput(output);
+    }
+  output << "}";
+}
+
 OptimWeightsStatement::OptimWeightsStatement(const var_weights_t &var_weights_arg,
                                              const covar_weights_t &covar_weights_arg,
                                              const SymbolTable &symbol_table_arg) :
@@ -1469,6 +1939,38 @@ OptimWeightsStatement::writeOutput(ostream &output, const string &basename, bool
     }
 }
 
+void
+OptimWeightsStatement::writeJsonOutput(ostream &output) const
+{
+  deriv_node_temp_terms_t tef_terms;
+  output << "{\"statementName\": \"optim_weights\", "
+         << "\"weights\": [";
+  for (var_weights_t::const_iterator it = var_weights.begin();
+       it != var_weights.end(); it++)
+    {
+      if (it != var_weights.begin())
+        output << ", ";
+      output << "{\"name\": \"" << it->first << "\""
+             << ", \"value\": \"";
+      it->second->writeJsonOutput(output, temporary_terms_t(), tef_terms);
+      output << "\"}";
+    }
+
+  for (covar_weights_t::const_iterator it = covar_weights.begin();
+       it != covar_weights.end(); it++)
+    {
+      if (it != covar_weights.begin() || !var_weights.empty())
+        output << ", ";
+      output << "{\"name1\": \"" << it->first.first << "\""
+             << ", \"name2\": \"" << it->first.second << "\""
+             << ", \"value\": \"";
+      it->second->writeJsonOutput(output, temporary_terms_t(), tef_terms);
+      output << "\"}";
+    }
+  output << "]"
+         << "}";
+}
+
 DynaSaveStatement::DynaSaveStatement(const SymbolList &symbol_list_arg,
                                      const string &filename_arg) :
   symbol_list(symbol_list_arg),
@@ -1484,6 +1986,19 @@ DynaSaveStatement::writeOutput(ostream &output, const string &basename, bool min
          << "',var_list_);" << endl;
 }
 
+void
+DynaSaveStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"dynasave\", "
+         << "\"filename\": \"" << filename << "\"";
+  if (!symbol_list.empty())
+    {
+      output << ", ";
+      symbol_list.writeJsonOutput(output);
+    }
+  output << "}";
+}
+
 DynaTypeStatement::DynaTypeStatement(const SymbolList &symbol_list_arg,
                                      const string &filename_arg) :
   symbol_list(symbol_list_arg),
@@ -1499,6 +2014,19 @@ DynaTypeStatement::writeOutput(ostream &output, const string &basename, bool min
          << "',var_list_);" << endl;
 }
 
+void
+DynaTypeStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"dynatype\", "
+         << "\"filename\": \"" << filename << "\"";
+  if (!symbol_list.empty())
+    {
+      output << ", ";
+      symbol_list.writeJsonOutput(output);
+    }
+  output << "}";
+}
+
 ModelComparisonStatement::ModelComparisonStatement(const filename_list_t &filename_list_arg,
                                                    const OptionsList &options_list_arg) :
   filename_list(filename_list_arg),
@@ -1523,8 +2051,37 @@ ModelComparisonStatement::writeOutput(ostream &output, const string &basename, b
   output << "oo_ = model_comparison(ModelNames_,ModelPriors_,oo_,options_,M_.fname);" << endl;
 }
 
+void
+ModelComparisonStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"model_comparison\"";
+  if (!filename_list.empty())
+    output << ", \"filename_list\": {";
+
+  for (filename_list_t::const_iterator it = filename_list.begin();
+       it != filename_list.end(); it++)
+    {
+      if (it != filename_list.begin())
+        output << ", ";
+      output << "\"name\": \"" << it->first << "\""
+             << "\"prior\": \"" << it->second << "\"";
+    }
+
+  if (!filename_list.empty())
+    output << "}";
+
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+
+  output << "}";
+}
+
 PlannerObjectiveStatement::PlannerObjectiveStatement(StaticModel *model_tree_arg) :
-  model_tree(model_tree_arg)
+  model_tree(model_tree_arg),
+  computing_pass_called(false)
 {
 }
 
@@ -1557,6 +2114,7 @@ void
 PlannerObjectiveStatement::computingPass()
 {
   model_tree->computingPass(eval_context_t(), false, true, true, none, false, false);
+  computing_pass_called = true;
 }
 
 void
@@ -1565,6 +2123,19 @@ PlannerObjectiveStatement::writeOutput(ostream &output, const string &basename,
   model_tree->writeStaticFile(basename + "_objective", false, false, false, false);
 }
 
+void
+PlannerObjectiveStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"planner_objective\""
+         << ", ";
+  if (computing_pass_called)
+    model_tree->writeJsonComputingPassOutput(output, false);
+  else
+    model_tree->writeJsonOutput(output);
+
+  output << "}";
+}
+
 BVARDensityStatement::BVARDensityStatement(int maxnlags_arg, const OptionsList &options_list_arg) :
   maxnlags(maxnlags_arg),
   options_list(options_list_arg)
@@ -1584,6 +2155,18 @@ BVARDensityStatement::writeOutput(ostream &output, const string &basename, bool
   output << "bvar_density(" << maxnlags << ");" << endl;
 }
 
+void
+BVARDensityStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"bvar_density\"";
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+  output << "}";
+}
+
 BVARForecastStatement::BVARForecastStatement(int nlags_arg, const OptionsList &options_list_arg) :
   nlags(nlags_arg),
   options_list(options_list_arg)
@@ -1603,6 +2186,18 @@ BVARForecastStatement::writeOutput(ostream &output, const string &basename, bool
   output << "bvar_forecast(" << nlags << ");" << endl;
 }
 
+void
+BVARForecastStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"bvar_forecast\"";
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+  output << "}";
+}
+
 SBVARStatement::SBVARStatement(const OptionsList &options_list_arg) :
   options_list(options_list_arg)
 {
@@ -1621,6 +2216,18 @@ SBVARStatement::writeOutput(ostream &output, const string &basename, bool minima
   output << "sbvar(M_,options_);" << endl;
 }
 
+void
+SBVARStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"sbvar\"";
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+  output << "}";
+}
+
 MSSBVAREstimationStatement::MSSBVAREstimationStatement(const OptionsList &options_list_arg) :
   options_list(options_list_arg)
 {
@@ -1650,6 +2257,18 @@ MSSBVAREstimationStatement::writeOutput(ostream &output, const string &basename,
   output << "[options_, oo_] = ms_estimation(M_, options_, oo_);" << endl;
 }
 
+void
+MSSBVAREstimationStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"ms_sbvar_estimation\"";
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+  output << "}";
+}
+
 MSSBVARSimulationStatement::MSSBVARSimulationStatement(const OptionsList &options_list_arg) :
   options_list(options_list_arg)
 {
@@ -1678,6 +2297,18 @@ MSSBVARSimulationStatement::writeOutput(ostream &output, const string &basename,
   output << "[options_, oo_] = ms_simulation(M_, options_, oo_);" << endl;
 }
 
+void
+MSSBVARSimulationStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"ms_sbvar_simulation\"";
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+  output << "}";
+}
+
 MSSBVARComputeMDDStatement::MSSBVARComputeMDDStatement(const OptionsList &options_list_arg) :
   options_list(options_list_arg)
 {
@@ -1697,6 +2328,18 @@ MSSBVARComputeMDDStatement::writeOutput(ostream &output, const string &basename,
   output << "[options_, oo_] = ms_compute_mdd(M_, options_, oo_);" << endl;
 }
 
+void
+MSSBVARComputeMDDStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"ms_sbvar_compute_mdd\"";
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+  output << "}";
+}
+
 MSSBVARComputeProbabilitiesStatement::MSSBVARComputeProbabilitiesStatement(const OptionsList &options_list_arg) :
   options_list(options_list_arg)
 {
@@ -1724,6 +2367,18 @@ MSSBVARComputeProbabilitiesStatement::writeOutput(ostream &output, const string
   output << "[options_, oo_] = ms_compute_probabilities(M_, options_, oo_);" << endl;
 }
 
+void
+MSSBVARComputeProbabilitiesStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"ms_sbvar_compute_probabilities\"";
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+  output << "}";
+}
+
 MSSBVARIrfStatement::MSSBVARIrfStatement(const SymbolList &symbol_list_arg,
                                          const OptionsList &options_list_arg) :
   symbol_list(symbol_list_arg),
@@ -1771,6 +2426,23 @@ MSSBVARIrfStatement::writeOutput(ostream &output, const string &basename, bool m
   output << "[options_, oo_] = ms_irf(var_list_,M_, options_, oo_);" << endl;
 }
 
+void
+MSSBVARIrfStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"ms_sbvar_irf\"";
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+  if (!symbol_list.empty())
+    {
+      output << ", ";
+      symbol_list.writeJsonOutput(output);
+    }
+  output << "}";
+}
+
 MSSBVARForecastStatement::MSSBVARForecastStatement(const OptionsList &options_list_arg) :
   options_list(options_list_arg)
 {
@@ -1797,6 +2469,18 @@ MSSBVARForecastStatement::writeOutput(ostream &output, const string &basename, b
   output << "[options_, oo_] = ms_forecast(M_, options_, oo_);" << endl;
 }
 
+void
+MSSBVARForecastStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"ms_sbvar_forecast\"";
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+  output << "}";
+}
+
 MSSBVARVarianceDecompositionStatement::MSSBVARVarianceDecompositionStatement(const OptionsList &options_list_arg) :
   options_list(options_list_arg)
 {
@@ -1841,6 +2525,18 @@ MSSBVARVarianceDecompositionStatement::writeOutput(ostream &output, const string
   output << "[options_, oo_] = ms_variance_decomposition(M_, options_, oo_);" << endl;
 }
 
+void
+MSSBVARVarianceDecompositionStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"ms_sbvar_variance_decomposition\"";
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+  output << "}";
+}
+
 IdentificationStatement::IdentificationStatement(const OptionsList &options_list_arg)
 {
   options_list = options_list_arg;
@@ -1880,6 +2576,18 @@ IdentificationStatement::writeOutput(ostream &output, const string &basename, bo
   output << "dynare_identification(options_ident);" << endl;
 }
 
+void
+IdentificationStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"identification\"";
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+  output << "}";
+}
+
 WriteLatexDynamicModelStatement::WriteLatexDynamicModelStatement(const DynamicModel &dynamic_model_arg, bool write_equation_tags_arg) :
   dynamic_model(dynamic_model_arg),
   write_equation_tags(write_equation_tags_arg)
@@ -1892,6 +2600,12 @@ WriteLatexDynamicModelStatement::writeOutput(ostream &output, const string &base
   dynamic_model.writeLatexFile(basename, write_equation_tags);
 }
 
+void
+WriteLatexDynamicModelStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"write_latex_dynamic_model\"}";
+}
+
 WriteLatexStaticModelStatement::WriteLatexStaticModelStatement(const StaticModel &static_model_arg) :
   static_model(static_model_arg)
 {
@@ -1903,6 +2617,12 @@ WriteLatexStaticModelStatement::writeOutput(ostream &output, const string &basen
   static_model.writeLatexFile(basename);
 }
 
+void
+WriteLatexStaticModelStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"write_latex_static_model\"}";
+}
+
 WriteLatexOriginalModelStatement::WriteLatexOriginalModelStatement(const DynamicModel &original_model_arg) :
   original_model(original_model_arg)
 {
@@ -1914,6 +2634,12 @@ WriteLatexOriginalModelStatement::writeOutput(ostream &output, const string &bas
   original_model.writeLatexOriginalFile(basename);
 }
 
+void
+WriteLatexOriginalModelStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"write_latex_original_model\"}";
+}
+
 ShockDecompositionStatement::ShockDecompositionStatement(const SymbolList &symbol_list_arg,
                                                          const OptionsList &options_list_arg) :
   symbol_list(symbol_list_arg),
@@ -1926,7 +2652,24 @@ ShockDecompositionStatement::writeOutput(ostream &output, const string &basename
 {
   options_list.writeOutput(output);
   symbol_list.writeOutput("var_list_", output);
-  output << "[oo_,M_]= shock_decomposition(M_,oo_,options_,var_list_,bayestopt_,estim_params_);" << endl;
+  output << "oo_ = shock_decomposition(M_,oo_,options_,var_list_,bayestopt_,estim_params_);" << endl;
+}
+
+void
+ShockDecompositionStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"shock_decomposition\"";
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+  if (!symbol_list.empty())
+    {
+      output << ", ";
+      symbol_list.writeJsonOutput(output);
+    }
+  output << "}";
 }
 
 RealtimeShockDecompositionStatement::RealtimeShockDecompositionStatement(const SymbolList &symbol_list_arg,
@@ -1988,6 +2731,18 @@ ConditionalForecastStatement::writeOutput(ostream &output, const string &basenam
   output << "imcforecast(constrained_paths_, constrained_vars_, options_cond_fcst_);" << endl;
 }
 
+void
+ConditionalForecastStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"conditional_forecast\"";
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+  output << "}";
+}
+
 PlotConditionalForecastStatement::PlotConditionalForecastStatement(int periods_arg, const SymbolList &symbol_list_arg) :
   periods(periods_arg),
   symbol_list(symbol_list_arg)
@@ -2004,6 +2759,19 @@ PlotConditionalForecastStatement::writeOutput(ostream &output, const string &bas
     output << "plot_icforecast(var_list_, " << periods << ",options_);" << endl;
 }
 
+void
+PlotConditionalForecastStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"plot_conditional_forecast\", "
+         << "\"periods\": " << periods;
+  if (!symbol_list.empty())
+    {
+      output << ", ";
+      symbol_list.writeJsonOutput(output);
+    }
+  output << "}";
+}
+
 SvarIdentificationStatement::SvarIdentificationStatement(const svar_identification_restrictions_t &restrictions_arg,
                                                          const bool &upper_cholesky_present_arg,
                                                          const bool &lower_cholesky_present_arg,
@@ -2114,6 +2882,42 @@ SvarIdentificationStatement::writeOutput(ostream &output, const string &basename
     }
 }
 
+void
+SvarIdentificationStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"svar_identification\"";
+
+  if (upper_cholesky_present)
+    output << ", \"upper_cholesky\": 1";
+
+  if (lower_cholesky_present)
+    output << ", \"lower_cholesky\": 1";
+
+  if (constants_exclusion_present)
+    output << ", \"constants_exclusion\": 1";
+
+  if (!upper_cholesky_present && !lower_cholesky_present)
+    {
+      output << ", \"nlags\": " << getMaxLag()
+             << ", \"restrictions\": [";
+
+      for (svar_identification_restrictions_t::const_iterator it = restrictions.begin(); it != restrictions.end(); it++)
+        {
+          if (it != restrictions.begin())
+            output << ", ";
+          output << "{"
+                 << "\"equation_number\": " << it->equation << ", "
+                 << "\"restriction_number\": " << it->restriction_nbr << ", "
+                 << "\"variable\": \"" << symbol_table.getName(it->variable) << "\", "
+                 << "\"expression\": \"";
+          it->value->writeOutput(output);
+          output << "\"}";
+        }
+      output << "]";
+    }
+  output << "}";
+}
+
 MarkovSwitchingStatement::MarkovSwitchingStatement(const OptionsList &options_list_arg) :
   options_list(options_list_arg)
 {
@@ -2353,6 +3157,33 @@ MarkovSwitchingStatement::writeCOutput(ostream &output, const string &basename)
          << "     chain, number_of_regimes, number_of_lags, number_of_lags_was_passed, parameters, duration, restriction_map));" << endl;
 }
 
+void
+MarkovSwitchingStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"markov_switching\"";
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+
+  if (!restriction_map.empty())
+    output << ", {";
+  for (map<pair<int, int>, double >::const_iterator it = restriction_map.begin();
+       it != restriction_map.end(); it++)
+    {
+      if (it != restriction_map.begin())
+        output << ", ";
+      output << "{\"current_period_regime\": " << it->first.first
+             << ", \"next_period_regime\": " << it->first.second
+             << ", \"transition_probability\": "<< it->second
+             << "}";
+    }
+  if (!restriction_map.empty())
+    output << "}";
+  output << "}";
+}
+
 SvarStatement::SvarStatement(const OptionsList &options_list_arg) :
   options_list(options_list_arg)
 {
@@ -2417,6 +3248,18 @@ SvarStatement::writeOutput(ostream &output, const string &basename, bool minimal
     output << "'ALL';" << endl;
 }
 
+void
+SvarStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"svar\"";
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+  output << "}";
+}
+
 SvarGlobalIdentificationCheckStatement::SvarGlobalIdentificationCheckStatement(void)
 {
 }
@@ -2427,6 +3270,12 @@ SvarGlobalIdentificationCheckStatement::writeOutput(ostream &output, const strin
   output << "svar_global_identification_check(options_);" << std::endl;
 }
 
+void
+SvarGlobalIdentificationCheckStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"svar_global_identification\"}";
+}
+
 SetTimeStatement::SetTimeStatement(const OptionsList &options_list_arg) :
   options_list(options_list_arg)
 {
@@ -2438,6 +3287,18 @@ SetTimeStatement::writeOutput(ostream &output, const string &basename, bool mini
   options_list.writeOutput(output);
 }
 
+void
+SetTimeStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"set_time\"";
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+  output << "}";
+}
+
 EstimationDataStatement::EstimationDataStatement(const OptionsList &options_list_arg) :
   options_list(options_list_arg)
 {
@@ -2477,6 +3338,18 @@ EstimationDataStatement::writeOutput(ostream &output, const string &basename, bo
   options_list.writeOutput(output, "options_.dataset");
 }
 
+void
+EstimationDataStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"estimation_data\"";
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+  output << "}";
+}
+
 SubsamplesStatement::SubsamplesStatement(const string &name1_arg,
                                          const string &name2_arg,
                                          const subsample_declaration_map_t subsample_declaration_map_arg,
@@ -2550,6 +3423,30 @@ SubsamplesStatement::writeOutput(ostream &output, const string &basename, bool m
          << endl;
 }
 
+void
+SubsamplesStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"subsamples\""
+         << ", \"name1\": \"" << name1 << "\"";
+  if (!name2.empty())
+    output << ", \"name2\": \"" << name2 << "\"";
+
+  output << ", \"declarations\": {";
+  for (subsample_declaration_map_t::const_iterator it = subsample_declaration_map.begin();
+       it != subsample_declaration_map.end(); it++)
+    {
+      if (it != subsample_declaration_map.begin())
+        output << ",";
+      output << "{"
+             << "\"range_index\": \"" << it->first << "\""
+             << ", \"date1\": \"" << it->second.first << "\""
+             << ", \"date2\": \"" << it->second.second << "\""
+             << "}";
+    }
+  output << "}"
+         << "}";
+}
+
 SubsamplesEqualStatement::SubsamplesEqualStatement(const string &to_name1_arg,
                                                    const string &to_name2_arg,
                                                    const string &from_name1_arg,
@@ -2612,6 +3509,19 @@ SubsamplesEqualStatement::writeOutput(ostream &output, const string &basename, b
          << endl;
 }
 
+void
+SubsamplesEqualStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"subsamples_equal\""
+         << ", \"to_name1\": \"" << to_name1 << "\"";
+  if (!to_name2.empty())
+    output << ", \"to_name2\": \"" << to_name2 << "\"";
+  output << ", \"from_name1\": \"" << from_name1 << "\"";
+  if (!from_name2.empty())
+    output << ", \"from_name2\": \"" << from_name2 << "\"";
+  output << "}";
+}
+
 JointPriorStatement::JointPriorStatement(const vector<string> joint_parameters_arg,
                                          const PriorDistributions &prior_shape_arg,
                                          const OptionsList &options_list_arg) :
@@ -2718,6 +3628,59 @@ JointPriorStatement::writeOutputHelper(ostream &output, const string &field, con
   output << "};" << endl;
 }
 
+void
+JointPriorStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"joint_prior\""
+         << ", \"key\": [";
+  for (vector<string>::const_iterator it = joint_parameters.begin(); it != joint_parameters.end(); it++)
+    {
+      if (it != joint_parameters.begin())
+        output << ", ";
+      output << "\"" << *it << "\"";
+    }
+  output << "]";
+
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+
+  output << ", \"shape\": ";
+  switch (prior_shape)
+    {
+    case eBeta:
+      output << "\"beta\"";
+      break;
+    case eGamma:
+      output << "\"gamma\"";
+      break;
+    case eNormal:
+      output << "\"normal\"";
+      break;
+    case eInvGamma:
+      output << "\"inv_gamma\"";
+      break;
+    case eUniform:
+      output << "\"uniform\"";
+      break;
+    case eInvGamma2:
+      output << "\"inv_gamma2\"";
+      break;
+    case eDirichlet:
+      output << "\"dirichlet\"";
+      break;
+    case eWeibull:
+      output << "\"weibull\"";
+      break;
+    case eNoShape:
+      cerr << "Impossible case." << endl;
+      exit(EXIT_FAILURE);
+    }
+  output << "}";
+}
+
 BasicPriorStatement::~BasicPriorStatement()
 {
 }
@@ -2838,6 +3801,27 @@ BasicPriorStatement::writePriorOutput(ostream &output, string &lhs_field, const
   writeCommonOutput(output, lhs_field);
 }
 
+void
+BasicPriorStatement::writeJsonPriorOutput(ostream &output) const
+{
+  output << ", \"name\": \"" << name << "\""
+         << ", \"subsample\": \"" << subsample_name << "\""
+         << ", ";
+  writeJsonShape(output);
+  if (variance != NULL)
+    {
+      deriv_node_temp_terms_t tef_terms;
+      output << ", \"variance\": \"";
+      variance->writeJsonOutput(output, temporary_terms_t(), tef_terms);
+      output << "\"";
+    }
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+}
+
 void
 BasicPriorStatement::writeCVarianceOption(ostream &output) const
 {
@@ -2911,6 +3895,41 @@ BasicPriorStatement::writeCShape(ostream &output) const
     }
 }
 
+void
+BasicPriorStatement::writeJsonShape(ostream &output) const
+{
+  output << "\"shape\": ";
+  switch (prior_shape)
+    {
+    case eBeta:
+      output << "\"beta\"";
+      break;
+    case eGamma:
+      output << "\"gamma\"";
+      break;
+    case eNormal:
+      output << "\"normal\"";
+      break;
+    case eInvGamma:
+      output << "\"inv_gamma\"";
+      break;
+    case eUniform:
+      output << "\"uniform\"";
+      break;
+    case eInvGamma2:
+      output << "\"inv_gamma2\"";
+      break;
+    case eDirichlet:
+      output << "\"dirichlet\"";
+      break;
+    case eWeibull:
+      output << "\"weibull\"";
+      break;
+    case eNoShape:
+      assert(prior_shape != eNoShape);
+    }
+}
+
 PriorStatement::PriorStatement(const string &name_arg,
                                const string &subsample_name_arg,
                                const PriorDistributions &prior_shape_arg,
@@ -2930,6 +3949,14 @@ PriorStatement::writeOutput(ostream &output, const string &basename, bool minima
   writePriorOutput(output, lhs_field, "");
 }
 
+void
+PriorStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"prior\"";
+  writeJsonPriorOutput(output);
+  output << "}";
+}
+
 void
 PriorStatement::writeCOutput(ostream &output, const string &basename)
 {
@@ -2970,6 +3997,14 @@ StdPriorStatement::writeOutput(ostream &output, const string &basename, bool min
   writePriorOutput(output, lhs_field, "");
 }
 
+void
+StdPriorStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"std_prior\"";
+  writeJsonPriorOutput(output);
+  output << "}";
+}
+
 void
 StdPriorStatement::writeCOutput(ostream &output, const string &basename)
 {
@@ -3035,6 +4070,15 @@ CorrPriorStatement::writeOutput(ostream &output, const string &basename, bool mi
   writePriorOutput(output, lhs_field, name1);
 }
 
+void
+CorrPriorStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"corr_prior\""
+         << ", \"name2\": \"" << name1 << "\"";
+  writeJsonPriorOutput(output);
+  output << "}";
+}
+
 void
 CorrPriorStatement::writeCOutput(ostream &output, const string &basename)
 {
@@ -3169,6 +4213,21 @@ PriorEqualStatement::writeOutput(ostream &output, const string &basename, bool m
   output << lhs_field << " = " << rhs_field << ";" << endl;
 }
 
+void
+PriorEqualStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"prior_equal\""
+         << ", \"to_name1\": \"" << to_name1 << "\"";
+  if (to_declaration_type == "corr")
+    output << ", \"to_name2\": \"" << to_name2 << "\"";
+  output << ", \"to_subsample\": \"" << to_subsample_name << "\""
+         << ", \"from_name1\": \"" << from_name1 << "\"";
+  if (to_declaration_type == "corr")
+    output << ", \"from_name2\": \"" << from_name2 << "\"";
+  output << ", \"from_subsample\": \"" << from_subsample_name << "\""
+         << "}";
+}
+
 BasicOptionsStatement::~BasicOptionsStatement()
 {
 }
@@ -3246,6 +4305,19 @@ BasicOptionsStatement::writeOptionsOutput(ostream &output, string &lhs_field, co
   writeCommonOutput(output, lhs_field);
 }
 
+void
+BasicOptionsStatement::writeJsonOptionsOutput(ostream &output) const
+{
+  output << ", \"name\": \"" << name << "\"";
+  if (!subsample_name.empty())
+    output << ", \"subsample_name\": \"" << subsample_name << "\"";
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+}
+
 OptionsStatement::OptionsStatement(const string &name_arg,
                                    const string &subsample_name_arg,
                                    const OptionsList &options_list_arg) :
@@ -3263,6 +4335,14 @@ OptionsStatement::writeOutput(ostream &output, const string &basename, bool mini
   writeOptionsOutput(output, lhs_field, "");
 }
 
+void
+OptionsStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"options\"";
+  writeJsonOptionsOutput(output);
+  output << "}";
+}
+
 void
 OptionsStatement::writeCOutput(ostream &output, const string &basename)
 {
@@ -3294,6 +4374,14 @@ StdOptionsStatement::writeOutput(ostream &output, const string &basename, bool m
   writeOptionsOutput(output, lhs_field, "");
 }
 
+void
+StdOptionsStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"std_options\"";
+  writeJsonOptionsOutput(output);
+  output << "}";
+}
+
 void
 StdOptionsStatement::writeCOutput(ostream &output, const string &basename)
 {
@@ -3351,6 +4439,15 @@ CorrOptionsStatement::writeOutput(ostream &output, const string &basename, bool
   writeOptionsOutput(output, lhs_field, name1);
 }
 
+void
+CorrOptionsStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"corr_options\""
+         << ", \"name2\": \"" << name1 << "\"";
+  writeJsonOptionsOutput(output);
+  output << "}";
+}
+
 void
 CorrOptionsStatement::writeCOutput(ostream &output, const string &basename)
 {
@@ -3410,6 +4507,21 @@ OptionsEqualStatement::checkPass(ModFileStructure &mod_file_struct, WarningConso
     }
 }
 
+void
+OptionsEqualStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"options_equal\""
+         << ", \"to_name1\": \"" << to_name1 << "\"";
+  if (to_declaration_type == "corr")
+    output << ", \"to_name2\": \"" << to_name2 << "\"";
+  output << ", \"to_subsample\": \"" << to_subsample_name << "\""
+         << ", \"from_name1\": \"" << from_name1 << "\"";
+  if (to_declaration_type == "corr")
+    output << ", \"from_name2\": \"" << from_name2 << "\"";
+  output << ", \"from_subsample\": \"" << from_subsample_name << "\""
+         << "}";
+}
+
 void
 OptionsEqualStatement::get_base_name(const SymbolType symb_type, string &lhs_field) const
 {
@@ -3502,6 +4614,23 @@ CalibSmootherStatement::writeOutput(ostream &output, const string &basename, boo
   output << "[oo_,M_,options_,bayestopt_]=evaluate_smoother('calibration',var_list_,M_,oo_,options_,bayestopt_,estim_params_);" << endl;
 }
 
+void
+CalibSmootherStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"calib_smoother\"";
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+  if (!symbol_list.empty())
+    {
+      output << ", ";
+      symbol_list.writeJsonOutput(output);
+    }
+  output << "}";
+}
+
 ExtendedPathStatement::ExtendedPathStatement(const OptionsList &options_list_arg)
   : options_list(options_list_arg)
 {
@@ -3538,6 +4667,18 @@ ExtendedPathStatement::writeOutput(ostream &output, const string &basename, bool
          << ", [], options_, M_, oo_);" << endl;
 }
 
+void
+ExtendedPathStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"extended_path\"";
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+  output << "}";
+}
+
 ModelDiagnosticsStatement::ModelDiagnosticsStatement()
 {
 }
@@ -3548,6 +4689,12 @@ ModelDiagnosticsStatement::writeOutput(ostream &output, const string &basename,
   output << "model_diagnostics(M_,options_,oo_);" << endl;
 }
 
+void
+ModelDiagnosticsStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"model_diagnostics\"}";
+}
+
 Smoother2histvalStatement::Smoother2histvalStatement(const OptionsList &options_list_arg) :
   options_list(options_list_arg)
 {
@@ -3559,3 +4706,15 @@ Smoother2histvalStatement::writeOutput(ostream &output, const string &basename,
   options_list.writeOutput(output, "options_smoother2histval");
   output << "smoother2histval(options_smoother2histval);" << endl;
 }
+
+void
+Smoother2histvalStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"smoother_2_histval\"";
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+  output << "}";
+}
diff --git a/ComputingTasks.hh b/ComputingTasks.hh
index 0291cc9e5c4fcee1bb9b73ea3802cf03fb4dca55..4fdd125643058e5d152fcf58cd497405dee5ca32 100644
--- a/ComputingTasks.hh
+++ b/ComputingTasks.hh
@@ -36,6 +36,7 @@ public:
   SteadyStatement(const OptionsList &options_list_arg);
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class CheckStatement : public Statement
@@ -46,6 +47,7 @@ public:
   CheckStatement(const OptionsList &options_list_arg);
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class SimulStatement : public Statement
@@ -56,6 +58,7 @@ public:
   SimulStatement(const OptionsList &options_list_arg);
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class PerfectForesightSetupStatement : public Statement
@@ -65,6 +68,7 @@ private:
 public:
   PerfectForesightSetupStatement(const OptionsList &options_list_arg);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class PerfectForesightSolverStatement : public Statement
@@ -75,6 +79,7 @@ public:
   PerfectForesightSolverStatement(const OptionsList &options_list_arg);
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class PriorPosteriorFunctionStatement : public Statement
@@ -86,6 +91,7 @@ public:
   PriorPosteriorFunctionStatement(const bool prior_func_arg, const OptionsList &options_list_arg);
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class ModelInfoStatement : public Statement
@@ -96,6 +102,7 @@ public:
   ModelInfoStatement(const OptionsList &options_list_arg);
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class StochSimulStatement : public Statement
@@ -108,6 +115,7 @@ public:
                       const OptionsList &options_list_arg);
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class VarModelStatement : public Statement
@@ -172,6 +180,7 @@ public:
   ForecastStatement(const SymbolList &symbol_list_arg,
                     const OptionsList &options_list_arg);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class RamseyModelStatement : public Statement
@@ -184,6 +193,7 @@ public:
                        const OptionsList &options_list_arg);
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class RamseyConstraintsStatement : public Statement
@@ -197,11 +207,13 @@ public:
   };
   typedef vector<Constraint> constraints_t;
 private:
+  const SymbolTable &symbol_table;
   const constraints_t constraints;
 public:
-  RamseyConstraintsStatement(const constraints_t &constraints_arg);
+  RamseyConstraintsStatement(const SymbolTable &symbol_table_arg, const constraints_t &constraints_arg);
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
   //  virtual Statement *cloneAndReindexSymbIds(DataTree &dynamic_datatree, SymbolTable &orig_symbol_table);
 };
 
@@ -218,6 +230,7 @@ public:
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   void checkRamseyPolicyList();
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class DiscretionaryPolicyStatement : public Statement
@@ -230,6 +243,7 @@ public:
                                const OptionsList &options_list_arg);
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class RplotStatement : public Statement
@@ -239,6 +253,7 @@ private:
 public:
   RplotStatement(const SymbolList &symbol_list_arg);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class UnitRootVarsStatement : public Statement
@@ -246,6 +261,7 @@ class UnitRootVarsStatement : public Statement
 public:
   UnitRootVarsStatement(void);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class PeriodsStatement : public Statement
@@ -255,6 +271,7 @@ private:
 public:
   PeriodsStatement(int periods_arg);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class DsampleStatement : public Statement
@@ -265,6 +282,7 @@ public:
   DsampleStatement(int val1_arg);
   DsampleStatement(int val1_arg, int val2_arg);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class EstimationStatement : public Statement
@@ -277,6 +295,7 @@ public:
                       const OptionsList &options_list_arg);
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class DynareSensitivityStatement : public Statement
@@ -287,6 +306,7 @@ public:
   DynareSensitivityStatement(const OptionsList &options_list_arg);
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class ObservationTrendsStatement : public Statement
@@ -300,6 +320,7 @@ public:
   ObservationTrendsStatement(const trend_elements_t &trend_elements_arg,
                              const SymbolTable &symbol_table_arg);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class OsrParamsStatement : public Statement
@@ -311,6 +332,7 @@ public:
   OsrParamsStatement(const SymbolList &symbol_list_arg, const SymbolTable &symbol_table_arg);
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class OsrStatement : public Statement
@@ -323,6 +345,7 @@ public:
                const OptionsList &options_list_arg);
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 //! Temporary structure used when parsing estimation_params* statements
@@ -349,6 +372,7 @@ public:
   OsrParamsBoundsStatement(const vector<OsrParams> &osr_params_list_arg);
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class DynaTypeStatement : public Statement
@@ -360,6 +384,7 @@ public:
   DynaTypeStatement(const SymbolList &symbol_list_arg,
                     const string &filename_arg);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class DynaSaveStatement : public Statement
@@ -371,6 +396,7 @@ public:
   DynaSaveStatement(const SymbolList &symbol_list_arg,
                     const string &filename_arg);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class ModelComparisonStatement : public Statement
@@ -384,6 +410,7 @@ public:
   ModelComparisonStatement(const filename_list_t &filename_list_arg,
                            const OptionsList &options_list_arg);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 //! Temporary structure used when parsing estimation_params* statements
@@ -423,6 +450,7 @@ public:
                            const SymbolTable &symbol_table_arg);
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class EstimatedParamsInitStatement : public Statement
@@ -437,6 +465,7 @@ public:
                                const bool use_calibration_arg);
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class EstimatedParamsBoundsStatement : public Statement
@@ -448,6 +477,7 @@ public:
   EstimatedParamsBoundsStatement(const vector<EstimationParams> &estim_params_list_arg,
                                  const SymbolTable &symbol_table_arg);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class OptimWeightsStatement : public Statement
@@ -465,6 +495,7 @@ public:
                         const SymbolTable &symbol_table_arg);
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 /*! \todo Make model_tree a member instead of a pointer */
@@ -472,6 +503,7 @@ class PlannerObjectiveStatement : public Statement
 {
 private:
   StaticModel *model_tree;
+  bool computing_pass_called;
 public:
   //! Constructor
   /*! \param model_tree_arg the model tree used to store the objective function.
@@ -485,6 +517,7 @@ public:
   /*! \todo allow for the possibility of disabling temporary terms */
   virtual void computingPass();
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
   //! Return the Planner Objective
   StaticModel *getPlannerObjective() const;
 };
@@ -498,6 +531,7 @@ public:
   BVARDensityStatement(int maxnlags_arg, const OptionsList &options_list_arg);
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class BVARForecastStatement : public Statement
@@ -509,6 +543,7 @@ public:
   BVARForecastStatement(int nlags_arg, const OptionsList &options_list_arg);
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class SBVARStatement : public Statement
@@ -519,6 +554,7 @@ public:
   SBVARStatement(const OptionsList &options_list_arg);
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class MSSBVAREstimationStatement : public Statement
@@ -529,6 +565,7 @@ public:
   MSSBVAREstimationStatement(const OptionsList &options_list_arg);
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class MSSBVARSimulationStatement : public Statement
@@ -539,6 +576,7 @@ public:
   MSSBVARSimulationStatement(const OptionsList &options_list_arg);
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class MSSBVARComputeMDDStatement : public Statement
@@ -549,6 +587,7 @@ public:
   MSSBVARComputeMDDStatement(const OptionsList &options_list_arg);
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class MSSBVARComputeProbabilitiesStatement : public Statement
@@ -559,6 +598,7 @@ public:
   MSSBVARComputeProbabilitiesStatement(const OptionsList &options_list_arg);
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class MSSBVARIrfStatement : public Statement
@@ -571,6 +611,7 @@ public:
                       const OptionsList &options_list_arg);
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class MSSBVARForecastStatement : public Statement
@@ -581,6 +622,7 @@ public:
   MSSBVARForecastStatement(const OptionsList &options_list_arg);
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class MSSBVARVarianceDecompositionStatement : public Statement
@@ -591,6 +633,7 @@ public:
   MSSBVARVarianceDecompositionStatement(const OptionsList &options_list_arg);
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class IdentificationStatement : public Statement
@@ -601,6 +644,7 @@ public:
   IdentificationStatement(const OptionsList &options_list_arg);
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class WriteLatexDynamicModelStatement : public Statement
@@ -611,6 +655,7 @@ private:
 public:
   WriteLatexDynamicModelStatement(const DynamicModel &dynamic_model_arg, bool write_equation_tags_arg);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class WriteLatexStaticModelStatement : public Statement
@@ -620,6 +665,7 @@ private:
 public:
   WriteLatexStaticModelStatement(const StaticModel &static_model_arg);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class WriteLatexOriginalModelStatement : public Statement
@@ -629,6 +675,7 @@ private:
 public:
   WriteLatexOriginalModelStatement(const DynamicModel &original_model_arg);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class ShockDecompositionStatement : public Statement
@@ -640,6 +687,7 @@ public:
   ShockDecompositionStatement(const SymbolList &symbol_list_arg,
                               const OptionsList &options_list_arg);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class RealtimeShockDecompositionStatement : public Statement
@@ -682,6 +730,7 @@ private:
 public:
   ConditionalForecastStatement(const OptionsList &options_list_arg);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class PlotConditionalForecastStatement : public Statement
@@ -693,6 +742,7 @@ private:
 public:
   PlotConditionalForecastStatement(int periods_arg, const SymbolList &symbol_list_arg);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class CalibSmootherStatement : public Statement
@@ -705,6 +755,7 @@ public:
                          const OptionsList &options_list_arg);
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class ExtendedPathStatement : public Statement
@@ -715,6 +766,7 @@ public:
   ExtendedPathStatement(const OptionsList &options_list_arg);
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class SvarIdentificationStatement : public Statement
@@ -746,6 +798,7 @@ public:
                               const SymbolTable &symbol_table_arg);
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class MarkovSwitchingStatement : public Statement
@@ -758,6 +811,7 @@ public:
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
   virtual void writeCOutput(ostream &output, const string &basename);
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class SvarStatement : public Statement
@@ -768,6 +822,7 @@ public:
   SvarStatement(const OptionsList &options_list_arg);
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class SvarGlobalIdentificationCheckStatement : public Statement
@@ -775,6 +830,7 @@ class SvarGlobalIdentificationCheckStatement : public Statement
 public:
   SvarGlobalIdentificationCheckStatement();
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class SetTimeStatement : public Statement
@@ -784,6 +840,7 @@ private:
 public:
   SetTimeStatement(const OptionsList &options_list_arg);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class EstimationDataStatement : public Statement
@@ -794,6 +851,7 @@ public:
   EstimationDataStatement(const OptionsList &options_list_arg);
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class SubsamplesStatement : public Statement
@@ -813,6 +871,7 @@ public:
                       const SymbolTable &symbol_table_arg);
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class SubsamplesEqualStatement : public Statement
@@ -830,6 +889,7 @@ public:
                            const string &from_name2_arg,
                            const SymbolTable &symbol_table_arg);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class JointPriorStatement : public Statement
@@ -845,6 +905,7 @@ public:
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
   void writeOutputHelper(ostream &output, const string &field, const string &lhs_field) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class BasicPriorStatement : public Statement
@@ -877,6 +938,8 @@ protected:
   void writeCShape(ostream &output) const;
   void writeCVarianceOption(ostream &output) const;
   void writeCDomain(ostream &output) const;
+  void writeJsonShape(ostream &output) const;
+  void writeJsonPriorOutput(ostream &output) const;
 };
 
 class PriorStatement : public BasicPriorStatement
@@ -889,6 +952,7 @@ public:
                  const OptionsList &options_list_arg);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
   virtual void writeCOutput(ostream &output, const string &basename);
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class StdPriorStatement : public BasicPriorStatement
@@ -904,6 +968,7 @@ public:
                     const SymbolTable &symbol_table_arg);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
   virtual void writeCOutput(ostream &output, const string &basename);
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class CorrPriorStatement : public BasicPriorStatement
@@ -922,6 +987,7 @@ public:
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
   virtual void writeCOutput(ostream &output, const string &basename);
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class PriorEqualStatement : public Statement
@@ -949,6 +1015,7 @@ public:
   void get_base_name(const SymbolType symb_type, string &lhs_field) const;
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class BasicOptionsStatement : public Statement
@@ -972,6 +1039,7 @@ protected:
   void writeOptionsIndex(ostream &output, const string &lhs_field) const;
   void writeOutputHelper(ostream &output, const string &field, const string &lhs_field) const;
   void writeCOutputHelper(ostream &output, const string &field) const;
+  void writeJsonOptionsOutput(ostream &output) const;
 };
 
 class OptionsStatement : public BasicOptionsStatement
@@ -980,6 +1048,7 @@ public:
   OptionsStatement(const string &name_arg, const string &subsample_name_arg, const OptionsList &options_list_arg);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
   virtual void writeCOutput(ostream &output, const string &basename);
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class StdOptionsStatement : public BasicOptionsStatement
@@ -993,6 +1062,7 @@ public:
                       const SymbolTable &symbol_table_arg);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
   virtual void writeCOutput(ostream &output, const string &basename);
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class CorrOptionsStatement : public BasicOptionsStatement
@@ -1008,6 +1078,7 @@ public:
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
   virtual void writeCOutput(ostream &output, const string &basename);
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class OptionsEqualStatement : public Statement
@@ -1035,6 +1106,7 @@ public:
   void get_base_name(const SymbolType symb_type, string &lhs_field) const;
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class ModelDiagnosticsStatement : public Statement
@@ -1042,6 +1114,7 @@ class ModelDiagnosticsStatement : public Statement
 public:
   ModelDiagnosticsStatement();
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class Smoother2histvalStatement : public Statement
@@ -1051,6 +1124,7 @@ private:
 public:
   Smoother2histvalStatement(const OptionsList &options_list_arg);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 #endif
diff --git a/DynamicModel.cc b/DynamicModel.cc
index 7bce38a28e45add287626d3007cf0877e85367b0..a4c0e16223436487d94b0e4124ea342fee78f286 100644
--- a/DynamicModel.cc
+++ b/DynamicModel.cc
@@ -5544,3 +5544,470 @@ DynamicModel::writeCCOutput(ostream &output, const string &basename, bool block_
     output << "NNZDerivatives.push_back(-1);" << endl
            << "NNZDerivatives.push_back(-1);" << endl;
 }
+
+void
+DynamicModel::writeJsonOutput(ostream &output) const
+{
+  writeJsonModelEquations(output, false);
+  output << ", ";
+  writeJsonXrefs(output);
+}
+
+void
+DynamicModel::writeJsonXrefs(ostream &output) const
+{
+  output << "\"xrefs\": {"
+         << "\"parameters\": [";
+  for (map<pair<int, int>, set<int> >::const_iterator it = xref_param.begin();
+       it != xref_param.end(); it++)
+    {
+      if (it != xref_param.begin())
+        output << ", ";
+      output << "{\"parameter\": \"" << symbol_table.getName(it->first.first) << "\""
+             << ", \"equations\": [";
+      for (set<int>::const_iterator it1 = it->second.begin();
+           it1 != it->second.end(); it1++)
+        {
+          if (it1 != it->second.begin())
+            output << ", ";
+          output << *it1 + 1;
+        }
+      output << "]}";
+    }
+  output << "]"
+         << ", \"endogenous\": [";
+  for (map<pair<int, int>, set<int> >::const_iterator it = xref_endo.begin();
+       it != xref_endo.end(); it++)
+    {
+      if (it != xref_endo.begin())
+        output << ", ";
+      output << "{\"endogenous\": \"" << symbol_table.getName(it->first.first) << "\""
+             << ", \"shift\": " << it->first.second
+             << ", \"equations\": [";
+      for (set<int>::const_iterator it1 = it->second.begin();
+           it1 != it->second.end(); it1++)
+        {
+          if (it1 != it->second.begin())
+            output << ", ";
+          output << *it1 + 1;
+        }
+      output << "]}";
+    }
+  output << "]"
+         << ", \"exogenous\": [";
+  for (map<pair<int, int>, set<int> >::const_iterator it = xref_exo.begin();
+       it != xref_exo.end(); it++)
+    {
+      if (it != xref_exo.begin())
+        output << ", ";
+      output << "{\"exogenous\": \"" << symbol_table.getName(it->first.first) << "\""
+             << ", \"shift\": " << it->first.second
+             << ", \"equations\": [";
+      for (set<int>::const_iterator it1 = it->second.begin();
+           it1 != it->second.end(); it1++)
+        {
+          if (it1 != it->second.begin())
+            output << ", ";
+          output << *it1 + 1;
+        }
+      output << "]}";
+    }
+  output << "]"
+         << ", \"exogenous_deterministic\": [";
+  for (map<pair<int, int>, set<int> >::const_iterator it = xref_exo_det.begin();
+       it != xref_exo_det.end(); it++)
+    {
+      if (it != xref_exo_det.begin())
+        output << ", ";
+      output << "{\"exogenous_det\": \"" << symbol_table.getName(it->first.first) << "\""
+             << ", \"shift\": " << it->first.second
+             << ", \"equations\": [";
+      for (set<int>::const_iterator it1 = it->second.begin();
+           it1 != it->second.end(); it1++)
+        {
+          if (it1 != it->second.begin())
+            output << ", ";
+          output << *it1 + 1;
+        }
+      output << "]}";
+    }
+  output << "]}" << endl;
+}
+
+void
+DynamicModel::writeJsonComputingPassOutput(ostream &output, bool writeDetails) const
+{
+  ostringstream model_local_vars_output;  // Used for storing model local vars
+  ostringstream model_output;             // Used for storing model temp vars and equations
+  ostringstream jacobian_output;          // Used for storing jacobian equations
+  ostringstream hessian_output;           // Used for storing Hessian equations
+  ostringstream third_derivatives_output; // Used for storing third order derivatives equations
+
+  deriv_node_temp_terms_t tef_terms;
+  temporary_terms_t temp_term_empty;
+  temporary_terms_t temp_term_union = temporary_terms_res;
+  temporary_terms_t temp_term_union_m_1;
+
+  string concat = "";
+  int hessianColsNbr = dynJacobianColsNbr * dynJacobianColsNbr;
+
+  writeJsonModelLocalVariables(model_local_vars_output, tef_terms);
+
+  writeJsonTemporaryTerms(temporary_terms_res, temp_term_union_m_1, model_output, tef_terms, concat);
+  model_output << ", ";
+  writeJsonModelEquations(model_output, true);
+
+  // Writing Jacobian
+  temp_term_union_m_1 = temp_term_union;
+  temp_term_union.insert(temporary_terms_g1.begin(), temporary_terms_g1.end());
+  concat = "jacobian";
+  writeJsonTemporaryTerms(temp_term_union, temp_term_union_m_1, jacobian_output, tef_terms, concat);
+  jacobian_output << ", \"jacobian\": {"
+                  << "  \"nrows\": " << equations.size()
+                  << ", \"ncols\": " << dynJacobianColsNbr
+                  << ", \"entries\": [";
+  for (first_derivatives_t::const_iterator it = first_derivatives.begin();
+       it != first_derivatives.end(); it++)
+    {
+      if (it != first_derivatives.begin())
+        jacobian_output << ", ";
+
+      int eq = it->first.first;
+      int var = it->first.second;
+      int col =  getDynJacobianCol(var);
+      expr_t d1 = it->second;
+
+      if (writeDetails)
+        jacobian_output << "{\"eq\": " << eq + 1
+                        << ", \"var\": \"" << symbol_table.getName(getSymbIDByDerivID(var)) << "\""
+                        << ", \"lag\": " << getLagByDerivID(var);
+      else
+        jacobian_output << "{\"row\": " << eq + 1;
+      jacobian_output << ", \"col\": " << col + 1
+                      << ", \"val\": \"";
+      d1->writeJsonOutput(jacobian_output, temp_term_union, tef_terms);
+      jacobian_output << "\"}" << endl;
+    }
+  jacobian_output << "]}";
+
+  // Writing Hessian
+  temp_term_union_m_1 = temp_term_union;
+  temp_term_union.insert(temporary_terms_g2.begin(), temporary_terms_g2.end());
+  concat = "hessian";
+  writeJsonTemporaryTerms(temp_term_union, temp_term_union_m_1, hessian_output, tef_terms, concat);
+  hessian_output << ", \"hessian\": {"
+                 << "  \"nrows\": " << equations.size()
+                 << ", \"ncols\": " << hessianColsNbr
+                 << ", \"entries\": [";
+  for (second_derivatives_t::const_iterator it = second_derivatives.begin();
+       it != second_derivatives.end(); it++)
+    {
+      if (it != second_derivatives.begin())
+        hessian_output << ", ";
+
+      int eq = it->first.first;
+      int var1 = it->first.second.first;
+      int var2 = it->first.second.second;
+      expr_t d2 = it->second;
+      int id1 = getDynJacobianCol(var1);
+      int id2 = getDynJacobianCol(var2);
+      int col_nb = id1 * dynJacobianColsNbr + id2;
+      int col_nb_sym = id2 * dynJacobianColsNbr + id1;
+
+      if (writeDetails)
+        hessian_output << "{\"eq\": " << eq + 1
+                       << ", \"var1\": \"" << symbol_table.getName(getSymbIDByDerivID(var1)) << "\""
+                       << ", \"lag1\": " << getLagByDerivID(var1)
+                       << ", \"var2\": \"" << symbol_table.getName(getSymbIDByDerivID(var2)) << "\""
+                       << ", \"lag2\": " << getLagByDerivID(var2);
+      else
+        hessian_output << "{\"row\": " << eq + 1;
+
+      hessian_output << ", \"col\": [" << col_nb + 1;
+      if (id1 != id2)
+        hessian_output << ", " << col_nb_sym + 1;
+      hessian_output << "]"
+                     << ", \"val\": \"";
+      d2->writeJsonOutput(hessian_output, temp_term_union, tef_terms);
+      hessian_output << "\"}" << endl;
+    }
+  hessian_output << "]}";
+
+  // Writing third derivatives
+  temp_term_union_m_1 = temp_term_union;
+  temp_term_union.insert(temporary_terms_g3.begin(), temporary_terms_g3.end());
+  concat = "third_derivatives";
+  writeJsonTemporaryTerms(temp_term_union, temp_term_union_m_1, third_derivatives_output, tef_terms, concat);
+  third_derivatives_output << ", \"third_derivative\": {"
+                           << "  \"nrows\": " << equations.size()
+                           << ", \"ncols\": " << hessianColsNbr * dynJacobianColsNbr
+                           << ", \"entries\": [";
+  for (third_derivatives_t::const_iterator it = third_derivatives.begin();
+       it != third_derivatives.end(); it++)
+    {
+      if (it != third_derivatives.begin())
+        third_derivatives_output << ", ";
+
+      int eq = it->first.first;
+      int var1 = it->first.second.first;
+      int var2 = it->first.second.second.first;
+      int var3 = it->first.second.second.second;
+      expr_t d3 = it->second;
+
+      if (writeDetails)
+        third_derivatives_output << "{\"eq\": " << eq + 1
+                                 << ", \"var1\": \"" << symbol_table.getName(getSymbIDByDerivID(var1)) << "\""
+                                 << ", \"lag1\": " << getLagByDerivID(var1)
+                                 << ", \"var2\": \"" << symbol_table.getName(getSymbIDByDerivID(var2)) << "\""
+                                 << ", \"lag2\": " << getLagByDerivID(var2)
+                                 << ", \"var3\": \"" << symbol_table.getName(getSymbIDByDerivID(var3)) << "\""
+                                 << ", \"lag3\": " << getLagByDerivID(var3);
+      else
+        third_derivatives_output << "{\"row\": " << eq + 1;
+
+      int id1 = getDynJacobianCol(var1);
+      int id2 = getDynJacobianCol(var2);
+      int id3 = getDynJacobianCol(var3);
+      set<int> cols;
+      cols.insert(id1 * hessianColsNbr + id2 * dynJacobianColsNbr + id3);
+      cols.insert(id1 * hessianColsNbr + id3 * dynJacobianColsNbr + id2);
+      cols.insert(id2 * hessianColsNbr + id1 * dynJacobianColsNbr + id3);
+      cols.insert(id2 * hessianColsNbr + id3 * dynJacobianColsNbr + id1);
+      cols.insert(id3 * hessianColsNbr + id1 * dynJacobianColsNbr + id2);
+      cols.insert(id3 * hessianColsNbr + id2 * dynJacobianColsNbr + id1);
+
+      third_derivatives_output << ", \"col\": [";
+      for (set<int>::iterator it2 = cols.begin(); it2 != cols.end(); it2++)
+        {
+          if (it2 != cols.begin())
+            third_derivatives_output << ", ";
+          third_derivatives_output << *it2 + 1;
+        }
+      third_derivatives_output << "]"
+                               << ", \"val\": \"";
+      d3->writeJsonOutput(third_derivatives_output, temp_term_union, tef_terms);
+      third_derivatives_output << "\"}" << endl;
+    }
+  third_derivatives_output << "]}";
+
+  if (writeDetails)
+    output << "\"dynamic_model_derivative_details\": {";
+  else
+    output << "\"dynamic_model_derivatives\": {";
+  output << model_local_vars_output.str()
+         << ", " << model_output.str()
+         << ", " << jacobian_output.str()
+         << ", " << hessian_output.str()
+         << ", " << third_derivatives_output.str()
+         << "}";
+}
+
+void
+DynamicModel::writeJsonParamsDerivativesFile(ostream &output, bool writeDetails) const
+{
+  if (!residuals_params_derivatives.size()
+      && !residuals_params_second_derivatives.size()
+      && !jacobian_params_derivatives.size()
+      && !jacobian_params_second_derivatives.size()
+      && !hessian_params_derivatives.size())
+    return;
+
+  ostringstream model_local_vars_output;   // Used for storing model local vars
+  ostringstream model_output;              // Used for storing model temp vars and equations
+  ostringstream jacobian_output;           // Used for storing jacobian equations
+  ostringstream hessian_output;            // Used for storing Hessian equations
+  ostringstream hessian1_output;           // Used for storing Hessian equations
+  ostringstream third_derivs_output;       // Used for storing third order derivatives equations
+  ostringstream third_derivs1_output;      // Used for storing third order derivatives equations
+
+  deriv_node_temp_terms_t tef_terms;
+  writeJsonModelLocalVariables(model_local_vars_output, tef_terms);
+
+  temporary_terms_t temp_terms_empty;
+  string concat = "all";
+  writeJsonTemporaryTerms(params_derivs_temporary_terms, temp_terms_empty, model_output, tef_terms, concat);
+  jacobian_output << "\"deriv_wrt_params\": {"
+                  << "  \"neqs\": " << equations.size()
+                  << ", \"nparamcols\": " << symbol_table.param_nbr()
+                  << ", \"entries\": [";
+  for (first_derivatives_t::const_iterator it = residuals_params_derivatives.begin();
+       it != residuals_params_derivatives.end(); it++)
+    {
+      if (it != residuals_params_derivatives.begin())
+        jacobian_output << ", ";
+
+      int eq = it->first.first;
+      int param = it->first.second;
+      expr_t d1 = it->second;
+
+      int param_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param)) + 1;
+
+      if (writeDetails)
+        jacobian_output << "{\"eq\": " << eq + 1
+                        << ", \"param\": \"" << symbol_table.getName(getSymbIDByDerivID(param)) << "\"";
+      else
+        jacobian_output << "{\"row\": " << eq + 1;
+      jacobian_output << ", \"param_col\": " << param_col + 1
+                      << ", \"val\": \"";
+      d1->writeJsonOutput(jacobian_output, params_derivs_temporary_terms, tef_terms);
+      jacobian_output << "\"}" << endl;
+    }
+  jacobian_output << "]}";
+  hessian_output << "\"deriv_jacobian_wrt_params\": {"
+                 << "  \"neqs\": " << equations.size()
+                 << ", \"nvarcols\": " << dynJacobianColsNbr
+                 << ", \"nparamcols\": " << symbol_table.param_nbr()
+                 << ", \"entries\": [";
+  for (second_derivatives_t::const_iterator it = jacobian_params_derivatives.begin();
+       it != jacobian_params_derivatives.end(); it++)
+    {
+      if (it != jacobian_params_derivatives.begin())
+        hessian_output << ", ";
+
+      int eq = it->first.first;
+      int var = it->first.second.first;
+      int param = it->first.second.second;
+      expr_t d2 = it->second;
+
+      int var_col = getDynJacobianCol(var) + 1;
+      int param_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param)) + 1;
+
+      if (writeDetails)
+        hessian_output << "{\"eq\": " << eq + 1
+                       << ", \"var\": \"" << symbol_table.getName(getSymbIDByDerivID(var)) << "\""
+                       << ", \"lag\": " << getLagByDerivID(var)
+                       << ", \"param\": \"" << symbol_table.getName(getSymbIDByDerivID(param)) << "\"";
+      else
+        hessian_output << "{\"row\": " << eq + 1;
+      hessian_output << ", \"var_col\": " << var_col + 1
+                     << ", \"param_col\": " << param_col + 1
+                     << ", \"val\": \"";
+      d2->writeJsonOutput(hessian_output, params_derivs_temporary_terms, tef_terms);
+      hessian_output << "\"}" << endl;
+    }
+  hessian_output << "]}";
+
+  hessian1_output << "\"second_deriv_residuals_wrt_params\": {"
+                  << "  \"nrows\": " << equations.size()
+                  << ", \"nparam1cols\": " << symbol_table.param_nbr()
+                  << ", \"nparam2cols\": " << symbol_table.param_nbr()
+                  << ", \"entries\": [";
+  for (second_derivatives_t::const_iterator it = residuals_params_second_derivatives.begin();
+       it != residuals_params_second_derivatives.end(); ++it)
+    {
+      if (it != residuals_params_second_derivatives.begin())
+        hessian1_output << ", ";
+
+      int eq = it->first.first;
+      int param1 = it->first.second.first;
+      int param2 = it->first.second.second;
+      expr_t d2 = it->second;
+
+      int param1_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param1)) + 1;
+      int param2_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param2)) + 1;
+
+      if (writeDetails)
+        hessian1_output << "{\"eq\": " << eq + 1
+                        << ", \"param1\": \"" << symbol_table.getName(getSymbIDByDerivID(param1)) << "\""
+                        << ", \"param2\": \"" << symbol_table.getName(getSymbIDByDerivID(param2)) << "\"";
+      else
+        hessian1_output << "{\"row\": " << eq + 1;
+      hessian1_output << ", \"param1_col\": " << param1_col + 1
+                      << ", \"param2_col\": " << param2_col + 1
+                      << ", \"val\": \"";
+      d2->writeJsonOutput(hessian1_output, params_derivs_temporary_terms, tef_terms);
+      hessian1_output << "\"}" << endl;
+    }
+  hessian1_output << "]}";
+  third_derivs_output << "\"second_deriv_jacobian_wrt_params\": {"
+                      << "  \"neqs\": " << equations.size()
+                      << ", \"nvarcols\": " << dynJacobianColsNbr
+                      << ", \"nparam1cols\": " << symbol_table.param_nbr()
+                      << ", \"nparam2cols\": " << symbol_table.param_nbr()
+                      << ", \"entries\": [";
+  for (third_derivatives_t::const_iterator it = jacobian_params_second_derivatives.begin();
+       it != jacobian_params_second_derivatives.end(); ++it)
+    {
+      if (it != jacobian_params_second_derivatives.begin())
+        third_derivs_output << ", ";
+
+      int eq = it->first.first;
+      int var = it->first.second.first;
+      int param1 = it->first.second.second.first;
+      int param2 = it->first.second.second.second;
+      expr_t d2 = it->second;
+
+      int var_col = getDynJacobianCol(var) + 1;
+      int param1_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param1)) + 1;
+      int param2_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param2)) + 1;
+
+      if (writeDetails)
+        third_derivs_output << "{\"eq\": " << eq + 1
+                            << ", \"var\": \"" << symbol_table.getName(var) << "\""
+                            << ", \"lag\": " << getLagByDerivID(var)
+                            << ", \"param1\": \"" << symbol_table.getName(getSymbIDByDerivID(param1)) << "\""
+                            << ", \"param2\": \"" << symbol_table.getName(getSymbIDByDerivID(param2)) << "\"";
+      else
+        third_derivs_output << "{\"row\": " << eq + 1;
+      third_derivs_output << ", \"var_col\": " << var_col + 1
+                          << ", \"param1_col\": " << param1_col + 1
+                          << ", \"param2_col\": " << param2_col + 1
+                          << ", \"val\": \"";
+      d2->writeJsonOutput(third_derivs_output, params_derivs_temporary_terms, tef_terms);
+      third_derivs_output << "\"}" << endl;
+    }
+  third_derivs_output << "]}" << endl;
+
+  third_derivs1_output << "\"derivative_hessian_wrt_params\": {"
+                       << "  \"neqs\": " << equations.size()
+                       << ", \"nvar1cols\": " << dynJacobianColsNbr
+                       << ", \"nvar2cols\": " << dynJacobianColsNbr
+                       << ", \"nparamcols\": " << symbol_table.param_nbr()
+                       << ", \"entries\": [";
+  for (third_derivatives_t::const_iterator it = hessian_params_derivatives.begin();
+       it != hessian_params_derivatives.end(); ++it)
+    {
+      if (it != hessian_params_derivatives.begin())
+        third_derivs1_output << ", ";
+
+      int eq = it->first.first;
+      int var1 = it->first.second.first;
+      int var2 = it->first.second.second.first;
+      int param = it->first.second.second.second;
+      expr_t d2 = it->second;
+
+      int var1_col = getDynJacobianCol(var1) + 1;
+      int var2_col = getDynJacobianCol(var2) + 1;
+      int param_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param)) + 1;
+
+      if (writeDetails)
+        third_derivs1_output << "{\"eq\": " << eq + 1
+                             << ", \"var1\": \"" << symbol_table.getName(getSymbIDByDerivID(var1)) << "\""
+                             << ", \"lag1\": " << getLagByDerivID(var1)
+                             << ", \"var2\": \"" << symbol_table.getName(getSymbIDByDerivID(var2)) << "\""
+                             << ", \"lag2\": " << getLagByDerivID(var2)
+                             << ", \"param\": \"" << symbol_table.getName(getSymbIDByDerivID(param)) << "\"";
+      else
+        third_derivs1_output << "{\"row\": " << eq + 1;
+      third_derivs1_output << ", \"var1_col\": " << var1_col + 1
+                           << ", \"var2_col\": " << var2_col + 1
+                           << ", \"param_col\": " << param_col + 1
+                           << ", \"val\": \"";
+      d2->writeJsonOutput(third_derivs1_output, params_derivs_temporary_terms, tef_terms);
+      third_derivs1_output << "\"}" << endl;
+    }
+  third_derivs1_output << "]}" << endl;
+
+  if (writeDetails)
+    output << "\"dynamic_model_params_derivative_details\": {";
+  else
+    output << "\"dynamic_model_params_derivatives\": {";
+  output << model_local_vars_output.str()
+         << ", " << model_output.str()
+         << ", " << jacobian_output.str()
+         << ", " << hessian_output.str()
+         << ", " << hessian1_output.str()
+         << ", " << third_derivs_output.str()
+         << ", " << third_derivs1_output.str()
+         << "}";
+}
diff --git a/DynamicModel.hh b/DynamicModel.hh
index 7c742f41d6a3f692c27e7a5d3dd19748ee5f4171..fa7e68c4f9617227c11199ab188c1ad446cd5cf2 100644
--- a/DynamicModel.hh
+++ b/DynamicModel.hh
@@ -241,6 +241,18 @@ public:
   //! Writes model initialization and lead/lag incidence matrix to output
   void writeOutput(ostream &output, const string &basename, bool block, bool byte_code, bool use_dll, int order, bool estimation_present, bool compute_xrefs, bool julia) const;
 
+  //! Write JSON Output
+  void writeJsonOutput(ostream &output) const;
+
+  //! Write JSON Output representation of dynamic model after computing pass
+  void writeJsonComputingPassOutput(ostream &output, bool writeDetails) const;
+
+  //! Write JSON prams derivatives file
+  void writeJsonParamsDerivativesFile(ostream &output, bool writeDetails) const;
+
+  //! Write cross reference output if the xref maps have been filed
+  void writeJsonXrefs(ostream &output) const;
+
   //! Return true if the hessian is equal to zero
   inline bool checkHessianZero() const;
 
diff --git a/DynareBison.yy b/DynareBison.yy
index 06b7db9dab354fe99e42733926a167b0342ba4a6..d95f77d3cf275b5e30fda0cc08cbacf9613c92f8 100644
--- a/DynareBison.yy
+++ b/DynareBison.yy
@@ -3518,7 +3518,7 @@ o_use_shock_groups : USE_SHOCK_GROUPS { driver.option_str("use_shock_groups","de
 o_psd_use_shock_groups : USE_SHOCK_GROUPS { driver.option_str("plot_shock_decomp.use_shock_groups","default"); }
                        | USE_SHOCK_GROUPS EQUAL symbol { driver.option_str("plot_shock_decomp.use_shock_groups", $3); }
                        ;
-o_colormap : COLORMAP EQUAL symbol { driver.option_num("colormap",$3); };
+o_colormap : COLORMAP EQUAL symbol { driver.option_num("plot_shock_decomp.colormap",$3); };
 o_psd_colormap : COLORMAP EQUAL symbol { driver.option_num("plot_shock_decomp.colormap",$3); };
 
 range : symbol ':' symbol
diff --git a/DynareMain.cc b/DynareMain.cc
index 887cf28188637c58ad8f17eb20a3b94c944b71e1..14d594c49757b644263369beedb198c0c4fd2aa2 100644
--- a/DynareMain.cc
+++ b/DynareMain.cc
@@ -45,6 +45,7 @@ void main2(stringstream &in, string &basename, bool debug, bool clear_all, bool
 #if defined(_WIN32) || defined(__CYGWIN32__) || defined(__MINGW32__)
            , bool cygwin, bool msvc, bool mingw
 #endif
+           , JsonOutputPointType json, JsonFileOutputType json_output_mode, bool onlyjson, bool jsonprintderivdetail
            );
 
 void main1(char *modfile, string &basename, bool debug, bool save_macro, string &save_macro_file,
@@ -61,6 +62,7 @@ usage()
 #if defined(_WIN32) || defined(__CYGWIN32__) || defined(__MINGW32__)
        << " [cygwin] [msvc] [mingw]"
 #endif
+       << "[json=parse|check|transform|compute] [jsonstdout] [onlyjson] [jsonprintderivdetail]"
        << endl;
   exit(EXIT_FAILURE);
 }
@@ -113,6 +115,10 @@ main(int argc, char **argv)
   map<string, string> defines;
   vector<string> path;
   FileOutputType output_mode = none;
+  JsonOutputPointType json = nojson;
+  JsonFileOutputType json_output_mode = file;
+  bool onlyjson = false;
+  bool jsonprintderivdetail = false;
   LanguageOutputType language = matlab;
 
   // Parse options
@@ -291,6 +297,33 @@ main(int argc, char **argv)
                 }
             }
         }
+      else if (!strcmp(argv[arg], "jsonstdout"))
+        json_output_mode = standardout;
+      else if (!strcmp(argv[arg], "onlyjson"))
+        onlyjson = true;
+      else if (!strcmp(argv[arg], "jsonprintderivdetail"))
+        jsonprintderivdetail = true;
+      else if (strlen(argv[arg]) >= 4 && !strncmp(argv[arg], "json", 4))
+        {
+          if (strlen(argv[arg]) <= 5 || argv[arg][4] != '=')
+            {
+              cerr << "Incorrect syntax for json option" << endl;
+              usage();
+            }
+          if (strlen(argv[arg]) == 10 && !strncmp(argv[arg] + 5, "parse", 5))
+            json = parsing;
+          else if (strlen(argv[arg]) ==  10 && !strncmp(argv[arg] + 5, "check", 5))
+            json = checkpass;
+          else if (strlen(argv[arg]) == 14 && !strncmp(argv[arg] + 5, "transform", 9))
+            json = transformpass;
+          else if (strlen(argv[arg]) == 12 && !strncmp(argv[arg] + 5, "compute", 7))
+            json = computingpass;
+          else
+            {
+              cerr << "Incorrect syntax for json option" << endl;
+              usage();
+            }
+        }
       else
         {
           cerr << "Unknown option: " << argv[arg] << endl;
@@ -337,6 +370,7 @@ main(int argc, char **argv)
 #if defined(_WIN32) || defined(__CYGWIN32__) || defined(__MINGW32__)
         , cygwin, msvc, mingw
 #endif
+        , json, json_output_mode, onlyjson, jsonprintderivdetail
         );
 
   return EXIT_SUCCESS;
diff --git a/DynareMain2.cc b/DynareMain2.cc
index dc9420ca0a6a12f6b6b1f709cc173847ccc91d76..758b278fa280ef3a1a9c8573d34d7419df9644c1 100644
--- a/DynareMain2.cc
+++ b/DynareMain2.cc
@@ -34,24 +34,33 @@ main2(stringstream &in, string &basename, bool debug, bool clear_all, bool clear
 #if defined(_WIN32) || defined(__CYGWIN32__) || defined(__MINGW32__)
       , bool cygwin, bool msvc, bool mingw
 #endif
+      , JsonOutputPointType json, JsonFileOutputType json_output_mode, bool onlyjson, bool jsonprintderivdetail
       )
 {
   ParsingDriver p(warnings, nostrict);
 
   // Do parsing and construct internal representation of mod file
   ModFile *mod_file = p.parse(in, debug);
+  if (json == parsing)
+    mod_file->writeJsonOutput(basename, json, json_output_mode, onlyjson);
 
   // Run checking pass
   mod_file->checkPass(nostrict);
+  if (json == checkpass)
+    mod_file->writeJsonOutput(basename, json, json_output_mode, onlyjson);
 
   // Perform transformations on the model (creation of auxiliary vars and equations)
-  mod_file->transformPass(nostrict, compute_xrefs);
+  mod_file->transformPass(nostrict, compute_xrefs || json == transformpass);
+  if (json == transformpass)
+    mod_file->writeJsonOutput(basename, json, json_output_mode, onlyjson);
 
   // Evaluate parameters initialization, initval, endval and pounds
   mod_file->evalAllExpressions(warn_uninit);
 
   // Do computations
   mod_file->computingPass(no_tmp_terms, output_mode, params_derivs_order);
+  if (json == computingpass)
+    mod_file->writeJsonOutput(basename, json, json_output_mode, onlyjson, jsonprintderivdetail);
 
   // Write outputs
   if (output_mode != none)
diff --git a/ExprNode.cc b/ExprNode.cc
index 7fcd58fcfe9352c363c06459cfabd1a7df9314e7..c2d2a518c6d736c2ffbaaf1ff89b8f407859b03f 100644
--- a/ExprNode.cc
+++ b/ExprNode.cc
@@ -73,6 +73,13 @@ ExprNode::precedence(ExprNodeOutputType output_type, const temporary_terms_t &te
   return 100;
 }
 
+int
+ExprNode::precedenceJson(const temporary_terms_t &temporary_terms) const
+{
+  // For a constant, a variable, or a unary op, the precedence is maximal
+  return 100;
+}
+
 int
 ExprNode::cost(int cost, bool is_matlab) const
 {
@@ -185,6 +192,14 @@ ExprNode::writeExternalFunctionOutput(ostream &output, ExprNodeOutputType output
   // Nothing to do
 }
 
+void
+ExprNode::writeJsonExternalFunctionOutput(vector<string> &efout,
+                                          const temporary_terms_t &temporary_terms,
+                                          deriv_node_temp_terms_t &tef_terms) const
+{
+  // Nothing to do
+}
+
 void
 ExprNode::compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number,
                                         bool lhs_rhs, const temporary_terms_t &temporary_terms,
@@ -327,6 +342,14 @@ NumConstNode::writeOutput(ostream &output, ExprNodeOutputType output_type,
     output << datatree.num_constants.get(id);
 }
 
+void
+NumConstNode::writeJsonOutput(ostream &output,
+                              const temporary_terms_t &temporary_terms,
+                              deriv_node_temp_terms_t &tef_terms) const
+{
+  output << datatree.num_constants.get(id);
+}
+
 bool
 NumConstNode::containsExternalFunction() const
 {
@@ -643,6 +666,23 @@ VariableNode::containsExternalFunction() const
   return false;
 }
 
+void
+VariableNode::writeJsonOutput(ostream &output,
+                              const temporary_terms_t &temporary_terms,
+                              deriv_node_temp_terms_t &tef_terms) const
+{
+  temporary_terms_t::const_iterator it = temporary_terms.find(const_cast<VariableNode *>(this));
+  if (it != temporary_terms.end())
+    {
+      output << "T" << idx;
+      return;
+    }
+
+  output << datatree.symbol_table.getName(symb_id);
+  if (lag != 0)
+    output << "(" << lag << ")";
+}
+
 void
 VariableNode::writeOutput(ostream &output, ExprNodeOutputType output_type,
                           const temporary_terms_t &temporary_terms,
@@ -1918,6 +1958,147 @@ UnaryOpNode::containsExternalFunction() const
   return arg->containsExternalFunction();
 }
 
+void
+UnaryOpNode::writeJsonOutput(ostream &output,
+                             const temporary_terms_t &temporary_terms,
+                             deriv_node_temp_terms_t &tef_terms) const
+{
+  temporary_terms_t::const_iterator it = temporary_terms.find(const_cast<UnaryOpNode *>(this));
+  if (it != temporary_terms.end())
+    {
+      output << "T" << idx;
+      return;
+    }
+
+  // Always put parenthesis around uminus nodes
+  if (op_code == oUminus)
+    output << "(";
+
+  switch (op_code)
+    {
+    case oUminus:
+      output << "-";
+      break;
+    case oExp:
+      output << "exp";
+      break;
+    case oLog:
+      output << "log";
+      break;
+    case oLog10:
+      output << "log10";
+      break;
+    case oCos:
+      output << "cos";
+      break;
+    case oSin:
+      output << "sin";
+      break;
+    case oTan:
+      output << "tan";
+      break;
+    case oAcos:
+      output << "acos";
+      break;
+    case oAsin:
+      output << "asin";
+      break;
+    case oAtan:
+      output << "atan";
+      break;
+    case oCosh:
+      output << "cosh";
+      break;
+    case oSinh:
+      output << "sinh";
+      break;
+    case oTanh:
+      output << "tanh";
+      break;
+    case oAcosh:
+      output << "acosh";
+      break;
+    case oAsinh:
+      output << "asinh";
+      break;
+    case oAtanh:
+      output << "atanh";
+      break;
+    case oSqrt:
+      output << "sqrt";
+      break;
+    case oAbs:
+      output << "abs";
+      break;
+    case oSign:
+      output << "sign";
+      break;
+    case oDiff:
+      output << "diff";
+      break;
+    case oSteadyState:
+      output << "(";
+      arg->writeJsonOutput(output, temporary_terms, tef_terms);
+      output << ")";
+      return;
+    case oSteadyStateParamDeriv:
+      {
+        VariableNode *varg = dynamic_cast<VariableNode *>(arg);
+        assert(varg != NULL);
+        assert(datatree.symbol_table.getType(varg->symb_id) == eEndogenous);
+        assert(datatree.symbol_table.getType(param1_symb_id) == eParameter);
+        int tsid_endo = datatree.symbol_table.getTypeSpecificID(varg->symb_id);
+        int tsid_param = datatree.symbol_table.getTypeSpecificID(param1_symb_id);
+        output << "ss_param_deriv(" << tsid_endo+1 << "," << tsid_param+1 << ")";
+      }
+      return;
+    case oSteadyStateParam2ndDeriv:
+      {
+        VariableNode *varg = dynamic_cast<VariableNode *>(arg);
+        assert(varg != NULL);
+        assert(datatree.symbol_table.getType(varg->symb_id) == eEndogenous);
+        assert(datatree.symbol_table.getType(param1_symb_id) == eParameter);
+        assert(datatree.symbol_table.getType(param2_symb_id) == eParameter);
+        int tsid_endo = datatree.symbol_table.getTypeSpecificID(varg->symb_id);
+        int tsid_param1 = datatree.symbol_table.getTypeSpecificID(param1_symb_id);
+        int tsid_param2 = datatree.symbol_table.getTypeSpecificID(param2_symb_id);
+        output << "ss_param_2nd_deriv(" << tsid_endo+1 << "," << tsid_param1+1
+               << "," << tsid_param2+1 << ")";
+      }
+      return;
+    case oExpectation:
+      output << "EXPECTATION(" << expectation_information_set << ")";
+      break;
+    case oErf:
+      output << "erf";
+      break;
+    }
+
+  bool close_parenthesis = false;
+
+  /* Enclose argument with parentheses if:
+     - current opcode is not uminus, or
+     - current opcode is uminus and argument has lowest precedence
+  */
+  if (op_code != oUminus
+      || (op_code == oUminus
+          && arg->precedenceJson(temporary_terms) < precedenceJson(temporary_terms)))
+    {
+      output << "(";
+      close_parenthesis = true;
+    }
+
+  // Write argument
+  arg->writeJsonOutput(output, temporary_terms, tef_terms);
+
+  if (close_parenthesis)
+    output << ")";
+
+  // Close parenthesis for uminus
+  if (op_code == oUminus)
+    output << ")";
+}
+
 void
 UnaryOpNode::writeOutput(ostream &output, ExprNodeOutputType output_type,
                          const temporary_terms_t &temporary_terms,
@@ -2115,6 +2296,14 @@ UnaryOpNode::writeExternalFunctionOutput(ostream &output, ExprNodeOutputType out
   arg->writeExternalFunctionOutput(output, output_type, temporary_terms, tef_terms);
 }
 
+void
+UnaryOpNode::writeJsonExternalFunctionOutput(vector<string> &efout,
+                                             const temporary_terms_t &temporary_terms,
+                                             deriv_node_temp_terms_t &tef_terms) const
+{
+  arg->writeJsonExternalFunctionOutput(efout, temporary_terms, tef_terms);
+}
+
 void
 UnaryOpNode::compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number,
                                            bool lhs_rhs, const temporary_terms_t &temporary_terms,
@@ -2923,6 +3112,44 @@ BinaryOpNode::precedence(ExprNodeOutputType output_type, const temporary_terms_t
   exit(EXIT_FAILURE);
 }
 
+int
+BinaryOpNode::precedenceJson(const temporary_terms_t &temporary_terms) const
+{
+  temporary_terms_t::const_iterator it = temporary_terms.find(const_cast<BinaryOpNode *>(this));
+  // A temporary term behaves as a variable
+  if (it != temporary_terms.end())
+    return 100;
+
+  switch (op_code)
+    {
+    case oEqual:
+      return 0;
+    case oEqualEqual:
+    case oDifferent:
+      return 1;
+    case oLessEqual:
+    case oGreaterEqual:
+    case oLess:
+    case oGreater:
+      return 2;
+    case oPlus:
+    case oMinus:
+      return 3;
+    case oTimes:
+    case oDivide:
+      return 4;
+    case oPower:
+    case oPowerDeriv:
+      return 5;
+    case oMin:
+    case oMax:
+    case oAdl:
+      return 100;
+    }
+  // Suppress GCC warning
+  exit(EXIT_FAILURE);
+}
+
 int
 BinaryOpNode::cost(const map<NodeTreeReference, temporary_terms_t> &temp_terms_map, bool is_matlab) const
 {
@@ -3194,6 +3421,127 @@ BinaryOpNode::containsExternalFunction() const
     || arg2->containsExternalFunction();
 }
 
+void
+BinaryOpNode::writeJsonOutput(ostream &output,
+                              const temporary_terms_t &temporary_terms,
+                              deriv_node_temp_terms_t &tef_terms) const
+{
+  // If current node is a temporary term
+  temporary_terms_t::const_iterator it = temporary_terms.find(const_cast<BinaryOpNode *>(this));
+  if (it != temporary_terms.end())
+    {
+      output << "T" << idx;
+      return;
+    }
+
+  if (op_code == oMax || op_code == oMin)
+    {
+      switch (op_code)
+        {
+        case oMax:
+          output << "max(";
+          break;
+        case oMin:
+          output << "min(";
+          break;
+        default:
+          ;
+        }
+      arg1->writeJsonOutput(output, temporary_terms, tef_terms);
+      output << ",";
+      arg2->writeJsonOutput(output, temporary_terms, tef_terms);
+      output << ")";
+      return;
+    }
+
+  int prec = precedenceJson(temporary_terms);
+
+  bool close_parenthesis = false;
+
+  // If left argument has a lower precedence, or if current and left argument are both power operators,
+  // add parenthesis around left argument
+  BinaryOpNode *barg1 = dynamic_cast<BinaryOpNode *>(arg1);
+  if (arg1->precedenceJson(temporary_terms) < prec
+      || (op_code == oPower && barg1 != NULL && barg1->op_code == oPower))
+    {
+      output << "(";
+      close_parenthesis = true;
+    }
+
+  // Write left argument
+  arg1->writeJsonOutput(output, temporary_terms, tef_terms);
+
+  if (close_parenthesis)
+    output << ")";
+
+  // Write current operator symbol
+  switch (op_code)
+    {
+    case oPlus:
+      output << "+";
+      break;
+    case oMinus:
+      output << "-";
+      break;
+    case oTimes:
+      output << "*";
+      break;
+    case oDivide:
+      output << "/";
+      break;
+    case oPower:
+      output << "^";
+      break;
+    case oLess:
+      output << "<";
+      break;
+    case oGreater:
+      output << ">";
+      break;
+    case oLessEqual:
+      output << "<=";
+      break;
+    case oGreaterEqual:
+      output << ">=";
+      break;
+    case oEqualEqual:
+      output << "==";
+      break;
+    case oDifferent:
+      output << "!=";
+      break;
+    case oEqual:
+      output << "=";
+      break;
+    default:
+      ;
+    }
+
+  close_parenthesis = false;
+
+  /* Add parenthesis around right argument if:
+     - its precedence is lower than those of the current node
+     - it is a power operator and current operator is also a power operator
+     - it is a minus operator with same precedence than current operator
+     - it is a divide operator with same precedence than current operator */
+  BinaryOpNode *barg2 = dynamic_cast<BinaryOpNode *>(arg2);
+  int arg2_prec = arg2->precedenceJson(temporary_terms);
+  if (arg2_prec < prec
+      || (op_code == oPower && barg2 != NULL && barg2->op_code == oPower)
+      || (op_code == oMinus && arg2_prec == prec)
+      || (op_code == oDivide && arg2_prec == prec))
+    {
+      output << "(";
+      close_parenthesis = true;
+    }
+
+  // Write right argument
+  arg2->writeJsonOutput(output, temporary_terms, tef_terms);
+
+  if (close_parenthesis)
+    output << ")";
+}
+
 void
 BinaryOpNode::writeOutput(ostream &output, ExprNodeOutputType output_type,
                           const temporary_terms_t &temporary_terms,
@@ -3383,6 +3731,15 @@ BinaryOpNode::writeExternalFunctionOutput(ostream &output, ExprNodeOutputType ou
   arg2->writeExternalFunctionOutput(output, output_type, temporary_terms, tef_terms);
 }
 
+void
+BinaryOpNode::writeJsonExternalFunctionOutput(vector<string> &efout,
+                                              const temporary_terms_t &temporary_terms,
+                                              deriv_node_temp_terms_t &tef_terms) const
+{
+  arg1->writeJsonExternalFunctionOutput(efout, temporary_terms, tef_terms);
+  arg2->writeJsonExternalFunctionOutput(efout, temporary_terms, tef_terms);
+}
+
 void
 BinaryOpNode::compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number,
                                             bool lhs_rhs, const temporary_terms_t &temporary_terms,
@@ -4382,6 +4739,37 @@ TrinaryOpNode::containsExternalFunction() const
     || arg3->containsExternalFunction();
 }
 
+void
+TrinaryOpNode::writeJsonOutput(ostream &output,
+                               const temporary_terms_t &temporary_terms,
+                               deriv_node_temp_terms_t &tef_terms) const
+{
+  // If current node is a temporary term
+  temporary_terms_t::const_iterator it = temporary_terms.find(const_cast<TrinaryOpNode *>(this));
+  if (it != temporary_terms.end())
+    {
+      output << "T" << idx;
+      return;
+    }
+
+  switch (op_code)
+    {
+    case oNormcdf:
+      output << "normcdf(";
+      break;
+    case oNormpdf:
+      output << "normpdf(";
+      break;
+    }
+
+  arg1->writeJsonOutput(output, temporary_terms, tef_terms);
+  output << ",";
+  arg2->writeJsonOutput(output, temporary_terms, tef_terms);
+  output << ",";
+  arg3->writeJsonOutput(output, temporary_terms, tef_terms);
+  output << ")";
+}
+
 void
 TrinaryOpNode::writeOutput(ostream &output, ExprNodeOutputType output_type,
                            const temporary_terms_t &temporary_terms,
@@ -4458,6 +4846,16 @@ TrinaryOpNode::writeExternalFunctionOutput(ostream &output, ExprNodeOutputType o
   arg3->writeExternalFunctionOutput(output, output_type, temporary_terms, tef_terms);
 }
 
+void
+TrinaryOpNode::writeJsonExternalFunctionOutput(vector<string> &efout,
+                                               const temporary_terms_t &temporary_terms,
+                                               deriv_node_temp_terms_t &tef_terms) const
+{
+  arg1->writeJsonExternalFunctionOutput(efout, temporary_terms, tef_terms);
+  arg2->writeJsonExternalFunctionOutput(efout, temporary_terms, tef_terms);
+  arg3->writeJsonExternalFunctionOutput(efout, temporary_terms, tef_terms);
+}
+
 void
 TrinaryOpNode::compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number,
                                              bool lhs_rhs, const temporary_terms_t &temporary_terms,
@@ -5126,6 +5524,21 @@ AbstractExternalFunctionNode::writeExternalFunctionArguments(ostream &output, Ex
     }
 }
 
+void
+AbstractExternalFunctionNode::writeJsonExternalFunctionArguments(ostream &output,
+                                                                 const temporary_terms_t &temporary_terms,
+                                                                 deriv_node_temp_terms_t &tef_terms) const
+{
+  for (vector<expr_t>::const_iterator it = arguments.begin();
+       it != arguments.end(); it++)
+    {
+      if (it != arguments.begin())
+        output << ",";
+
+      (*it)->writeJsonOutput(output, temporary_terms, tef_terms);
+    }
+}
+
 void
 AbstractExternalFunctionNode::writePrhs(ostream &output, ExprNodeOutputType output_type,
                                         const temporary_terms_t &temporary_terms,
@@ -5289,6 +5702,23 @@ ExternalFunctionNode::compileExternalFunctionOutput(ostream &CompileCode, unsign
     }
 }
 
+void
+ExternalFunctionNode::writeJsonOutput(ostream &output,
+                                      const temporary_terms_t &temporary_terms,
+                                      deriv_node_temp_terms_t &tef_terms) const
+{
+  temporary_terms_t::const_iterator it = temporary_terms.find(const_cast<ExternalFunctionNode *>(this));
+  if (it != temporary_terms.end())
+    {
+      output << "T" << idx;
+      return;
+    }
+
+  output << datatree.symbol_table.getName(symb_id) << "(";
+  writeJsonExternalFunctionArguments(output, temporary_terms, tef_terms);
+  output << ")";
+}
+
 void
 ExternalFunctionNode::writeOutput(ostream &output, ExprNodeOutputType output_type,
                                   const temporary_terms_t &temporary_terms,
@@ -5398,6 +5828,42 @@ ExternalFunctionNode::writeExternalFunctionOutput(ostream &output, ExprNodeOutpu
     }
 }
 
+void
+ExternalFunctionNode::writeJsonExternalFunctionOutput(vector<string> &efout,
+                                                      const temporary_terms_t &temporary_terms,
+                                                      deriv_node_temp_terms_t &tef_terms) const
+{
+  int first_deriv_symb_id = datatree.external_functions_table.getFirstDerivSymbID(symb_id);
+  assert(first_deriv_symb_id != eExtFunSetButNoNameProvided);
+
+  for (vector<expr_t>::const_iterator it = arguments.begin();
+       it != arguments.end(); it++)
+    (*it)->writeJsonExternalFunctionOutput(efout, temporary_terms, tef_terms);
+
+  if (!alreadyWrittenAsTefTerm(symb_id, tef_terms))
+    {
+      tef_terms[make_pair(symb_id, arguments)] = (int) tef_terms.size();
+      int indx = getIndxInTefTerms(symb_id, tef_terms);
+      int second_deriv_symb_id = datatree.external_functions_table.getSecondDerivSymbID(symb_id);
+      assert(second_deriv_symb_id != eExtFunSetButNoNameProvided);
+
+      stringstream ef;
+      ef << "{\"external_function\": {"
+         << "\"external_function_term\": \"TEF_" << indx << "\"";
+
+      if (symb_id == first_deriv_symb_id)
+        ef << ", \"external_function_term_d\": \"TEFD_" << indx << "\"";
+
+      if (symb_id == second_deriv_symb_id)
+        ef << ", \"external_function_term_dd\": \"TEFDD_" << indx << "\"";
+
+      ef << ", \"value\": \"" << datatree.symbol_table.getName(symb_id) << "(";
+      writeJsonExternalFunctionArguments(ef, temporary_terms, tef_terms);
+      ef << ")\"}}";
+      efout.push_back(ef.str());
+    }
+}
+
 expr_t
 ExternalFunctionNode::toStatic(DataTree &static_datatree) const
 {
@@ -5479,6 +5945,34 @@ FirstDerivExternalFunctionNode::composeDerivatives(const vector<expr_t> &dargs)
   return theDeriv;
 }
 
+void
+FirstDerivExternalFunctionNode::writeJsonOutput(ostream &output,
+                                                const temporary_terms_t &temporary_terms,
+                                                deriv_node_temp_terms_t &tef_terms) const
+{
+  // If current node is a temporary term
+  temporary_terms_t::const_iterator it = temporary_terms.find(const_cast<FirstDerivExternalFunctionNode *>(this));
+  if (it != temporary_terms.end())
+    {
+      output << "T" << idx;
+      return;
+    }
+
+  const int first_deriv_symb_id = datatree.external_functions_table.getFirstDerivSymbID(symb_id);
+  assert(first_deriv_symb_id != eExtFunSetButNoNameProvided);
+
+  const int tmpIndx = inputIndex - 1;
+
+  if (first_deriv_symb_id == symb_id)
+    output << "TEFD_" << getIndxInTefTerms(symb_id, tef_terms)
+           << "[" << tmpIndx << "]";
+  else if (first_deriv_symb_id == eExtFunNotSet)
+    output << "TEFD_fdd_" << getIndxInTefTerms(symb_id, tef_terms) << "_" << inputIndex;
+  else
+    output << "TEFD_def_" << getIndxInTefTerms(first_deriv_symb_id, tef_terms)
+           << "[" << tmpIndx << "]";
+}
+
 void
 FirstDerivExternalFunctionNode::writeOutput(ostream &output, ExprNodeOutputType output_type,
                                             const temporary_terms_t &temporary_terms,
@@ -5666,6 +6160,47 @@ FirstDerivExternalFunctionNode::writeExternalFunctionOutput(ostream &output, Exp
     }
 }
 
+void
+FirstDerivExternalFunctionNode::writeJsonExternalFunctionOutput(vector<string> &efout,
+                                                                const temporary_terms_t &temporary_terms,
+                                                                deriv_node_temp_terms_t &tef_terms) const
+{
+  int first_deriv_symb_id = datatree.external_functions_table.getFirstDerivSymbID(symb_id);
+  assert(first_deriv_symb_id != eExtFunSetButNoNameProvided);
+
+  /* For a node with derivs provided by the user function, call the method
+     on the non-derived node */
+  if (first_deriv_symb_id == symb_id)
+    {
+      expr_t parent = datatree.AddExternalFunction(symb_id, arguments);
+      parent->writeJsonExternalFunctionOutput(efout, temporary_terms, tef_terms);
+      return;
+    }
+
+  if (alreadyWrittenAsTefTerm(first_deriv_symb_id, tef_terms))
+    return;
+
+  stringstream ef;
+  if (first_deriv_symb_id == eExtFunNotSet)
+    ef << "{\"first_deriv_external_function\": {"
+       << "\"external_function_term\": \"TEFD_fdd_" << getIndxInTefTerms(symb_id, tef_terms) << "_" << inputIndex << "\""
+       << ", \"analytic_derivative\": false"
+       << ", \"wrt\": " << inputIndex
+       << ", \"value\": \"" << datatree.symbol_table.getName(symb_id) << "(";
+  else
+    {
+      tef_terms[make_pair(first_deriv_symb_id, arguments)] = (int) tef_terms.size();
+      ef << "{\"first_deriv_external_function\": {"
+         << "\"external_function_term\": \"TEFD_def_" << getIndxInTefTerms(first_deriv_symb_id, tef_terms) << "\""
+         << ", \"analytic_derivative\": true"
+         << ", \"value\": \"" << datatree.symbol_table.getName(first_deriv_symb_id) << "(";
+    }
+
+  writeJsonExternalFunctionArguments(ef, temporary_terms, tef_terms);
+  ef << ")\"}}";
+  efout.push_back(ef.str());
+}
+
 void
 FirstDerivExternalFunctionNode::compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number,
                                                               bool lhs_rhs, const temporary_terms_t &temporary_terms,
@@ -5791,6 +6326,35 @@ SecondDerivExternalFunctionNode::composeDerivatives(const vector<expr_t> &dargs)
   exit(EXIT_FAILURE);
 }
 
+void
+SecondDerivExternalFunctionNode::writeJsonOutput(ostream &output,
+                                                 const temporary_terms_t &temporary_terms,
+                                                 deriv_node_temp_terms_t &tef_terms) const
+{
+  // If current node is a temporary term
+  temporary_terms_t::const_iterator it = temporary_terms.find(const_cast<SecondDerivExternalFunctionNode *>(this));
+  if (it != temporary_terms.end())
+    {
+      output << "T" << idx;
+      return;
+    }
+
+  const int second_deriv_symb_id = datatree.external_functions_table.getSecondDerivSymbID(symb_id);
+  assert(second_deriv_symb_id != eExtFunSetButNoNameProvided);
+
+  const int tmpIndex1 = inputIndex1 - 1;
+  const int tmpIndex2 = inputIndex2 - 1;
+
+  if (second_deriv_symb_id == symb_id)
+    output << "TEFDD_" << getIndxInTefTerms(symb_id, tef_terms)
+           << "[" << tmpIndex1 << "," << tmpIndex2 << "]";
+  else if (second_deriv_symb_id == eExtFunNotSet)
+    output << "TEFDD_fdd_" << getIndxInTefTerms(symb_id, tef_terms) << "_" << inputIndex1 << "_" << inputIndex2;
+  else
+    output << "TEFDD_def_" << getIndxInTefTerms(second_deriv_symb_id, tef_terms)
+           << "[" << tmpIndex1 << "," << tmpIndex2 << "]";
+}
+
 void
 SecondDerivExternalFunctionNode::writeOutput(ostream &output, ExprNodeOutputType output_type,
                                              const temporary_terms_t &temporary_terms,
@@ -5955,6 +6519,48 @@ SecondDerivExternalFunctionNode::writeExternalFunctionOutput(ostream &output, Ex
     }
 }
 
+void
+SecondDerivExternalFunctionNode::writeJsonExternalFunctionOutput(vector<string> &efout,
+                                                                 const temporary_terms_t &temporary_terms,
+                                                                 deriv_node_temp_terms_t &tef_terms) const
+{
+  int second_deriv_symb_id = datatree.external_functions_table.getSecondDerivSymbID(symb_id);
+  assert(second_deriv_symb_id != eExtFunSetButNoNameProvided);
+
+  /* For a node with derivs provided by the user function, call the method
+     on the non-derived node */
+  if (second_deriv_symb_id == symb_id)
+    {
+      expr_t parent = datatree.AddExternalFunction(symb_id, arguments);
+      parent->writeJsonExternalFunctionOutput(efout, temporary_terms, tef_terms);
+      return;
+    }
+
+  if (alreadyWrittenAsTefTerm(second_deriv_symb_id, tef_terms))
+    return;
+
+  stringstream ef;
+  if (second_deriv_symb_id == eExtFunNotSet)
+    ef << "{\"second_deriv_external_function\": {"
+       << "\"external_function_term\": \"TEFDD_fdd_" << getIndxInTefTerms(symb_id, tef_terms) << "_" << inputIndex1 << "_" << inputIndex2 << "\""
+       << ", \"analytic_derivative\": false"
+       << ", \"wrt1\": " << inputIndex1
+       << ", \"wrt2\": " << inputIndex2
+       << ", \"value\": \"" << datatree.symbol_table.getName(symb_id) << "(";
+  else
+    {
+      tef_terms[make_pair(second_deriv_symb_id, arguments)] = (int) tef_terms.size();
+      ef << "{\"second_deriv_external_function\": {"
+         << "\"external_function_term\": \"TEFDD_def_" << getIndxInTefTerms(second_deriv_symb_id, tef_terms) << "\""
+         << ", \"analytic_derivative\": true"
+         << ", \"value\": \"" << datatree.symbol_table.getName(second_deriv_symb_id) << "(";
+    }
+
+  writeJsonExternalFunctionArguments(ef, temporary_terms, tef_terms);
+  ef << ")\"}}" << endl;
+  efout.push_back(ef.str());
+}
+
 expr_t
 SecondDerivExternalFunctionNode::cloneDynamic(DataTree &dynamic_datatree) const
 {
@@ -6312,3 +6918,16 @@ VarExpectationNode::substituteStaticAuxiliaryVariable() const
 {
   return const_cast<VarExpectationNode *>(this);
 }
+
+void
+VarExpectationNode::writeJsonOutput(ostream &output,
+                                    const temporary_terms_t &temporary_terms,
+                                    deriv_node_temp_terms_t &tef_terms) const
+{
+  output << "var_expectation("
+         << "forecast_horizon = " << forecast_horizon
+         << ", name = " << datatree.symbol_table.getName(symb_id)
+         << ", model_name = " << model_name
+         << ", yindex = " << yidx
+         << ")";
+}
diff --git a/ExprNode.hh b/ExprNode.hh
index b4d0ce153456c8b58abeb756b8eaf046391a8b2e..4845e4a68fafcb66b2aada243fa40d1ccc7c286a 100644
--- a/ExprNode.hh
+++ b/ExprNode.hh
@@ -224,11 +224,22 @@ enum ExprNodeOutputType
       //! Writes output of node, using a Txxx notation for nodes in temporary_terms
       void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms) const;
 
+      //! Writes output of node in JSON syntax
+      virtual void writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const = 0;
+
+      virtual int precedenceJson(const temporary_terms_t &temporary_terms) const;
+
       //! Writes the output for an external function, ensuring that the external function is called as few times as possible using temporary terms
       virtual void writeExternalFunctionOutput(ostream &output, ExprNodeOutputType output_type,
                                                const temporary_terms_t &temporary_terms,
                                                deriv_node_temp_terms_t &tef_terms) const;
 
+      //! Write the JSON output of an external function in a string vector
+      //! Allows the insertion of commas if necessary
+      virtual void writeJsonExternalFunctionOutput(vector<string> &efout,
+                                                   const temporary_terms_t &temporary_terms,
+                                                   deriv_node_temp_terms_t &tef_terms) const;
+
       virtual void compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number,
                                                  bool lhs_rhs, const temporary_terms_t &temporary_terms,
                                                  const map_idx_t &map_idx, bool dynamic, bool steady_dynamic,
@@ -497,6 +508,7 @@ public:
   };
   virtual void prepareForDerivation();
   virtual void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
+  virtual void writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
   virtual bool containsExternalFunction() const;
   virtual void collectDynamicVariables(SymbolType type_arg, set<pair<int, int> > &result) const;
   virtual void collectTemporary_terms(const temporary_terms_t &temporary_terms, temporary_terms_inuse_t &temporary_terms_inuse, int Curr_Block) const;
@@ -550,6 +562,7 @@ public:
   VariableNode(DataTree &datatree_arg, int symb_id_arg, int lag_arg);
   virtual void prepareForDerivation();
   virtual void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
+  virtual void writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
   virtual bool containsExternalFunction() const;
   virtual void collectDynamicVariables(SymbolType type_arg, set<pair<int, int> > &result) const;
   virtual void computeTemporaryTerms(map<expr_t, int > &reference_count,
@@ -633,10 +646,14 @@ public:
                                      map<NodeTreeReference, temporary_terms_t> &temp_terms_map,
                                      bool is_matlab, NodeTreeReference tr) const;
   virtual void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
+  virtual void writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
   virtual bool containsExternalFunction() const;
   virtual void writeExternalFunctionOutput(ostream &output, ExprNodeOutputType output_type,
                                            const temporary_terms_t &temporary_terms,
                                            deriv_node_temp_terms_t &tef_terms) const;
+  virtual void writeJsonExternalFunctionOutput(vector<string> &efout,
+                                               const temporary_terms_t &temporary_terms,
+                                               deriv_node_temp_terms_t &tef_terms) const;
   virtual void compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number,
                                              bool lhs_rhs, const temporary_terms_t &temporary_terms,
                                              const map_idx_t &map_idx, bool dynamic, bool steady_dynamic,
@@ -719,15 +736,20 @@ public:
   BinaryOpNode(DataTree &datatree_arg, const expr_t arg1_arg,
                BinaryOpcode op_code_arg, const expr_t arg2_arg, int powerDerivOrder);
   virtual void prepareForDerivation();
+  virtual int precedenceJson(const temporary_terms_t &temporary_terms) const;
   virtual int precedence(ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms) const;
   virtual void computeTemporaryTerms(map<expr_t, pair<int, NodeTreeReference> > &reference_count,
                                      map<NodeTreeReference, temporary_terms_t> &temp_terms_map,
                                      bool is_matlab, NodeTreeReference tr) const;
   virtual void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
+  virtual void writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
   virtual bool containsExternalFunction() const;
   virtual void writeExternalFunctionOutput(ostream &output, ExprNodeOutputType output_type,
                                            const temporary_terms_t &temporary_terms,
                                            deriv_node_temp_terms_t &tef_terms) const;
+  virtual void writeJsonExternalFunctionOutput(vector<string> &efout,
+                                               const temporary_terms_t &temporary_terms,
+                                               deriv_node_temp_terms_t &tef_terms) const;
   virtual void compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number,
                                              bool lhs_rhs, const temporary_terms_t &temporary_terms,
                                              const map_idx_t &map_idx, bool dynamic, bool steady_dynamic,
@@ -833,10 +855,14 @@ public:
                                      map<NodeTreeReference, temporary_terms_t> &temp_terms_map,
                                      bool is_matlab, NodeTreeReference tr) const;
   virtual void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
+  virtual void writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
   virtual bool containsExternalFunction() const;
   virtual void writeExternalFunctionOutput(ostream &output, ExprNodeOutputType output_type,
                                            const temporary_terms_t &temporary_terms,
                                            deriv_node_temp_terms_t &tef_terms) const;
+  virtual void writeJsonExternalFunctionOutput(vector<string> &efout,
+                                               const temporary_terms_t &temporary_terms,
+                                               deriv_node_temp_terms_t &tef_terms) const;
   virtual void compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number,
                                              bool lhs_rhs, const temporary_terms_t &temporary_terms,
                                              const map_idx_t &map_idx, bool dynamic, bool steady_dynamic,
@@ -907,6 +933,7 @@ protected:
   int getIndxInTefTerms(int the_symb_id, deriv_node_temp_terms_t &tef_terms) const throw (UnknownFunctionNameAndArgs);
   //! Helper function to write output arguments of any given external function
   void writeExternalFunctionArguments(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
+  void writeJsonExternalFunctionArguments(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
 public:
   AbstractExternalFunctionNode(DataTree &datatree_arg, int symb_id_arg,
                                const vector<expr_t> &arguments_arg);
@@ -915,10 +942,14 @@ public:
                                      map<NodeTreeReference, temporary_terms_t> &temp_terms_map,
                                      bool is_matlab, NodeTreeReference tr) const = 0;
   virtual void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const = 0;
+  virtual void writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const = 0;
   virtual bool containsExternalFunction() const;
   virtual void writeExternalFunctionOutput(ostream &output, ExprNodeOutputType output_type,
                                            const temporary_terms_t &temporary_terms,
                                            deriv_node_temp_terms_t &tef_terms) const = 0;
+  virtual void writeJsonExternalFunctionOutput(vector<string> &efout,
+                                               const temporary_terms_t &temporary_terms,
+                                               deriv_node_temp_terms_t &tef_terms) const = 0;
   virtual void compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number,
                                              bool lhs_rhs, const temporary_terms_t &temporary_terms,
                                              const map_idx_t &map_idx, bool dynamic, bool steady_dynamic,
@@ -985,9 +1016,13 @@ public:
                                      map<NodeTreeReference, temporary_terms_t> &temp_terms_map,
                                      bool is_matlab, NodeTreeReference tr) const;
   virtual void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
+  virtual void writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
   virtual void writeExternalFunctionOutput(ostream &output, ExprNodeOutputType output_type,
                                            const temporary_terms_t &temporary_terms,
                                            deriv_node_temp_terms_t &tef_terms) const;
+  virtual void writeJsonExternalFunctionOutput(vector<string> &efout,
+                                               const temporary_terms_t &temporary_terms,
+                                               deriv_node_temp_terms_t &tef_terms) const;
   virtual void compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number,
                                              bool lhs_rhs, const temporary_terms_t &temporary_terms,
                                              const map_idx_t &map_idx, bool dynamic, bool steady_dynamic,
@@ -1025,6 +1060,7 @@ public:
                                      vector< vector<temporary_terms_t> > &v_temporary_terms,
                                      int equation) const;
   virtual void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
+  virtual void writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
   virtual void compile(ostream &CompileCode, unsigned int &instruction_number,
                        bool lhs_rhs, const temporary_terms_t &temporary_terms,
                        const map_idx_t &map_idx, bool dynamic, bool steady_dynamic,
@@ -1032,6 +1068,9 @@ public:
   virtual void writeExternalFunctionOutput(ostream &output, ExprNodeOutputType output_type,
                                            const temporary_terms_t &temporary_terms,
                                            deriv_node_temp_terms_t &tef_terms) const;
+  virtual void writeJsonExternalFunctionOutput(vector<string> &efout,
+                                               const temporary_terms_t &temporary_terms,
+                                               deriv_node_temp_terms_t &tef_terms) const;
   virtual void compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number,
                                              bool lhs_rhs, const temporary_terms_t &temporary_terms,
                                              const map_idx_t &map_idx, bool dynamic, bool steady_dynamic,
@@ -1064,6 +1103,7 @@ public:
                                      vector< vector<temporary_terms_t> > &v_temporary_terms,
                                      int equation) const;
   virtual void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
+  virtual void writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
   virtual void compile(ostream &CompileCode, unsigned int &instruction_number,
                        bool lhs_rhs, const temporary_terms_t &temporary_terms,
                        const map_idx_t &map_idx, bool dynamic, bool steady_dynamic,
@@ -1071,6 +1111,9 @@ public:
   virtual void writeExternalFunctionOutput(ostream &output, ExprNodeOutputType output_type,
                                            const temporary_terms_t &temporary_terms,
                                            deriv_node_temp_terms_t &tef_terms) const;
+  virtual void writeJsonExternalFunctionOutput(vector<string> &efout,
+                                               const temporary_terms_t &temporary_terms,
+                                               deriv_node_temp_terms_t &tef_terms) const;
   virtual void compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number,
                                              bool lhs_rhs, const temporary_terms_t &temporary_terms,
                                              const map_idx_t &map_idx, bool dynamic, bool steady_dynamic,
@@ -1141,6 +1184,7 @@ public:
   virtual bool isVarModelReferenced(const string &model_info_name) const;
   virtual void getEndosAndMaxLags(map<string, int> &model_endos_and_lags) const;
   virtual expr_t substituteStaticAuxiliaryVariable() const;
+  virtual void writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms) const;
 };
 
 #endif
diff --git a/ExtendedPreprocessorTypes.hh b/ExtendedPreprocessorTypes.hh
index bf57a19f5632266f933e982784c925608b34e37b..e40c73eeb5f7794f1e7daf94eee0a05e4b5b40b9 100644
--- a/ExtendedPreprocessorTypes.hh
+++ b/ExtendedPreprocessorTypes.hh
@@ -38,4 +38,19 @@ enum LanguageOutputType
     julia,                            // outputs files for Julia
     python,                           // outputs files for Python (not yet implemented) (not yet implemented)
   };
+
+enum JsonFileOutputType
+  {
+    file,                             // output JSON files to file
+    standardout,                      // output JSON files to stdout
+  };
+
+enum JsonOutputPointType
+  {
+    nojson,                            // don't output JSON
+    parsing,                           // output JSON after the parsing step
+    checkpass,                         // output JSON after the check pass
+    transformpass,                     // output JSON after the transform pass
+    computingpass                      // output JSON after the computing pass
+  };
 #endif
diff --git a/ModFile.cc b/ModFile.cc
index 88ef7f929923b7956a5ec1d1309b6ad906e3fb96..11e9bc54d23b123aac0abb189f5eca067de5d9b2 100644
--- a/ModFile.cc
+++ b/ModFile.cc
@@ -1288,3 +1288,229 @@ ModFile::writeExternalFilesJulia(const string &basename, FileOutputType output)
   jlOutputFile.close();
   cout << "done" << endl;
 }
+
+void
+ModFile::writeJsonOutput(const string &basename, JsonOutputPointType json, JsonFileOutputType json_output_mode, bool onlyjson, bool jsonprintderivdetail)
+{
+  if (json == nojson)
+    return;
+
+  if (json == parsing || json == checkpass)
+    symbol_table.freeze();
+
+  writeJsonOutputParsingCheck(basename, json_output_mode);
+
+  if (json == parsing || json == checkpass)
+    symbol_table.unfreeze();
+
+  if (json == computingpass)
+    writeJsonComputingPassOutput(basename, json_output_mode, jsonprintderivdetail);
+
+  switch (json)
+    {
+    case parsing:
+      cout << "JSON written after Parsing step." << endl;
+      break;
+    case checkpass:
+      cout << "JSON written after Check step." << endl;
+      break;
+    case transformpass:
+      cout << "JSON written after Transform step." << endl;
+      break;
+    case computingpass:
+      cout << "JSON written after Computing step." << endl;
+      break;
+    case nojson:
+      cerr << "ModFile::writeJsonOutput: should not arrive here." << endl;
+      exit(EXIT_FAILURE);
+    }
+
+  if (onlyjson)
+    exit(EXIT_SUCCESS);
+}
+
+void
+ModFile::writeJsonOutputParsingCheck(const string &basename, JsonFileOutputType json_output_mode) const
+{
+  ostringstream output;
+  output << "{" << endl;
+
+  symbol_table.writeJsonOutput(output);
+  output << ", ";
+  dynamic_model.writeJsonOutput(output);
+
+  if (!statements.empty())
+    {
+      output << ", \"statements\": [";
+      for (vector<Statement *>::const_iterator it = statements.begin();
+           it != statements.end(); it++)
+        {
+          if (it != statements.begin())
+            output << ", " << endl;
+          (*it)->writeJsonOutput(output);
+        }
+      output << "]" << endl;
+    }
+  output << "}" << endl;
+
+  if (json_output_mode == standardout)
+    cout << output.str();
+  else
+    {
+      ofstream jsonOutputFile;
+
+      if (basename.size())
+        {
+          string fname(basename);
+          fname += ".json";
+          jsonOutputFile.open(fname.c_str(), ios::out | ios::binary);
+          if (!jsonOutputFile.is_open())
+            {
+              cerr << "ERROR: Can't open file " << fname << " for writing" << endl;
+              exit(EXIT_FAILURE);
+            }
+        }
+      else
+        {
+          cerr << "ERROR: Missing file name" << endl;
+          exit(EXIT_FAILURE);
+        }
+
+      jsonOutputFile << output.str();
+      jsonOutputFile.close();
+    }
+}
+
+void
+ModFile::writeJsonComputingPassOutput(const string &basename, JsonFileOutputType json_output_mode, bool jsonprintderivdetail) const
+{
+  ostringstream static_output, static_detail_output;
+  static_output << "{";
+  static_model.writeJsonComputingPassOutput(static_output, false);
+  static_output << "}" << endl;
+
+  ostringstream dynamic_output, dynamic_detail_output;
+  dynamic_output << "{";
+  dynamic_model.writeJsonComputingPassOutput(dynamic_output, false);
+  dynamic_output << "}" << endl;
+
+  ostringstream tmp_out, static_paramsd_output, static_paramsd_detail_output;
+  tmp_out << "";
+  static_paramsd_output << "";
+  static_paramsd_detail_output << "";
+  static_model.writeJsonParamsDerivativesFile(tmp_out, false);
+  if (!tmp_out.str().empty())
+    static_paramsd_output << "{" << tmp_out.str() << "}" << endl;
+
+  ostringstream tmp1_out, dynamic_paramsd_output, dynamic_paramsd_detail_output;
+  tmp1_out << "";
+  dynamic_paramsd_output << "";
+  dynamic_paramsd_detail_output << "";
+  dynamic_model.writeJsonParamsDerivativesFile(tmp1_out, false);
+  if (!tmp1_out.str().empty())
+    dynamic_paramsd_output << "{" << tmp1_out.str() << "}" << endl;
+
+  if (jsonprintderivdetail)
+    {
+      static_detail_output << "{";
+      static_model.writeJsonComputingPassOutput(static_detail_output, true);
+      static_detail_output << "}";
+
+      dynamic_detail_output << "{";
+      dynamic_model.writeJsonComputingPassOutput(dynamic_detail_output, true);
+      dynamic_detail_output << "}";
+
+      ostringstream tmpd_out, tmpd1_out;
+      tmpd_out << "";
+      tmpd1_out << "";
+      static_model.writeJsonParamsDerivativesFile(tmpd_out, true);
+      if (!tmpd_out.str().empty())
+        static_paramsd_detail_output << "{" << tmpd_out.str() << "}" << endl;
+
+      dynamic_model.writeJsonParamsDerivativesFile(tmpd1_out, true);
+      if (!tmpd1_out.str().empty())
+        dynamic_paramsd_detail_output << "{" << tmpd1_out.str() << "}" << endl;
+    }
+
+  if (json_output_mode == standardout)
+    {
+      cout << static_output.str() << endl
+           << dynamic_output.str() << endl;
+
+      if (!static_paramsd_output.str().empty())
+        cout << static_paramsd_output.str() << endl;
+
+      if (!dynamic_paramsd_output.str().empty())
+        cout << dynamic_paramsd_output.str() << endl;
+
+      if (jsonprintderivdetail)
+        {
+          cout << static_detail_output.str() << endl
+               << dynamic_detail_output.str() << endl;
+
+          if (!static_paramsd_detail_output.str().empty())
+            cout << static_paramsd_detail_output.str() << endl;
+
+          if (!dynamic_paramsd_detail_output.str().empty())
+            cout << dynamic_paramsd_detail_output.str() << endl;
+        }
+    }
+  else
+    {
+      if (basename.empty())
+        {
+          cerr << "ERROR: Missing file name" << endl;
+          exit(EXIT_FAILURE);
+        }
+
+      string fname_static, fname_dynamic;
+      fname_static = basename + "_static.json";
+      fname_dynamic = basename + "_dynamic.json";
+
+      writeJsonFileHelper(fname_static, static_output);
+      writeJsonFileHelper(fname_dynamic, dynamic_output);
+
+      if (jsonprintderivdetail)
+        {
+          string fname_static_details, fname_dynamic_details;
+          fname_static_details = basename + "_static_details.json";
+          fname_dynamic_details = basename + "_dynamic_details.json";
+
+          writeJsonFileHelper(fname_static_details, static_detail_output);
+          writeJsonFileHelper(fname_dynamic_details, dynamic_detail_output);
+        }
+
+      if (!static_paramsd_output.str().empty())
+        {
+          string fname_static_params, fname_static_params_details;
+          fname_static_params = basename + "_static_params_derivs.json";
+          fname_static_params_details = basename + "_static_params_derivs_details.json";
+          writeJsonFileHelper(fname_static_params, static_paramsd_output);
+          writeJsonFileHelper(fname_static_params_details, static_paramsd_detail_output);
+        }
+
+      if (!dynamic_paramsd_output.str().empty())
+        {
+          string fname_dynamic_params, fname_dynamic_params_details;
+          fname_dynamic_params = basename + "_params_derivs.json";
+          fname_dynamic_params_details = basename + "_params_derivs_details.json";
+          writeJsonFileHelper(fname_dynamic_params, dynamic_paramsd_output);
+          writeJsonFileHelper(fname_dynamic_params_details, dynamic_paramsd_detail_output);
+        }
+    }
+}
+
+void
+ModFile::writeJsonFileHelper(string &fname, ostringstream &output) const
+{
+  ofstream jsonOutput;
+  jsonOutput.open(fname.c_str(), ios::out | ios::binary);
+  if (!jsonOutput.is_open())
+    {
+      cerr << "ERROR: Can't open file " << fname << " for writing" << endl;
+      exit(EXIT_FAILURE);
+    }
+  jsonOutput << output.str();
+  jsonOutput.close();
+
+}
diff --git a/ModFile.hh b/ModFile.hh
index a4812471ee502fe2bb7f288a2d6cc688273a2c9c..d8bb587cbf052c2dad8149a66b0b9f14f46c39b8 100644
--- a/ModFile.hh
+++ b/ModFile.hh
@@ -117,7 +117,10 @@ private:
   ModFileStructure mod_file_struct;
   //! Warnings Encountered
   WarningConsolidation &warnings;
-
+  //! Functions used in writing of JSON outut. See writeJsonOutput
+  void writeJsonOutputParsingCheck(const string &basename, JsonFileOutputType json_output_mode) const;
+  void writeJsonComputingPassOutput(const string &basename, JsonFileOutputType json_output_mode, bool jsonprintderivdetail) const;
+  void writeJsonFileHelper(string &fname, ostringstream &output) const;
 public:
   //! Add a statement
   void addStatement(Statement *st);
@@ -167,6 +170,11 @@ public:
   void writeModelCC(const string &basename) const;
 
   void computeChecksum();
+  //! Write JSON representation of ModFile object
+  //! Initially created to enable Julia to work with .mod files
+  //! Potentially outputs ModFile after the various parts of processing (parsing, checkPass, transformPass, computingPass)
+  //! Allows user of other host language platforms (python, fortran, etc) to provide support for dynare .mod files
+  void writeJsonOutput(const string &basename, JsonOutputPointType json, JsonFileOutputType json_output_mode, bool onlyjson, bool jsonprintderivdetail = false);
 };
 
 #endif // ! MOD_FILE_HH
diff --git a/ModelTree.cc b/ModelTree.cc
index 9bfb30eaff3b0a0ad3aa7f13853b2de4bf9dc3a1..2282f292d1b442a724637c7123598477d5e6d853 100644
--- a/ModelTree.cc
+++ b/ModelTree.cc
@@ -232,7 +232,7 @@ ModelTree::computeNonSingularNormalization(jacob_map_t &contemporaneous_jacobian
 void
 ModelTree::computeNormalizedEquations(multimap<int, int> &endo2eqs) const
 {
-  for (int i = 0; i < equations.size(); i++)
+  for (size_t i = 0; i < equations.size(); i++)
     {
       VariableNode *lhs = dynamic_cast<VariableNode *>(equations[i]->get_arg1());
       if (lhs == NULL)
@@ -247,7 +247,7 @@ ModelTree::computeNormalizedEquations(multimap<int, int> &endo2eqs) const
       if (endo.find(make_pair(symbol_table.getTypeSpecificID(symb_id), 0)) != endo.end())
         continue;
 
-      endo2eqs.insert(make_pair(symbol_table.getTypeSpecificID(symb_id), i));
+      endo2eqs.insert(make_pair(symbol_table.getTypeSpecificID(symb_id), (int) i));
       cout << "Endogenous " << symbol_table.getName(symb_id) << " normalized in equation " << (i+1) << endl;
     }
 }
@@ -1195,6 +1195,60 @@ ModelTree::writeTemporaryTerms(const temporary_terms_t &tt, const temporary_term
       }
 }
 
+void
+ModelTree::writeJsonTemporaryTerms(const temporary_terms_t &tt, const temporary_terms_t &ttm1, ostream &output,
+                                   deriv_node_temp_terms_t &tef_terms, string &concat) const
+{
+  // Local var used to keep track of temp nodes already written
+  bool wrote_term = false;
+  temporary_terms_t tt2 = ttm1;
+
+  output << "\"external_functions_temporary_terms_" << concat << "\": [";
+  for (temporary_terms_t::const_iterator it = tt.begin();
+       it != tt.end(); it++)
+    if (ttm1.find(*it) == ttm1.end())
+      {
+        if (dynamic_cast<AbstractExternalFunctionNode *>(*it) != NULL)
+          {
+            if (wrote_term)
+              output << ", ";
+            vector<string> efout;
+            (*it)->writeJsonExternalFunctionOutput(efout, tt2, tef_terms);
+            for (vector<string>::const_iterator it1 = efout.begin(); it1 != efout.end(); it1++)
+              {
+                if (it1 != efout.begin())
+                  output << ", ";
+                output << *it1;
+              }
+            wrote_term = true;
+          }
+        tt2.insert(*it);
+      }
+
+  tt2 = ttm1;
+  wrote_term = false;
+  output << "]"
+         << ", \"temporary_terms_" << concat << "\": [";
+  for (temporary_terms_t::const_iterator it = tt.begin();
+       it != tt.end(); it++)
+    if (ttm1.find(*it) == ttm1.end())
+      {
+        if (wrote_term)
+          output << ", ";
+        output << "{\"temporary_term\": \"";
+        (*it)->writeJsonOutput(output, tt, tef_terms);
+        output << "\""
+               << ", \"value\": \"";
+        (*it)->writeJsonOutput(output, tt2, tef_terms);
+        output << "\"}" << endl;
+        wrote_term = true;
+
+        // Insert current node into tt2
+        tt2.insert(*it);
+      }
+  output << "]";
+}
+
 void
 ModelTree::fixNestedParenthesis(ostringstream &output, map<string, string> &tmp_paren_vars, bool &message_printed) const
 {
@@ -1384,6 +1438,54 @@ ModelTree::writeModelLocalVariables(ostream &output, ExprNodeOutputType output_t
     }
 }
 
+void
+ModelTree::writeJsonModelLocalVariables(ostream &output, deriv_node_temp_terms_t &tef_terms) const
+{
+  /* Collect all model local variables appearing in equations, and print only
+     them. Printing unused model local variables can lead to a crash (see
+     ticket #101). */
+  set<int> used_local_vars;
+
+  // Use an empty set for the temporary terms
+  const temporary_terms_t tt;
+
+  for (size_t i = 0; i < equations.size(); i++)
+    equations[i]->collectVariables(eModelLocalVariable, used_local_vars);
+
+  output << "\"external_functions_model_local_variables\": [";
+  for (set<int>::const_iterator it = used_local_vars.begin();
+       it != used_local_vars.end(); ++it)
+    {
+      vector<string> efout;
+      expr_t value = local_variables_table.find(*it)->second;
+      value->writeJsonExternalFunctionOutput(efout, tt, tef_terms);
+      for (vector<string>::const_iterator it1 = efout.begin(); it1 != efout.end(); it1++)
+        {
+          if (it1 != efout.begin())
+            output << ", ";
+          output << *it1;
+        }
+    }
+  output << "]"
+         << ", \"model_local_variables\": [";
+  for (set<int>::const_iterator it = used_local_vars.begin();
+       it != used_local_vars.end(); ++it)
+    {
+      if (it != used_local_vars.begin())
+        output << ", ";
+      int id = *it;
+      expr_t value = local_variables_table.find(id)->second;
+
+      /* We append underscores to avoid name clashes with "g1" or "oo_" (see
+         also VariableNode::writeOutput) */
+      output << "{\"variable\": \"" << symbol_table.getName(id) << "__\""
+             << ", \"value\": \"";
+      value->writeJsonOutput(output, tt, tef_terms);
+      output << "\"}" << endl;
+    }
+  output << "]";
+}
+
 void
 ModelTree::writeModelEquations(ostream &output, ExprNodeOutputType output_type) const
 {
@@ -1588,7 +1690,7 @@ ModelTree::writeLatexModelFile(const string &basename, ExprNodeOutputType output
 
                 content_output << iteqt->second.first;
 
-                if (!empty(iteqt->second.second))
+                if (iteqt->second.second.empty())
                   content_output << "= `" << iteqt->second.second << "'";
 
                 wrote_eq_tag = true;
@@ -1667,7 +1769,7 @@ ModelTree::addNonstationaryVariables(vector<int> nonstationary_vars, bool log_de
 void
 ModelTree::initializeVariablesAndEquations()
 {
-  for (int j = 0; j < equations.size(); j++)
+  for (size_t j = 0; j < equations.size(); j++)
     {
       equation_reordered.push_back(j);
       variable_reordered.push_back(j);
@@ -1845,3 +1947,80 @@ ModelTree::isNonstationary(int symb_id) const
   return (nonstationary_symbols_map.find(symb_id)
           != nonstationary_symbols_map.end());
 }
+
+void
+ModelTree::writeJsonModelEquations(ostream &output, bool residuals) const
+{
+  deriv_node_temp_terms_t tef_terms;
+  vector<pair<string, string> > eqtags;
+  temporary_terms_t tt_empty;
+  if (residuals)
+    output << endl << "\"residuals\":[" << endl;
+  else
+    output << endl << "\"model\":[" << endl;
+  for (int eq = 0; eq < (int) equations.size(); eq++)
+    {
+      if (eq > 0)
+        output << ", ";
+
+      BinaryOpNode *eq_node = equations[eq];
+      expr_t lhs = eq_node->get_arg1();
+      expr_t rhs = eq_node->get_arg2();
+
+      if (residuals)
+        {
+          output << "{\"residual\": {"
+                 << "\"lhs\": \"";
+          lhs->writeJsonOutput(output, temporary_terms, tef_terms);
+          output << "\"";
+
+          output << ", \"rhs\": \"";
+          rhs->writeJsonOutput(output, temporary_terms, tef_terms);
+          output << "\"";
+          try
+            {
+              // Test if the right hand side of the equation is empty.
+              if (rhs->eval(eval_context_t()) != 0)
+                {
+                  output << ", \"rhs\": \"";
+                  rhs->writeJsonOutput(output, temporary_terms, tef_terms);
+                  output << "\"";
+                }
+            }
+          catch (ExprNode::EvalException &e)
+            {
+            }
+          output << "}";
+        }
+      else
+        {
+          output << "{\"lhs\": \"";
+          lhs->writeJsonOutput(output, tt_empty, tef_terms);
+          output << "\", \"rhs\": \"";
+          rhs->writeJsonOutput(output, tt_empty, tef_terms);
+          output << "\""
+                 << ", \"line\": " << equations_lineno[eq];
+
+          for (vector<pair<int, pair<string, string> > >::const_iterator it = equation_tags.begin();
+               it != equation_tags.end(); it++)
+            if (it->first == eq)
+              eqtags.push_back(it->second);
+
+          if (!eqtags.empty())
+            {
+              output << ", \"tags\": {";
+              int i = 0;
+              for (vector<pair<string, string> >::const_iterator it = eqtags.begin(); it != eqtags.end(); it++, i++)
+                {
+                  if (i != 0)
+                    output << ", ";
+                  output << "\"" << it->first << "\": \"" << it->second << "\"";
+                }
+              output << "}";
+              eqtags.clear();
+            }
+        }
+      output << "}" << endl;
+    }
+  output << endl << "]" << endl;
+}
diff --git a/ModelTree.hh b/ModelTree.hh
index f3c34836480b1fe8d7fa35b41306879e13e999a7..24db008abc4b05dcddfb974a23020f503f166343 100644
--- a/ModelTree.hh
+++ b/ModelTree.hh
@@ -177,6 +177,7 @@ protected:
   void computeParamsDerivativesTemporaryTerms();
   //! Writes temporary terms
   void writeTemporaryTerms(const temporary_terms_t &tt, const temporary_terms_t &ttm1, ostream &output, ExprNodeOutputType output_type, deriv_node_temp_terms_t &tef_terms) const;
+  void writeJsonTemporaryTerms(const temporary_terms_t &tt, const temporary_terms_t &ttm1, ostream &output, deriv_node_temp_terms_t &tef_terms, string &concat) const;
   //! Compiles temporary terms
   void compileTemporaryTerms(ostream &code_file, unsigned int &instruction_number, const temporary_terms_t &tt, map_idx_t map_idx, bool dynamic, bool steady_dynamic) const;
   //! Adds informations for simulation in a binary file
@@ -190,6 +191,11 @@ protected:
   void writeModelLocalVariables(ostream &output, ExprNodeOutputType output_type, deriv_node_temp_terms_t &tef_terms) const;
   //! Writes model equations
   void writeModelEquations(ostream &output, ExprNodeOutputType output_type) const;
+  //! Writes JSON model equations
+  //! if residuals = true, we are writing the dynamic/static model.
+  //! Otherwise, just the model equations (with line numbers, no tmp terms)
+  void writeJsonModelEquations(ostream &output, bool residuals) const;
+  void writeJsonModelLocalVariables(ostream &output, deriv_node_temp_terms_t &tef_terms) const;
   //! Compiles model equations
   void compileModelEquations(ostream &code_file, unsigned int &instruction_number, const temporary_terms_t &tt, const map_idx_t &map_idx, bool dynamic, bool steady_dynamic) const;
 
diff --git a/NumericalInitialization.cc b/NumericalInitialization.cc
index 7d94397648575616b7af7cd0ca9e04fe6a5fe75d..843026517243ddd088d32a72024f8cf9f1cda271 100644
--- a/NumericalInitialization.cc
+++ b/NumericalInitialization.cc
@@ -63,6 +63,15 @@ InitParamStatement::writeJuliaOutput(ostream &output, const string &basename)
   //   output << symbol_table.getName(symb_id) << " = model_.params[ " << id << " ]" << endl;
 }
 
+void
+InitParamStatement::writeJsonOutput(ostream &output) const
+{
+  deriv_node_temp_terms_t tef_terms;
+  output << "{\"statementName\": \"param_init\", \"name\": \"" << symbol_table.getName(symb_id) << "\", " << "\"value\": \"";
+  param_value->writeJsonOutput(output, temporary_terms_t(), tef_terms);
+  output << "\"}";
+}
+
 void
 InitParamStatement::writeCOutput(ostream &output, const string &basename)
 {
@@ -165,6 +174,21 @@ InitOrEndValStatement::writeInitValues(ostream &output) const
     }
 }
 
+void
+InitOrEndValStatement::writeJsonInitValues(ostream &output) const
+{
+  deriv_node_temp_terms_t tef_terms;
+  for (init_values_t::const_iterator it = init_values.begin();
+       it != init_values.end(); it++)
+    {
+      if (it != init_values.begin())
+        output << ", ";
+      output << "{\"name\": \"" << symbol_table.getName(it->first) << "\", " << "\"value\": \"";
+      it->second->writeJsonOutput(output, temporary_terms_t(), tef_terms);
+      output << "\"}";
+    }
+}
+
 InitValStatement::InitValStatement(const init_values_t &init_values_arg,
                                    const SymbolTable &symbol_table_arg,
                                    const bool &all_values_required_arg) :
@@ -210,6 +234,14 @@ InitValStatement::writeOutput(ostream &output, const string &basename, bool mini
   writeInitValues(output);
 }
 
+void
+InitValStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"init_val\", \"vals\": [";
+  writeJsonInitValues(output);
+  output << "]}";
+}
+
 void
 InitValStatement::writeOutputPostInit(ostream &output) const
 {
@@ -267,6 +299,14 @@ EndValStatement::writeOutput(ostream &output, const string &basename, bool minim
   writeInitValues(output);
 }
 
+void
+EndValStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"end_val\", \"vals\": [";
+  writeJsonInitValues(output);
+  output << "]}";
+}
+
 HistValStatement::HistValStatement(const hist_values_t &hist_values_arg,
                                    const SymbolTable &symbol_table_arg,
                                    const bool &all_values_required_arg) :
@@ -373,6 +413,25 @@ HistValStatement::writeOutput(ostream &output, const string &basename, bool mini
     }
 }
 
+void
+HistValStatement::writeJsonOutput(ostream &output) const
+{
+  deriv_node_temp_terms_t tef_terms;
+  output << "{\"statementName\": \"hist_val\", \"vals\": [";
+  for (hist_values_t::const_iterator it = hist_values.begin();
+       it != hist_values.end(); it++)
+    {
+      if (it != hist_values.begin())
+        output << ", ";
+      output << "{ \"name\": \"" << symbol_table.getName(it->first.first) << "\""
+             << ", \"lag\": " << it->first.second
+             << ", \"value\": \"";
+      it->second->writeJsonOutput(output, temporary_terms_t(), tef_terms);
+      output << "\"}";
+    }
+  output << "]}";
+}
+
 InitvalFileStatement::InitvalFileStatement(const string &filename_arg) :
   filename(filename_arg)
 {
@@ -388,6 +447,14 @@ InitvalFileStatement::writeOutput(ostream &output, const string &basename, bool
          << "initvalf('" << filename << "');" << endl;
 }
 
+void
+InitvalFileStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"init_val_file\""
+         << ", \"filename\": \"" << filename << "\""
+         << "}";
+}
+
 HistvalFileStatement::HistvalFileStatement(const string &filename_arg) :
   filename(filename_arg)
 {
@@ -399,6 +466,14 @@ HistvalFileStatement::writeOutput(ostream &output, const string &basename, bool
   output << "histvalf('" << filename << "');" << endl;
 }
 
+void
+HistvalFileStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"hist_val_file\""
+         << ", \"filename\": \"" << filename << "\""
+         << "}";
+}
+
 HomotopyStatement::HomotopyStatement(const homotopy_values_t &homotopy_values_arg,
                                      const SymbolTable &symbol_table_arg) :
   homotopy_values(homotopy_values_arg),
@@ -435,6 +510,31 @@ HomotopyStatement::writeOutput(ostream &output, const string &basename, bool min
     }
 }
 
+void
+HomotopyStatement::writeJsonOutput(ostream &output) const
+{
+  deriv_node_temp_terms_t tef_terms;
+  output << "{\"statementName\": \"homotopy\", "
+         << "\"values\": [";
+  for (homotopy_values_t::const_iterator it = homotopy_values.begin();
+       it != homotopy_values.end(); it++)
+    {
+      if (it != homotopy_values.begin())
+        output << ", ";
+      output << "{\"name\": \"" << symbol_table.getName(it->first) << "\""
+             << ", \"initial_value\": \"";
+      if (it->second.first != NULL)
+        it->second.first->writeJsonOutput(output, temporary_terms_t(), tef_terms);
+      else
+        output << "NaN";
+      output << "\", \"final_value\": \"";
+      it->second.second->writeJsonOutput(output, temporary_terms_t(), tef_terms);
+      output << "\"}";
+    }
+  output << "]"
+         << "}";
+}
+
 SaveParamsAndSteadyStateStatement::SaveParamsAndSteadyStateStatement(const string &filename_arg) :
   filename(filename_arg)
 {
@@ -446,6 +546,14 @@ SaveParamsAndSteadyStateStatement::writeOutput(ostream &output, const string &ba
   output << "save_params_and_steady_state('" << filename << "');" << endl;
 }
 
+void
+SaveParamsAndSteadyStateStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"save_params_and_steady_state\""
+         << ", \"filename\": \"" << filename << "\""
+         << "}";
+}
+
 LoadParamsAndSteadyStateStatement::LoadParamsAndSteadyStateStatement(const string &filename,
                                                                      const SymbolTable &symbol_table_arg,
                                                                      WarningConsolidation &warnings) :
@@ -511,6 +619,24 @@ LoadParamsAndSteadyStateStatement::writeOutput(ostream &output, const string &ba
     }
 }
 
+void
+LoadParamsAndSteadyStateStatement::writeJsonOutput(ostream &output) const
+{
+  deriv_node_temp_terms_t tef_terms;
+  output << "{\"statementName\": \"load_params_and_steady_state\""
+         << "\"values\": [";
+  for (map<int, string>::const_iterator it = content.begin();
+       it != content.end(); it++)
+    {
+      if (it != content.begin())
+        output << ", ";
+      output << "{\"name\": \"" << symbol_table.getName(it->first) << "\""
+             << ", \"value\": \"" << it->second << "\"}";
+    }
+  output << "]"
+         << "}";
+}
+
 void
 LoadParamsAndSteadyStateStatement::fillEvalContext(eval_context_t &eval_context) const
 {
diff --git a/NumericalInitialization.hh b/NumericalInitialization.hh
index 2e34677b816155039e4dce226f387938a9b84d0b..58a7e6e0437298f37f1ddfc540ddacbccb318caf 100644
--- a/NumericalInitialization.hh
+++ b/NumericalInitialization.hh
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2003-2016 Dynare Team
+ * Copyright (C) 2003-2017 Dynare Team
  *
  * This file is part of Dynare.
  *
@@ -43,6 +43,7 @@ public:
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
   virtual void writeJuliaOutput(ostream &output, const string &basename);
   virtual void writeCOutput(ostream &output, const string &basename);
+  virtual void writeJsonOutput(ostream &output) const;
   //! Fill eval context with parameter value
   void fillEvalContext(eval_context_t &eval_context) const;
 };
@@ -69,6 +70,7 @@ public:
   void fillEvalContext(eval_context_t &eval_context) const;
 protected:
   void writeInitValues(ostream &output) const;
+  void writeJsonInitValues(ostream &output) const;
 };
 
 class InitValStatement : public InitOrEndValStatement
@@ -79,6 +81,7 @@ public:
                    const bool &all_values_required_arg);
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
   //! Writes initializations for oo_.exo_simul and oo_.exo_det_simul
   void writeOutputPostInit(ostream &output) const;
 };
@@ -92,6 +95,7 @@ public:
   //! Workaround for trac ticket #35
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class HistValStatement : public Statement
@@ -114,6 +118,7 @@ public:
   //! Workaround for trac ticket #157
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class InitvalFileStatement : public Statement
@@ -123,6 +128,7 @@ private:
 public:
   InitvalFileStatement(const string &filename_arg);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class HistvalFileStatement : public Statement
@@ -132,6 +138,7 @@ private:
 public:
   HistvalFileStatement(const string &filename_arg);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class HomotopyStatement : public Statement
@@ -147,6 +154,7 @@ public:
   HomotopyStatement(const homotopy_values_t &homotopy_values_arg,
                     const SymbolTable &symbol_table_arg);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class SaveParamsAndSteadyStateStatement : public Statement
@@ -156,6 +164,7 @@ private:
 public:
   SaveParamsAndSteadyStateStatement(const string &filename_arg);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class LoadParamsAndSteadyStateStatement : public Statement
@@ -172,6 +181,7 @@ public:
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
   //! Fill eval context with parameters/variables values
   void fillEvalContext(eval_context_t &eval_context) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 #endif
diff --git a/ParsingDriver.cc b/ParsingDriver.cc
index e71b632124cb6cd601de5b8e192c094bf50aaeb6..cb7e82e859eb53d04e49749460544a07d7cacc49 100644
--- a/ParsingDriver.cc
+++ b/ParsingDriver.cc
@@ -3189,7 +3189,7 @@ ParsingDriver::prior_posterior_function(bool prior_func)
 void
 ParsingDriver::add_ramsey_constraints_statement()
 {
-  mod_file->addStatement(new RamseyConstraintsStatement(ramsey_constraints));
+  mod_file->addStatement(new RamseyConstraintsStatement(mod_file->symbol_table, ramsey_constraints));
   ramsey_constraints.clear();
 }
 
diff --git a/Shocks.cc b/Shocks.cc
index 6f95a7a9a226ba1f19d5ef1b2e2b0f1b8cc09148..5a93206105d150a710048067a1a29f8e50b9a602 100644
--- a/Shocks.cc
+++ b/Shocks.cc
@@ -67,6 +67,34 @@ AbstractShocksStatement::writeDetShocks(ostream &output) const
   output << "M_.exo_det_length = " << exo_det_length << ";\n";
 }
 
+void
+AbstractShocksStatement::writeJsonDetShocks(ostream &output) const
+{
+  deriv_node_temp_terms_t tef_terms;
+  output << "\"deterministic_shocks\": [";
+  for (det_shocks_t::const_iterator it = det_shocks.begin();
+       it != det_shocks.end(); it++)
+    {
+      if (it != det_shocks.begin())
+        output << ", ";
+      output << "{\"var\": \"" << symbol_table.getName(it->first) << "\", "
+             << "\"values\": [";
+      for (vector<DetShockElement>::const_iterator it1 = it->second.begin();
+           it1 != it->second.end(); it1++)
+        {
+          if (it1 != it->second.begin())
+            output << ", ";
+          output << "{\"period1\": " << it1->period1 << ", "
+                 << "\"period2\": " << it1->period2 << ", "
+                 << "\"value\": \"";
+          it1->value->writeJsonOutput(output, temporary_terms_t(), tef_terms);
+          output << "\"}";
+        }
+      output << "]}";
+    }
+  output << "]";
+}
+
 ShocksStatement::ShocksStatement(bool overwrite_arg,
                                  const det_shocks_t &det_shocks_arg,
                                  const var_and_std_shocks_t &var_shocks_arg,
@@ -123,6 +151,72 @@ ShocksStatement::writeOutput(ostream &output, const string &basename, bool minim
     output << "M_.sigma_e_is_diagonal = 1;" << endl;
 }
 
+void
+ShocksStatement::writeJsonOutput(ostream &output) const
+{
+  deriv_node_temp_terms_t tef_terms;
+  output << "{\"statementName\": \"shocks\""
+         << ", \"overwrite\": ";
+  if (overwrite)
+    output << "true";
+  else
+    output << "false";
+  if (!det_shocks.empty())
+    {
+      output << ", ";
+      writeJsonDetShocks(output);
+    }
+  output<< ", \"variance\": [";
+  for (var_and_std_shocks_t::const_iterator it = var_shocks.begin(); it != var_shocks.end(); it++)
+    {
+      if (it != var_shocks.begin())
+        output << ", ";
+      output << "{\"name\": \"" << symbol_table.getName(it->first) << "\", "
+             << "\"variance\": \"";
+      it->second->writeJsonOutput(output, temporary_terms_t(), tef_terms);
+      output << "\"}";
+    }
+  output << "]"
+         << ", \"stderr\": [";
+  for (var_and_std_shocks_t::const_iterator it = std_shocks.begin(); it != std_shocks.end(); it++)
+    {
+      if (it != std_shocks.begin())
+        output << ", ";
+      output << "{\"name\": \"" << symbol_table.getName(it->first) << "\", "
+             << "\"stderr\": \"";
+      it->second->writeJsonOutput(output, temporary_terms_t(), tef_terms);
+      output << "\"}";
+    }
+  output << "]"
+         << ", \"covariance\": [";
+  for (covar_and_corr_shocks_t::const_iterator it = covar_shocks.begin(); it != covar_shocks.end(); it++)
+    {
+      if (it != covar_shocks.begin())
+        output << ", ";
+      output << "{"
+             << "\"name\": \"" << symbol_table.getName(it->first.first) << "\", "
+             << "\"name2\": \"" << symbol_table.getName(it->first.second) << "\", "
+             << "\"covariance\": \"";
+      it->second->writeJsonOutput(output, temporary_terms_t(), tef_terms);
+      output << "\"}";
+    }
+  output << "]"
+         << ", \"correlation\": [";
+  for (covar_and_corr_shocks_t::const_iterator it = corr_shocks.begin(); it != corr_shocks.end(); it++)
+    {
+      if (it != corr_shocks.begin())
+        output << ", ";
+      output << "{"
+             << "\"name\": \"" << symbol_table.getName(it->first.first) << "\", "
+             << "\"name2\": \"" << symbol_table.getName(it->first.second) << "\", "
+             << "\"correlation\": \"";
+      it->second->writeJsonOutput(output, temporary_terms_t(), tef_terms);
+      output << "\"}";
+    }
+  output << "]"
+         << "}";
+}
+
 void
 ShocksStatement::writeVarOrStdShock(ostream &output, var_and_std_shocks_t::const_iterator &it,
                                     bool stddev) const
@@ -430,6 +524,26 @@ MomentCalibration::writeOutput(ostream &output, const string &basename, bool min
   output << "};" << endl;
 }
 
+void
+MomentCalibration::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"moment_calibration\""
+         << ", \"moment_calibration_criteria\": [";
+  for (constraints_t::const_iterator it = constraints.begin(); it != constraints.end(); it++)
+    {
+      if (it != constraints.begin())
+        output << ", ";
+      output << "{\"endogenous1\": \"" << symbol_table.getName(it->endo1) << "\""
+             << ", \"endogenous2\": \"" << symbol_table.getName(it->endo2) << "\""
+             << ", \"lags\": \"" << it->lags << "\""
+             << ", \"lower_bound\": \"" << it->lower_bound << "\""
+             << ", \"upper_bound\": \"" << it->upper_bound << "\""
+             << "}";
+    }
+  output << "]"
+         << "}";
+}
+
 IrfCalibration::IrfCalibration(const constraints_t &constraints_arg,
                                const SymbolTable &symbol_table_arg,
                                const OptionsList &options_list_arg)
@@ -455,6 +569,32 @@ IrfCalibration::writeOutput(ostream &output, const string &basename, bool minima
   output << "};" << endl;
 }
 
+void
+IrfCalibration::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"irf_calibration\"";
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+
+  output << ", \"irf_restrictions\": [";
+  for (constraints_t::const_iterator it = constraints.begin(); it != constraints.end(); it++)
+    {
+      if (it != constraints.begin())
+        output << ", ";
+      output << "{\"endogenous\": \"" << symbol_table.getName(it->endo) << "\""
+             << ", \"exogenous\": \"" << symbol_table.getName(it->exo) << "\""
+             << ", \"periods\": \"" << it->periods << "\""
+             << ", \"lower_bound\": \"" << it->lower_bound << "\""
+             << ", \"upper_bound\": \"" << it->upper_bound << "\""
+             << "}";
+    }
+  output << "]"
+         << "}";
+}
+
 ShockGroupsStatement::ShockGroupsStatement(const group_t &shock_groups_arg, const string &name_arg)
   : shock_groups(shock_groups_arg), name(name_arg)
 {
diff --git a/Shocks.hh b/Shocks.hh
index 0710e663068334a66b88456f64a4b300e9bbd907..618bf34b2418271d2fc14c5d219a3a5280bb6c2c 100644
--- a/Shocks.hh
+++ b/Shocks.hh
@@ -50,6 +50,7 @@ protected:
   const det_shocks_t det_shocks;
   const SymbolTable &symbol_table;
   void writeDetShocks(ostream &output) const;
+  void writeJsonDetShocks(ostream &output) const;
 
   AbstractShocksStatement(bool mshocks_arg, bool overwrite_arg,
                           const det_shocks_t &det_shocks_arg,
@@ -77,8 +78,9 @@ public:
                   const covar_and_corr_shocks_t &covar_shocks_arg,
                   const covar_and_corr_shocks_t &corr_shocks_arg,
                   const SymbolTable &symbol_table_arg);
-  virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
   virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
+  virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class MShocksStatement : public AbstractShocksStatement
@@ -120,6 +122,7 @@ public:
   MomentCalibration(const constraints_t &constraints_arg,
                     const SymbolTable &symbol_table_arg);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class IrfCalibration : public Statement
@@ -141,6 +144,7 @@ public:
                  const SymbolTable &symbol_table_arg,
                  const OptionsList &options_list_arg);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class ShockGroupsStatement : public Statement
diff --git a/Statement.cc b/Statement.cc
index d1a34bd2cc158bffe279b5d7c6219b0ef7049de1..14bffcc3bcc197f264062525060dc86605a370b3 100644
--- a/Statement.cc
+++ b/Statement.cc
@@ -82,6 +82,11 @@ Statement::writeJuliaOutput(ostream &output, const string &basename)
 {
 }
 
+void
+Statement::writeJsonOutput(ostream &output) const
+{
+}
+
 void
 Statement::computingPass()
 {
@@ -105,6 +110,14 @@ NativeStatement::writeOutput(ostream &output, const string &basename, bool minim
   output << ns << endl;
 }
 
+void
+NativeStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"native\""
+         << ", \"string\": \"" << native_statement << "\""
+         << "}";
+}
+
 VerbatimStatement::VerbatimStatement(const string &verbatim_statement_arg) :
   verbatim_statement(verbatim_statement_arg)
 {
@@ -116,6 +129,14 @@ VerbatimStatement::writeOutput(ostream &output, const string &basename, bool min
   output << verbatim_statement << endl;
 }
 
+void
+VerbatimStatement::writeJsonOutput(ostream &output) const
+{
+  output << "{\"statementName\": \"verbatim\""
+         << ", \"string\": \"" << verbatim_statement << "\""
+         << "}";
+}
+
 void
 OptionsList::writeOutput(ostream &output) const
 {
@@ -209,6 +230,100 @@ OptionsList::writeOutput(ostream &output, const string &option_group) const
     }
 }
 
+void
+OptionsList::writeJsonOutput(ostream &output) const
+{
+  if (getNumberOfOptions() == 0)
+    return;
+
+  output << "\"options\": {";
+  for (num_options_t::const_iterator it = num_options.begin();
+       it != num_options.end();)
+    {
+      output << "\""<< it->first << "\": " << it->second;
+      it++;
+      if (it != num_options.end()
+          || !(paired_num_options.empty()
+               && string_options.empty()
+               && date_options.empty()
+               && symbol_list_options.empty()
+               && vector_int_options.empty()))
+        output << ", ";
+    }
+
+  for (paired_num_options_t::const_iterator it = paired_num_options.begin();
+       it != paired_num_options.end();)
+    {
+      output << "\""<< it->first << "\": [" << it->second.first << " " << it->second.second << "]";
+      it++;
+      if (it != paired_num_options.end()
+          || !(string_options.empty()
+               && date_options.empty()
+               && symbol_list_options.empty()
+               && vector_int_options.empty()))
+        output << ", ";
+    }
+
+  for (string_options_t::const_iterator it = string_options.begin();
+       it != string_options.end();)
+    {
+      output << "\""<< it->first << "\": \"" << it->second << "\"";
+      it++;
+      if (it != string_options.end()
+          || !(date_options.empty()
+               && symbol_list_options.empty()
+               && vector_int_options.empty()))
+        output << ", ";
+    }
+
+  for (date_options_t::const_iterator it = date_options.begin();
+       it != date_options.end();)
+    {
+      output << "\""<< it->first << "\": \"" << it->second << "\"";
+      it++;
+      if (it != date_options.end()
+          || !(symbol_list_options.empty()
+               && vector_int_options.empty()))
+        output << ", ";
+    }
+
+  for (symbol_list_options_t::const_iterator it = symbol_list_options.begin();
+       it != symbol_list_options.end(); it++)
+    {
+      output << "\""<< it->first << "\":";
+      it->second.writeJsonOutput(output);
+      it++;
+      if (it != symbol_list_options.end()
+          || !vector_int_options.empty())
+        output << ", ";
+    }
+
+  for (vec_int_options_t::const_iterator it = vector_int_options.begin();
+       it != vector_int_options.end();)
+    {
+      output << "\""<< it->first << "\": [";
+      if (it->second.size() > 1)
+        {
+          for (vector<int>::const_iterator viit = it->second.begin();
+               viit != it->second.end();)
+            {
+              output << *viit;
+              viit++;
+              if (viit != it->second.end())
+                output << ", ";
+            }
+        }
+      else
+        output << it->second.front() << endl;
+      output << "]";
+      it++;
+      if (it != vector_int_options.end())
+        output << ", ";
+    }
+
+  output << "}";
+}
+
 void
 OptionsList::clear()
 {
@@ -219,3 +334,14 @@ OptionsList::clear()
   symbol_list_options.clear();
   vector_int_options.clear();
 }
+
+int
+OptionsList::getNumberOfOptions() const
+{
+  return num_options.size()
+    + paired_num_options.size()
+    + string_options.size()
+    + date_options.size()
+    + symbol_list_options.size()
+    + vector_int_options.size();
+}
diff --git a/Statement.hh b/Statement.hh
index d189f73ab7b73f1e121aca17e3ac9c6ebc61a3a8..7e77e12e28a39fe3074263e7b02405ac89f145f7 100644
--- a/Statement.hh
+++ b/Statement.hh
@@ -141,6 +141,7 @@ public:
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const = 0;
   virtual void writeCOutput(ostream &output, const string &basename);
   virtual void writeJuliaOutput(ostream &output, const string &basename);
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class NativeStatement : public Statement
@@ -150,6 +151,7 @@ private:
 public:
   NativeStatement(const string &native_statement_arg);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class VerbatimStatement : public Statement
@@ -159,6 +161,7 @@ private:
 public:
   VerbatimStatement(const string &verbatim_statement_arg);
   virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
+  virtual void writeJsonOutput(ostream &output) const;
 };
 
 class OptionsList
@@ -176,8 +179,10 @@ public:
   date_options_t date_options;
   symbol_list_options_t symbol_list_options;
   vec_int_options_t vector_int_options;
+  int getNumberOfOptions() const;
   void writeOutput(ostream &output) const;
   void writeOutput(ostream &output, const string &option_group) const;
+  void writeJsonOutput(ostream &output) const;
   void clear();
 };
 
diff --git a/StaticModel.cc b/StaticModel.cc
index 1038ac5324ea78680faf314d00fd27cea17cc53f..ecc50640d9a83100ab34624804c8d28347b7fdf6 100644
--- a/StaticModel.cc
+++ b/StaticModel.cc
@@ -2412,3 +2412,384 @@ StaticModel::writeParamsDerivativesFile(const string &basename, bool julia) cons
 
   paramsDerivsFile.close();
 }
+
+void
+StaticModel::writeJsonOutput(ostream &output) const
+{
+  writeJsonModelEquations(output, false);
+}
+
+void
+StaticModel::writeJsonComputingPassOutput(ostream &output, bool writeDetails) const
+{
+  ostringstream model_local_vars_output;   // Used for storing model local vars
+  ostringstream model_output;              // Used for storing model
+  ostringstream jacobian_output;           // Used for storing jacobian equations
+  ostringstream hessian_output;            // Used for storing Hessian equations
+  ostringstream third_derivatives_output;  // Used for storing third order derivatives equations
+
+  deriv_node_temp_terms_t tef_terms;
+  temporary_terms_t temp_term_empty;
+  temporary_terms_t temp_term_union = temporary_terms_res;
+  temporary_terms_t temp_term_union_m_1;
+
+  string concat = "";
+
+  writeJsonModelLocalVariables(model_local_vars_output, tef_terms);
+
+  writeJsonTemporaryTerms(temporary_terms_res, temp_term_union_m_1, model_output, tef_terms, concat);
+  model_output << ", ";
+  writeJsonModelEquations(model_output, true);
+
+  int nrows = equations.size();
+  int JacobianColsNbr = symbol_table.endo_nbr();
+  int hessianColsNbr = JacobianColsNbr*JacobianColsNbr;
+
+  // Write Jacobian w.r. to endogenous only
+  temp_term_union_m_1 = temp_term_union;
+  temp_term_union.insert(temporary_terms_g1.begin(), temporary_terms_g1.end());
+  concat = "jacobian";
+  writeJsonTemporaryTerms(temp_term_union, temp_term_union_m_1, jacobian_output, tef_terms, concat);
+  jacobian_output << ", \"jacobian\": {"
+                  << "  \"nrows\": " << nrows
+                  << ", \"ncols\": " << JacobianColsNbr
+                  << ", \"entries\": [";
+  for (first_derivatives_t::const_iterator it = first_derivatives.begin();
+       it != first_derivatives.end(); it++)
+    {
+      if (it != first_derivatives.begin())
+        jacobian_output << ", ";
+
+      int eq = it->first.first;
+      int var = it->first.second;
+      int symb_id = getSymbIDByDerivID(var);
+      int col = symbol_table.getTypeSpecificID(symb_id);
+      expr_t d1 = it->second;
+
+      if (writeDetails)
+        jacobian_output << "{\"eq\": " << eq + 1
+                        << ", \"var\": \"" << symbol_table.getName(symb_id) << "\"";
+      else
+        jacobian_output << "{\"row\": " << eq + 1;
+      jacobian_output << ", \"col\": " << col + 1
+                      << ", \"val\": \"";
+      d1->writeJsonOutput(jacobian_output, temp_term_union, tef_terms);
+      jacobian_output << "\"}" << endl;
+    }
+  jacobian_output << "]}";
+
+  int g2ncols = symbol_table.endo_nbr() * symbol_table.endo_nbr();
+  // Write Hessian w.r. to endogenous only (only if 2nd order derivatives have been computed)
+  temp_term_union_m_1 = temp_term_union;
+  temp_term_union.insert(temporary_terms_g2.begin(), temporary_terms_g2.end());
+  concat = "hessian";
+  writeJsonTemporaryTerms(temp_term_union, temp_term_union_m_1, hessian_output, tef_terms, concat);
+  hessian_output << ", \"hessian\": {"
+                 << "  \"nrows\": " << equations.size()
+                 << ", \"ncols\": " << g2ncols
+                 << ", \"entries\": [";
+  for (second_derivatives_t::const_iterator it = second_derivatives.begin();
+       it != second_derivatives.end(); it++)
+    {
+      if (it != second_derivatives.begin())
+        hessian_output << ", ";
+
+      int eq = it->first.first;
+      int symb_id1 = getSymbIDByDerivID(it->first.second.first);
+      int symb_id2 = getSymbIDByDerivID(it->first.second.second);
+      expr_t d2 = it->second;
+
+      int tsid1 = symbol_table.getTypeSpecificID(symb_id1);
+      int tsid2 = symbol_table.getTypeSpecificID(symb_id2);
+
+      int col = tsid1*symbol_table.endo_nbr()+tsid2;
+      int col_sym = tsid2*symbol_table.endo_nbr()+tsid1;
+
+      if (writeDetails)
+        hessian_output << "{\"eq\": " << eq + 1
+                       << ", \"var1\": \"" << symbol_table.getName(symb_id1) << "\""
+                       << ", \"var2\": \"" << symbol_table.getName(symb_id2) << "\"";
+      else
+        hessian_output << "{\"row\": " << eq + 1;
+
+      hessian_output << ", \"col\": [" << col + 1;
+      if (symb_id1 != symb_id2)
+        hessian_output << ", " <<  col_sym + 1;
+      hessian_output << "]"
+                     << ", \"val\": \"";
+      d2->writeJsonOutput(hessian_output, temp_term_union, tef_terms);
+      hessian_output << "\"}" << endl;
+    }
+  hessian_output << "]}";
+
+  // Writing third derivatives
+  temp_term_union_m_1 = temp_term_union;
+  temp_term_union.insert(temporary_terms_g3.begin(), temporary_terms_g3.end());
+  concat = "third_derivatives";
+  writeJsonTemporaryTerms(temp_term_union, temp_term_union_m_1, third_derivatives_output, tef_terms, concat);
+  third_derivatives_output << ", \"third_derivative\": {"
+                           << "  \"nrows\": " << equations.size()
+                           << ", \"ncols\": " << hessianColsNbr * JacobianColsNbr
+                           << ", \"entries\": [";
+  for (third_derivatives_t::const_iterator it = third_derivatives.begin();
+       it != third_derivatives.end(); it++)
+    {
+      if (it != third_derivatives.begin())
+        third_derivatives_output << ", ";
+
+      int eq = it->first.first;
+      int var1 = it->first.second.first;
+      int var2 = it->first.second.second.first;
+      int var3 = it->first.second.second.second;
+      expr_t d3 = it->second;
+
+      if (writeDetails)
+        third_derivatives_output << "{\"eq\": " << eq + 1
+                                 << ", \"var1\": \"" << symbol_table.getName(getSymbIDByDerivID(var1)) << "\""
+                                 << ", \"var2\": \"" << symbol_table.getName(getSymbIDByDerivID(var2)) << "\""
+                                 << ", \"var3\": \"" << symbol_table.getName(getSymbIDByDerivID(var3)) << "\"";
+      else
+        third_derivatives_output << "{\"row\": " << eq + 1;
+
+      int id1 = getSymbIDByDerivID(var1);
+      int id2 = getSymbIDByDerivID(var2);
+      int id3 = getSymbIDByDerivID(var3);
+      set<int> cols;
+      cols.insert(id1 * hessianColsNbr + id2 * JacobianColsNbr + id3);
+      cols.insert(id1 * hessianColsNbr + id3 * JacobianColsNbr + id2);
+      cols.insert(id2 * hessianColsNbr + id1 * JacobianColsNbr + id3);
+      cols.insert(id2 * hessianColsNbr + id3 * JacobianColsNbr + id1);
+      cols.insert(id3 * hessianColsNbr + id1 * JacobianColsNbr + id2);
+      cols.insert(id3 * hessianColsNbr + id2 * JacobianColsNbr + id1);
+
+      third_derivatives_output << ", \"col\": [";
+      for (set<int>::iterator it2 = cols.begin(); it2 != cols.end(); it2++)
+        {
+          if (it2 != cols.begin())
+            third_derivatives_output << ", ";
+          third_derivatives_output << *it2 + 1;
+        }
+      third_derivatives_output << "]"
+                               << ", \"val\": \"";
+      d3->writeJsonOutput(third_derivatives_output, temp_term_union, tef_terms);
+      third_derivatives_output << "\"}" << endl;
+    }
+  third_derivatives_output << "]}";
+
+  if (writeDetails)
+    output << "\"static_model_derivative_details\": {";
+  else
+    output << "\"static_model_derivatives\": {";
+  output << model_local_vars_output.str()
+         << ", " << model_output.str()
+         << ", " << jacobian_output.str()
+         << ", " << hessian_output.str()
+         << ", " << third_derivatives_output.str()
+         << "}";
+}
+
+void
+StaticModel::writeJsonParamsDerivativesFile(ostream &output, bool writeDetails) const
+{
+  if (!residuals_params_derivatives.size()
+      && !residuals_params_second_derivatives.size()
+      && !jacobian_params_derivatives.size()
+      && !jacobian_params_second_derivatives.size()
+      && !hessian_params_derivatives.size())
+    return;
+
+  ostringstream model_local_vars_output;   // Used for storing model local vars
+  ostringstream model_output;              // Used for storing model temp vars and equations
+  ostringstream jacobian_output;           // Used for storing jacobian equations
+  ostringstream hessian_output;            // Used for storing Hessian equations
+  ostringstream hessian1_output;           // Used for storing Hessian equations
+  ostringstream third_derivs_output;       // Used for storing third order derivatives equations
+  ostringstream third_derivs1_output;      // Used for storing third order derivatives equations
+
+  deriv_node_temp_terms_t tef_terms;
+  writeJsonModelLocalVariables(model_local_vars_output, tef_terms);
+
+  temporary_terms_t temp_terms_empty;
+  string concat = "all";
+  writeJsonTemporaryTerms(params_derivs_temporary_terms, temp_terms_empty, model_output, tef_terms, concat);
+  jacobian_output << "\"deriv_wrt_params\": {"
+                  << "  \"neqs\": " << equations.size()
+                  << ", \"nparamcols\": " << symbol_table.param_nbr()
+                  << ", \"entries\": [";
+  for (first_derivatives_t::const_iterator it = residuals_params_derivatives.begin();
+       it != residuals_params_derivatives.end(); it++)
+    {
+      if (it != residuals_params_derivatives.begin())
+        jacobian_output << ", ";
+
+      int eq = it->first.first;
+      int param = it->first.second;
+      expr_t d1 = it->second;
+
+      int param_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param)) + 1;
+
+      if (writeDetails)
+        jacobian_output << "{\"eq\": " << eq + 1
+                        << ", \"param\": \"" << symbol_table.getName(getSymbIDByDerivID(param)) << "\"";
+      else
+        jacobian_output << "{\"row\": " << eq + 1;
+      jacobian_output << ", \"param_col\": " << param_col
+                      << ", \"val\": \"";
+      d1->writeJsonOutput(jacobian_output, params_derivs_temporary_terms, tef_terms);
+      jacobian_output << "\"}" << endl;
+    }
+  jacobian_output << "]}";
+  hessian_output << "\"deriv_jacobian_wrt_params\": {"
+                 << "  \"neqs\": " << equations.size()
+                 << ", \"nvarcols\": " << symbol_table.endo_nbr()
+                 << ", \"nparamcols\": " << symbol_table.param_nbr()
+                 << ", \"entries\": [";
+  for (second_derivatives_t::const_iterator it = jacobian_params_derivatives.begin();
+       it != jacobian_params_derivatives.end(); it++)
+    {
+      if (it != jacobian_params_derivatives.begin())
+        hessian_output << ", ";
+
+      int eq = it->first.first;
+      int var = it->first.second.first;
+      int param = it->first.second.second;
+      expr_t d2 = it->second;
+
+      int var_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(var)) + 1;
+      int param_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param)) + 1;
+
+      if (writeDetails)
+        hessian_output << "{\"eq\": " << eq + 1
+                       << ", \"var\": \"" << symbol_table.getName(getSymbIDByDerivID(var)) << "\""
+                       << ", \"param\": \"" << symbol_table.getName(getSymbIDByDerivID(param)) << "\"";
+      else
+        hessian_output << "{\"row\": " << eq + 1;
+      hessian_output << ", \"var_col\": " << var_col
+                     << ", \"param_col\": " << param_col
+                     << ", \"val\": \"";
+      d2->writeJsonOutput(hessian_output, params_derivs_temporary_terms, tef_terms);
+      hessian_output << "\"}" << endl;
+    }
+  hessian_output << "]}";
+
+  hessian1_output << "\"second_deriv_residuals_wrt_params\": {"
+                  << "  \"nrows\": " << equations.size()
+                  << ", \"nparam1cols\": " << symbol_table.param_nbr()
+                  << ", \"nparam2cols\": " << symbol_table.param_nbr()
+                  << ", \"entries\": [";
+  for (second_derivatives_t::const_iterator it = residuals_params_second_derivatives.begin();
+       it != residuals_params_second_derivatives.end(); ++it)
+    {
+      if (it != residuals_params_second_derivatives.begin())
+        hessian1_output << ", ";
+
+      int eq = it->first.first;
+      int param1 = it->first.second.first;
+      int param2 = it->first.second.second;
+      expr_t d2 = it->second;
+
+      int param1_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param1)) + 1;
+      int param2_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param2)) + 1;
+
+      if (writeDetails)
+        hessian1_output << "{\"eq\": " << eq + 1
+                        << ", \"param1\": \"" << symbol_table.getName(getSymbIDByDerivID(param1)) << "\""
+                        << ", \"param2\": \"" << symbol_table.getName(getSymbIDByDerivID(param2)) << "\"";
+      else
+        hessian1_output << "{\"row\": " << eq + 1;
+      hessian1_output << ", \"param1_col\": " << param1_col
+                      << ", \"param2_col\": " << param2_col
+                      << ", \"val\": \"";
+      d2->writeJsonOutput(hessian1_output, params_derivs_temporary_terms, tef_terms);
+      hessian1_output << "\"}" << endl;
+    }
+  hessian1_output << "]}";
+  third_derivs_output << "\"second_deriv_jacobian_wrt_params\": {"
+                      << "  \"neqs\": " << equations.size()
+                      << ", \"nvarcols\": " << symbol_table.endo_nbr()
+                      << ", \"nparam1cols\": " << symbol_table.param_nbr()
+                      << ", \"nparam2cols\": " << symbol_table.param_nbr()
+                      << ", \"entries\": [";
+  for (third_derivatives_t::const_iterator it = jacobian_params_second_derivatives.begin();
+       it != jacobian_params_second_derivatives.end(); ++it)
+    {
+      if (it != jacobian_params_second_derivatives.begin())
+        third_derivs_output << ", ";
+
+      int eq = it->first.first;
+      int var = it->first.second.first;
+      int param1 = it->first.second.second.first;
+      int param2 = it->first.second.second.second;
+      expr_t d2 = it->second;
+
+      int var_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(var)) + 1;
+      int param1_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param1)) + 1;
+      int param2_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param2)) + 1;
+
+      if (writeDetails)
+        third_derivs_output << "{\"eq\": " << eq + 1
+                            << ", \"var\": \"" << symbol_table.getName(var) << "\""
+                            << ", \"param1\": \"" << symbol_table.getName(getSymbIDByDerivID(param1)) << "\""
+                            << ", \"param2\": \"" << symbol_table.getName(getSymbIDByDerivID(param2)) << "\"";
+      else
+        third_derivs_output << "{\"row\": " << eq + 1;
+      third_derivs_output << ", \"var_col\": " << var_col
+                          << ", \"param1_col\": " << param1_col
+                          << ", \"param2_col\": " << param2_col
+                          << ", \"val\": \"";
+      d2->writeJsonOutput(third_derivs_output, params_derivs_temporary_terms, tef_terms);
+      third_derivs_output << "\"}" << endl;
+    }
+  third_derivs_output << "]}" << endl;
+
+  third_derivs1_output << "\"derivative_hessian_wrt_params\": {"
+                       << "  \"neqs\": " << equations.size()
+                       << ", \"nvar1cols\": " << symbol_table.endo_nbr()
+                       << ", \"nvar2cols\": " << symbol_table.endo_nbr()
+                       << ", \"nparamcols\": " << symbol_table.param_nbr()
+                       << ", \"entries\": [";
+  for (third_derivatives_t::const_iterator it = hessian_params_derivatives.begin();
+       it != hessian_params_derivatives.end(); ++it)
+    {
+      if (it != hessian_params_derivatives.begin())
+        third_derivs1_output << ", ";
+
+      int eq = it->first.first;
+      int var1 = it->first.second.first;
+      int var2 = it->first.second.second.first;
+      int param = it->first.second.second.second;
+      expr_t d2 = it->second;
+
+      int var1_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(var1)) + 1;
+      int var2_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(var2)) + 1;
+      int param_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param)) + 1;
+
+      if (writeDetails)
+        third_derivs1_output << "{\"eq\": " << eq + 1
+                             << ", \"var1\": \"" << symbol_table.getName(getSymbIDByDerivID(var1)) << "\""
+                             << ", \"var2\": \"" << symbol_table.getName(getSymbIDByDerivID(var2)) << "\""
+                             << ", \"param1\": \"" << symbol_table.getName(getSymbIDByDerivID(param)) << "\"";
+      else
+        third_derivs1_output << "{\"row\": " << eq + 1;
+      third_derivs1_output << ", \"var1_col\": " << var1_col
+                           << ", \"var2_col\": " << var2_col
+                           << ", \"param_col\": " << param_col
+                           << ", \"val\": \"";
+      d2->writeJsonOutput(third_derivs1_output, params_derivs_temporary_terms, tef_terms);
+      third_derivs1_output << "\"}" << endl;
+    }
+  third_derivs1_output << "]}" << endl;
+
+  if (writeDetails)
+    output << "\"static_model_params_derivative_details\": {";
+  else
+    output << "\"static_model_params_derivatives\": {";
+  output << model_local_vars_output.str()
+         << ", " << model_output.str()
+         << ", " << jacobian_output.str()
+         << ", " << hessian_output.str()
+         << ", " << hessian1_output.str()
+         << ", " << third_derivs_output.str()
+         << ", " << third_derivs1_output.str()
+         << "}";
+}
diff --git a/StaticModel.hh b/StaticModel.hh
index abf2aa01b29f17c763dffc4a9b6cae525679565e..2dcc81976458208eb694139962f75d12f48a2d43 100644
--- a/StaticModel.hh
+++ b/StaticModel.hh
@@ -170,6 +170,15 @@ public:
   //! Writes static model file
   void writeStaticFile(const string &basename, bool block, bool bytecode, bool use_dll, bool julia) const;
 
+  //! Write JSON Output (used by PlannerObjectiveStatement)
+  void writeJsonOutput(ostream &output) const;
+
+  //! Write JSON representation of static model
+  void writeJsonComputingPassOutput(ostream &output, bool writeDetails) const;
+
+  //! Writes file containing static parameters derivatives
+  void writeJsonParamsDerivativesFile(ostream &output, bool writeDetails) const;
+
   //! Writes file containing static parameters derivatives
   void writeParamsDerivativesFile(const string &basename, bool julia) const;
 
diff --git a/SymbolList.cc b/SymbolList.cc
index 8a8f8c62b4bbd1801bd6e0962971d235d663f10f..6e5251f1a2cee0e59bc0512c32246c107ee15efe 100644
--- a/SymbolList.cc
+++ b/SymbolList.cc
@@ -59,6 +59,20 @@ SymbolList::getSymbols() const
   return symbols;
 }
 
+void
+SymbolList::writeJsonOutput(ostream &output) const
+{
+  output << "\"symbol_list\": [";
+  for (vector<string>::const_iterator it = symbols.begin();
+       it != symbols.end(); ++it)
+    {
+      if (it != symbols.begin())
+        output << ",";
+      output << "\"" << *it << "\"";
+    }
+  output << "]";
+}
+
 void
 SymbolList::clear()
 {
diff --git a/SymbolList.hh b/SymbolList.hh
index b29f459636a21d18d4417709b51a726d957830cc..e010723097fd139e54e2420e036af2fb2c60999d 100644
--- a/SymbolList.hh
+++ b/SymbolList.hh
@@ -41,6 +41,8 @@ public:
   void writeOutput(const string &varname, ostream &output) const;
   //! Output content in Matlab format without preceding varname of writeOutput
   void write(ostream &output) const;
+  //! Write JSON output
+  void writeJsonOutput(ostream &output) const;
   //! Clears all content
   void clear();
   //! Get a copy of the string vector
diff --git a/SymbolTable.cc b/SymbolTable.cc
index 0657fe2af048fb93955031f8b8a1f0a6a25825ac..2745036321d0669c9c9a91b64316158122ec8b71 100644
--- a/SymbolTable.cc
+++ b/SymbolTable.cc
@@ -21,6 +21,7 @@
 #include <sstream>
 #include <iostream>
 #include <cassert>
+#include <boost/algorithm/string/replace.hpp>
 
 #include "SymbolTable.hh"
 
@@ -138,6 +139,17 @@ SymbolTable::freeze() throw (FrozenException)
     }
 }
 
+void
+SymbolTable::unfreeze()
+{
+  frozen = false;
+  endo_ids.clear();
+  exo_ids.clear();
+  exo_det_ids.clear();
+  param_ids.clear();
+  type_specific_ids.clear();
+}
+
 void
 SymbolTable::changeType(int id, SymbolType newtype) throw (UnknownSymbolIDException, FrozenException)
 {
@@ -1067,3 +1079,36 @@ SymbolTable::writeJuliaOutput(ostream &output) const throw (NotYetFrozenExceptio
       output << "                   ]" << endl;
     }
 }
+
+void
+SymbolTable::writeJsonOutput(ostream &output) const
+{
+  output << "\"endogenous\": ";
+  writeJsonVarVector(output, endo_ids);
+
+  output << ", \"exogenous\":";
+  writeJsonVarVector(output, exo_ids);
+
+  output << ", \"exogenous_deterministic\": ";
+  writeJsonVarVector(output, exo_det_ids);
+
+  output << ", \"parameters\": ";
+  writeJsonVarVector(output, param_ids);
+}
+
+void
+SymbolTable::writeJsonVarVector(ostream &output, const vector<int> &varvec) const
+{
+  output << "[";
+  for (size_t i = 0; i < varvec.size(); i++)
+    {
+      if (i != 0)
+        output << ", ";
+      output << "{"
+             << "\"name\":\"" << getName(varvec[i]) << "\", "
+             << "\"texName\":\"" << boost::replace_all_copy(getTeXName(varvec[i]), "\\", "\\\\") << "\", "
+             << "\"longName\":\"" << boost::replace_all_copy(getLongName(varvec[i]), "\\", "\\\\") << "\"}"
+             << endl;
+    }
+  output << "]" << endl;
+}
diff --git a/SymbolTable.hh b/SymbolTable.hh
index 9dd260ee595842e31180dea8f57deb81ece1c806..a804c908b08c159d246c8e26cddb180246a826df 100644
--- a/SymbolTable.hh
+++ b/SymbolTable.hh
@@ -224,7 +224,8 @@ private:
   int addLagAuxiliaryVarInternal(bool endo, int orig_symb_id, int orig_lead_lag, expr_t arg) throw (FrozenException);
   //! Factorized code for adding aux lead variables
   int addLeadAuxiliaryVarInternal(bool endo, int index, expr_t arg) throw (FrozenException);
-
+  //! Factorized code for Json writing
+  void writeJsonVarVector(ostream &output, const vector<int> &varvec) const;
 public:
   //! Add a symbol
   /*! Returns the symbol ID */
@@ -317,6 +318,9 @@ public:
   int getID(SymbolType type, int tsid) const throw (UnknownTypeSpecificIDException, NotYetFrozenException);
   //! Freeze symbol table
   void freeze() throw (FrozenException);
+  //! unreeze symbol table
+  //! Used after having written JSON files
+  void unfreeze();
   //! Change the type of a symbol
   void changeType(int id, SymbolType newtype) throw (UnknownSymbolIDException, FrozenException);
   //! Get type specific ID (by symbol ID)
@@ -337,6 +341,8 @@ public:
   inline int orig_endo_nbr() const throw (NotYetFrozenException);
   //! Write output of this class
   void writeOutput(ostream &output) const throw (NotYetFrozenException);
+  //! Write JSON Output
+  void writeJsonOutput(ostream &output) const;
   //! Write Julia output of this class
   void writeJuliaOutput(ostream &output) const throw (NotYetFrozenException);
   //! Write C output of this class