aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/parsetools/src/yecc.erl16
-rw-r--r--lib/parsetools/test/yecc_SUITE.erl28
2 files changed, 40 insertions, 4 deletions
diff --git a/lib/parsetools/src/yecc.erl b/lib/parsetools/src/yecc.erl
index b8b2b2308c..7fb6aae31a 100644
--- a/lib/parsetools/src/yecc.erl
+++ b/lib/parsetools/src/yecc.erl
@@ -1582,6 +1582,11 @@ find_action_conflicts2(Rs, Cxt0) ->
find_reduce_reduce([R], Cxt) ->
{R, Cxt};
+find_reduce_reduce([accept=A, #reduce{}=R | Rs], Cxt0) ->
+ Confl = conflict(R, A, Cxt0),
+ St = conflict_error(Confl, Cxt0#cxt.yecc),
+ Cxt = Cxt0#cxt{yecc = St},
+ find_reduce_reduce([R | Rs], Cxt);
find_reduce_reduce([#reduce{head = Categ1, prec = {P1, _}}=R1,
#reduce{head = Categ2, prec = {P2, _}}=R2 | Rs], Cxt0) ->
#cxt{res = Res0, yecc = St0} = Cxt0,
@@ -1773,6 +1778,8 @@ add_conflict(Conflict, St) ->
case Conflict of
{Symbol, StateN, _, {reduce, _, _, _}} ->
St#yecc{reduce_reduce = [{StateN,Symbol} |St#yecc.reduce_reduce]};
+ {Symbol, StateN, _, {accept, _}} ->
+ St#yecc{reduce_reduce = [{StateN,Symbol} |St#yecc.reduce_reduce]};
{Symbol, StateN, _, {shift, _, _}} ->
St#yecc{shift_reduce = [{StateN,Symbol} | St#yecc.shift_reduce]};
{_Symbol, _StateN, {one_level_up, _, _}, _Confl} ->
@@ -1791,6 +1798,8 @@ conflict(#reduce{rule_nmbr = RuleNmbr1}, NewAction, Cxt) ->
#cxt{terminal = Symbol, state_n = N, yecc = St} = Cxt,
{R1, RuleLine1, RuleN1} = rule(RuleNmbr1, St),
Confl = case NewAction of
+ accept ->
+ {accept, St#yecc.rootsymbol};
#reduce{rule_nmbr = RuleNmbr2} ->
{R2, RuleLine2, RuleN2} = rule(RuleNmbr2, St),
{reduce, R2, RuleN2, RuleLine2};
@@ -1830,7 +1839,10 @@ format_conflict({Symbol, N, Reduce, Confl}) ->
{shift, NewState, Sym} ->
io_lib:fwrite(<<" shift to state ~w, adding right "
"sisters to ~s.">>,
- [NewState, format_symbol(Sym)])
+ [NewState, format_symbol(Sym)]);
+ {accept, Rootsymbol} ->
+ io_lib:fwrite(<<" reduce to rootsymbol ~s.">>,
+ [format_symbol(Rootsymbol)])
end,
[S1, S2, S3].
@@ -2078,7 +2090,7 @@ output_action(St0, State, Terminal, #shift{state = NewState}, IsFirst, _SI) ->
output_action(St0, State, Terminal, accept, IsFirst, _SI) ->
St10 = delim(St0, IsFirst),
St = fwrite(St10,
- <<"yeccpars2_~w(_S, ~s, _Ss, Stack, _T, _Ts, _Tzr) ->\n">>,
+ <<"yeccpars2_~w(_S, ~s, _Ss, Stack, _T, _Ts, _Tzr) ->\n">>,
[State, quoted_atom(Terminal)]),
fwrite(St, <<" {ok, hd(Stack)}">>, []);
output_action(St, _State, _Terminal, nonassoc, _IsFirst, _SI) ->
diff --git a/lib/parsetools/test/yecc_SUITE.erl b/lib/parsetools/test/yecc_SUITE.erl
index b5da414f7b..2e287f413a 100644
--- a/lib/parsetools/test/yecc_SUITE.erl
+++ b/lib/parsetools/test/yecc_SUITE.erl
@@ -44,7 +44,7 @@
empty/1, prec/1, yeccpre/1, lalr/1, old_yecc/1,
other_examples/1,
bugs/1,
- otp_5369/1, otp_6362/1, otp_7945/1,
+ otp_5369/1, otp_6362/1, otp_7945/1, otp_8483/1,
improvements/1,
otp_7292/1, otp_7969/1]).
@@ -1284,7 +1284,7 @@ other_examples(Config) when is_list(Config) ->
ok.
bugs(suite) ->
- [otp_5369, otp_6362, otp_7945].
+ [otp_5369, otp_6362, otp_7945, otp_8483].
otp_5369(doc) ->
"OTP-5369. A bug in parse_and_scan reported on erlang questions.";
@@ -1486,6 +1486,30 @@ otp_7945(Config) when is_list(Config) ->
?line {error,_} = erl_parse:parse([{atom,3,foo},{'.',2,9,9}]),
ok.
+otp_8483(doc) ->
+ "OTP-8483. reduce/accept conflict";
+otp_8483(suite) -> [];
+otp_8483(Config) when is_list(Config) ->
+ Dir = ?privdir,
+ Input = filename:join(Dir, "bug.yrl"),
+
+ Bug1 = <<"Nonterminals elem seq.
+ Terminals 'foo'.
+ Rootsymbol elem.
+ elem -> 'foo'.
+ elem -> seq.
+ seq -> elem.
+ seq -> seq elem.">>,
+ ?line ok = file:write_file(Input, Bug1),
+ Ret = [return, {report, true}],
+ ?line {error,[{_,[{none,yecc,{conflict,_}},
+ {none,yecc,{conflict,_}},
+ {none,yecc,{conflict,_}}]}],
+ [{_,[{none,yecc,{conflicts,1,3}}]}]} =
+ yecc:file(Input, Ret),
+ file:delete(Input),
+ ok.
+
improvements(suite) ->
[otp_7292, otp_7969].