diff --git a/src/ComputingTasks.cc b/src/ComputingTasks.cc
index 949914e2cde12018c39d9728afd0b0e2e8628a73..c13bfe52aeeb3546e837b6b11a2076d97cf2d2b8 100644
--- a/src/ComputingTasks.cc
+++ b/src/ComputingTasks.cc
@@ -4883,15 +4883,15 @@ Smoother2histvalStatement::writeJsonOutput(ostream &output) const
   output << "}";
 }
 
-GMMEstimationStatement::GMMEstimationStatement(SymbolList symbol_list_arg,
-                                               OptionsList options_list_arg) :
+MethodOfMomentsStatement::MethodOfMomentsStatement(SymbolList symbol_list_arg,
+                                                     OptionsList options_list_arg) :
   symbol_list{move(symbol_list_arg)},
   options_list{move(options_list_arg)}
 {
 }
 
 void
-GMMEstimationStatement::checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings)
+MethodOfMomentsStatement::checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings)
 {
   try
     {
@@ -4899,71 +4899,48 @@ GMMEstimationStatement::checkPass(ModFileStructure &mod_file_struct, WarningCons
     }
   catch (SymbolList::SymbolListException &e)
     {
-      cerr << "ERROR: gmm_estimation: " << e.message << endl;
+      cerr << "ERROR: method_of_moments: " << e.message << endl;
       exit(EXIT_FAILURE);
     }
-}
+  mod_file_struct.mom_estimation_present = true;
+  // Fill in option_order of mod_file_struct
+  if (auto it = options_list.num_options.find("order");
+      it != options_list.num_options.end())
+    {
+      int order = stoi(it->second);
 
-void
-GMMEstimationStatement::writeOutput(ostream &output, const string &basename, bool minimal_workspace) const
-{
-  symbol_list.writeOutput("var_list_", output);
-  options_list.writeOutput(output);
-  output << "[M_, oo_, estim_params_, bayestopt_, dataset_, dataset_info] = "
-         << "GMM_SMM_estimation_core(var_list_, M_, options_, oo_, estim_params_, bayestopt_, dataset_, dataset_info, 'GMM');" << endl;
-}
+      if (order > 2)
+        mod_file_struct.k_order_solver = true;
 
-void
-GMMEstimationStatement::writeJsonOutput(ostream &output) const
-{
-  output << R"({"statementName": "gmm_estimation")";
-  if (options_list.getNumberOfOptions())
-    {
-      output << ", ";
-      options_list.writeJsonOutput(output);
-    }
-  if (!symbol_list.empty())
-    {
-      output << ", ";
-      symbol_list.writeJsonOutput(output);
+      mod_file_struct.order_option = max(mod_file_struct.order_option, order);
     }
-  output << "}";
-}
-
-SMMEstimationStatement::SMMEstimationStatement(SymbolList symbol_list_arg,
-                                               OptionsList options_list_arg) :
-  symbol_list{move(symbol_list_arg)},
-  options_list{move(options_list_arg)}
-{
-}
 
-void
-SMMEstimationStatement::checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings)
-{
-  try
+    if (options_list.string_options.find("datafile") == options_list.string_options.end())
     {
-      symbol_list.checkPass(warnings, { SymbolType::endogenous });
+      cerr << "ERROR: The method_of_moments statement requires a data file to be supplied via the datafile option." << endl;
+      exit(EXIT_FAILURE);
     }
-  catch (SymbolList::SymbolListException &e)
+
+    if (options_list.string_options.find("mom.mom_method") == options_list.string_options.end())
     {
-      cerr << "ERROR: smm_estimation: " << e.message << endl;
+      cerr << "ERROR: The method_of_moments statement requires a method to be supplied via the mom_method option. Possible values are GMM or SMM." << endl;
       exit(EXIT_FAILURE);
     }
 }
 
 void
-SMMEstimationStatement::writeOutput(ostream &output, const string &basename, bool minimal_workspace) const
+MethodOfMomentsStatement::writeOutput(ostream &output, const string &basename, bool minimal_workspace) const
 {
   symbol_list.writeOutput("var_list_", output);
-  options_list.writeOutput(output);
-  output << "[M_, oo_, estim_params_, bayestopt_, dataset_, dataset_info] = "
-         << "GMM_SMM_estimation_core(var_list_, M_, options_, oo_, estim_params_, bayestopt_, dataset_, dataset_info, 'SMM');" << endl;
+  options_list.writeOutput(output, "options_mom_");
+
+  output << "[oo_, options_mom_, M_] = method_of_moments(bayestopt_, options_, oo_, estim_params_, M_, matched_moments_, options_mom_);" << endl;  
 }
 
 void
-SMMEstimationStatement::writeJsonOutput(ostream &output) const
+MethodOfMomentsStatement::writeJsonOutput(ostream &output) const
 {
-  output << R"({"statementName": "smm_estimation")";
+  output << R"({"statementName": "method_of_moments")";
   if (options_list.getNumberOfOptions())
     {
       output << ", ";
@@ -4977,6 +4954,7 @@ SMMEstimationStatement::writeJsonOutput(ostream &output) const
   output << "}";
 }
 
+
 GenerateIRFsStatement::GenerateIRFsStatement(OptionsList options_list_arg,
                                              vector<string> generate_irf_names_arg,
                                              vector<map<string, double>> generate_irf_elements_arg) :
diff --git a/src/ComputingTasks.hh b/src/ComputingTasks.hh
index 53c6a96e8a2e0a30aa93d818b8a09a6e310b80a5..4a89182e4f927eb80850b6c14efdec0bb87b2a88 100644
--- a/src/ComputingTasks.hh
+++ b/src/ComputingTasks.hh
@@ -1144,25 +1144,13 @@ public:
   void writeJsonOutput(ostream &output) const override;
 };
 
-class GMMEstimationStatement : public Statement
+class MethodOfMomentsStatement : public Statement
 {
-private:
-  const SymbolList symbol_list;
-  const OptionsList options_list;
-public:
-  GMMEstimationStatement(SymbolList symbol_list_arg, OptionsList options_list_arg);
-  void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings) override;
-  void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const override;
-  void writeJsonOutput(ostream &output) const override;
-};
-
-class SMMEstimationStatement : public Statement
-{
-private:
+private:  
   const SymbolList symbol_list;
   const OptionsList options_list;
 public:
-  SMMEstimationStatement(SymbolList symbol_list_arg, OptionsList options_list_arg);
+  MethodOfMomentsStatement(SymbolList symbol_list_arg, OptionsList options_list_arg);
   void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings) override;
   void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const override;
   void writeJsonOutput(ostream &output) const override;
