From 9db21a231c5ab8f8aa26680ffecf3abfcf45bfab Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Villemot?= <sebastien@dynare.org>
Date: Tue, 1 Mar 2022 12:29:21 +0100
Subject: [PATCH] =?UTF-8?q?Handle=20=E2=80=9Cresid=E2=80=9D=20command=20at?=
 =?UTF-8?q?=20the=20preprocessor=20level=20and=20add=20=E2=80=9Cnon=5Fzero?=
 =?UTF-8?q?=E2=80=9D=20option?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/ComputingTasks.cc | 24 ++++++++++++++++++++++++
 src/ComputingTasks.hh | 10 ++++++++++
 src/DynareBison.yy    | 11 ++++++++++-
 src/DynareFlex.ll     |  2 ++
 src/ParsingDriver.cc  |  7 +++++++
 src/ParsingDriver.hh  |  4 +++-
 6 files changed, 56 insertions(+), 2 deletions(-)

diff --git a/src/ComputingTasks.cc b/src/ComputingTasks.cc
index 4164f9bb..d06309a2 100644
--- a/src/ComputingTasks.cc
+++ b/src/ComputingTasks.cc
@@ -5290,3 +5290,27 @@ OccbinConstraintsStatement::writeJsonOutput(ostream &output) const
     }
   output << "]}" << endl;
 }
+
+ResidStatement::ResidStatement(OptionsList options_list_arg) :
+  options_list{move(options_list_arg)}
+{
+}
+
+void
+ResidStatement::writeOutput(ostream &output, const string &basename, bool minimal_workspace) const
+{
+  options_list.writeOutput(output, "options_resid_");
+  output << "resid(options_resid_);" << endl;
+}
+
+void
+ResidStatement::writeJsonOutput(ostream &output) const
+{
+  output << R"({"statementName": "resid")";
+  if (options_list.getNumberOfOptions())
+    {
+      output << ", ";
+      options_list.writeJsonOutput(output);
+    }
+  output << "}";
+}
diff --git a/src/ComputingTasks.hh b/src/ComputingTasks.hh
index 85f5b280..542e9777 100644
--- a/src/ComputingTasks.hh
+++ b/src/ComputingTasks.hh
@@ -1239,4 +1239,14 @@ public:
   void writeJsonOutput(ostream &output) const override;
 };
 
+class ResidStatement : public Statement
+{
+private:
+  const OptionsList options_list;
+public:
+  explicit ResidStatement(OptionsList options_list_arg);
+  void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const override;
+  void writeJsonOutput(ostream &output) const override;
+};
+
 #endif
diff --git a/src/DynareBison.yy b/src/DynareBison.yy
index a17d774e..1d746a1b 100644
--- a/src/DynareBison.yy
+++ b/src/DynareBison.yy
@@ -186,7 +186,7 @@ class ParsingDriver;
 %token NO_IDENTIFICATION_MINIMAL NO_IDENTIFICATION_SPECTRUM NORMALIZE_JACOBIANS GRID_NBR
 %token TOL_RANK TOL_DERIV TOL_SV CHECKS_VIA_SUBSETS MAX_DIM_SUBSETS_GROUPS ZERO_MOMENTS_TOLERANCE
 %token MAX_NROWS SQUEEZE_SHOCK_DECOMPOSITION WITH_EPILOGUE MODEL_REMOVE MODEL_REPLACE MODEL_OPTIONS
-%token VAR_REMOVE ESTIMATED_PARAMS_REMOVE STATIC INCIDENCE
+%token VAR_REMOVE ESTIMATED_PARAMS_REMOVE STATIC INCIDENCE RESID NON_ZERO
 
 %token <vector<string>> SYMBOL_VEC
 
@@ -352,6 +352,7 @@ statement : parameters
           | model_options
           | var_remove
           | pac_target_info
+          | resid
           ;
 
 dsample : DSAMPLE INT_NUMBER ';'
