parser: keep string aliases as the user wrote it

Currently our scanner decodes all the escapes in the strings, and we
later reescape the strings when we emit them.

This is troublesome, as we do not respect the user input.  For
instance, when the user writes in UTF-8, we destroy her string when we
write it back.  And this shows everywhere: in the reports we show the
escaped string instead of the actual alias:

    0 $accept: . exp $end
    1 exp: . exp "\342\212\225" exp
    2    | . exp "+" exp
    3    | . exp "+" exp
    4    | . "number"
    5    | . "\303\221\303\271\341\271\203\303\251\342\204\235\303\264"

    "number"                                                    shift, and go to state 1
    "\303\221\303\271\341\271\203\303\251\342\204\235\303\264"  shift, and go to state 2

This commit preserves the user's exact spelling of the string aliases,
instead of interpreting the escapes and then reescaping.  The report
now shows:

    0 $accept: . exp $end
    1 exp: . exp "⊕" exp
    2    | . exp "+" exp
    3    | . exp "+" exp
    4    | . "number"
    5    | . "Ñùṃéℝô"

    "number"          shift, and go to state 1
    "Ñùṃéℝô"  shift, and go to state 2

Likewise, the XML (and therefore HTML) outputs are fixed.

* src/scan-gram.l (STRING, TSTRING): Do not interpret the escapes in
the resulting string.
* src/parse-gram.y (unquote, parser_init, parser_free, unquote_free)
(handle_defines, handle_language, obstack_for_unquote): New.
Use them to unquote where needed.
* tests/regression.at, tests/report.at: Update.
This commit is contained in:
Akim Demaille
2020-06-13 08:46:58 +02:00
parent 5d5e1df1dc
commit 5855da4722
7 changed files with 266 additions and 129 deletions

View File

@@ -45,6 +45,7 @@
#include "muscle-tab.h" #include "muscle-tab.h"
#include "nullable.h" #include "nullable.h"
#include "output.h" #include "output.h"
#include "parse-gram.h"
#include "print-graph.h" #include "print-graph.h"
#include "print-xml.h" #include "print-xml.h"
#include "print.h" #include "print.h"
@@ -223,9 +224,12 @@ main (int argc, char *argv[])
counterexample_free (); counterexample_free ();
output_file_names_free (); output_file_names_free ();
/* The scanner memory cannot be released right after parsing, as it /* The scanner and parser memory cannot be released right after
contains things such as user actions, prologue, epilogue etc. */ parsing, as it contains things such as user actions, prologue,
epilogue etc. */
gram_scanner_free (); gram_scanner_free ();
parser_free ();
muscle_free (); muscle_free ();
code_scanner_free (); code_scanner_free ();
skel_scanner_free (); skel_scanner_free ();

View File

