From 67b8ef1a1937e8434bf252a616eeda2e3d7e5c4b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Villemot?= <sebastien@dynare.org>
Date: Fri, 19 Nov 2021 14:13:30 +0100
Subject: [PATCH] Macroprocessor: fix line counter inside @{} constructs
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

There were two bugs:
– with the LF convention, newlines were counted twice
– with the CR+LF convention, they were counted four times (because the CR was
  included in yyleng, alongside the LF)

The fix consists in implementing a location_increment() method similar to the
one used for the Dynare parser. This is the most robust solution.

By the way, mark the method DynareFlex::location_increment() method static.

(cherry picked from commit 1de3476546da22eb6bc11bfa23d78b3576f83217)
---
 src/ParsingDriver.hh   |  2 +-
 src/macro/Driver.hh    |  3 ++-
 src/macro/Tokenizer.ll | 27 +++++++++++++++------------
 3 files changed, 18 insertions(+), 14 deletions(-)

diff --git a/src/ParsingDriver.hh b/src/ParsingDriver.hh
index 0c21db3b..a4aee28b 100644
--- a/src/ParsingDriver.hh
+++ b/src/ParsingDriver.hh
@@ -75,7 +75,7 @@ public:
   string filename;
 
   //! Increment the location counter given a token
-  void location_increment(Dynare::parser::location_type *yylloc, const char *yytext);
+  static void location_increment(Dynare::parser::location_type *yylloc, const char *yytext);
 
   //! Count parens in dates statement
   int dates_parens_nb;
diff --git a/src/macro/Driver.hh b/src/macro/Driver.hh
index 5f1367f3..4d600a80 100644
--- a/src/macro/Driver.hh
+++ b/src/macro/Driver.hh
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2019-2020 Dynare Team
+ * Copyright © 2019-2021 Dynare Team
  *
  * This file is part of Dynare.
  *
@@ -56,6 +56,7 @@ namespace macro
     Tokenizer::parser::token_type lex(Tokenizer::parser::semantic_type *yylval,
                                       Tokenizer::parser::location_type *yylloc,
                                       macro::Driver &driver);
+    static void location_increment(Tokenizer::parser::location_type *yylloc, const char *yytext);
   };
 
   //! Implements the macro expansion using a Flex scanner and a Bison parser
diff --git a/src/macro/Tokenizer.ll b/src/macro/Tokenizer.ll
index c72561e4..c930cc54 100644
--- a/src/macro/Tokenizer.ll
+++ b/src/macro/Tokenizer.ll
@@ -50,7 +50,7 @@ using token = Tokenizer::parser::token;
 
 %{
   // Increments location counter for every token read
-  # define YY_USER_ACTION yylloc->columns(yyleng);
+  #define YY_USER_ACTION location_increment(yylloc, yytext);
 %}
 
 SPC  [ \t]+
@@ -175,22 +175,15 @@ CONT \\\\{SPC}*
 }
 
 <expr,eval>{SPC}+                         { }
-<eval>{EOL}+                              { yylloc->lines(yyleng); yylloc->lines(yyleng); }
+<eval>{EOL}+                              { }
 <eval>\}                                  { BEGIN(INITIAL); return token::END_EVAL; }
 
-<expr,end_line>{CONT}("//".*)?{SPC}*{EOL} { yylloc->lines(1); yylloc->step(); }
-<expr,end_line>{SPC}*("//".*)?{EOL}       {
-                                            yylloc->lines(1);
-                                            BEGIN(INITIAL);
-                                            return token::EOL;
-                                          }
+<expr,end_line>{CONT}("//".*)?{SPC}*{EOL} { yylloc->step(); }
+<expr,end_line>{SPC}*("//".*)?{EOL}       { BEGIN(INITIAL); return token::EOL; }
 
 <INITIAL>^{SPC}*@#{SPC}*                  { BEGIN(directive); }
 <INITIAL>@\{                              { BEGIN(eval); return token::BEGIN_EVAL; }
-<INITIAL>{EOL}                            {
-                                            yylloc->lines(1);
-                                            return token::EOL;
-                                          }
+<INITIAL>{EOL}                            { return token::EOL; }
 <INITIAL><<EOF>>                          { yyterminate(); }
 
 <directive,expr,eval,end_line><<EOF>>     { driver.error(*yylloc, "unexpected end of file"); }
@@ -200,6 +193,16 @@ CONT \\\\{SPC}*
 
 %%
 
+void
+TokenizerFlex::location_increment(Tokenizer::parser::location_type *yylloc, const char *yytext)
+{
+  while (*yytext != 0)
+    if (*yytext++ == '\n')
+      yylloc->lines(1);
+    else
+      yylloc->columns(1);
+}
+
 /* This implementation of TokenizerFlexLexer::yylex() is required to fill the
  * vtable of the class TokenizerFlexLexer. We define the scanner's main yylex
  * function via YY_DECL to reside in the TokenizerFlex class instead. */
-- 
GitLab