diff --git a/src/DynareBison.yy b/src/DynareBison.yy
index 78a087d93405647dcf8ac599e2fb147ef1fa788f..0ee489eb95c006b3b1f029bf6f32598ba10bdd3d 100644
--- a/src/DynareBison.yy
+++ b/src/DynareBison.yy
@@ -94,7 +94,7 @@ class ParsingDriver;
 %token INV_GAMMA_PDF INV_GAMMA1_PDF INV_GAMMA2_PDF IRF IRF_SHOCKS IRF_PLOT_THRESHOLD IRF_CALIBRATION
 %token FAST_KALMAN_FILTER KALMAN_ALGO KALMAN_TOL DIFFUSE_KALMAN_TOL SUBSAMPLES OPTIONS TOLF TOLX PLOT_INIT_DATE PLOT_END_DATE
 %token LAPLACE LIK_ALGO LIK_INIT LINEAR LINEAR_DECOMPOSITION LOAD_IDENT_FILES LOAD_MH_FILE LOAD_RESULTS_AFTER_LOAD_MH LOAD_PARAMS_AND_STEADY_STATE LOGLINEAR LOGDATA LYAPUNOV LINEAR_APPROXIMATION
-%token LYAPUNOV_FIXED_POINT_TOL LYAPUNOV_DOUBLING_TOL LOG_DEFLATOR LOG_TREND_VAR LOG_GROWTH_FACTOR MARKOWITZ MARGINAL_DENSITY MAX MAXIT
+%token LYAPUNOV_COMPLEX_THRESHOLD LYAPUNOV_FIXED_POINT_TOL LYAPUNOV_DOUBLING_TOL LOG_DEFLATOR LOG_TREND_VAR LOG_GROWTH_FACTOR MARKOWITZ MARGINAL_DENSITY MAX MAXIT
 %token MFS MH_CONF_SIG MH_DROP MH_INIT_SCALE MH_JSCALE MH_TUNE_JSCALE MH_TUNE_GUESS MH_MODE MH_NBLOCKS MH_REPLIC MH_RECOVER POSTERIOR_MAX_SUBSAMPLE_DRAWS MIN MINIMAL_SOLVING_PERIODS
 %token MODE_CHECK MODE_CHECK_NEIGHBOURHOOD_SIZE MODE_CHECK_SYMMETRIC_PLOTS MODE_CHECK_NUMBER_OF_POINTS MODE_COMPUTE MODE_FILE MODEL MODEL_COMPARISON MODEL_INFO MSHOCKS ABS SIGN
 %token MODEL_DIAGNOSTICS MODIFIEDHARMONICMEAN MOMENTS_VARENDO CONTEMPORANEOUS_CORRELATION DIFFUSE_FILTER SUB_DRAWS TAPER_STEPS GEWEKE_INTERVAL RAFTERY_LEWIS_QRS RAFTERY_LEWIS_DIAGNOSTICS MCMC_JUMPING_COVARIANCE MOMENT_CALIBRATION
@@ -140,7 +140,7 @@ class ParsingDriver;
 %token VLISTLOG VLISTPER SPECTRAL_DENSITY INIT2SHOCKS
 %token RESTRICTION RESTRICTION_FNAME CROSS_RESTRICTIONS NLAGS CONTEMP_REDUCED_FORM REAL_PSEUDO_FORECAST
 %token DUMMY_OBS NSTATES INDXSCALESSTATES NO_BAYESIAN_PRIOR SPECIFICATION SIMS_ZHA
-%token <string> ALPHA BETA ABAND NINV CMS NCMS CNUM GAMMA INV_GAMMA INV_GAMMA1 INV_GAMMA2 NORMAL UNIFORM EPS PDF FIG DR NONE PRIOR PRIOR_VARIANCE HESSIAN IDENTITY_MATRIX DIRICHLET DIAGONAL OPTIMAL
+%token <string> ALPHA BETA ABAND NINV CMS NCMS CNUM GAMMA INV_GAMMA INV_GAMMA1 INV_GAMMA2 NORMAL UNIFORM EPS PDF FIG DR NONE PRIOR PRIOR_VARIANCE HESSIAN IDENTITY_MATRIX DIRICHLET DIAGONAL OPTIMAL GMM SMM
 %token GSIG2_LMDM Q_DIAG FLAT_PRIOR NCSK NSTD WEIBULL WEIBULL_PDF
 %token INDXPARR INDXOVR INDXAP APBAND INDXIMF INDXFORE FOREBAND INDXGFOREHAT INDXGIMFHAT
 %token INDXESTIMA INDXGDLS EQ_MS FILTER_COVARIANCE FILTER_DECOMPOSITION SMOOTHED_STATE_UNCERTAINTY
@@ -157,15 +157,18 @@ class ParsingDriver;
 %token SHOCK_DRAWS FREE_PARAMETERS MEDIAN DATA_OBS_NBR NEIGHBORHOOD_WIDTH PVALUE_KS PVALUE_CORR
 %token FILTERED_PROBABILITIES REAL_TIME_SMOOTHED PRIOR_FUNCTION POSTERIOR_FUNCTION SAMPLING_DRAWS
 %token PROPOSAL_TYPE PROPOSAL_UPPER_BOUND PROPOSAL_LOWER_BOUND PROPOSAL_DRAWS USE_MEAN_CENTER