@@ -996,6 +997,13 @@ pac_target_kind : LL
                   { $$ = PacTargetKind::dd; }
                 ;
 
+resid : RESID ';'
+        { driver.resid(); }
+      | RESID '(' o_non_zero ')' ';'
+        { driver.resid(); }
+      ;
+
+
 /* The tokens below must be accepted in both DYNARE_STATEMENT and DYNARE_BLOCK
    states in the lexer, because of model block and model_options statement */
 model_option : BLOCK { driver.block(); }
@@ -4171,6 +4179,7 @@ o_emas_girf : EMAS_GIRF { driver.option_num("irf_opt.ergodic_mean_irf", "true");
 o_emas_drop : EMAS_DROP EQUAL INT_NUMBER { driver.option_num("irf_opt.EM.drop", $3); };
 o_emas_tolf : EMAS_TOLF EQUAL non_negative_number { driver.option_num("irf_opt.EM.tolf", $3); };
 o_emas_max_iter : EMAS_MAX_ITER EQUAL INT_NUMBER { driver.option_num("irf_opt.EM.iter", $3); };
+o_non_zero : NON_ZERO { driver.option_num("non_zero", "true"); };
 
 // Some options to "identification"
 o_no_identification_strength : NO_IDENTIFICATION_STRENGTH { driver.option_num("no_identification_strength", "true"); };
diff --git a/src/DynareFlex.ll b/src/DynareFlex.ll
index 84906f52..17167d04 100644
--- a/src/DynareFlex.ll
+++ b/src/DynareFlex.ll
@@ -195,6 +195,7 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
 <INITIAL>model_remove {BEGIN DYNARE_STATEMENT; return token::MODEL_REMOVE;}
 <INITIAL>model_options {BEGIN DYNARE_STATEMENT; return token::MODEL_OPTIONS;}
 <INITIAL>var_remove {BEGIN DYNARE_STATEMENT; return token::VAR_REMOVE;}
+<INITIAL>resid {BEGIN DYNARE_STATEMENT; return token::RESID;}
 
 <DYNARE_STATEMENT>; {
   if (!sigma_e)
@@ -754,6 +755,7 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
 <DYNARE_STATEMENT>max_nrows {return token::MAX_NROWS;}
 <DYNARE_STATEMENT>with_epilogue {return token::WITH_EPILOGUE;}
 <DYNARE_STATEMENT>heteroskedastic_filter {return token::HETEROSKEDASTIC_FILTER;}
+<DYNARE_STATEMENT>non_zero {return token::NON_ZERO;}
 
 <DYNARE_STATEMENT>\$[^$]*\$ {
   strtok(yytext+1, "$");
diff --git a/src/ParsingDriver.cc b/src/ParsingDriver.cc
index 89d32bc8..48b200ec 100644
--- a/src/ParsingDriver.cc
+++ b/src/ParsingDriver.cc
@@ -3650,3 +3650,10 @@ ParsingDriver::var_remove()
     }
   symbol_list.clear();
 }
+
+void
+ParsingDriver::resid()
+{
+  mod_file->addStatement(make_unique<ResidStatement>(options_list));
+  options_list.clear();
+}
diff --git a/src/ParsingDriver.hh b/src/ParsingDriver.hh
index 2d7f321e..f43d8fcc 100644
--- a/src/ParsingDriver.hh
+++ b/src/ParsingDriver.hh
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2003-2021 Dynare Team
+ * Copyright © 2003-2022 Dynare Team
  *
  * This file is part of Dynare.
  *
@@ -921,6 +921,8 @@ public:
   void set_pac_target_info_component_growth(expr_t growth);
   void set_pac_target_info_component_auxname(string auxname);
   void set_pac_target_info_component_kind(PacTargetKind kind);
+  // Add a resid statement
+  void resid();
   // Equivalent of MATLAB’s strsplit. Returns an empty vector given an empty string.
   static vector<string> strsplit(const string &str, char delim);
   // Returns true iff the string is a legal symbol identifier (see NAME token in lexer)
-- 
GitLab