Re: [Dlang] Internationalisation WIP
Adela Vais <[email protected]> Wed, 6 Jan 2021 17:11:00 +0200
| Newsgroups | gmane.comp.parsers.bison.patches |
|---|---|
| Message-ID | <CAPk8xGfq2=RE6+eXhVoN79hwnyjOAhqv49_TUHJMC97pkgqo+Q@mail.gmail.com> |
Hello, I took another look in the C skeleton and only now I see that _ is not handled there. It's the user's task to handle it. Bisthromatic has this, for example: #if defined ENABLE_NLS && ENABLE_NLS # define _(Msgid) gettext (Msgid) #else # define _(Msgid) (Msgid) #endif I am changing the skeleton to remove it. Adela În mar., 5 ian. 2021 la 20:57, Akim Demaille <[email protected]> a scris: > > > > Le 5 janv. 2021 à 17:19, Adela Vais <[email protected]> a écrit : > > > > Hello! > > > > The following 4 commits regard the internationalisation, and the removal > of: yytnamerr, $end, and some unused imports caused by the > internationalisation (now the import of std.conv is at global scope, not > only used by lookahead correction). > > Excellent work, thanks Adela! > > I squashed 2 and 3 together (2 was modifying yytnamerr, and 3 removed it). > > I was about to push this, but it does not run properly on my machine. > > 572. calc.at:1460: testing Calculator D parse.error=custom ... > /Users/akim/src/gnu/bison/tests/calc.at:1460: COLUMNS=1000; export > COLUMNS; NO_TERM_HYPERLINKS=1; export NO_TERM_HYPERLINKS; bison --color=no > -fno-caret -Wno-deprecated -o calc.d calc.y > /Users/akim/src/gnu/bison/tests/calc.at:1460: $DC $DCFLAGS -ofcalc > calc.d > stderr: > Undefined symbols for architecture x86_64: > "_gettext", referenced from: > __D4calc1_FAyaZQe in calc.o > ld: symbol(s) not found for architecture x86_64 > clang: error: linker command failed with exit code 1 (use -v to see > invocation) > Error: linker exited with status 1 > stdout: > /Users/akim/src/gnu/bison/tests/calc.at:1460: exit code was 1, expected 0 > 572. calc.at:1460: 572. Calculator D parse.error=custom (calc.at:1460): > FAILED (calc.at:1460) > > We need a way to make this portable. I expect we'd also get a failure on > the CI. > > Why is this failing on my machine? What have you done for it to work for > you? > > Unfortunately the patches don't commute, I can't install 2 and 3 without 1.
0001-d-add-internationalisation-support.patch
(application/octet-stream, 7.5 KB)
From 9c0d524d055525a4574cfce211f2688608110020 Mon Sep 17 00:00:00 2001 From: Adela Vais <[email protected]> Date: Sat, 28 Nov 2020 21:09:39 +0200 Subject: [PATCH for Dlang support 1/3] d: add internationalisation support The D parser implements this feature similarly to the C parser, by using Gettext. Functions gettext() and dgettext() are imported using extern(C). The internationalisation uses yysymbol_name to report the name of the SymbolKinds. * data/skeletons/d.m4 (SymbolKind.toString.yytranslatable, SymbolKind.toString.yysymbol_name: New), data/skeletons/lalr1.d: Here. * doc/bison.texi: Document it. * tests/calc.at: Test it. --- data/skeletons/d.m4 | 22 ++++++++++++---- data/skeletons/lalr1.d | 59 ++++++++++++++++++++++++++++++++++------- doc/bison.texi | 60 ++++++++++++++++++++++++++++++++++++++++++ tests/calc.at | 19 ++++++++++++- 4 files changed, 145 insertions(+), 15 deletions(-) diff --git a/data/skeletons/d.m4 b/data/skeletons/d.m4 index 331c06a8..5320c483 100644 --- a/data/skeletons/d.m4 +++ b/data/skeletons/d.m4 @@ -192,7 +192,12 @@ b4_symbol_foreach([b4_token_enum])dnl } ]) - +# b4_symbol_translate(STRING) +# --------------------------- +# Used by "bison" in the array of symbol names to mark those that +# require translation. +m4_define([b4_symbol_translate], +[[_($1)]]) ## -------------- ## ## Symbol kinds. ## @@ -252,8 +257,17 @@ m4_define([b4_declare_symbol_enum], final void toString(W)(W sink) const if (isOutputRange!(W, char)) { + immutable string[] yy_sname = @{ + ]b4_symbol_names[ + @};]b4_has_translations_if([[ + /* YYTRANSLATABLE[SYMBOL-NUM] -- Whether YY_SNAME[SYMBOL-NUM] is + internationalizable. */ + immutable ]b4_int_type_for([b4_translatable])[[] yytranslatable = @{ + ]b4_translatable[ + @}; + + put(sink, yy_sname[yycode_]);]], [[ string yystr = yytname_[yycode_]; - if (yystr[0] == '"') { strip_quotes: @@ -280,9 +294,7 @@ m4_define([b4_declare_symbol_enum], { put(sink, "end of input"); return; - } - - put(sink, yystr); + }]])[ } } ]]) diff --git a/data/skeletons/lalr1.d b/data/skeletons/lalr1.d index fd0038d6..ede7d8c7 100644 --- a/data/skeletons/lalr1.d +++ b/data/skeletons/lalr1.d @@ -40,6 +40,29 @@ version(D_Version2) { ]b4_user_post_prologue[ ]b4_percent_code_get([[imports]])[ import std.format; +import std.conv; + +/** + * Handle error message internationalisation. + */ +static if (!is(typeof(YY_))) { + version(YYENABLE_NLS) + { + version(ENABLE_NLS) + { + extern(C) char* dgettext(const char*, const char*); + string YY_(const char* s) + { + return to!string(dgettext("bison-runtime", s)); + } + } + } + static if (!is(typeof(YY_))) + { + pragma(inline, true) + string YY_(string msg) { return msg; } + } +} /** * A Bison parser, automatically generated from <tt>]m4_bpatsubst(b4_file_name, [^"\(.*\)"$], [\1])[</tt>. @@ -680,20 +703,38 @@ m4_popdef([b4_at_dollar])])dnl immutable int argmax = 5; SymbolKind[] yyarg = new SymbolKind[argmax]; int yycount = yysyntaxErrorArguments(yyctx, yyarg, argmax); - string res = "syntax error, unexpected "; - res ~= format!"%s"(yyarg[0]); - if (yycount < argmax + 1) + string res, yyformat; + import std.string; + switch (yycount) { - for (int yyi = 1; yyi < yycount; yyi++) - { - res ~= yyi == 1 ? ", expecting " : " or "; - res ~= format!"%s"(SymbolKind(yyarg[yyi])); - } + case 1: + yyformat = YY_("syntax error, unexpected %s"); + res = format(yyformat, yyarg[0]); + break; + case 2: + yyformat = YY_("syntax error, unexpected %s, expecting %s"); + res = format(yyformat, yyarg[0], yyarg[1]); + break; + case 3: + yyformat = YY_("syntax error, unexpected %s, expecting %s or %s"); + res = format(yyformat, yyarg[0], yyarg[1], yyarg[2]); + break; + case 4: + yyformat = YY_("syntax error, unexpected %s, expecting %s or %s or %s"); + res = format(yyformat, yyarg[0], yyarg[1], yyarg[2], yyarg[3]); + break; + case 5: + yyformat = YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); + res = format(yyformat, yyarg[0], yyarg[1], yyarg[2], yyarg[3], yyarg[4]); + break; + default: + res = YY_("syntax error"); + break; } yyerror(]b4_locations_if([yyctx.getLocation(), ])[res); }]], [[simple]], [[ - yyerror(]b4_locations_if([yyctx.getLocation(), ])["syntax error");]])[ + yyerror(]b4_locations_if([yyctx.getLocation(), ])[YY_("syntax error"));]])[ } ]b4_parse_error_bmatch( diff --git a/doc/bison.texi b/doc/bison.texi index 0a55f343..c749079f 100644 --- a/doc/bison.texi +++ b/doc/bison.texi @@ -13953,6 +13953,66 @@ or nonzero, full tracing. Identify the Bison version and skeleton used to generate this parser. @end deftypecv +The internationalization in D is very simmilar to the one in C. The D +parser uses @code{dgettext} for translating Bison messages. + +To enable internationalisation, compile using +@code{-version ENABLE_NLS -version YYENABLE_NLS} and import +@code{bindtextdomain} and @code{textdomain} from C: + +@example +extern(C) char* bindtextdomain(const char* domainname, const char* dirname); +extern(C) char* textdomain(const char* domainname); +@end example + +The main function should load the translation catalogues, similarly to the +@file{c/bistromathic} example: + +@example +int main() +@{ + import core.stdc.locale; + + // Set up internationalization. + setlocale(LC_ALL, ""); + // Use Bison's standard translation catalogue for error messages + // (the generated messages). + bindtextdomain("bison-runtime", BISON_LOCALEDIR); + // For the translation catalogue of your own project, use the + // name of your project. + bindtextdomain("bison", LOCALEDIR); + textdomain("bison"); + + // usual main content + ... +@} +@end example + +For user messages translations, the user must implement the +@code{string} _(@code{const char*} @var{msg}) function and it is recommended +to use @code{gettext}: + +@example +%code imports @{ + static if (!is(typeof(_))) + @{ + version(ENABLE_NLS) + @{ + extern(C) char* gettext(const char*); + string _(const char* s) + @{ + return to!string(gettext(s)); + @} + @} + @} + static if (!is(typeof(_))) + @{ + pragma(inline, true) + string _(string msg) @{ return msg; @} + @} +@} +@end example + @node D Parser Context Interface @subsection D Parser Context Interface The parser context provides information to build error reports when you diff --git a/tests/calc.at b/tests/calc.at index b1428316..3d319645 100644 --- a/tests/calc.at +++ b/tests/calc.at @@ -654,6 +654,23 @@ m4_define([_AT_DATA_CALC_Y(d)], }; %printer { fprintf (yyo, "%d", $$); } <ival>; +%code { +]AT_TOKEN_TRANSLATE_IF([[ + static string _(string s) + { + switch (s) + { + case "end of input": + return "end of file"; + case "number": + return "nombre"; + default: + return s; + } + } +]])[ +} + /* Bison Declarations */ %token EOF 0 ]AT_TOKEN_TRANSLATE_IF([_("end of file")], ["end of input"])[ %token <ival> NUM "number" @@ -665,7 +682,7 @@ m4_define([_AT_DATA_CALC_Y(d)], STAR "*" SLASH "/" POW "^" - EOL "\n" + EOL "'\\n'" LPAR "(" RPAR ")" NOT "!" -- 2.17.1
0002-d-remove-yytnamerr-usage.patch
(application/octet-stream, 2.1 KB)
From 05b159624c4f82874d99b84d4af82e093c825ee6 Mon Sep 17 00:00:00 2001 From: Adela Vais <[email protected]> Date: Tue, 5 Jan 2021 16:47:29 +0200 Subject: [PATCH for Dlang support 2/3] d: remove yytnamerr usage It is a backwards-compatible feature for the other parsers. D should not support this option. * data/skeletons/d.m4: Here. --- data/skeletons/d.m4 | 40 +++------------------------------------- 1 file changed, 3 insertions(+), 37 deletions(-) diff --git a/data/skeletons/d.m4 b/data/skeletons/d.m4 index 5320c483..cfb87944 100644 --- a/data/skeletons/d.m4 +++ b/data/skeletons/d.m4 @@ -243,12 +243,6 @@ m4_define([b4_declare_symbol_enum], yycode_ = code; } - /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. - First, the terminals, then, starting at \a YYNTOKENS_, nonterminals. */ - static immutable string[] yytname_ = @{ - ]b4_tname[ - @}; - /* Return YYSTR after stripping away unnecessary quotes and backslashes, so that it's suitable for yyerror. The heuristic is that double-quoting is unnecessary unless the string contains an @@ -264,37 +258,9 @@ m4_define([b4_declare_symbol_enum], internationalizable. */ immutable ]b4_int_type_for([b4_translatable])[[] yytranslatable = @{ ]b4_translatable[ - @}; - - put(sink, yy_sname[yycode_]);]], [[ - string yystr = yytname_[yycode_]; - if (yystr[0] == '"') - { - strip_quotes: - for (int i = 1; i < yystr.length; i++) - switch (yystr[i]) - { - case '\'': - case ',': - break strip_quotes; - - case '\\': - if (yystr[++i] != '\\') - break strip_quotes; - goto default; - default: - put(sink, yystr[i]); - break; - - case '"': - return; - } - } - else if (yystr == "$end") - { - put(sink, "end of input"); - return; - }]])[ + @};]])[ + + put(sink, yy_sname[yycode_]); } } ]]) -- 2.17.1
0003-d-remove-unnecessary-imports.patch
(application/octet-stream, 2 KB)
From 6ef304b24eb52531348e51a0cfee2755c69f8660 Mon Sep 17 00:00:00 2001 From: Adela Vais <[email protected]> Date: Tue, 5 Jan 2021 17:20:11 +0200 Subject: [PATCH for Dlang support 3/3] d: remove unnecessary imports * data/skeletons/lalr1.d: Here. --- data/skeletons/lalr1.d | 5 ----- 1 file changed, 5 deletions(-) diff --git a/data/skeletons/lalr1.d b/data/skeletons/lalr1.d index ede7d8c7..e97613b6 100644 --- a/data/skeletons/lalr1.d +++ b/data/skeletons/lalr1.d @@ -382,7 +382,6 @@ b4_user_union_members } ]b4_parse_trace_if([[ - import std.conv : to; yy_symbol_print ("-> $$ =", to!SymbolKind (yyr1_[yyn]), yyval]b4_locations_if([, yyloc])[);]])[ yystack.pop (yylen); @@ -664,7 +663,6 @@ m4_popdef([b4_at_dollar])])dnl /* Shift the error token. */]b4_lac_if([[ yylacDiscard("error recovery");]])[]b4_parse_trace_if([[ - import std.conv : to; yy_symbol_print ("Shifting", to!SymbolKind (yystos_[yyn]), yylval]b4_locations_if([, yyloc])[);]])[ yystate = yyn; yystack.push (yyn, yylval]b4_locations_if([, yyloc])[); @@ -704,7 +702,6 @@ m4_popdef([b4_at_dollar])])dnl SymbolKind[] yyarg = new SymbolKind[argmax]; int yycount = yysyntaxErrorArguments(yyctx, yyarg, argmax); string res, yyformat; - import std.string; switch (yycount) { case 1: @@ -882,7 +879,6 @@ m4_popdef([b4_at_dollar])])dnl destroy(yylacStack); // Reduce until we encounter a shift and thereby accept the token. ]b4_parse_trace_if([[ - import std.conv; yycdebug("LAC: checking lookahead " ~ format("%s", yytoken) ~ ":");]])[ int lacTop = 0; while (true) @@ -1073,7 +1069,6 @@ m4_popdef([b4_at_dollar])])dnl yyrule - 1, yylno)); /* The symbols being reduced. */ - import std.conv : to; for (int yyi = 0; yyi < yynrhs; yyi++) yy_symbol_print (format(" $%d =", yyi + 1), to!SymbolKind (yystos_[yystack.stateAt(yynrhs - (yyi + 1))]), -- 2.17.1