-%token ADAPTIVE_MH_DRAWS THINNING_FACTOR COEFFICIENTS_PRIOR_HYPERPARAMETERS SMM_ESTIMATION GMM_ESTIMATION
+%token ADAPTIVE_MH_DRAWS THINNING_FACTOR COEFFICIENTS_PRIOR_HYPERPARAMETERS
 %token CONVERGENCE_STARTING_VALUE CONVERGENCE_ENDING_VALUE CONVERGENCE_INCREMENT_VALUE
 %token MAX_ITERATIONS_STARTING_VALUE MAX_ITERATIONS_INCREMENT_VALUE MAX_BLOCK_ITERATIONS
 %token MAX_REPEATED_OPTIMIZATION_RUNS FUNCTION_CONVERGENCE_CRITERION SAVE_REALTIME
 %token PARAMETER_CONVERGENCE_CRITERION NUMBER_OF_LARGE_PERTURBATIONS NUMBER_OF_SMALL_PERTURBATIONS
 %token NUMBER_OF_POSTERIOR_DRAWS_AFTER_PERTURBATION MAX_NUMBER_OF_STAGES
 %token RANDOM_FUNCTION_CONVERGENCE_CRITERION RANDOM_PARAMETER_CONVERGENCE_CRITERION
-%token CENTERED_MOMENTS AUTOLAG RECURSIVE_ORDER_ESTIMATION BARTLETT_KERNEL_LAG WEIGHTING_MATRIX PENALIZED_ESTIMATOR VERBOSE
-%token SIMULATION_MULTIPLE SEED BOUNDED_SHOCK_SUPPORT EQTAGS STEADY_STATE_GROWTH
+/* Method of Moments */
+%token METHOD_OF_MOMENTS MOM_METHOD
+%token BARTLETT_KERNEL_LAG WEIGHTING_MATRIX WEIGHTING_MATRIX_SCALING_FACTOR PENALIZED_ESTIMATOR VERBOSE 
+%token SIMULATION_MULTIPLE MOM_SEED SEED BOUNDED_SHOCK_SUPPORT ADDITIONAL_OPTIMIZER_STEPS MOM_SE_TOLX SE_TOLX MOM_BURNIN BURNIN 
+%token EQTAGS STEADY_STATE_GROWTH
 %token ANALYTICAL_GIRF IRF_IN_PERCENT EMAS_GIRF EMAS_DROP EMAS_TOLF EMAS_MAX_ITER
 %token NO_IDENTIFICATION_STRENGTH NO_IDENTIFICATION_REDUCEDFORM NO_IDENTIFICATION_MOMENTS
 %token NO_IDENTIFICATION_MINIMAL NO_IDENTIFICATION_SPECTRUM NORMALIZE_JACOBIANS GRID_NBR
@@ -307,8 +310,7 @@ statement : parameters
           | perfect_foresight_solver
           | prior_function
           | posterior_function
-          | gmm_estimation
-          | smm_estimation
+          | method_of_moments
           | shock_groups
           | init2shocks
           | det_cond_forecast
@@ -1341,99 +1343,69 @@ perfect_foresight_solver_options : o_stack_solve_algo
                                  | o_print
                                  ;
 
-gmm_smm_common_option : o_datafile
-                      | o_nobs
-                      | o_first_obs
-                      | o_optim
-                      | o_mode_file
-                      | o_mode_compute
-                      | o_prior_trunc
-                      | o_loglinear
-                      | o_logdata
-                      | o_relative_irf
-                      | o_irf
-                      | o_tex
-                      | o_xls_sheet
-                      | o_xls_range
-                      | o_solve_algo
-                      | o_plot_priors
-                      | o_aim_solver
-                      | o_selected_variables_only
-                      | o_irf_shocks
-                      | o_sylvester
-                      | o_sylvester_fixed_point_tol
-                      | o_lyapunov
-                      | o_lyapunov_fixed_point_tol
-                      | o_lyapunov_doubling_tol
-                      | o_dr
-                      | o_dr_cycle_reduction_tol
-                      | o_dr_logarithmic_reduction_tol
-                      | o_dr_logarithmic_reduction_maxiter
-                      | o_qz_zero_threshold
-                      | o_irf_plot_threshold
-                      | o_consider_all_endogenous
-                      | o_consider_only_observed
-                      | o_dirname
-                      | o_huge_number
-                      | o_silent_optimizer
-                      | o_nograph
-                      | o_nodisplay
-                      | o_graph_format
-                      | o_analytical_girf
-                      | o_irf_in_percent
-                      | o_emas_girf
-                      | o_emas_drop
-                      | o_emas_tolf
-                      | o_emas_max_iter
-                      | o_stderr_multiples
-                      | o_diagonal_only
-                      ;
-
-gmm_estimation : GMM_ESTIMATION '(' gmm_estimation_options_list ')' ';'
-                { driver.gmm_estimation(); }
-               | GMM_ESTIMATION '(' gmm_estimation_options_list ')' symbol_list ';'
-                { driver.gmm_estimation(); }
-               ;
-
-gmm_estimation_options_list : gmm_estimation_option COMMA gmm_estimation_options_list
-                            | gmm_estimation_option
-                            ;
-
-gmm_estimation_option : gmm_smm_common_option
-                       | o_gmm_order
-                       | o_gmm_centered_moments
-                       | o_gmm_autolag
-                       | o_gmm_recursive_order_estimation
-                       | o_gmm_bartlett_kernel_lag
-                       | o_gmm_weighting_matrix
-                       | o_gmm_penalized_estimator
-                       | o_gmm_verbose
-                       ;
+method_of_moments : METHOD_OF_MOMENTS ';'
+                    { driver.method_of_moments(); }
+                  | METHOD_OF_MOMENTS '(' method_of_moments_options_list ')' ';'
+                    { driver.method_of_moments(); }
+                  | METHOD_OF_MOMENTS '(' method_of_moments_options_list ')' symbol_list ';'
+                    { driver.method_of_moments(); }
 
