From a0ffc1751e712e55b27aa7349ec7db302557476b Mon Sep 17 00:00:00 2001
From: Akim Demaille <demaille@gostai.com>
Date: Thu, 21 Aug 2008 21:46:13 +0200
Subject: [PATCH] Support i18n of the parse error messages.

	* TODO (lalr1.cc/I18n): Remove.
	* data/lalr1.cc (yysyntax_error_): Support the translation of the
	error messages, as done in yacc.c.
	Stay within the yy* pseudo namespace.
---
 ChangeLog     |  8 ++++++
 TODO          |  4 ---
 data/lalr1.cc | 77 ++++++++++++++++++++++++++++++++-------------------
 3 files changed, 56 insertions(+), 33 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 8f973721..fad6f317 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2008-11-11  Akim Demaille  <demaille@gostai.com>
+
+	Support i18n of the parse error messages.
+	* TODO (lalr1.cc/I18n): Remove.
+	* data/lalr1.cc (yysyntax_error_): Support the translation of the
+	error messages, as done in yacc.c.
+	Stay within the yy* pseudo namespace.
+
 2008-11-11  Akim Demaille  <demaille@gostai.com>
 
 	More TODO.
diff --git a/TODO b/TODO
index ae89c927..1b9aaed7 100644
--- a/TODO
+++ b/TODO
@@ -106,10 +106,6 @@ find something clean (not like YYLSP_NEEDED...).
 Before releasing, make sure the documentation ("Understanding your
 parser") refers to the current `output' format.
 
-* lalr1.cc
-** I18n
-Catch up with yacc.c.
-
 * Report
 
 **  GLR
diff --git a/data/lalr1.cc b/data/lalr1.cc
index 5a9d5c08..bacdf37c 100644
--- a/data/lalr1.cc
+++ b/data/lalr1.cc
@@ -1385,9 +1385,9 @@ m4_ifdef([b4_lex_param], [, ]b4_lex_param)));])[
   // Generate an error message.
   std::string
   ]b4_parser_class_name[::yysyntax_error_ (int yystate, int]dnl
-b4_error_verbose_if([ tok])[)
+b4_error_verbose_if([ yytoken])[)
   {
-    std::string res;
+    std::string yyres;
     YYUSE (yystate);
 #if YYERROR_VERBOSE
     int yyn = yypact_[yystate];
@@ -1400,36 +1400,55 @@ b4_error_verbose_if([ tok])[)
 	/* Stay within bounds of both yycheck and yytname.  */
 	int yychecklim = yylast_ - yyn + 1;
 	int yyxend = yychecklim < yyntokens_ ? yychecklim : yyntokens_;
-	int count = 0;
-	for (int x = yyxbegin; x < yyxend; ++x)
-	  if (yycheck_[x + yyn] == x && x != yyterror_)
-	    ++count;
-
-	// FIXME: This method of building the message is not compatible
-	// with internationalization.  It should work like yacc.c does it.
-	// That is, first build a string that looks like this:
-	// "syntax error, unexpected %s or %s or %s"
-	// Then, invoke YY_ on this string.
-	// Finally, use the string as a format to output
-	// yytname_[tok], etc.
-	// Until this gets fixed, this message appears in English only.
-	res = "syntax error, unexpected ";
-	res += yytnamerr_ (yytname_[tok]);
-	if (count < 5)
-	  {
-	    count = 0;
-	    for (int x = yyxbegin; x < yyxend; ++x)
-	      if (yycheck_[x + yyn] == x && x != yyterror_)
-		{
-		  res += (!count++) ? ", expecting " : " or ";
-		  res += yytnamerr_ (yytname_[x]);
-		}
-	  }
+
+        // Number of "expected" tokens.
+	size_t yycount = 0;
+        // Its maximum.
+        enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+        // Arguments of yyformat.
+        char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+        yyarg[yycount++] = yytname_[yytoken];
+	for (int yyx = yyxbegin; yyx < yyxend; ++yyx)
+	  if (yycheck_[yyx + yyn] == yyx && yyx != yyterror_)
+          {
+            if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+            {
+              yycount = 1;
+              break;
+            }
+            else
+              yyarg[yycount++] = yytname_[yyx];
+          }
+
+        char const* yyformat = 0;
+        switch (yycount)
+        {
+#define YYCASE_(N, S)                           \
+          case N:                               \
+            yyformat = S;                       \
+          break
+          YYCASE_(1, YY_("syntax error, unexpected %s"));
+          YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
+          YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
+          YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
+          YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
+#undef YYCASE_
+        }
+        // Argument number.
+        size_t yyi = 0;
+        for (char const* yyp = yyformat; *yyp; ++yyp)
+          if (yyp[0] == '%' && yyp[1] == 's' && yyi < yycount)
+          {
+            yyres += yytnamerr_ (yyarg[yyi++]);
+            ++yyp;
+          }
+          else
+            yyres += *yyp;
       }
     else
 #endif
-      res = YY_("syntax error");
-    return res;
+      yyres = YY_("syntax error");
+    return yyres;
   }
 
 
-- 
2.47.2