@@ -141,8 +141,7 @@ muscle_free (void)
} }
/* Look for the muscle named KEY. Return NULL if does not exist. */ /* Look for the muscle named KEY. Return NULL if does not exist. */
static static muscle_entry *
muscle_entry *
muscle_lookup (char const *key) muscle_lookup (char const *key)
{ {
muscle_entry probe; muscle_entry probe;

View File

@@ -23,6 +23,14 @@
#include "symtab.h" #include "symtab.h"
} }
%code provides
{
/* Initialize unquote. */
void parser_init (void);
/* Deallocate storage for unquote. */
void parser_free (void);
}
%code top %code top
{ {
/* On column 0 to please syntax-check. */ /* On column 0 to please syntax-check. */
@@ -73,17 +81,20 @@
static char *strip_braces (char *code); static char *strip_braces (char *code);
/* Convert CODE by calling code_props_plain_init if PLAIN, otherwise /* Convert CODE by calling code_props_plain_init if PLAIN, otherwise
code_props_symbol_action_init. Call code_props_symbol_action_init. Calls
gram_scanner_last_string_free to release the latest string from gram_scanner_last_string_free to release the latest string from
the scanner (should be CODE). */ the scanner (should be CODE). */
static char const *translate_code (char *code, location loc, bool plain); static char const *translate_code (char *code, location loc, bool plain);
/* Convert CODE by calling code_props_plain_init after having /* Convert CODE by calling code_props_plain_init after having
stripped the first and last characters (expected to be '{', and stripped the first and last characters (expected to be '{', and
'}'). Call gram_scanner_last_string_free to release the latest '}'). Calls gram_scanner_last_string_free to release the latest
string from the scanner (should be CODE). */ string from the scanner (should be CODE). */
static char const *translate_code_braceless (char *code, location loc); static char const *translate_code_braceless (char *code, location loc);
/* Handle a %defines directive. */
static void handle_defines (char const *value);
/* Handle a %error-verbose directive. */ /* Handle a %error-verbose directive. */
static void handle_error_verbose (location const *loc, char const *directive); static void handle_error_verbose (location const *loc, char const *directive);
@@ -92,6 +103,9 @@
location const *dir_loc, location const *dir_loc,
char const *directive, char const *value); char const *directive, char const *value);
/* Handle a %language directive. */
static void handle_language (location const *loc, char const *lang);
/* Handle a %name-prefix directive. */ /* Handle a %name-prefix directive. */
static void handle_name_prefix (location const *loc, static void handle_name_prefix (location const *loc,
char const *directive, char const *value); char const *directive, char const *value);
@@ -117,6 +131,13 @@
/* Add style to semantic values in traces. */ /* Add style to semantic values in traces. */
static void tron (FILE *yyo); static void tron (FILE *yyo);
static void troff (FILE *yyo); static void troff (FILE *yyo);
/* Interpret a quoted string (such as `"Hello, \"World\"\n\""`).
Manages the memory of the result. */
static char *unquote (const char *str);
/* Discard the latest unquoted string. */
static void unquote_free (char *last_string);
} }
%define api.header.include {"parse-gram.h"} %define api.header.include {"parse-gram.h"}
@@ -315,11 +336,7 @@ prologue_declaration:
MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE); MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE);
} }
| "%defines" { defines_flag = true; } | "%defines" { defines_flag = true; }
| "%defines" STRING | "%defines" STRING { handle_defines ($2); }
{
defines_flag = true;
spec_header_file = xstrdup ($2);
}
| "%error-verbose" { handle_error_verbose (&@$, $1); } | "%error-verbose" { handle_error_verbose (&@$, $1); }
| "%expect" INT { expected_sr_conflicts = $2; } | "%expect" INT { expected_sr_conflicts = $2; }
| "%expect-rr" INT { expected_rr_conflicts = $2; } | "%expect-rr" INT { expected_rr_conflicts = $2; }
@@ -334,11 +351,11 @@ prologue_declaration:
muscle_code_grow ("initial_action", translate_code ($2, @2, false), @2); muscle_code_grow ("initial_action", translate_code ($2, @2, false), @2);
code_scanner_last_string_free (); code_scanner_last_string_free ();
} }
| "%language" STRING { language_argmatch ($2, grammar_prio, @1); } | "%language" STRING { handle_language (&@1, $2); }
| "%name-prefix" STRING { handle_name_prefix (&@$, $1, $2); } | "%name-prefix" STRING { handle_name_prefix (&@$, $1, $2); }
| "%no-lines" { no_lines_flag = true; } | "%no-lines" { no_lines_flag = true; }
| "%nondeterministic-parser" { nondeterministic_parser = true; } | "%nondeterministic-parser" { nondeterministic_parser = true; }
| "%output" STRING { spec_outfile = $2; } | "%output" STRING { spec_outfile = unquote ($2); gram_scanner_last_string_free (); }
| "%param" { current_param = $1; } params { current_param = param_none; } | "%param" { current_param = $1; } params { current_param = param_none; }
| "%pure-parser" { handle_pure_parser (&@$, $1); } | "%pure-parser" { handle_pure_parser (&@$, $1); }
| "%require" STRING { handle_require (&@2, $2); } | "%require" STRING { handle_require (&@2, $2); }
@@ -549,7 +566,7 @@ alias:
| string_as_id { $$ = $1; } | string_as_id { $$ = $1; }
| TSTRING | TSTRING
{ {
$$ = symbol_get (quotearg_style (c_quoting_style, $1), @1); $$ = symbol_get ($1, @1);
symbol_class_set ($$, token_sym, @1, false); symbol_class_set ($$, token_sym, @1, false);
$$->translatable = true; $$->translatable = true;
} }
@@ -729,8 +746,8 @@ variable:
value: value:
%empty { $$.kind = muscle_keyword; $$.chars = ""; } %empty { $$.kind = muscle_keyword; $$.chars = ""; }
| ID { $$.kind = muscle_keyword; $$.chars = $1; } | ID { $$.kind = muscle_keyword; $$.chars = $1; }
| STRING { $$.kind = muscle_string; $$.chars = $1; } | STRING { $$.kind = muscle_string; $$.chars = unquote ($1); gram_scanner_last_string_free ();}
| "{...}" { $$.kind = muscle_code; $$.chars = strip_braces ($1); } | "{...}" { $$.kind = muscle_code; $$.chars = strip_braces ($1); gram_scanner_last_string_free (); }
; ;
@@ -777,11 +794,11 @@ symbol:
| string_as_id | string_as_id
; ;
/* A string used as an ID: quote it. */ /* A string used as an ID. */
string_as_id: string_as_id:
STRING STRING
{ {
$$ = symbol_get (quotearg_style (c_quoting_style, $1), @1); $$ = symbol_get ($1, @1);
symbol_class_set ($$, token_sym, @1, false); symbol_class_set ($$, token_sym, @1, false);
} }
; ;
@@ -925,6 +942,17 @@ add_param (param_type type, char *decl, location loc)
} }
static void
handle_defines (char const *value)
{
defines_flag = true;
char *file = unquote (value);
spec_header_file = xstrdup (file);
gram_scanner_last_string_free ();
unquote_free (file);
}
static void static void
handle_error_verbose (location const *loc, char const *directive) handle_error_verbose (location const *loc, char const *directive)
{ {
@@ -937,8 +965,9 @@ handle_error_verbose (location const *loc, char const *directive)
static void static void
handle_file_prefix (location const *loc, handle_file_prefix (location const *loc,
location const *dir_loc, location const *dir_loc,
char const *directive, char const *value) char const *directive, char const *value_quoted)
{ {
char *value = unquote (value_quoted);
bison_directive (loc, directive); bison_directive (loc, directive);
bool warned = false; bool warned = false;
@@ -958,11 +987,18 @@ handle_file_prefix (location const *loc,
deprecated_directive (dir_loc, directive, "%file-prefix"); deprecated_directive (dir_loc, directive, "%file-prefix");
} }
static void
handle_language (location const *loc, char const *lang)
{
language_argmatch (unquote (lang), grammar_prio, *loc);
}
static void static void
handle_name_prefix (location const *loc, handle_name_prefix (location const *loc,
char const *directive, char const *value) char const *directive, char const *value_quoted)
{ {
char *value = unquote (value_quoted);
bison_directive (loc, directive); bison_directive (loc, directive);
char buf1[1024]; char buf1[1024];
@@ -1034,34 +1070,39 @@ str_to_version (char const *version)
static void static void
handle_require (location const *loc, char const *version) handle_require (location const *loc, char const *version_quoted)
{ {
char *version = unquote (version_quoted);
required_version = str_to_version (version); required_version = str_to_version (version);
if (required_version == -1) if (required_version == -1)
{ {
complain (loc, complaint, _("invalid version requirement: %s"), complain (loc, complaint, _("invalid version requirement: %s"),
version); version);
required_version = 0; required_version = 0;
return;
} }
else
/* Pretend to be at least that version, to check features published
in that version while developping it. */
const char* api_version = "3.6";
const char* package_version =
0 < strverscmp (api_version, PACKAGE_VERSION)
? api_version : PACKAGE_VERSION;
if (0 < strverscmp (version, package_version))
{ {
complain (loc, complaint, _("require bison %s, but have %s"), /* Pretend to be at least that version, to check features published
version, package_version); in that version while developping it. */
exit (EX_MISMATCH); const char* api_version = "3.6";
const char* package_version =
0 < strverscmp (api_version, PACKAGE_VERSION)
? api_version : PACKAGE_VERSION;
if (0 < strverscmp (version, package_version))
{
complain (loc, complaint, _("require bison %s, but have %s"),
version, package_version);
exit (EX_MISMATCH);
}
} }
unquote_free (version);
gram_scanner_last_string_free ();
} }
static void static void
handle_skeleton (location const *loc, char const *skel) handle_skeleton (location const *loc, char const *skel_quoted)
{ {
char *skel = unquote (skel_quoted);
char const *skeleton_user = skel; char const *skeleton_user = skel;
if (strchr (skeleton_user, '/')) if (strchr (skeleton_user, '/'))
{ {
@@ -1142,3 +1183,95 @@ static void troff (FILE *yyo)
{ {
end_use_class ("value", yyo); end_use_class ("value", yyo);
} }
/*----------.
| Unquote. |
`----------*/
struct obstack obstack_for_unquote;
void
parser_init (void)
{
obstack_init (&obstack_for_unquote);
}
void
parser_free (void)
{
obstack_free (&obstack_for_unquote, 0);
}
static void
unquote_free (char *last_string)
{
obstack_free (&obstack_for_unquote, last_string);
}
static char *
unquote (const char *cp)
{
#define GROW(Char) \
obstack_1grow (&obstack_for_unquote, Char);
for (++cp; *cp && *cp != '"'; ++cp)
switch (*cp)
{
case '"':
break;
case '\\':
++cp;
switch (*cp)
{
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
{
int c = cp[0] - '0';
if (c_isdigit (cp[1]))
{
++cp;
c = c * 8 + cp[0] - '0';
}
if (c_isdigit (cp[1]))
{
++cp;
c = c * 8 + cp[0] - '0';
}
GROW (c);
}
break;
case 'a': GROW ('\a'); break;
case 'b': GROW ('\b'); break;
case 'f': GROW ('\f'); break;
case 'n': GROW ('\n'); break;
case 'r': GROW ('\r'); break;
case 't': GROW ('\t'); break;
case 'v': GROW ('\v'); break;
case 'x':
{
int c = 0;
while (c_isxdigit (cp[1]))
{
++cp;
c = (c * 16 + (c_isdigit (cp[0]) ? cp[0] - '0'
: c_isupper (cp[0]) ? cp[0] - 'A'
: cp[0] - '0'));
}
GROW (c);
break;
}
}
break;
default:
GROW (*cp);
break;
}
assert (*cp == '"');
++cp;
assert (*cp == '\0');
#undef GROW
return obstack_finish0 (&obstack_for_unquote);
}

View File

@@ -710,6 +710,7 @@ reader (const char *gram)
symbols_new (); symbols_new ();
gram_scanner_open (gram); gram_scanner_open (gram);
parser_init ();
gram_parse (); gram_parse ();
gram_scanner_close (); gram_scanner_close ();

View File

@@ -88,16 +88,15 @@ static boundary scanner_cursor;
do { \ do { \
verify (UCHAR_MAX < ULONG_MAX); \ verify (UCHAR_MAX < ULONG_MAX); \
long c = Char; \ long c = Char; \
if (0 < c && c <= UCHAR_MAX) \ bool valid = 0 < c && c <= UCHAR_MAX; \
STRING_1GROW (c); \ if (!valid) \
complain (loc, complaint, \
_("invalid number after \\-escape: %s"), \
yytext + 1); \
if (YY_START == SC_ESCAPED_CHARACTER) \
STRING_1GROW (valid ? c : '?'); \
else \ else \
{ \ STRING_GROW (); \
complain (loc, complaint, \
_("invalid number after \\-escape: %s"), \
yytext + 1); \
/* Avoid additional errors about empty char literal. */ \
STRING_1GROW ('?'); \
} \
} while (0) } while (0)
@@ -337,8 +336,8 @@ eqopt ({sp}=)?
"'" token_start = loc->start; BEGIN SC_ESCAPED_CHARACTER; "'" token_start = loc->start; BEGIN SC_ESCAPED_CHARACTER;
/* Strings. */ /* Strings. */
"\"" token_start = loc->start; BEGIN SC_ESCAPED_STRING; "\"" token_start = loc->start; STRING_1GROW ('"'); BEGIN SC_ESCAPED_STRING;
"_(\"" token_start = loc->start; BEGIN SC_ESCAPED_TSTRING; "_(\"" token_start = loc->start; STRING_1GROW ('"'); BEGIN SC_ESCAPED_TSTRING;
/* Prologue. */ /* Prologue. */
"%{" code_start = loc->start; BEGIN SC_PROLOGUE; "%{" code_start = loc->start; BEGIN SC_PROLOGUE;
@@ -559,6 +558,7 @@ eqopt ({sp}=)?
<SC_ESCAPED_STRING> <SC_ESCAPED_STRING>
{ {
"\"" { "\"" {
STRING_1GROW ('"');
STRING_FINISH (); STRING_FINISH ();
BEGIN INITIAL; BEGIN INITIAL;
loc->start = token_start; loc->start = token_start;
@@ -571,6 +571,7 @@ eqopt ({sp}=)?
<SC_ESCAPED_TSTRING> <SC_ESCAPED_TSTRING>
{ {
"\")" { "\")" {
STRING_1GROW ('"');
STRING_FINISH (); STRING_FINISH ();
BEGIN INITIAL; BEGIN INITIAL;
loc->start = token_start; loc->start = token_start;
@@ -664,16 +665,16 @@ eqopt ({sp}=)?
STRING_GROW_ESCAPE (strtol (yytext + 2, NULL, 16)); STRING_GROW_ESCAPE (strtol (yytext + 2, NULL, 16));
} }
\\a STRING_1GROW ('\a'); \\a STRING_GROW_ESCAPE ('\a');
\\b STRING_1GROW ('\b'); \\b STRING_GROW_ESCAPE ('\b');
\\f STRING_1GROW ('\f'); \\f STRING_GROW_ESCAPE ('\f');
\\n STRING_1GROW ('\n'); \\n STRING_GROW_ESCAPE ('\n');
\\r STRING_1GROW ('\r'); \\r STRING_GROW_ESCAPE ('\r');
\\t STRING_1GROW ('\t'); \\t STRING_GROW_ESCAPE ('\t');
\\v STRING_1GROW ('\v'); \\v STRING_GROW_ESCAPE ('\v');
/* \\[\"\'?\\] would be shorter, but it confuses xgettext. */ /* \\[\"\'?\\] would be shorter, but it confuses xgettext. */
\\("\""|"'"|"?"|"\\") STRING_1GROW (yytext[1]); \\("\""|"'"|"?"|"\\") STRING_GROW_ESCAPE (yytext[1]);
\\(u|U[0-9abcdefABCDEF]{4})[0-9abcdefABCDEF]{4} { \\(u|U[0-9abcdefABCDEF]{4})[0-9abcdefABCDEF]{4} {
STRING_GROW_ESCAPE (convert_ucn_to_byte (yytext)); STRING_GROW_ESCAPE (convert_ucn_to_byte (yytext));
@@ -1024,7 +1025,7 @@ gram_scanner_open (const char *gram)
void void
gram_scanner_close () gram_scanner_close (void)
{ {
xfclose (gram_in); xfclose (gram_in);
/* Reclaim Flex's buffers. */ /* Reclaim Flex's buffers. */
@@ -1032,7 +1033,6 @@ gram_scanner_close ()
} }
void void
gram_scanner_free (void) gram_scanner_free (void)
{ {

View File

@@ -415,7 +415,7 @@ AT_BISON_CHECK([-fcaret -o input.c input.y], [[0]], [[]],
input.y:25.8-14: note: previous declaration input.y:25.8-14: note: previous declaration
25 | %token SPECIAL "\\\'\?\"\a\b\f\n\r\t\v\001\201\x001\x000081??!" 25 | %token SPECIAL "\\\'\?\"\a\b\f\n\r\t\v\001\201\x001\x000081??!"
| ^~~~~~~ | ^~~~~~~
input.y:26.16-63: warning: symbol "\\'?\"\a\b\f\n\r\t\v\001\201\001\201??!" used more than once as a literal string [-Wother] input.y:26.16-63: warning: symbol "\\\'\?\"\a\b\f\n\r\t\v\001\201\x001\x000081??!" used more than once as a literal string [-Wother]
26 | %token SPECIAL "\\\'\?\"\a\b\f\n\r\t\v\001\201\x001\x000081??!" 26 | %token SPECIAL "\\\'\?\"\a\b\f\n\r\t\v\001\201\x001\x000081??!"
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
]]) ]])
@@ -427,7 +427,7 @@ AT_COMPILE([input])
# symbol name reported by the parser is exactly the same as that reported by # symbol name reported by the parser is exactly the same as that reported by
# Bison itself. # Bison itself.
AT_PARSER_CHECK([input], 1, [], AT_PARSER_CHECK([input], 1, [],
[[syntax error, unexpected a, expecting ]AT_ERROR_VERBOSE_IF([["\\'?\"\a\b\f\n\r\t\v\001\201\001\201??!"]], [[∃¬∩∪∀]])[ [[syntax error, unexpected a, expecting ]AT_ERROR_VERBOSE_IF([["\\\'\?\"\a\b\f\n\r\t\v\001\201\x001\x000081??!"]], [[∃¬∩∪∀]])[
]]) ]])
AT_BISON_OPTION_POPDEFS AT_BISON_OPTION_POPDEFS

View File

@@ -1184,11 +1184,11 @@ Grammar
0 $accept: exp $end 0 $accept: exp $end
1 exp: exp "\342\212\225" exp 1 exp: exp "" exp
2 | exp "+" exp 2 | exp "+" exp
3 | exp "+" exp 3 | exp "+" exp
4 | "number" 4 | "number"
5 | "\303\221\303\271\341\271\203\303\251\342\204\235\303\264" 5 | "Ñùṃéℝô"
Terminals, with rules where they appear Terminals, with rules where they appear
@@ -1196,9 +1196,9 @@ Terminals, with rules where they appear
$end (0) 0 $end (0) 0
error (256) error (256)
"+" (258) 2 3 "+" (258) 2 3
"\342\212\225" (259) 1 "" (259) 1
"number" (260) 4 "number" (260) 4
"\303\221\303\271\341\271\203\303\251\342\204\235\303\264" (261) 5 "Ñùṃéℝô" (261) 5
Nonterminals, with rules where they appear Nonterminals, with rules where they appear
@@ -1213,14 +1213,14 @@ Nonterminals, with rules where they appear
State 0 State 0
0 $accept: . exp $end 0 $accept: . exp $end
1 exp: . exp "\342\212\225" exp 1 exp: . exp "" exp
2 | . exp "+" exp 2 | . exp "+" exp
3 | . exp "+" exp 3 | . exp "+" exp
4 | . "number" 4 | . "number"
5 | . "\303\221\303\271\341\271\203\303\251\342\204\235\303\264" 5 | . "Ñùṃéℝô"
"number" shift, and go to state 1 "number" shift, and go to state 1
"\303\221\303\271\341\271\203\303\251\342\204\235\303\264" shift, and go to state 2 "Ñùṃéℝô" shift, and go to state 2
exp go to state 3 exp go to state 3
@@ -1234,7 +1234,7 @@ State 1
State 2 State 2
5 exp: "\303\221\303\271\341\271\203\303\251\342\204\235\303\264" . 5 exp: "Ñùṃéℝô" .
$default reduce using rule 5 (exp) $default reduce using rule 5 (exp)
@@ -1242,13 +1242,13 @@ State 2
State 3 State 3
0 $accept: exp . $end 0 $accept: exp . $end
1 exp: exp . "\342\212\225" exp 1 exp: exp . "" exp
2 | exp . "+" exp 2 | exp . "+" exp
3 | exp . "+" exp 3 | exp . "+" exp
$end shift, and go to state 4 $end shift, and go to state 4
"+" shift, and go to state 5 "+" shift, and go to state 5
"\342\212\225" shift, and go to state 6 "" shift, and go to state 6
State 4 State 4
@@ -1260,69 +1260,69 @@ State 4
State 5 State 5
1 exp: . exp "\342\212\225" exp 1 exp: . exp "" exp
2 | . exp "+" exp 2 | . exp "+" exp
2 | exp "+" . exp 2 | exp "+" . exp
3 | . exp "+" exp 3 | . exp "+" exp
3 | exp "+" . exp 3 | exp "+" . exp
4 | . "number" 4 | . "number"
5 | . "\303\221\303\271\341\271\203\303\251\342\204\235\303\264" 5 | . "Ñùṃéℝô"
"number" shift, and go to state 1 "number" shift, and go to state 1
"\303\221\303\271\341\271\203\303\251\342\204\235\303\264" shift, and go to state 2 "Ñùṃéℝô" shift, and go to state 2
exp go to state 7 exp go to state 7
State 6 State 6
1 exp: . exp "\342\212\225" exp 1 exp: . exp "" exp
1 | exp "\342\212\225" . exp 1 | exp "" . exp
2 | . exp "+" exp 2 | . exp "+" exp
3 | . exp "+" exp 3 | . exp "+" exp
4 | . "number" 4 | . "number"
5 | . "\303\221\303\271\341\271\203\303\251\342\204\235\303\264" 5 | . "Ñùṃéℝô"
"number" shift, and go to state 1 "number" shift, and go to state 1
"\303\221\303\271\341\271\203\303\251\342\204\235\303\264" shift, and go to state 2 "Ñùṃéℝô" shift, and go to state 2
exp go to state 8 exp go to state 8
State 7 State 7
1 exp: exp . "\342\212\225" exp 1 exp: exp . "" exp
2 | exp . "+" exp 2 | exp . "+" exp
2 | exp "+" exp . [$end, "+", "\342\212\225"] 2 | exp "+" exp . [$end, "+", ""]
3 | exp . "+" exp 3 | exp . "+" exp
3 | exp "+" exp . [$end, "+", "\342\212\225"] 3 | exp "+" exp . [$end, "+", ""]
"\342\212\225" shift, and go to state 6 "" shift, and go to state 6
$end reduce using rule 2 (exp) $end reduce using rule 2 (exp)
$end [reduce using rule 3 (exp)] $end [reduce using rule 3 (exp)]
"+" reduce using rule 2 (exp) "+" reduce using rule 2 (exp)
"+" [reduce using rule 3 (exp)] "+" [reduce using rule 3 (exp)]
"\342\212\225" [reduce using rule 2 (exp)] "⊕" [reduce using rule 2 (exp)]
"\342\212\225" [reduce using rule 3 (exp)] "⊕" [reduce using rule 3 (exp)]
$default reduce using rule 2 (exp) $default reduce using rule 2 (exp)
Conflict between rule 2 and token "+" resolved as reduce (%left "+"). Conflict between rule 2 and token "+" resolved as reduce (%left "+").
State 8 State 8
1 exp: exp . "\342\212\225" exp 1 exp: exp . "" exp
1 | exp "\342\212\225" exp . [$end, "+", "\342\212\225"] 1 | exp "" exp . [$end, "+", ""]
2 | exp . "+" exp 2 | exp . "+" exp
3 | exp . "+" exp 3 | exp . "+" exp
"+" shift, and go to state 5 "+" shift, and go to state 5
"\342\212\225" shift, and go to state 6 "" shift, and go to state 6
"+" [reduce using rule 1 (exp)] "+" [reduce using rule 1 (exp)]
"\342\212\225" [reduce using rule 1 (exp)] "⊕" [reduce using rule 1 (exp)]
$default reduce using rule 1 (exp) $default reduce using rule 1 (exp)
]]) ]])
@@ -1338,43 +1338,43 @@ digraph "input.y"
node [fontname = courier, shape = box, colorscheme = paired6] node [fontname = courier, shape = box, colorscheme = paired6]
edge [fontname = courier] edge [fontname = courier]
0 [label="State 0\n\l 0 $accept: . exp $end\l 1 exp: . exp \"\\342\\212\\225\" exp\l 2 | . exp \"+\" exp\l 3 | . exp \"+\" exp\l 4 | . \"number\"\l 5 | . \"\\303\\221\\303\\271\\341\\271\\203\\303\\251\\342\\204\\235\\303\\264\"\l"] 0 [label="State 0\n\l 0 $accept: . exp $end\l 1 exp: . exp \"\342\212\225\" exp\l 2 | . exp \"+\" exp\l 3 | . exp \"+\" exp\l 4 | . \"number\"\l 5 | . \"\303\221\303\271\341\271\203\303\251\342\204\235\303\264\"\l"]
0 -> 1 [style=solid label="\"number\""] 0 -> 1 [style=solid label="\"number\""]
0 -> 2 [style=solid label="\"\\303\\221\\303\\271\\341\\271\\203\\303\\251\\342\\204\\235\\303\\264\""] 0 -> 2 [style=solid label="\"\303\221\303\271\341\271\203\303\251\342\204\235\303\264\""]
0 -> 3 [style=dashed label="exp"] 0 -> 3 [style=dashed label="exp"]
1 [label="State 1\n\l 4 exp: \"number\" .\l"] 1 [label="State 1\n\l 4 exp: \"number\" .\l"]
1 -> "1R4" [style=solid] 1 -> "1R4" [style=solid]
"1R4" [label="R4", fillcolor=3, shape=diamond, style=filled] "1R4" [label="R4", fillcolor=3, shape=diamond, style=filled]
2 [label="State 2\n\l 5 exp: \"\\303\\221\\303\\271\\341\\271\\203\\303\\251\\342\\204\\235\\303\\264\" .\l"] 2 [label="State 2\n\l 5 exp: \"\303\221\303\271\341\271\203\303\251\342\204\235\303\264\" .\l"]
2 -> "2R5" [style=solid] 2 -> "2R5" [style=solid]
"2R5" [label="R5", fillcolor=3, shape=diamond, style=filled] "2R5" [label="R5", fillcolor=3, shape=diamond, style=filled]
3 [label="State 3\n\l 0 $accept: exp . $end\l 1 exp: exp . \"\\342\\212\\225\" exp\l 2 | exp . \"+\" exp\l 3 | exp . \"+\" exp\l"] 3 [label="State 3\n\l 0 $accept: exp . $end\l 1 exp: exp . \"\342\212\225\" exp\l 2 | exp . \"+\" exp\l 3 | exp . \"+\" exp\l"]
3 -> 4 [style=solid label="$end"] 3 -> 4 [style=solid label="$end"]
3 -> 5 [style=solid label="\"+\""] 3 -> 5 [style=solid label="\"+\""]
3 -> 6 [style=solid label="\"\\342\\212\\225\""] 3 -> 6 [style=solid label="\"\342\212\225\""]
4 [label="State 4\n\l 0 $accept: exp $end .\l"] 4 [label="State 4\n\l 0 $accept: exp $end .\l"]
4 -> "4R0" [style=solid] 4 -> "4R0" [style=solid]
"4R0" [label="Acc", fillcolor=1, shape=diamond, style=filled] "4R0" [label="Acc", fillcolor=1, shape=diamond, style=filled]
5 [label="State 5\n\l 1 exp: . exp \"\\342\\212\\225\" exp\l 2 | . exp \"+\" exp\l 2 | exp \"+\" . exp\l 3 | . exp \"+\" exp\l 3 | exp \"+\" . exp\l 4 | . \"number\"\l 5 | . \"\\303\\221\\303\\271\\341\\271\\203\\303\\251\\342\\204\\235\\303\\264\"\l"] 5 [label="State 5\n\l 1 exp: . exp \"\342\212\225\" exp\l 2 | . exp \"+\" exp\l 2 | exp \"+\" . exp\l 3 | . exp \"+\" exp\l 3 | exp \"+\" . exp\l 4 | . \"number\"\l 5 | . \"\303\221\303\271\341\271\203\303\251\342\204\235\303\264\"\l"]
5 -> 1 [style=solid label="\"number\""] 5 -> 1 [style=solid label="\"number\""]
5 -> 2 [style=solid label="\"\\303\\221\\303\\271\\341\\271\\203\\303\\251\\342\\204\\235\\303\\264\""] 5 -> 2 [style=solid label="\"\303\221\303\271\341\271\203\303\251\342\204\235\303\264\""]
5 -> 7 [style=dashed label="exp"] 5 -> 7 [style=dashed label="exp"]
6 [label="State 6\n\l 1 exp: . exp \"\\342\\212\\225\" exp\l 1 | exp \"\\342\\212\\225\" . exp\l 2 | . exp \"+\" exp\l 3 | . exp \"+\" exp\l 4 | . \"number\"\l 5 | . \"\\303\\221\\303\\271\\341\\271\\203\\303\\251\\342\\204\\235\\303\\264\"\l"] 6 [label="State 6\n\l 1 exp: . exp \"\342\212\225\" exp\l 1 | exp \"\342\212\225\" . exp\l 2 | . exp \"+\" exp\l 3 | . exp \"+\" exp\l 4 | . \"number\"\l 5 | . \"\303\221\303\271\341\271\203\303\251\342\204\235\303\264\"\l"]
6 -> 1 [style=solid label="\"number\""] 6 -> 1 [style=solid label="\"number\""]
6 -> 2 [style=solid label="\"\\303\\221\\303\\271\\341\\271\\203\\303\\251\\342\\204\\235\\303\\264\""] 6 -> 2 [style=solid label="\"\303\221\303\271\341\271\203\303\251\342\204\235\303\264\""]
6 -> 8 [style=dashed label="exp"] 6 -> 8 [style=dashed label="exp"]
7 [label="State 7\n\l 1 exp: exp . \"\\342\\212\\225\" exp\l 2 | exp . \"+\" exp\l 2 | exp \"+\" exp . [$end, \"+\", \"\\342\\212\\225\"]\l 3 | exp . \"+\" exp\l 3 | exp \"+\" exp . [$end, \"+\", \"\\342\\212\\225\"]\l"] 7 [label="State 7\n\l 1 exp: exp . \"\342\212\225\" exp\l 2 | exp . \"+\" exp\l 2 | exp \"+\" exp . [$end, \"+\", \"\342\212\225\"]\l 3 | exp . \"+\" exp\l 3 | exp \"+\" exp . [$end, \"+\", \"\342\212\225\"]\l"]
7 -> 6 [style=solid label="\"\\342\\212\\225\""] 7 -> 6 [style=solid label="\"\342\212\225\""]
7 -> "7R2d" [label="[\"\\342\\212\\225\"]", style=solid] 7 -> "7R2d" [label="[\"\342\212\225\"]", style=solid]
"7R2d" [label="R2", fillcolor=5, shape=diamond, style=filled] "7R2d" [label="R2", fillcolor=5, shape=diamond, style=filled]
7 -> "7R2" [style=solid] 7 -> "7R2" [style=solid]
"7R2" [label="R2", fillcolor=3, shape=diamond, style=filled] "7R2" [label="R2", fillcolor=3, shape=diamond, style=filled]
7 -> "7R3d" [label="[$end, \"+\", \"\\342\\212\\225\"]", style=solid] 7 -> "7R3d" [label="[$end, \"+\", \"\342\212\225\"]", style=solid]
"7R3d" [label="R3", fillcolor=5, shape=diamond, style=filled] "7R3d" [label="R3", fillcolor=5, shape=diamond, style=filled]
8 [label="State 8\n\l 1 exp: exp . \"\\342\\212\\225\" exp\l 1 | exp \"\\342\\212\\225\" exp . [$end, \"+\", \"\\342\\212\\225\"]\l 2 | exp . \"+\" exp\l 3 | exp . \"+\" exp\l"] 8 [label="State 8\n\l 1 exp: exp . \"\342\212\225\" exp\l 1 | exp \"\342\212\225\" exp . [$end, \"+\", \"\342\212\225\"]\l 2 | exp . \"+\" exp\l 3 | exp . \"+\" exp\l"]
8 -> 5 [style=solid label="\"+\""] 8 -> 5 [style=solid label="\"+\""]
8 -> 6 [style=solid label="\"\\342\\212\\225\""] 8 -> 6 [style=solid label="\"\342\212\225\""]
8 -> "8R1d" [label="[\"+\", \"\\342\\212\\225\"]", style=solid] 8 -> "8R1d" [label="[\"+\", \"\342\212\225\"]", style=solid]
"8R1d" [label="R1", fillcolor=5, shape=diamond, style=filled] "8R1d" [label="R1", fillcolor=5, shape=diamond, style=filled]
8 -> "8R1" [style=solid] 8 -> "8R1" [style=solid]
"8R1" [label="R1", fillcolor=3, shape=diamond, style=filled] "8R1" [label="R1", fillcolor=3, shape=diamond, style=filled]
@@ -1402,7 +1402,7 @@ AT_CHECK([[sed -e 's/bison-xml-report version="[^"]*"/bison-xml-report version="
<lhs>exp</lhs> <lhs>exp</lhs>
<rhs> <rhs>
<symbol>exp</symbol> <symbol>exp</symbol>
<symbol>&quot;\342\212\225&quot;</symbol> <symbol>&quot;&quot;</symbol>
<symbol>exp</symbol> <symbol>exp</symbol>
</rhs> </rhs>
</rule> </rule>
@@ -1431,7 +1431,7 @@ AT_CHECK([[sed -e 's/bison-xml-report version="[^"]*"/bison-xml-report version="
<rule number="5" usefulness="useful"> <rule number="5" usefulness="useful">
<lhs>exp</lhs> <lhs>exp</lhs>
<rhs> <rhs>
<symbol>&quot;\303\221\303\271\341\271\203\303\251\342\204\235\303\264&quot;</symbol> <symbol>&quot;Ñùṃéℝô&quot;</symbol>
</rhs> </rhs>
</rule> </rule>
</rules> </rules>
@@ -1439,9 +1439,9 @@ AT_CHECK([[sed -e 's/bison-xml-report version="[^"]*"/bison-xml-report version="
<terminal symbol-number="0" token-number="0" name="$end" usefulness="useful"/> <terminal symbol-number="0" token-number="0" name="$end" usefulness="useful"/>
<terminal symbol-number="1" token-number="256" name="error" usefulness="useful"/> <terminal symbol-number="1" token-number="256" name="error" usefulness="useful"/>
<terminal symbol-number="3" token-number="258" name="&quot;+&quot;" usefulness="useful" prec="1" assoc="left"/> <terminal symbol-number="3" token-number="258" name="&quot;+&quot;" usefulness="useful" prec="1" assoc="left"/>
<terminal symbol-number="4" token-number="259" name="&quot;\342\212\225&quot;" usefulness="useful"/> <terminal symbol-number="4" token-number="259" name="&quot;&quot;" usefulness="useful"/>
<terminal symbol-number="5" token-number="260" name="&quot;number&quot;" usefulness="useful"/> <terminal symbol-number="5" token-number="260" name="&quot;number&quot;" usefulness="useful"/>
<terminal symbol-number="6" token-number="261" name="&quot;\303\221\303\271\341\271\203\303\251\342\204\235\303\264&quot;" usefulness="useful"/> <terminal symbol-number="6" token-number="261" name="&quot;Ñùṃéℝô&quot;" usefulness="useful"/>
</terminals> </terminals>
<nonterminals> <nonterminals>
<nonterminal symbol-number="7" name="$accept" usefulness="useful"/> <nonterminal symbol-number="7" name="$accept" usefulness="useful"/>
@@ -1463,7 +1463,7 @@ AT_CHECK([[sed -e 's/bison-xml-report version="[^"]*"/bison-xml-report version="
<actions> <actions>
<transitions> <transitions>
<transition type="shift" symbol="&quot;number&quot;" state="1"/> <transition type="shift" symbol="&quot;number&quot;" state="1"/>
<transition type="shift" symbol="&quot;\303\221\303\271\341\271\203\303\251\342\204\235\303\264&quot;" state="2"/> <transition type="shift" symbol="&quot;Ñùṃéℝô&quot;" state="2"/>
<transition type="goto" symbol="exp" state="3"/> <transition type="goto" symbol="exp" state="3"/>
</transitions> </transitions>
<errors/> <errors/>
@@ -1511,7 +1511,7 @@ AT_CHECK([[sed -e 's/bison-xml-report version="[^"]*"/bison-xml-report version="
<transitions> <transitions>
<transition type="shift" symbol="$end" state="4"/> <transition type="shift" symbol="$end" state="4"/>
<transition type="shift" symbol="&quot;+&quot;" state="5"/> <transition type="shift" symbol="&quot;+&quot;" state="5"/>
<transition type="shift" symbol="&quot;\342\212\225&quot;" state="6"/> <transition type="shift" symbol="&quot;&quot;" state="6"/>
</transitions> </transitions>
<errors/> <errors/>
<reductions/> <reductions/>
@@ -1546,7 +1546,7 @@ AT_CHECK([[sed -e 's/bison-xml-report version="[^"]*"/bison-xml-report version="
<actions> <actions>
<transitions> <transitions>
<transition type="shift" symbol="&quot;number&quot;" state="1"/> <transition type="shift" symbol="&quot;number&quot;" state="1"/>
<transition type="shift" symbol="&quot;\303\221\303\271\341\271\203\303\251\342\204\235\303\264&quot;" state="2"/> <transition type="shift" symbol="&quot;Ñùṃéℝô&quot;" state="2"/>
<transition type="goto" symbol="exp" state="7"/> <transition type="goto" symbol="exp" state="7"/>
</transitions> </transitions>
<errors/> <errors/>
@@ -1567,7 +1567,7 @@ AT_CHECK([[sed -e 's/bison-xml-report version="[^"]*"/bison-xml-report version="
<actions> <actions>
<transitions> <transitions>
<transition type="shift" symbol="&quot;number&quot;" state="1"/> <transition type="shift" symbol="&quot;number&quot;" state="1"/>
<transition type="shift" symbol="&quot;\303\221\303\271\341\271\203\303\251\342\204\235\303\264&quot;" state="2"/> <transition type="shift" symbol="&quot;Ñùṃéℝô&quot;" state="2"/>
<transition type="goto" symbol="exp" state="8"/> <transition type="goto" symbol="exp" state="8"/>
</transitions> </transitions>
<errors/> <errors/>
@@ -1584,7 +1584,7 @@ AT_CHECK([[sed -e 's/bison-xml-report version="[^"]*"/bison-xml-report version="
<lookaheads> <lookaheads>
<symbol>$end</symbol> <symbol>$end</symbol>
<symbol>&quot;+&quot;</symbol> <symbol>&quot;+&quot;</symbol>
<symbol>&quot;\342\212\225&quot;</symbol> <symbol>&quot;&quot;</symbol>
</lookaheads> </lookaheads>
</item> </item>
<item rule-number="3" point="1"/> <item rule-number="3" point="1"/>
@@ -1592,13 +1592,13 @@ AT_CHECK([[sed -e 's/bison-xml-report version="[^"]*"/bison-xml-report version="
<lookaheads> <lookaheads>
<symbol>$end</symbol> <symbol>$end</symbol>
<symbol>&quot;+&quot;</symbol> <symbol>&quot;+&quot;</symbol>
<symbol>&quot;\342\212\225&quot;</symbol> <symbol>&quot;&quot;</symbol>
</lookaheads> </lookaheads>
</item> </item>
</itemset> </itemset>
<actions> <actions>
<transitions> <transitions>
<transition type="shift" symbol="&quot;\342\212\225&quot;" state="6"/> <transition type="shift" symbol="&quot;&quot;" state="6"/>
</transitions> </transitions>
<errors/> <errors/>
<reductions> <reductions>
@@ -1606,8 +1606,8 @@ AT_CHECK([[sed -e 's/bison-xml-report version="[^"]*"/bison-xml-report version="
<reduction symbol="$end" rule="3" enabled="false"/> <reduction symbol="$end" rule="3" enabled="false"/>
<reduction symbol="&quot;+&quot;" rule="2" enabled="true"/> <reduction symbol="&quot;+&quot;" rule="2" enabled="true"/>
<reduction symbol="&quot;+&quot;" rule="3" enabled="false"/> <reduction symbol="&quot;+&quot;" rule="3" enabled="false"/>
<reduction symbol="&quot;\342\212\225&quot;" rule="2" enabled="false"/> <reduction symbol="&quot;&quot;" rule="2" enabled="false"/>
<reduction symbol="&quot;\342\212\225&quot;" rule="3" enabled="false"/> <reduction symbol="&quot;&quot;" rule="3" enabled="false"/>
<reduction symbol="$default" rule="2" enabled="true"/> <reduction symbol="$default" rule="2" enabled="true"/>
</reductions> </reductions>
</actions> </actions>
@@ -1623,7 +1623,7 @@ AT_CHECK([[sed -e 's/bison-xml-report version="[^"]*"/bison-xml-report version="
<lookaheads> <lookaheads>
<symbol>$end</symbol> <symbol>$end</symbol>
<symbol>&quot;+&quot;</symbol> <symbol>&quot;+&quot;</symbol>
<symbol>&quot;\342\212\225&quot;</symbol> <symbol>&quot;&quot;</symbol>
</lookaheads> </lookaheads>
</item> </item>
<item rule-number="2" point="1"/> <item rule-number="2" point="1"/>
@@ -1632,12 +1632,12 @@ AT_CHECK([[sed -e 's/bison-xml-report version="[^"]*"/bison-xml-report version="
<actions> <actions>
<transitions> <transitions>
<transition type="shift" symbol="&quot;+&quot;" state="5"/> <transition type="shift" symbol="&quot;+&quot;" state="5"/>
<transition type="shift" symbol="&quot;\342\212\225&quot;" state="6"/> <transition type="shift" symbol="&quot;&quot;" state="6"/>
</transitions> </transitions>
<errors/> <errors/>
<reductions> <reductions>
<reduction symbol="&quot;+&quot;" rule="1" enabled="false"/> <reduction symbol="&quot;+&quot;" rule="1" enabled="false"/>
<reduction symbol="&quot;\342\212\225&quot;" rule="1" enabled="false"/> <reduction symbol="&quot;&quot;" rule="1" enabled="false"/>
<reduction symbol="$default" rule="1" enabled="true"/> <reduction symbol="$default" rule="1" enabled="true"/>
</reductions> </reductions>
</actions> </actions>