-smm_estimation : SMM_ESTIMATION '(' smm_estimation_options_list ')' ';'
-                { driver.smm_estimation(); }
-               | SMM_ESTIMATION '(' smm_estimation_options_list ')' symbol_list ';'
-                { driver.smm_estimation(); }
-               ;
-
-smm_estimation_options_list : smm_estimation_option COMMA smm_estimation_options_list
-                            | smm_estimation_option
-                            ;
+method_of_moments_options_list : method_of_moments_option COMMA method_of_moments_options_list
+                               | method_of_moments_option
+                               ;
 
-smm_estimation_option : gmm_smm_common_option
-                       | o_smm_order
-                       | o_smm_centered_moments
-                       | o_smm_autolag
-                       | o_smm_recursive_order_estimation
-                       | o_smm_bartlett_kernel_lag
-                       | o_smm_weighting_matrix
-                       | o_smm_penalized_estimator
-                       | o_smm_verbose
-                       | o_smm_simulation_multiple
-                       | o_smm_drop
-                       | o_smm_seed
-                       | o_smm_bounded_shock_support
-                       ;
+method_of_moments_option : o_mom_method
+                         | o_datafile
+                         | o_bartlett_kernel_lag
+                         | o_order
+                         | o_penalized_estimator
+                         | o_pruning
+                         | o_verbose
+                         | o_weighting_matrix
+                         | o_weighting_matrix_scaling_factor
+                         | o_additional_optimizer_steps
+                         | o_prefilter
+                         | o_bounded_shock_support
+                         | o_mom_seed
+                         | o_simulation_multiple
+                         | o_mom_burnin
+                         | o_dirname
+                         | o_graph_format
+                         | o_nodisplay
+                         | o_nograph
+                         | o_noprint
+                         | o_plot_priors
+                         | o_prior_trunc
+                         | o_tex
+                         | o_first_obs
+                         | o_logdata
+                         | o_nobs
+                         | o_xls_sheet
+                         | o_xls_range
+                         | o_huge_number
+                         | o_mode_compute
+                         | o_optim
+                         | o_silent_optimizer
+                         | o_mom_se_tolx
+                         | o_aim_solver
+                         | o_dr
+                         | o_dr_cycle_reduction_tol
+                         | o_dr_logarithmic_reduction_tol
+                         | o_dr_logarithmic_reduction_maxiter
+                         | o_k_order_solver
+                         | o_lyapunov
+                         | o_lyapunov_complex_threshold
+                         | o_lyapunov_fixed_point_tol
+                         | o_lyapunov_doubling_tol
+                         | o_sylvester
+                         | o_sylvester_fixed_point_tol
+                         | o_qz_criterium
+                         | o_qz_zero_threshold
+                         | o_mode_check
+                         | o_mode_check_neighbourhood_size
+                         | o_mode_check_symmetric_plots
+                         | o_mode_check_number_of_points
+                         ;
 
 prior_function : PRIOR_FUNCTION '(' prior_posterior_function_options_list ')' ';'
                 { driver.prior_posterior_function(true); }
