From ee6880bfdb2b3c17dab0f87a8768187d9dc0a8e7 Mon Sep 17 00:00:00 2001
From: Houtan Bastani <houtan@dynare.org>
Date: Fri, 28 Aug 2015 12:38:25 +0200
Subject: [PATCH] preprocessor: macroprocessor: add @#includepath macro. #1039

---
 macro/MacroDriver.hh |  8 ++++--
 macro/MacroFlex.ll   | 60 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 66 insertions(+), 2 deletions(-)

diff --git a/macro/MacroDriver.hh b/macro/MacroDriver.hh
index 92d90ee4..83828b2e 100644
--- a/macro/MacroDriver.hh
+++ b/macro/MacroDriver.hh
@@ -79,7 +79,7 @@ private:
   //! Should we omit the @#line statements ?
   const bool no_line_macro;
   //! The paths to search when looking for .mod files
-  const vector<string> path;
+  vector<string> path;
   //! True iff current context is the body of a loop
   bool is_for_context;
   //! If current context is the body of a loop, contains the string of the loop body
@@ -122,6 +122,10 @@ private:
   //! Restore last scanning context
   void restore_context(Macro::parser::location_type *yylloc);
 
+  //! pushes the colon-separated paths passed to @#includepath onto the path vector
+  void push_path(string *includepath, Macro::parser::location_type *yylloc,
+                 MacroDriver &driver);
+
   //! Saves current scanning context and create a new context with content of filename
   /*! Filename must be a newly allocated string which will be deleted by the lexer */
   void create_include_context(string *filename, Macro::parser::location_type *yylloc,
@@ -178,7 +182,7 @@ public:
   //! Starts parsing a file, returns output in out
   /*! \param no_line_macro should we omit the @#line statements ? */
   void parse(const string &f, ostream &out, bool debug, bool no_line_macro,
-             map<string,string> defines, const vector<string> path);
+             map<string,string> defines, vector<string> path);
 
   //! Name of main file being parsed
   string file;
diff --git a/macro/MacroFlex.ll b/macro/MacroFlex.ll
index 994d2420..9e694eb4 100644
--- a/macro/MacroFlex.ll
+++ b/macro/MacroFlex.ll
@@ -21,6 +21,9 @@
 using namespace std;
 
 #include <fstream>
+#include <boost/algorithm/string/trim.hpp>
+#include <boost/algorithm/string/split.hpp>
+#include <boost/tokenizer.hpp>
 
 #include "MacroDriver.hh"
 
@@ -68,6 +71,47 @@ CONT \\\\
   yylloc->step();
 %}
 
+<INITIAL>^{SPC}*@#{SPC}*includepath{SPC}+\"([^\"\r\n:;|<>]*){1}(:[^\"\r\n:;|<>]*)*\"{SPC}*{EOL} {
+                              yylloc->lines(1);
+                              yylloc->step();
+
+                              // Get path
+                              string *includepath = new string(yytext);
+                              int dblq_idx1 = includepath->find('"');
+                              int dblq_idx2 = includepath->find('"', dblq_idx1 + 1);
+                              includepath->erase(dblq_idx2);
+                              includepath->erase(0, dblq_idx1 + 1);
+
+                              push_path(includepath, yylloc, driver);
+                              BEGIN(INITIAL);
+                            }
+
+<INITIAL>^{SPC}*@#{SPC}*includepath{SPC}+[^\"\r\n]*{SPC}*{EOL} {
+                              yylloc->lines(1);
+                              yylloc->step();
+
+                              // Get variable name
+                              string pathvar = string(yytext);
+                              int dblq_idx1 = pathvar.find("includepath");
+                              pathvar.erase(0, dblq_idx1 + 11);
+                              pathvar.erase(0, pathvar.find_first_not_of(" \t"));
+                              size_t p = pathvar.find_last_not_of(" \t\n\r");
+                              if (string::npos != p)
+                                pathvar.erase(p+1);
+
+                              string *includepath = NULL;
+                              try
+                              {
+                                includepath = new string(driver.get_variable(pathvar)->toString());
+                              }
+                              catch(MacroDriver::UnknownVariable(&e))
+                              {
+                                driver.error(*yylloc, "Unknown variable: " + pathvar);
+                              }
+                              push_path(includepath, yylloc, driver);
+                              BEGIN(INITIAL);
+                            }
+
 <INITIAL>^{SPC}*@#{SPC}*include{SPC}+\"[^\"\r\n]*\"{SPC}*{EOL} {
                               yylloc->lines(1);
                               yylloc->step();
@@ -383,6 +427,22 @@ MacroFlex::restore_context(Macro::parser::location_type *yylloc)
   output_line(yylloc);
 }
 
+void
+MacroFlex::push_path(string *includepath, Macro::parser::location_type *yylloc,
+                                  MacroDriver &driver)
+{
+  using namespace boost;
+  vector<string> tokenizedPath;
+  split(tokenizedPath, *includepath, is_any_of(":"), token_compress_on);
+  for (vector<string>::iterator it = tokenizedPath.begin();
+       it != tokenizedPath.end(); it++ )
+    if (!it->empty())
+      {
+        trim(*it);
+        path.push_back(*it);
+      }
+}
+
 void
 MacroFlex::create_include_context(string *filename, Macro::parser::location_type *yylloc,
                                   MacroDriver &driver)
-- 
GitLab