@@ -3444,6 +3416,7 @@ o_lyapunov : LYAPUNOV EQUAL FIXED_POINT {driver.option_num("lyapunov_fp", "true"
               | LYAPUNOV EQUAL DOUBLING {driver.option_num("lyapunov_db", "true"); }
               | LYAPUNOV EQUAL SQUARE_ROOT_SOLVER {driver.option_num("lyapunov_srs", "true"); }
               | LYAPUNOV EQUAL DEFAULT {driver.option_num("lyapunov_fp", "false"); driver.option_num("lyapunov_db", "false"); driver.option_num("lyapunov_srs", "false");};
+o_lyapunov_complex_threshold : LYAPUNOV_COMPLEX_THRESHOLD EQUAL non_negative_number {driver.option_num("lyapunov_complex_threshold",$3);};
 o_lyapunov_fixed_point_tol : LYAPUNOV_FIXED_POINT_TOL EQUAL non_negative_number {driver.option_num("lyapunov_fixed_point_tol",$3);};
 o_lyapunov_doubling_tol : LYAPUNOV_DOUBLING_TOL EQUAL non_negative_number {driver.option_num("lyapunov_doubling_tol",$3);};
 o_dr : DR EQUAL CYCLE_REDUCTION {driver.option_num("dr_cycle_reduction", "true"); }
@@ -3800,51 +3773,28 @@ o_use_shock_groups : USE_SHOCK_GROUPS { driver.option_str("plot_shock_decomp.use
 o_colormap : COLORMAP EQUAL symbol { driver.option_num("plot_shock_decomp.colormap",$3); };
 o_icd_colormap : COLORMAP EQUAL symbol { driver.option_num("initial_condition_decomp.colormap",$3); };
 
-o_gmm_order : ORDER EQUAL INT_NUMBER { driver.option_num("gmm.order", $3); };
-o_smm_order : ORDER EQUAL INT_NUMBER { driver.option_num("smm.order", $3); };
-o_gmm_centered_moments : CENTERED_MOMENTS { driver.option_num("gmm.centered_moments", "true"); };
-o_smm_centered_moments : CENTERED_MOMENTS { driver.option_num("smm.centered_moments", "true"); };
-o_gmm_autolag : AUTOLAG EQUAL vec_int
-                { driver.option_vec_int("gmm.autolag", $3); }
-              | AUTOLAG EQUAL vec_int_number
-                { driver.option_vec_int("gmm.autolag", $3); }
-              ;
-o_smm_autolag : AUTOLAG EQUAL vec_int
-                { driver.option_vec_int("smm.autolag", $3); }
-              | AUTOLAG EQUAL vec_int_number
-                { driver.option_vec_int("smm.autolag", $3); }
-              ;
-o_gmm_recursive_order_estimation : RECURSIVE_ORDER_ESTIMATION { driver.option_num("gmm.recursive_estimation", "true"); };
-o_smm_recursive_order_estimation : RECURSIVE_ORDER_ESTIMATION { driver.option_num("smm.recursive_estimation", "true"); };
-o_gmm_bartlett_kernel_lag : BARTLETT_KERNEL_LAG EQUAL INT_NUMBER { driver.option_num("gmm.qLag", $3); };
-o_smm_bartlett_kernel_lag : BARTLETT_KERNEL_LAG EQUAL INT_NUMBER { driver.option_num("smm.qLag", $3); };
-o_gmm_weighting_matrix : WEIGHTING_MATRIX EQUAL OPTIMAL
-                     { driver.option_str("gmm.weighting_matrix", $3); }
-                   | WEIGHTING_MATRIX EQUAL IDENTITY_MATRIX
-                     { driver.option_str("gmm.weighting_matrix", $3); }
-                   | WEIGHTING_MATRIX EQUAL DIAGONAL
-                     { driver.option_str("gmm.weighting_matrix", $3); }
-                   | WEIGHTING_MATRIX EQUAL filename
-                     { driver.option_str("gmm.weighting_matrix", $3); }
-                   ;
-o_smm_weighting_matrix : WEIGHTING_MATRIX EQUAL OPTIMAL
-                     { driver.option_str("smm.weighting_matrix", $3); }
-                   | WEIGHTING_MATRIX EQUAL IDENTITY_MATRIX
-                     { driver.option_str("smm.weighting_matrix", $3); }
-                   | WEIGHTING_MATRIX EQUAL DIAGONAL
-                     { driver.option_str("smm.weighting_matrix", $3); }
-                   | WEIGHTING_MATRIX EQUAL filename
-                     { driver.option_str("smm.weighting_matrix", $3); }
-                   ;
-o_gmm_penalized_estimator : PENALIZED_ESTIMATOR { driver.option_num("gmm.penalized_estimator", "true"); };
-o_smm_penalized_estimator : PENALIZED_ESTIMATOR { driver.option_num("smm.penalized_estimator", "true"); };
-o_gmm_verbose : VERBOSE { driver.option_num("gmm.verbose", "true"); };
-o_smm_verbose : VERBOSE { driver.option_num("smm.verbose", "true"); };
-
-o_smm_simulation_multiple : SIMULATION_MULTIPLE EQUAL INT_NUMBER { driver.option_num("smm.simulation_multiple", $3); };
-o_smm_drop : DROP EQUAL INT_NUMBER { driver.option_num("smm.drop", $3); };
-o_smm_seed : SEED EQUAL INT_NUMBER { driver.option_num("smm.seed", $3); };
-o_smm_bounded_shock_support : BOUNDED_SHOCK_SUPPORT { driver.option_num("smm.bounded_support", "true"); };
+// Some options to "method_of_moments"
+o_bartlett_kernel_lag : BARTLETT_KERNEL_LAG EQUAL INT_NUMBER { driver.option_num("mom.bartlett_kernel_lag", $3); };
+
+o_weighting_matrix : WEIGHTING_MATRIX EQUAL vec_str { driver.option_vec_cellstr("mom.weighting_matrix", $3); }
+
+o_weighting_matrix_scaling_factor : WEIGHTING_MATRIX_SCALING_FACTOR EQUAL non_negative_number { driver.option_num("mom.weighting_matrix_scaling_factor", $3); };
+
+o_mom_method : MOM_METHOD EQUAL GMM
+               { driver.option_str("mom.mom_method", $3); }
+             | MOM_METHOD EQUAL SMM
+               { driver.option_str("mom.mom_method", $3); }                    
+             ;
+o_penalized_estimator : PENALIZED_ESTIMATOR { driver.option_num("mom.penalized_estimator", "true"); };
+o_verbose : VERBOSE { driver.option_num("mom.verbose", "true"); };
+
+o_simulation_multiple : SIMULATION_MULTIPLE EQUAL INT_NUMBER { driver.option_num("mom.simulation_multiple", $3); };
+o_mom_burnin : BURNIN EQUAL INT_NUMBER { driver.option_num("mom.burnin", $3); };
+o_bounded_shock_support : BOUNDED_SHOCK_SUPPORT { driver.option_num("mom.bounded_shock_support", "true"); };
+o_mom_seed : SEED EQUAL INT_NUMBER { driver.option_num("mom.seed", $3); };
+o_additional_optimizer_steps : ADDITIONAL_OPTIMIZER_STEPS EQUAL vec_int { driver.option_vec_int("additional_optimizer_steps", $3); };
+
+o_mom_se_tolx : SE_TOLX EQUAL non_negative_number { driver.option_num("mom.se_tolx", $3); };
 
 o_analytical_girf : ANALYTICAL_GIRF { driver.option_num("irf_opt.analytical_GIRF", "true"); };
 o_irf_in_percent : IRF_IN_PERCENT { driver.option_num("irf_opt.percent", "true"); };
diff --git a/src/DynareFlex.ll b/src/DynareFlex.ll
index 47ccde607f2a1a309c26a223ab60d2d7100c5f59..b2a9a13342ab6b5a902bc17db28aa1fb23d25b26 100644
--- a/src/DynareFlex.ll
+++ b/src/DynareFlex.ll
@@ -173,8 +173,7 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
 <INITIAL>ms_variance_decomposition {BEGIN DYNARE_STATEMENT; return token::MS_VARIANCE_DECOMPOSITION;}
 <INITIAL>conditional_forecast {BEGIN DYNARE_STATEMENT; return token::CONDITIONAL_FORECAST;}
 <INITIAL>plot_conditional_forecast {BEGIN DYNARE_STATEMENT; return token::PLOT_CONDITIONAL_FORECAST;}
-<INITIAL>gmm_estimation {BEGIN DYNARE_STATEMENT; return token::GMM_ESTIMATION;}
-<INITIAL>smm_estimation {BEGIN DYNARE_STATEMENT; return token::SMM_ESTIMATION;}
+<INITIAL>method_of_moments {BEGIN DYNARE_STATEMENT; return token::METHOD_OF_MOMENTS;}
 
 <INITIAL>markov_switching {BEGIN DYNARE_STATEMENT; return token::MARKOV_SWITCHING;}
 <INITIAL>svar {BEGIN DYNARE_STATEMENT; return token::SVAR;}
@@ -670,9 +669,7 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
 <DYNARE_STATEMENT>silent_optimizer {return token::SILENT_OPTIMIZER;}
 <DYNARE_STATEMENT>lmmcp {return token::LMMCP;}
 <DYNARE_STATEMENT>occbin {return token::OCCBIN;}
-<DYNARE_STATEMENT>centered_moments {return token::CENTERED_MOMENTS; }
-<DYNARE_STATEMENT>autolag {return token::AUTOLAG; }
-<DYNARE_STATEMENT>recursive_order_estimation {return token::RECURSIVE_ORDER_ESTIMATION; }
+<DYNARE_STATEMENT>additional_optimizer_steps	{return token::ADDITIONAL_OPTIMIZER_STEPS;}
 <DYNARE_STATEMENT>bartlett_kernel_lag {return token::BARTLETT_KERNEL_LAG; }
 <DYNARE_STATEMENT>optimal {
   yylval->build<string>(yytext);
@@ -682,11 +679,23 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
   yylval->build<string>(yytext);
   return token::DIAGONAL;
 }
+<DYNARE_STATEMENT>gmm  {
+  yylval->build<string>(yytext);
+  return token::GMM;
+}
+<DYNARE_STATEMENT>smm  {
+  yylval->build<string>(yytext);
+  return token::SMM;
+}
 <DYNARE_STATEMENT>weighting_matrix {return token::WEIGHTING_MATRIX; }
+<DYNARE_STATEMENT>weighting_matrix_scaling_factor {return token::WEIGHTING_MATRIX_SCALING_FACTOR; }
+<DYNARE_STATEMENT>mom_method {return token::MOM_METHOD; }
 <DYNARE_STATEMENT>penalized_estimator {return token::PENALIZED_ESTIMATOR; }
 <DYNARE_STATEMENT>verbose {return token::VERBOSE; }
 <DYNARE_STATEMENT>simulation_multiple {return token::SIMULATION_MULTIPLE; }
+<DYNARE_STATEMENT>burnin {return token::BURNIN; }
 <DYNARE_STATEMENT>seed {return token::SEED; }
+<DYNARE_STATEMENT>se_tolx {return token::SE_TOLX;}
 <DYNARE_STATEMENT>bounded_shock_support {return token::BOUNDED_SHOCK_SUPPORT; }
 <DYNARE_STATEMENT>analytical_girf {return token::ANALYTICAL_GIRF; }
 <DYNARE_STATEMENT>irf_in_percent {return token::IRF_IN_PERCENT; }
@@ -755,6 +764,7 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
   return token::DR;
  }
 <DYNARE_STATEMENT>sylvester_fixed_point_tol {return token::SYLVESTER_FIXED_POINT_TOL;}
+<DYNARE_STATEMENT>lyapunov_complex_threshold {return token::LYAPUNOV_COMPLEX_THRESHOLD;}
 <DYNARE_STATEMENT>lyapunov_fixed_point_tol {return token::LYAPUNOV_FIXED_POINT_TOL;}
 <DYNARE_STATEMENT>lyapunov_doubling_tol {return token::LYAPUNOV_DOUBLING_TOL;}
 <DYNARE_STATEMENT>dr_cycle_reduction_tol {return token::DR_CYCLE_REDUCTION_TOL;}
diff --git a/src/ModFile.cc b/src/ModFile.cc
index 7670e2da7b8c338fd74046f7b892c7f14bb093ed..2e74af53cac5d43e7df51c523573e855322e2307 100644
--- a/src/ModFile.cc
+++ b/src/ModFile.cc
@@ -138,6 +138,7 @@ ModFile::checkPass(bool nostrict, bool stochastic)
     || mod_file_struct.discretionary_policy_present
     || mod_file_struct.calib_smoother_present
     || mod_file_struct.identification_present
+    || mod_file_struct.mom_estimation_present
     || mod_file_struct.sensitivity_present
     || stochastic;
 
@@ -619,6 +620,7 @@ ModFile::transformPass(bool nostrict, bool stochastic, bool compute_xrefs, bool
       || mod_file_struct.discretionary_policy_present
       || mod_file_struct.calib_smoother_present
       || mod_file_struct.identification_present
+      || mod_file_struct.mom_estimation_present
       || mod_file_struct.sensitivity_present
       || stochastic)
     {
@@ -746,7 +748,7 @@ ModFile::computingPass(bool no_tmp_terms, FileOutputType output, int params_deri
           if (mod_file_struct.stoch_simul_present
               || mod_file_struct.estimation_present || mod_file_struct.osr_present
               || mod_file_struct.ramsey_model_present || mod_file_struct.identification_present
-              || mod_file_struct.calib_smoother_present)
+              || mod_file_struct.calib_smoother_present || mod_file_struct.mom_estimation_present)
             static_model.set_cutoff_to_zero();
 
           int derivsOrder = 1;
@@ -763,7 +765,7 @@ ModFile::computingPass(bool no_tmp_terms, FileOutputType output, int params_deri
           || mod_file_struct.stoch_simul_present
           || mod_file_struct.estimation_present || mod_file_struct.osr_present
           || mod_file_struct.ramsey_model_present || mod_file_struct.identification_present
-          || mod_file_struct.calib_smoother_present)
+          || mod_file_struct.calib_smoother_present || mod_file_struct.mom_estimation_present)
         {
           if (mod_file_struct.perfect_foresight_solver_present)
             dynamic_model.computingPass(true, 1, 0, global_eval_context, no_tmp_terms, block, use_dll, bytecode, linear_decomposition);
@@ -772,7 +774,7 @@ ModFile::computingPass(bool no_tmp_terms, FileOutputType output, int params_deri
               if (mod_file_struct.stoch_simul_present
                   || mod_file_struct.estimation_present || mod_file_struct.osr_present
                   || mod_file_struct.ramsey_model_present || mod_file_struct.identification_present
-                  || mod_file_struct.calib_smoother_present)
+                  || mod_file_struct.calib_smoother_present || mod_file_struct.mom_estimation_present)
                 dynamic_model.set_cutoff_to_zero();
               if (mod_file_struct.order_option < 1)
                 {
diff --git a/src/ParsingDriver.cc b/src/ParsingDriver.cc
index 1165ec40277b73e0f63e0f388eacc64e5fcaa863..c847824477846b1fc5af6e4fbb96ac965203cd0b 100644
--- a/src/ParsingDriver.cc
+++ b/src/ParsingDriver.cc
@@ -1456,6 +1456,19 @@ ParsingDriver::option_vec_str(string name_option, vector<string> opt)
   options_list.vector_str_options[move(name_option)] = move(opt);
 }
 
+void
+ParsingDriver::option_vec_cellstr(string name_option, vector<string> opt)
+{
+  if (options_list.vector_cellstr_options.find(name_option)
+      != options_list.vector_cellstr_options.end())
+    error("option " + name_option + " declared twice");
+
+  if (opt.empty())
+    error("option " + name_option + " was passed an empty vector.");
+
+  options_list.vector_cellstr_options[move(name_option)] = move(opt);
+}
+
 void
 ParsingDriver::linear()
 {
@@ -3367,17 +3380,9 @@ ParsingDriver::perfect_foresight_solver()
 }
 
 void
-ParsingDriver::gmm_estimation()
-{
-  mod_file->addStatement(make_unique<GMMEstimationStatement>(symbol_list, options_list));
-  symbol_list.clear();
-  options_list.clear();
-}
-
-void
-ParsingDriver::smm_estimation()
+ParsingDriver::method_of_moments()
 {
-  mod_file->addStatement(make_unique<SMMEstimationStatement>(symbol_list, options_list));
+  mod_file->addStatement(make_unique<MethodOfMomentsStatement>(symbol_list, options_list));
   symbol_list.clear();
   options_list.clear();
 }
diff --git a/src/ParsingDriver.hh b/src/ParsingDriver.hh
index 58818be232eacafb78465e1861a24425e8703183..22626a55d717b539dc4a0764b1395f873aba5a4b 100644
--- a/src/ParsingDriver.hh
+++ b/src/ParsingDriver.hh
@@ -506,6 +506,8 @@ public:
   void option_vec_int(string name_option, vector<int> opt);
   //! Sets an option to a vector of strings
   void option_vec_str(string name_option, vector<string> opt);
+  //! Sets an option to a celll array of strings
+  void option_vec_cellstr(string name_option, vector<string> opt);
   //! Indicates that the model is linear
   void linear();
   //! Adds a variable to temporary symbol list
@@ -907,10 +909,8 @@ public:
   void add_VAR_covariance_pair_restriction(const string &name11, const string &name12, const string &name21, const string &name22);
   //! Runs VAR estimation process
   void run_var_estimation();
-  //! GMM Estimation statement
-  void gmm_estimation();
-  //! SMM Estimation statement
-  void smm_estimation();
+  //! Method of Moments estimation statement
+  void method_of_moments();
   //! Add a var_expectation_model statement
   void var_expectation_model();
 };
diff --git a/src/Shocks.cc b/src/Shocks.cc
index ec946f13ef567d4df8a00b5969ce8c2acc30dc9e..451abc343cacbf92b616a75da0130cf0017d6382 100644
--- a/src/Shocks.cc
+++ b/src/Shocks.cc
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2003-2019 Dynare Team
+ * Copyright © 2003-2020 Dynare Team
  *
  * This file is part of Dynare.
  *
diff --git a/src/Shocks.hh b/src/Shocks.hh
index 38ffb8b84dfa36750441c727ba915eca5fb27fb5..bcc7c3018ff62b1c15b666250eb84d8e91a6d3ad 100644
--- a/src/Shocks.hh
+++ b/src/Shocks.hh
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2003-2019 Dynare Team
+ * Copyright © 2003-2020 Dynare Team
  *
  * This file is part of Dynare.
  *
diff --git a/src/Statement.cc b/src/Statement.cc
index aeba4ed900045b296c6add3263d12350feca0e54..50f7e99ef276940374e77712060aecb72f074266 100644
--- a/src/Statement.cc
+++ b/src/Statement.cc
@@ -135,6 +135,20 @@ OptionsList::writeOutput(ostream &output) const
       else
         output << vals.front() << ";" << endl;
     }
+  
+  /* vector_cellstr_options should ideally be merged into vector_str_options
+     only difference is treatment of vals.size==1, where vector_str_options
+     does not add quotes and curly brackets, i.e. allows for type conversion of
+     '2' into the number 2 
+  */
+ 
+  for (const auto & [name, vals] : vector_cellstr_options)
+    {
+      output << "options_." << name << " = {";
+      for (const auto &viit : vals)
+        output << "'" << viit << "';";
+      output << "};" << endl;
+    }
 }
 
 void
@@ -194,6 +208,14 @@ OptionsList::writeOutput(ostream &output, const string &option_group) const
       else
         output << vals.front() << ";" << endl;
     }
+
+  for (const auto & [name, vals] : vector_cellstr_options)
+    {
+      output << option_group << "." << name << " = {";
+      for (const auto &viit : vals)
+        output << "'" << viit << "';";
+      output << "};" << endl;
+    }
 }
 
 void
@@ -213,7 +235,9 @@ OptionsList::writeJsonOutput(ostream &output) const
                && string_options.empty()
                && date_options.empty()
                && symbol_list_options.empty()
-               && vector_int_options.empty()))
+               && vector_int_options.empty()
+               && vector_str_options.empty()
+               && vector_cellstr_options.empty()))
         output << ", ";
     }
 
@@ -226,7 +250,9 @@ OptionsList::writeJsonOutput(ostream &output) const
           || !(string_options.empty()
                && date_options.empty()
                && symbol_list_options.empty()
-               && vector_int_options.empty()))
+               && vector_int_options.empty()
+               && vector_str_options.empty()
+               && vector_cellstr_options.empty()))
         output << ", ";
     }
 
@@ -238,7 +264,9 @@ OptionsList::writeJsonOutput(ostream &output) const
       if (it != string_options.end()
           || !(date_options.empty()
                && symbol_list_options.empty()
-               && vector_int_options.empty()))
+               && vector_int_options.empty()
+               && vector_str_options.empty()
+               && vector_cellstr_options.empty()))
         output << ", ";
     }
 
@@ -249,7 +277,9 @@ OptionsList::writeJsonOutput(ostream &output) const
       ++it;
       if (it != date_options.end()
           || !(symbol_list_options.empty()
-               && vector_int_options.empty()))
+               && vector_int_options.empty()
+               && vector_str_options.empty()
+               && vector_cellstr_options.empty()))
         output << ", ";
     }
 
@@ -261,7 +291,9 @@ OptionsList::writeJsonOutput(ostream &output) const
       output << "}";
       ++it;
       if (it != symbol_list_options.end()
-          || !vector_int_options.empty())
+          || !(vector_int_options.empty()
+               && vector_str_options.empty()
+               && vector_cellstr_options.empty()))
         output << ", ";
     }
 
@@ -276,7 +308,9 @@ OptionsList::writeJsonOutput(ostream &output) const
             {
               output << *viit;
               ++viit;
-              if (viit != it->second.end())
+              if (viit != it->second.end()
+                  || !(vector_str_options.empty()
+                       && vector_cellstr_options.empty()))
                 output << ", ";
             }
         }
@@ -284,7 +318,9 @@ OptionsList::writeJsonOutput(ostream &output) const
         output << it->second.front() << endl;
       output << "]";
       ++it;
-      if (it != vector_int_options.end())
+      if (it != vector_int_options.end()
+          || !(vector_str_options.empty()
+               && vector_cellstr_options.empty()))
         output << ", ";
     }
 
@@ -299,7 +335,8 @@ OptionsList::writeJsonOutput(ostream &output) const
             {
               output << R"(")" << *viit << R"(")";
               ++viit;
-              if (viit != it->second.end())
+              if (viit != it->second.end()
+                  || !(vector_cellstr_options.empty()))
                 output << ", ";
             }
         }
@@ -307,7 +344,26 @@ OptionsList::writeJsonOutput(ostream &output) const
         output << it->second.front() << endl;
       output << "]";
       ++it;
-      if (it != vector_str_options.end())
+      if (it != vector_str_options.end()
+          || !(vector_cellstr_options.empty()))
+        output << ", ";
+    }
+
+  for (auto it = vector_cellstr_options.begin();
+       it != vector_cellstr_options.end();)
+    {
+      output << R"(")"<< it->first << R"(": [)";
+        for (auto viit = it->second.begin();
+             viit != it->second.end();)
+          {
+            output << R"(")" << *viit << R"(")";
+            ++viit;
+            if (viit != it->second.end())
+              output << ", ";
+          }
+      output << "]";
+      ++it;
+      if (it != vector_cellstr_options.end())
         output << ", ";
     }
 
@@ -324,6 +380,7 @@ OptionsList::clear()
   symbol_list_options.clear();
   vector_int_options.clear();
   vector_str_options.clear();
+  vector_cellstr_options.clear();
 }
 
 int
@@ -335,5 +392,6 @@ OptionsList::getNumberOfOptions() const
     + date_options.size()
     + symbol_list_options.size()
     + vector_int_options.size()
-    + vector_str_options.size();
+    + vector_str_options.size()
+    + vector_cellstr_options.size();
 }
diff --git a/src/Statement.hh b/src/Statement.hh
index efc293cfc66679b25fdef74e49e37418e2afe420..e7febfd944fd86154a40cc175ac9b0469b9888be 100644
--- a/src/Statement.hh
+++ b/src/Statement.hh
@@ -78,6 +78,8 @@ public:
   bool partial_information{false};
   //! Whether the "k_order_solver" option is used (explictly, or implicitly if order >= 3)
   bool k_order_solver{false};
+  //! Whether an method_of_moments statement is present
+  bool mom_estimation_present{false};
   //! Whether there is a calibrated measurement error
   bool calibrated_measurement_errors{false};
   //! Whether dsge_prior_weight was initialized as a parameter
@@ -197,6 +199,7 @@ public:
   using symbol_list_options_t = map<string, SymbolList>;
   using vec_int_options_t = map<string, vector<int>>;
   using vec_str_options_t = map<string, vector<string >>;
+  using vec_cellstr_options_t = map<string, vector<string >>;
   num_options_t num_options;
   paired_num_options_t paired_num_options;
   string_options_t string_options;
@@ -204,6 +207,7 @@ public:
   symbol_list_options_t symbol_list_options;
   vec_int_options_t vector_int_options;
   vec_str_options_t vector_str_options;
+  vec_cellstr_options_t vector_cellstr_options;
   int getNumberOfOptions() const;
   void writeOutput(ostream &output) const;
   void writeOutput(ostream &output, const string &option_group) const;