1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20-module(yecc_SUITE).
21
22%-define(debug, true).
23
24-include_lib("stdlib/include/erl_compile.hrl").
25
26-ifdef(debug).
27-define(line, put(line, ?LINE), ).
28-define(config(X,Y), foo).
29-define(datadir, "yecc_SUITE_data").
30-define(privdir, "yecc_SUITE_priv").
31-define(t, test_server).
32-else.
33-include_lib("common_test/include/ct.hrl").
34-define(datadir, ?config(data_dir, Config)).
35-define(privdir, ?config(priv_dir, Config)).
36-endif.
37
38-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
39	 init_per_group/2,end_per_group/2,
40	 init_per_testcase/2, end_per_testcase/2]).
41
42-export([app_test/1,
43
44	 file/1, syntax/1, compile/1, rules/1, expect/1,
45	 conflicts/1,
46
47	 empty/1, prec/1, yeccpre/1, lalr/1, old_yecc/1,
48	 other_examples/1,
49
50	 otp_5369/1, otp_6362/1, otp_7945/1, otp_8483/1, otp_8486/1,
51
52	 otp_7292/1, otp_7969/1, otp_8919/1, otp_10302/1, otp_11269/1,
53         otp_11286/1, otp_14285/1]).
54
55% Default timetrap timeout (set in init_per_testcase).
56-define(default_timeout, ?t:minutes(1)).
57
58init_per_testcase(_Case, Config) ->
59    ?line Dog = ?t:timetrap(?default_timeout),
60    [{watchdog, Dog} | Config].
61
62end_per_testcase(_Case, Config) ->
63    Dog = ?config(watchdog, Config),
64    test_server:timetrap_cancel(Dog),
65    ok.
66
67suite() -> [{ct_hooks,[ts_install_cth]}].
68
69all() ->
70    [app_test, {group, checks}, {group, examples},
71     {group, bugs}, {group, improvements}].
72
73groups() ->
74    [{checks, [],
75      [file, syntax, compile, rules, expect, conflicts]},
76     {examples, [],
77      [empty, prec, yeccpre, lalr, old_yecc, other_examples]},
78     {bugs, [],
79      [otp_5369, otp_6362, otp_7945, otp_8483, otp_8486]},
80     {improvements, [], [otp_7292, otp_7969, otp_8919, otp_10302,
81                         otp_11269, otp_11286, otp_14285]}].
82
83init_per_suite(Config) ->
84    Config.
85
86end_per_suite(_Config) ->
87    ok.
88
89init_per_group(_GroupName, Config) ->
90    Config.
91
92end_per_group(_GroupName, Config) ->
93    Config.
94
95
96app_test(doc) ->
97    ["Tests the applications consistency."];
98app_test(suite) ->
99    [];
100app_test(Config) when is_list(Config) ->
101    ?line ok=?t:app_test(parsetools),
102    ok.
103
104
105file(doc) ->
106    "Bad files and options.";
107file(suite) -> [];
108file(Config) when is_list(Config) ->
109    Dir = ?privdir,
110    Ret = [return, {report, false}],
111    ?line {error,[{_,[{none,yecc,{file_error,_}}]}],[]} =
112        yecc:file("not_a_file", Ret),
113    ?line {error,[{_,[{none,yecc,{file_error,_}}]}],[]} =
114        yecc:file("not_a_file", [{return,true}]),
115    ?line {error,[{_,[{none,yecc,{file_error,_}}]}],[]} =
116        yecc:file("not_a_file", [{report,false},return_errors]),
117    ?line error = yecc:file("not_a_file"),
118    ?line error = yecc:file("not_a_file", [{return,false},report]),
119    ?line error = yecc:file("not_a_file", [return_warnings,{report,false}]),
120    Filename = filename:join(Dir, "file.yrl"),
121    file:delete(Filename),
122
123    ?line {'EXIT', {badarg, _}} = (catch yecc:file({foo})),
124    ?line {'EXIT', {badarg, _}} =
125        (catch yecc:file(Filename, {parserfile,{foo}})),
126    ?line {'EXIT', {badarg, _}} =
127        (catch yecc:file(Filename, {includefile,{foo}})),
128
129    ?line {'EXIT', {badarg, _}} = (catch yecc:file(Filename, no_option)),
130    ?line {'EXIT', {badarg, _}} =
131        (catch yecc:file(Filename, [return | report])),
132    ?line {'EXIT', {badarg, _}} =
133        (catch yecc:file(Filename, {return,foo})),
134    ?line {'EXIT', {badarg, _}} =
135        (catch yecc:file(Filename, includefile)),
136
137    Mini = <<"Nonterminals nt.
138              Terminals t.
139              Rootsymbol nt.
140              nt -> t.">>,
141    ?line ok = file:write_file(Filename, Mini),
142    ?line {error,[{_,[{none,yecc,{file_error,_}}]}],[]} =
143        yecc:file(Filename, [{parserfile,"//"} | Ret]),
144
145    ?line {error,[{_,[{none,yecc,{file_error,_}}]}],[]} =
146        yecc:file(Filename, [{includefile,"//"} | Ret]),
147    ?line {error,[{_,[{none,yecc,{file_error,_}}]}],[]} =
148        yecc:file(Filename, [{includefile,"/ /"} | Ret]),
149
150    YeccPre = filename:join(Dir, "yeccpre.hrl"),
151    ?line ok = file:write_file(YeccPre, <<"syntax error. ">>),
152    PreErrors1 = run_test(Config, Mini, YeccPre),
153    ?line {errors,[_],[]} = extract(YeccPre, PreErrors1),
154    ?line ok = file:write_file(YeccPre, my_yeccpre()),
155    ?line {'EXIT', {undef,_}} = (catch run_test(Config, Mini, YeccPre)),
156
157    MiniCode = <<"
158              Nonterminals nt.
159              Terminals t.
160              Rootsymbol nt.
161              nt -> t.
162              Erlang code.
163             ">>,
164    ?line {'EXIT', {undef,_}} = (catch run_test(Config, MiniCode, YeccPre)),
165
166    file:delete(YeccPre),
167    file:delete(Filename),
168
169    ok.
170
171syntax(doc) ->
172    "Syntax checks.";
173syntax(suite) -> [];
174syntax(Config) when is_list(Config) ->
175    Dir = ?privdir,
176    %% Report errors. Very simple test of format_error/1.
177    Ret = [return, {report, true}],
178    Filename = filename:join(Dir, "file.yrl"),
179    Parserfile = filename:join(Dir, "file.erl"),
180    Parserfile1 = filename:join(Dir, "a file"),
181
182    ?line ok = file:write_file(Filename, <<"">>),
183    ?line {error,[{_,[{none,yecc,no_grammar_rules},
184                      {none,yecc,nonterminals_missing},
185                      {none,yecc,rootsymbol_missing},
186                      {none,yecc,terminals_missing}]}],[]} =
187        yecc:file(Filename, Ret),
188
189    ?line ok = file:write_file(Filename, <<"Nonterminals">>),
190    ?line {error,[{_,[{_,yecc,{error,yeccparser,_}}]}],[]} =
191        yecc:file(Filename, Ret),
192
193    ?line ok = file:write_file(Filename, <<"Nonterminals nt.">>),
194    ?line {error,[{_,[{none,yecc,no_grammar_rules},
195                      {none,yecc,rootsymbol_missing},
196                      {none,yecc,terminals_missing}]}],[]} =
197        yecc:file(Filename, Ret),
198
199    ?line ok = file:write_file(Filename, <<"Nonterminals nt. Terminals t.">>),
200    ?line {error,[{_,[{none,yecc,no_grammar_rules},
201                      {none,yecc,rootsymbol_missing}]}],[]} =
202        yecc:file(Filename, Ret),
203
204    %% Nonterminals and terminals not disjoint.
205    ?line ok = file:write_file(Filename,
206         <<"Nonterminals nt 't t'. Terminals t 't t'. Rootsymbol nt.">>),
207    ?line {error,[{_,[{1,yecc,{symbol_terminal_and_nonterminal,'t t'}},
208                      {none,yecc,no_grammar_rules}]}],
209           []} = yecc:file(Filename, Ret),
210
211    %% Rootsymbol is not a nonterminal.
212    ?line ok = file:write_file(Filename,
213         <<"Nonterminals nt. Terminals t.
214            Rootsymbol t. nt -> t.">>),
215    ?line {error,[{_,[{2,yecc,{bad_rootsymbol,t}}]}],[]} =
216        yecc:file(Filename, Ret),
217
218    %% Rootsymbol is not a nonterminal.
219    ?line ok = file:write_file(Filename,
220         <<"Nonterminals nt. Terminals t.
221            Rootsymbol t. nt -> t.">>),
222    ?line {error,[{_,[{2,yecc,{bad_rootsymbol,t}}]}],[]} =
223        yecc:file(Filename, Ret),
224
225    %% Endsymbol is a nonterminal.
226    ?line ok = file:write_file(Filename,
227         <<"Nonterminals nt. Terminals t. Rootsymbol nt.
228            Endsymbol nt.
229            nt -> t.">>),
230    ?line {error,[{_,[{2,yecc,{endsymbol_is_nonterminal,nt}}]}],[]} =
231        yecc:file(Filename, Ret),
232
233    %% Endsymbol is a terminal.
234    ?line ok = file:write_file(Filename,
235         <<"Nonterminals nt. Terminals t. Rootsymbol nt.
236            Endsymbol t.
237            nt -> t.">>),
238    ?line {error,[{_,[{2,yecc,{endsymbol_is_terminal,t}}]}],[]} =
239        yecc:file(Filename, Ret),
240
241    %% No grammar rules.
242    ?line ok = file:write_file(Filename,
243         <<"Nonterminals nt. Terminals t. Rootsymbol nt. Endsymbol e.">>),
244    ?line {error,[{_,[{none,yecc,no_grammar_rules}]}],[]} =
245        yecc:file(Filename, Ret),
246
247    %% Bad declaration.
248    ?line ok = file:write_file(Filename,
249         <<"Nonterminals nt. Terminals t. Rootsymbol nt. Endsymbol e.
250            nt -> t. e e.">>),
251    ?line {ok,_,[{_,[{2,yecc,bad_declaration}]}]} =
252        yecc:file(Filename, Ret),
253
254    %% Bad declaration with warnings_as_errors.
255    ok = file:delete(Parserfile),
256    error = yecc:file(Filename, [warnings_as_errors]),
257    false = filelib:is_regular(Parserfile),
258    error = yecc:file(Filename, [return_warnings,warnings_as_errors]),
259    false = filelib:is_regular(Parserfile),
260    {error,_,[{_,[{2,yecc,bad_declaration}]}]} =
261        yecc:file(Filename, [return_errors,warnings_as_errors]),
262    false = filelib:is_regular(Parserfile),
263    {ok,_,[{_,[{2,yecc,bad_declaration}]}]} =
264        yecc:file(Filename, [return_warnings]),
265    true = filelib:is_regular(Parserfile),
266
267    %% Bad declaration.
268    ?line ok = file:write_file(Filename,
269         <<"Nonterminals nt. Terminals t.
270            Rootsymbol nt nt. Rootsymbol nt. Endsymbol e.
271            nt -> t.">>),
272    ?line {ok,_,[{_,[{2,yecc,bad_declaration}]}]} =
273        yecc:file(Filename, Ret),
274
275    %% Syntax error found by yeccparser.
276    ?line ok = file:write_file(Filename,
277         <<"Nonterminals nt. Terminals t. Rootsymbol nt. Endsymbol e.
278            a - a.">>),
279    ?line {error,[{_,[{2,yecc,{error,_yeccparser,_}}]}],[]} =
280        yecc:file(Filename, Ret),
281
282    %% Syntax error: unknown nonterminal.
283    ?line ok = file:write_file(Filename,
284         <<"Nonterminals nt. Terminals t. Rootsymbol nt. Endsymbol e.
285            'unknown ' -> t.">>),
286    ?line {error,[{_,[{2,yecc,{undefined_nonterminal,'unknown '}}]}],[]} =
287        yecc:file(Filename, Ret),
288
289    %% Undefined rhs symbols. Note quotes in output.
290    ?line ok = file:write_file(Filename,
291         <<"Nonterminals Nonterminals nt.
292            Terminals t Terminals.
293            Rootsymbol nt.
294            Endsymbol e.
295            nt -> Nonterminals.
296            Nonterminals -> Terminals receive foo 45
297                            '17' 'a b'.">>),
298    ?line {error,[{_,[{6,yecc,{undefined_symbol,45}},
299                      {6,yecc,{undefined_symbol,foo}},
300                      {6,yecc,{undefined_symbol,'receive'}},
301                      {7,yecc,{undefined_symbol,'17'}},
302                      {7,yecc,{undefined_symbol,'a b'}}]}],[]} =
303        yecc:file(Filename, Ret),
304
305    %% '$empty' used early, before Terminals. OK.
306    ?line ok = file:write_file(Filename,
307         <<"Nonterminals nt.
308            nt -> '$empty'.
309            Terminals t.
310            Rootsymbol nt.
311            Endsymbol e.">>),
312    ?line {ok,_,[{_,[{3,yecc,{unused_terminal,t}}]}]} =
313        yecc:file(Filename, Ret),
314
315    %% Illegal use of '$empty'.
316    ?line ok = file:write_file(Filename,
317         <<"Nonterminals nt nt2.
318            Terminals t.
319            Rootsymbol nt.
320            Endsymbol e.
321            nt -> t.
322            nt2 -> t '$empty'.">>),
323    ?line {error,[{_,[{6,yecc,illegal_empty}]}],[]} =
324        yecc:file(Filename, Ret),
325
326    ParserFile3 = [{parserfile, Parserfile1}],
327
328    %% Bad Erlang expression in action. Changed in OTP-7224.
329    ?line ok = file:write_file(Filename,
330         <<"Nonterminals nt.
331            Terminals t.
332            Rootsymbol nt.
333            Endsymbol e.
334            nt -> t : a bad code.">>),
335    ?line {ok, _, []} = yecc:file(Filename, ParserFile3 ++ Ret),
336
337    SzYeccPre = yeccpre_size(),
338    %% Note: checking the line numbers. Changes when yeccpre.hrl changes.
339    fun() ->
340            ?line {error,[{_,[{5,_,["syntax error before: ","bad"]}]},
341                          {_,[{L1,_,{undefined_function,{yeccpars2_2_,1}}},
342                              {L2,_,{bad_inline,{yeccpars2_2_,1}}}]}],
343                   []} = compile:file(Parserfile1, [basic_validation,return]),
344            ?line L1 = 31 + SzYeccPre,
345            ?line L2 = 39 + SzYeccPre
346    end(),
347
348    %% Bad macro in action. OTP-7224.
349    ?line ok = file:write_file(Filename,
350         <<"Nonterminals nt.
351            Terminals t.
352            Rootsymbol nt.
353            Endsymbol e.
354            nt -> t : ?F(3).">>),
355    ?line {ok, _, []} = yecc:file(Filename, ParserFile3 ++ Ret),
356    %% Note: checking the line numbers. Changes when yeccpre.hrl changes.
357    fun() ->
358            ?line {error,[{_,[{5,_,{undefined,'F',1}}]},
359                          {_,[{L1,_,{undefined_function,{yeccpars2_2_,1}}},
360                              {L2,_,{bad_inline,{yeccpars2_2_,1}}}]}],
361                   []} = compile:file(Parserfile1, [basic_validation,return]),
362            ?line L1 = 31 + SzYeccPre,
363            ?line L2 = 39 + SzYeccPre
364    end(),
365
366    %% Check line numbers. OTP-7224.
367    ?line ok = file:write_file(Filename,
368         <<"Terminals t.
369            Nonterminals nt.
370            Rootsymbol nt.
371            Endsymbol e.
372            nt -> t : ?F(3).
373            Erlang code.
374            -define(F(X), X).
375            t() ->
376               bad().">>),
377    ?line {ok, _, []} = yecc:file(Filename, ParserFile3 ++ Ret),
378    ?line {error,[{_,[{9,_,{undefined_function,{bad,0}}}]}],
379           [{_,[{8,_,{unused_function,{t,0}}}]}]}
380        = compile:file(Parserfile1, [basic_validation, return]),
381
382    %% Terminals defined before nonterminals. (One of many checks...)
383    %% Used to give an error message, but now allowed.
384    ?line ok = file:write_file(Filename,
385         <<"Terminals t.
386            Nonterminals nt.
387            Rootsymbol nt.
388            Endsymbol e.
389            nt -> t.
390            Erlang code.">>),
391    ?line {ok, _, []} = yecc:file(Filename, Ret),
392
393    %% Precedence with swapped arguments. Bad declaration.
394    ?line ok = file:write_file(Filename,
395         <<"Nonterminals nt.
396            Terminals t.
397            Rootsymbol nt.
398            Endsymbol e.
399            nt -> t.
400            Right t.
401            Left nt 100.">>),
402    ?line {ok,_,[{_,[{6,yecc,bad_declaration},{7,yecc,bad_declaration}]}]} =
403        yecc:file(Filename, Ret),
404
405    %% Precedence with unknown operator.
406    ?line ok = file:write_file(Filename,
407         <<"Nonterminals nt.
408            Terminals t.
409            Rootsymbol nt.
410            Endsymbol e.
411            nt -> t.
412            Unary 100 '-'.">>),
413    ?line {error,[{_,[{6,yecc,{precedence_op_is_unknown,'-'}}]}],[]} =
414        yecc:file(Filename, Ret),
415
416    %% Precedence with endsymbol operator.
417    ?line ok = file:write_file(Filename,
418         <<"Nonterminals nt.
419            Terminals t.
420            Rootsymbol nt.
421            Endsymbol e.
422            nt -> t.
423            Unary 100 e.">>),
424    ?line {error,[{_,[{6,yecc,{precedence_op_is_endsymbol,e}}]}],[]} =
425        yecc:file(Filename, Ret),
426
427    %% Duplicated precedence.
428    ?line ok = file:write_file(Filename, <<"
429            Nonterminals nt.
430            Terminals t '+'.
431            Rootsymbol nt.
432            nt -> t '+' nt.
433            Left 100 '+'.
434            Right 200 t.
435            Left 200 '+'.
436            Left 200 '+'.
437            Right 200 t.">>),
438    ?line {error,[{_,[{8,yecc,{duplicate_precedence,'+'}},
439                      {9,yecc,{duplicate_precedence,'+'}},
440                      {10,yecc,{duplicate_precedence,t}}]}],
441           []} = yecc:file(Filename, Ret),
442
443    %% Duplicated nonterminal.
444    ?line ok = file:write_file(Filename,
445         <<"Nonterminals 'n t' 'n t'. Terminals t.
446            Rootsymbol 'n t'. 'n t' -> t.">>),
447    ?line {ok, _, [{_,[{1,yecc,{duplicate_nonterminal,'n t'}}]}]} =
448        yecc:file(Filename, Ret),
449    ?line {ok, _, [{_,[{1,yecc,{duplicate_nonterminal,'n t'}}]}]} =
450        yecc:file(Filename, [return_warnings, {report, false}]),
451    ?line {ok, _} = yecc:file(Filename),
452    ?line {ok, _} =
453        yecc:file(Filename, [{report,false}, {return_warnings,false}]),
454
455    %% Duplicated terminal.
456    ?line ok = file:write_file(Filename,
457         <<"Nonterminals nt. Terminals 't t' 't t'.
458            Rootsymbol nt. nt -> 't t'.">>),
459    ?line {ok, _, [{_,[{1,yecc,{duplicate_terminal,'t t'}}]}]} =
460       yecc:file(Filename, Ret),
461
462    %% Two Nonterminals declarations.
463    ?line ok = file:write_file(Filename,
464         <<"Nonterminals nt. Terminals t.
465            Nonterminals nt2.
466            Rootsymbol nt2. nt -> t. nt2 -> nt.">>),
467    ?line {error,[{_,[{2,yecc,{duplicate_declaration,'Nonterminals'}}]}],
468           []} = yecc:file(Filename, Ret),
469
470    %% Three Terminals declarations.
471    ?line ok = file:write_file(Filename,
472         <<"Nonterminals nt. Terminals t.
473            Terminals t1.
474            Terminals t1.
475            Rootsymbol nt. nt -> t t1.">>),
476    ?line {error,[{_,[{2,yecc,{duplicate_declaration,'Terminals'}},
477                      {3,yecc,{duplicate_declaration,'Terminals'}}]}],
478           []} = yecc:file(Filename, Ret),
479
480    %% Two root symbols.
481    ?line ok = file:write_file(Filename,
482         <<"Nonterminals nt. Terminals t. Rootsymbol t.
483            Rootsymbol nt. nt -> t.">>),
484    ?line {error,[{_,[{2,yecc,{duplicate_declaration,'Rootsymbol'}}]}],[]} =
485        yecc:file(Filename, Ret),
486
487    %% Two end symbols.
488    ?line ok = file:write_file(Filename,
489         <<"Nonterminals nt. Terminals t. Rootsymbol t.
490            Endsymbol e.
491            Endsymbol e. nt -> t.">>),
492    ?line {error,[{_,[{3,yecc,{duplicate_declaration,'Endsymbol'}}]}],[]} =
493        yecc:file(Filename, Ret),
494
495    %% Two end symbols.
496    ?line ok = file:write_file(Filename,
497         <<"Nonterminals nt. Terminals t. Rootsymbol t.
498            Expect 1.
499            Expect 0.
500            Endsymbol e. nt -> t.">>),
501    ?line {error,[{_,[{3,yecc,{duplicate_declaration,'Expect'}}]}],[]} =
502        yecc:file(Filename, Ret),
503
504    %% Some words should not be used.
505    ?line ok = file:write_file(Filename, <<"
506            Terminals '$empty' '$end'.
507            Nonterminals '$undefined'.
508            Rootsymbol '$undefined'.
509            Endsymbol '$end'.
510            '$undefined' -> '$empty'.
511          ">>),
512    ?line {error,[{_,[{2,yecc,{reserved,'$empty'}},
513                      {2,yecc,{reserved,'$end'}},
514                      {3,yecc,{reserved,'$undefined'}},
515                      {5,yecc,{endsymbol_is_terminal,'$end'}}]}],[]} =
516        yecc:file(Filename, Ret),
517
518    %% Undefined pseudo variable.
519    ?line ok = file:write_file(Filename,<<"
520              Nonterminals nt.
521              Terminals t.
522              Rootsymbol nt.
523              nt -> t : '$2'.
524          ">>),
525    ?line {error,[{_,[{5,yecc,{undefined_pseudo_variable,'$2'}}]}],[]} =
526        yecc:file(Filename, Ret),
527
528    %% Space in module name.
529    ?line ok = file:write_file(Filename, <<"
530        Nonterminals list.
531        Terminals element.
532        Rootsymbol list.
533
534        list -> element : {single, '$1'}.
535        list -> list element : {pair, '$1', '$2'}.
536
537        Erlang code.
538
539        -export([t/0]).
540
541        t() ->
542            L = [{element, 1}, {element, 2}, {element, 3}],
543            {ok,_} = parse(L),
544            ok.
545       ">>),
546
547    Parserfile2 = filename:join(Dir, "a \"file\""),
548    %% The parser (yeccgramm.yrl) allows many symbol names...
549    ?line ok = file:write_file(Filename, <<"
550        Nonterminals Nonterminals Rootsymbol ':' '->'.
551        Terminals Terminals.
552        Rootsymbol Rootsymbol.
553        Endsymbol e.
554        Rootsymbol -> Nonterminals ':' '->'.
555        Nonterminals -> Terminals.
556        ':' -> '->'.
557        '->' -> Terminals.
558       ">>),
559    ?line {ok, _} = yecc:file(Filename, [{parserfile, Parserfile1}]),
560    ?line {ok, _} = yecc:file(Filename, [{parserfile, Parserfile1},time]),
561    ?line {ok,[]} = compile:file(Parserfile1, [basic_validation]),
562
563    Quotes = <<"
564            Nonterminals
565            tail try 17 42 Unused ' unused ' '42' 'fnutt\\'' receive.
566
567            Terminals
568            ']' '|' ',' '\"hi\"' 'there\\'' 'you\\'' ACCEPT.
569
570            Rootsymbol 17.
571
572            Endsymbol '$end'.
573
574            17 -> try : '$1':more([\"hi \\\" there\", '.', 3.14, % $3 , % '$1' is a module
575                                    -104, ' ', ' a', '->', $a, $\t]), '$1'.
576
577            try -> tail 'you\\'' 'fnutt\\''.
578
579            'fnutt\\'' -> 'you\\'' ACCEPT.
580
581            '42' -> tail.
582
583            tail -> ']' :
584                           (fun(Strange) -> foo end)(apa).
585            tail -> '|' try ']' :
586                           (fun(Strange) -> foo;
587                               (_) -> 'when' % warning
588                            end)('ap a', foo),
589                           %% This line intentionally left blank.
590                           R = #rec{},
591                           A = R#rec.a,
592                           <<\"hi\">> = <<\"hi\">>,
593                           there.
594            tail -> ',' try tail : {cons,line('$2'),'$2','$3'}.
595
596
597            Erlang code.
598
599            -export([t/0]).
600
601            -record(rec, {a}).
602
603            just(Some, Code) ->
604                true.
605
606            more(Code) ->
607                io:format(\"~p~n\", [Code]), true.
608
609            line(_) ->
610                17.
611
612            t() ->
613                ok. % compiled successfully...
614
615             ">>,
616
617    ?line ok = file:write_file(Filename, Quotes),
618    ?line {ok,_,[{_,
619                  [{3,yecc,{unused_nonterminal,42}},
620                   {3,yecc,{unused_nonterminal,' unused '}},
621                   {3,yecc,{unused_nonterminal,'42'}},
622                   {3,yecc,{unused_nonterminal,'Unused'}},
623                   {3,yecc,{unused_nonterminal,'receive'}},
624                   {6,yecc,{unused_terminal,'"hi"'}},
625                   {6,yecc,{unused_terminal,'there\''}}]}]} =
626        yecc:file(Filename, Ret),
627
628    Ts = [{quotes, Quotes, default, ok}],
629    ?line run(Config, Ts),
630
631    %% Non-terminal has no rules, but is unused.
632    ?line ok = file:write_file(Filename,<<"
633              Nonterminals nt bad.
634              Terminals t.
635              Rootsymbol nt.
636
637              nt -> t : something.
638          ">>),
639    ?line {ok,_,[{_,[{2,yecc,{unused_nonterminal,bad}}]}]} =
640        yecc:file(Filename, Ret),
641
642    %% Non-terminal has no rules and is used.
643    ?line ok = file:write_file(Filename,<<"
644              Nonterminals nt bad.
645              Terminals t.
646              Rootsymbol nt.
647
648              nt -> t bad : something.
649          ">>),
650    ?line {error,[{_,[{2,yecc,{missing_syntax_rule,bad}}]}],[]} =
651        yecc:file(Filename, Ret),
652
653    %% Warning in Erlang code. With and without file attributes.
654    ?line ok = file:write_file(Filename,<<"
655              Nonterminals nt.
656              Terminals t.
657              Rootsymbol nt.
658
659              nt -> t : t(17).
660
661              Erlang code.
662
663              t(A) ->
664                  b.
665          ">>),
666    ?line {ok, _, []} =
667        yecc:file(Filename, [file_attributes | Ret]),
668    Opts = [basic_validation, return],
669    Erlfile = filename:join(Dir, "file.erl"),
670    ?line {ok,[],[{_,[{10,_,_}]}]} = compile:file(Erlfile, Opts),
671    ?line {ok, _, []} =
672        yecc:file(Filename, [{file_attributes,false} | Ret]),
673    ?line {ok,[],[{_,[{4,_,_}]}]} = compile:file(Erlfile, Opts),
674
675    file:delete(Parserfile1 ++ ".erl"),
676    file:delete(Parserfile2 ++ ".erl"),
677    file:delete(Filename),
678
679    ok.
680
681compile(doc) ->
682    "Check of compile/3.";
683compile(suite) -> [];
684compile(Config) when is_list(Config) ->
685    Dir = ?privdir,
686    Filename = filename:join(Dir, "file.yrl"),
687    Parserfile = filename:join(Dir, "file.erl"),
688    ?line ok = file:write_file(Filename,
689                               <<"Nonterminals nt.
690                                  Terminals t.
691                                  Rootsymbol nt.
692                                  nt -> t.">>),
693    ?line error = yecc:compile(Filename, "//", #options{}),
694    ?line ok = yecc:compile(Filename, Parserfile, #options{}),
695    file:delete(Parserfile),
696    file:delete(Filename),
697    ok.
698
699rules(doc) ->
700    "Check of rules.";
701rules(suite) -> [];
702rules(Config) when is_list(Config) ->
703    Dir = ?privdir,
704    Ret = [return, {report, false}],
705    Filename = filename:join(Dir, "file.yrl"),
706
707    ?line ok = file:write_file(Filename,
708      <<"Nonterminals nt. Terminals t. Rootsymbol nt.
709         nt -> t. nt -> t.">>),
710    ?line {error,[{_,[{none,yecc,{conflict,_}}]}],
711           [{_,[{none,yecc,{conflicts,0,1}}]}]} =
712        yecc:file(Filename, [return, report]),
713
714    ?line ok = file:write_file(Filename, <<"
715                Nonterminals A B E.
716                Terminals c d f x y.
717                Rootsymbol A.
718
719                A -> B c d.
720                A -> E c f.
721                B -> x y.
722                E -> x y.
723                ">>),
724    ?line {error,[{_,[{none,yecc,{conflict,_}}]}],
725           [{_,[{none,yecc,{conflicts,0,1}}]}]} =
726        yecc:file(Filename, Ret),
727
728    ?line ok = file:write_file(Filename,<<"
729              Terminals t.
730              Nonterminals nt.
731              Rootsymbol nt.
732              nt -> '$empty' : '$1'.
733              nt -> t.
734          ">>),
735    ?line {error,[{_,[{5,yecc,{undefined_pseudo_variable,'$1'}}]}],[]} =
736        yecc:file(Filename, Ret),
737
738    ?line ok = file:write_file(Filename,<<"
739              Terminals t.
740              Nonterminals nt.
741              Rootsymbol nt.
742              nt -> '$empty' : '$0'.
743              nt -> t.
744          ">>),
745    ?line {error,[{_,[{5,yecc,{undefined_pseudo_variable,'$0'}}]}],[]} =
746        yecc:file(Filename, Ret),
747
748    file:delete(Filename),
749
750    %% No precedences.
751    Ts = [{rules_1,<<"
752              Nonterminals exp.
753              Terminals number '*' '+' '(' ')'.
754              Rootsymbol exp.
755
756              exp -> exp '+' exp : {plus,'$1','$3'}.
757              exp -> exp '*' exp : {times,'$1','$3'}.
758              exp -> number : element(2, '$1').
759              exp -> '(' exp ')' : '$2'.
760
761              Erlang code.
762
763              -export([t/0]).
764
765              t() ->
766                  {ok, {times, 1, {plus, 3, 5}}} =
767                    parse([{number,1}, {'*',2}, {number,3},
768                                       {'+',4}, {number,5}]),
769                  ok.
770          ">>,
771         default,
772         ok}],
773    ?line run(Config, Ts),
774    ok.
775
776
777expect(doc) ->
778    "Check of expect.";
779expect(suite) -> [];
780expect(Config) when is_list(Config) ->
781    Dir = ?privdir,
782    Ret = [return, {report, true}],
783    Filename = filename:join(Dir, "file.yrl"),
784
785    ?line ok = file:write_file(Filename, <<"
786                Nonterminals e.
787                Terminals i t else.
788                Rootsymbol e.
789                Expect a.
790
791                e -> i e t e.
792                e -> i e t e else e.
793                ">>),
794    ?line {error,[{_,[{5,yecc,{bad_expect,a}}]}],[]} =
795        yecc:file(Filename, Ret),
796
797    ?line ok = file:write_file(Filename, <<"
798                Nonterminals e.
799                Terminals i t else.
800                Rootsymbol e.
801                Expect 1.
802
803                e -> i e t e.
804                e -> i e t e else e.
805                ">>),
806    ?line {ok, _, []} = yecc:file(Filename, Ret),
807
808    ?line ok = file:write_file(Filename, <<"
809                Nonterminals e.
810                Terminals i t else.
811                Rootsymbol e.
812                Expect 2.
813
814                e -> i e t e.
815                e -> i e t e else e.
816                ">>),
817    ?line {ok, _, [{_,[{none,yecc,{conflicts,1,0}}]}]} =
818        yecc:file(Filename, Ret),
819
820    ?line ok = file:write_file(Filename, <<"
821                Nonterminals e.
822                Terminals i t else.
823                Rootsymbol e.
824                Expect -2.
825
826                e -> i e t e.
827                e -> i e t e else e.
828                ">>),
829    ?line {error,[{_,[{5,yecc,{error,_yeccparser,_}}]}],[]} =
830        yecc:file(Filename, Ret),
831
832    %% States N. An undocumented declaration used for testing.
833    ?line ok = file:write_file(Filename, <<"
834                Nonterminals nt.
835                Terminals t.
836                Rootsymbol nt.
837                States 100.
838                nt -> t.">>),
839    ?line {ok,_,[{_, [{none,yecc,{n_states,100,3}}]}]} =
840        yecc:file(Filename, Ret),
841
842    ?line ok = file:write_file(Filename, <<"
843                Nonterminals nt.
844                Terminals t.
845                Rootsymbol nt.
846                States bad.
847                nt -> t.">>),
848    ?line {error,[{_,[{5,yecc,{bad_states,bad}}]}],[]} =
849        yecc:file(Filename, Ret),
850
851    file:delete(Filename),
852    ok.
853
854conflicts(doc) ->
855    "Shift/reduce and reduce/reduce conflicts.";
856conflicts(suite) -> [];
857conflicts(Config) when is_list(Config) ->
858    Dir = ?privdir,
859    Ret = [return, {report, true}],
860    Filename = filename:join(Dir, "file.yrl"),
861
862    ?line ok = file:write_file(Filename, <<"
863            Nonterminals S List Tuple Elements Element.
864            Terminals '{' '}' '[' ']' ',' nil e.
865            Rootsymbol S.
866
867            S -> '$empty' : empty.
868            S -> List : '$1'.
869
870            List -> '$empty' : [].
871            List -> nil : [].
872            List -> '[' Tuple ']' : {list, '$2'}.
873
874            Tuple -> '$empty' : {}.
875            Tuple -> '{' '}' : {}.
876            Tuple -> '{' Elements '}' : {tuple, '$2'}.
877
878            Elements -> '$empty' : none.
879            Elements -> Elements ',' Element : {elements, '$3', '$1'}.
880            Elements -> Element : '$1'.
881
882            Element -> List : '$1'.
883            Element -> Tuple : '$1'.
884            Element -> e : '$1'.
885           ">>),
886    ?line {error,[{_,_}],[{_,[{none,yecc,{conflicts,1,5}}]}]} =
887        yecc:file(Filename, Ret),
888
889    %% Can easily be resolved (but don't do it!).
890    ?line ok = file:write_file(Filename, <<"
891            Nonterminals S List Tuple Elements Element.
892            Terminals '{' '}' '[' ']' ',' nil e.
893            Rootsymbol S.
894
895            Right 100 List.
896
897            S -> '$empty' : empty.
898            S -> List : '$1'.
899
900            List -> '$empty' : [].
901            List -> nil : [].
902            List -> '[' Tuple ']' : {list, '$2'}.
903
904            Tuple -> '$empty' : {}.
905            Tuple -> '{' '}' : {}.
906            Tuple -> '{' Elements '}' : {tuple, '$2'}.
907
908            Elements -> '$empty' : none.
909            Elements -> Elements ',' Element : {elements, '$3', '$1'}.
910            Elements -> Element : '$1'.
911
912            Element -> List : '$1'.
913            Element -> Tuple : '$1'.
914            Element -> e : '$1'.
915           ">>),
916    ?line {ok, _, []} =
917        yecc:file(Filename, Ret),
918
919    file:delete(Filename),
920    ok.
921
922empty(doc) ->
923    "'$empty'.";
924empty(suite) -> [];
925empty(Config) when is_list(Config) ->
926    Ts = [{empty_1, <<"
927            Nonterminals nt.
928            Terminals t.
929            Rootsymbol nt.
930            Endsymbol e.
931            nt -> '$empty': nothing.
932            nt -> t : something.
933
934            Erlang code.
935
936            -export([t/0]).
937
938            t() ->
939                {ok, nothing} = parse([{e,2}]),
940                {ok, something} = parse([{t,1},{e,2}]),
941                ok.">>,
942           default,
943           ok},
944          {empty_2, <<"
945            %% There used to be a bug when it came to the left
946            %% corners. In this example rule 2 is a prefix of rule 1
947            %% such that the rule 2 generates $empty but rule 1 does
948            %% not. The old buggy code seemingly worked well too.
949            Nonterminals top A B C D.
950            Terminals t.
951            Rootsymbol top.
952
953            top -> A B C D : {'$1','$2','$3','$4'}.
954            top -> A B C : {'$1','$2','$3'}.
955
956            A -> '$empty' : e.
957            B -> '$empty' : e.
958            C -> '$empty' : e.
959
960            D -> t : t.
961
962            Erlang code.
963
964            -export([t/0]).
965
966            t() ->
967                {ok,{e,e,e,t}} = parse([{t, 1}]),
968                {ok,{e,e,e}} = parse([]),
969                ok.
970           ">>,
971           default,
972           ok}],
973    ?line run(Config, Ts),
974    ok.
975
976prec(doc) ->
977    "Precedence.";
978prec(suite) -> [];
979prec(Config) when is_list(Config) ->
980    Dir = ?privdir,
981    Ret = [return, {report, false}],
982    Filename = filename:join(Dir, "file.yrl"),
983
984    %% Don't know what 'Unary' actually means, but this is how it has
985    %% always worked...
986    ?line ok = file:write_file(Filename, <<"
987                Nonterminals E.
988                Terminals '*' '+' '=' integer.
989                Rootsymbol E.
990
991                E -> E '=' E : {op, '=', '$1', '$3'}.
992                E -> E '*' E : {op, '*', '$1', '$3'}.
993                E -> E '+' E  : {op, '+', '$1', '$3'}.
994                E -> integer : '$1'.
995
996                Unary 100 '='.
997                Left 200 '+'.
998                Left 400 '*'.
999              ">>),
1000    ?line {error,[{_,[{none,yecc,{conflict,_}}]}],
1001           [{_,[{none,yecc,{conflicts,1,0}}]}]} =
1002        yecc:file(Filename, Ret),
1003
1004    Ts = [{prec_1, <<"
1005        Nonterminals E Expr Uminus.
1006        Terminals '=' '+' '*' '-' '(' ')' integer var dot.
1007        Rootsymbol Expr.
1008
1009        Expr -> E dot : '$1'.
1010        E -> var '=' E : {match, line_of('$1'), '$1', '$3'}.
1011        E -> E '+' E : {op, line_of('$1'), '+', '$1', '$3'}.
1012        E -> E '-' E : {op, line_of('$1'), '-', '$1', '$3'}.
1013        E -> E '*' E : {op, line_of('$1'), '*', '$1', '$3'}.
1014        E -> Uminus : '$1'.
1015        E -> '(' E ')' : '$2'.
1016        E -> integer : '$1'.
1017
1018        Uminus -> '-' E :   {op, line_of('$1'), '-', '$2'}.
1019
1020        Right 200 '='.
1021        Left 300 '+'.
1022        Left 300 '-'.
1023        Left 400 '*'.
1024        Unary 500 Uminus.
1025
1026        Erlang code.
1027
1028        -export([t/0, t/1]).
1029
1030        line_of(Token) ->
1031            element(2, Token).
1032
1033        t() ->
1034            {ok, -56} = t(\"A = (4 + 3) * - 8. \"),
1035            {ok, 28} = t(\"A = 4 + B=3 * 8. \"),
1036            {ok, 28} = t(\"4 - 3 * - 8. \"),
1037            {ok, -20} = t(\"4 - 3 * 8. \"),
1038            {ok, 2} = t(\"1 - - 1.\"),
1039            ok.
1040
1041        t(S) ->
1042            case erl_scan:string(S) of
1043                {ok, Tokens, _Line} ->
1044                    case parse(Tokens) of
1045                        {ok, Expr} ->
1046                            case catch erl_eval:expr(Expr, []) of
1047                                {value, Value, _Bs} ->
1048                                    {ok, Value};
1049                                {'EXIT', Reason} ->
1050                                    {error, Reason}
1051                            end;
1052                        Error ->
1053                            Error
1054                    end;
1055                Error ->
1056                    Error
1057            end.
1058        ">>,
1059        default,
1060        ok},
1061
1062          {prec_2, <<"
1063        Nonterminals E uminus.
1064        Terminals '*' '-' integer.
1065        Rootsymbol E.
1066
1067        E -> E '-' E : {op, '-', '$1', '$3'}.
1068        E -> E '*' E : {op, '*', '$1', '$3'}.
1069        E -> uminus: '$1'.
1070        E -> integer : '$1'.
1071
1072        uminus -> '-' E :  {op, '-', '$2'}.
1073
1074        Left 200 '-'.
1075        Left 400 '*'.
1076        Unary 500 uminus.
1077
1078        Erlang code.
1079
1080        -export([t/0]).
1081
1082        t() ->
1083            %% This used to be parsed -(4 * 3), but that has been corrected:
1084            {ok,{op,'*',{op,'-',{integer,1,4}},{integer,3,12}}} =
1085                parse([{'-',0},{integer,1,4},{'*',2},{integer,3,12}]),
1086
1087            {ok,{op,'-',{op,'-',{integer,1,4}},{integer,3,12}}} =
1088                parse([{'-',0},{integer,1,4},{'-',2},{integer,3,12}]),
1089            {ok,{op,'*',{op,'-',{op,'-',{integer,2,4}}},{integer,4,12}}} =
1090                parse([{'-',0},{'-',1},{integer,2,4},{'*',3},{integer,4,12}]),
1091            {ok,{op,'-',{integer,1,4},{op,'-',{integer,4,12}}}} =
1092                parse([{integer,1,4},{'-',2},{'-',3},{integer,4,12}]),
1093            ok.
1094        ">>,
1095        default,
1096        ok},
1097          {prec_3, <<"
1098            Nonterminals nt.
1099            Terminals '(' ')' t op.
1100            Rootsymbol nt.
1101
1102            Nonassoc 100 op.
1103
1104            nt -> nt op nt : {'$2', '$1', '$3'}.
1105            nt -> '(' nt ')' : '$2'.
1106            nt -> t : '$1'.
1107
1108            Erlang code.
1109
1110            -export([t/0]).
1111
1112            t() ->
1113                {error,{4,yecc_test,[\"syntax error before: \",\"op\"]}} =
1114                    parse([{t,1},{op,2},{t,3},{op,4},{t,5}]),
1115                {ok,{{op,2},{t,1},{{op,5},{t,4},{t,6}}}} =
1116                    parse([{t,1},{op,2},{'(',3},{t,4},{op,5},{t,6},{')',7}]),
1117                ok.
1118        ">>,
1119        default,
1120        ok},
1121
1122          {prec_4, <<"
1123            Nonterminals E.
1124            Terminals '-' '+' '=' id.
1125            Rootsymbol E.
1126
1127            E -> E '=' E : {op, '=', '$1', '$3'}.
1128            E -> E '+' E  : {op, '+', '$1', '$3'}.
1129            E -> '-' E : {op, '-', '$2'}.
1130            E -> id : '$1'.
1131
1132            Nonassoc 100 '='.
1133            Right 200 '+' '-'.
1134
1135            Erlang code.
1136
1137            -export([t/0]).
1138
1139            t() ->
1140                {ok,{op,'=',{id,1},{op,'-',{op,'+',{id,4},{id,6}}}}} =
1141                    parse([{id,1},{'=',2},{'-',3},{id,4},{'+',5},{id,6}]),
1142                ok.
1143
1144        ">>,
1145        default,
1146        ok}],
1147
1148    ?line run(Config, Ts),
1149    ok.
1150
1151yeccpre(doc) ->
1152    "Errors etc. in actions, handled by yeccpre. parse_and_scan.";
1153yeccpre(suite) -> [];
1154yeccpre(Config) when is_list(Config) ->
1155    Ts = [{error_1, <<"
1156            Nonterminals list.
1157            Terminals element e.
1158            Rootsymbol list.
1159
1160            list -> element : {single, '$1'}.
1161            list -> list element : throw(error).
1162            list -> e : return_error(element(2, '$1'), bad_element).
1163
1164            Erlang code.
1165
1166            -export([t/0]).
1167
1168            t() ->
1169               error = (catch parse([{element,1},{element,2}])),
1170               {error, {2, _, Mess}} = parse([{element,1},{e,2}]),
1171               ok.
1172           ">>,
1173           default,
1174           ok},
1175
1176          {error_2, <<"
1177            Nonterminals list.
1178            Terminals element.
1179            Rootsymbol list.
1180
1181            list -> element.
1182
1183            Erlang code.
1184
1185            -export([t/0, scan/1]).
1186
1187            scan(How) ->
1188                case How of
1189                    thrown -> throw(thrown);
1190                    error -> erlang:error(error);
1191                    exit -> exit(exit)
1192                end.
1193
1194            t() ->
1195                try parse_and_scan({yecc_test, scan, [thrown]})
1196                catch throw: thrown ->
1197                        ok
1198                end,
1199                try parse_and_scan({yecc_test, scan, [error]})
1200                catch error: error ->
1201                        ok
1202                end,
1203                try parse_and_scan({fun yecc_test:scan/1, [exit]})
1204                catch exit: exit ->
1205                        ok
1206                end,
1207                try parse_and_scan({fun scan/1, [thrown]})
1208                catch throw: thrown ->
1209                        ok
1210                end,
1211                ok.
1212           ">>,
1213           default,
1214           ok}],
1215
1216    ?line run(Config, Ts),
1217    ok.
1218
1219lalr(doc) ->
1220    "Examples of grammars that are LALR(1) but not SLR(1).";
1221lalr(suite) -> [];
1222lalr(Config) when is_list(Config) ->
1223    Ts = [{lalr_1, <<"
1224            %% http://inst.cs.berkeley.edu/~cs164/lectures/slide14a.pdf
1225            %% http://pages.cpsc.ucalgary.ca/~robin/class/411/LR.1.html
1226            %% b d . c. Shift or reduce?
1227            Nonterminals S A.
1228            Terminals a b c d.
1229            Rootsymbol S.
1230            S -> A a : {r1,'$1','$2'}.
1231            S -> b A c : {r2,'$1','$2','$3'}.
1232            S -> d c : {r3,'$1','$2'}.
1233            S -> b d a : {r4,'$1','$2','$3'}.
1234
1235            A -> d : {r5,'$1'}.
1236
1237            Erlang code.
1238
1239            -export([t/0]).
1240
1241            t() ->
1242               %% Reduce!
1243               {ok,{r2,{b,1},{r5,{d,2}},{c,3}}} = parse([{b,1},{d,2},{c,3}]),
1244               ok.
1245           ">>,
1246           default,
1247           ok},
1248         {lalr_2, <<"
1249            %% http://www.cs.pitt.edu/~mock/cs2210/lectures/lecture5.pdf
1250            Nonterminals S L R.
1251            Terminals '*' id '='.
1252            Rootsymbol S.
1253            S -> L '=' R : {r1,'$1','$3'}.
1254            S -> R : {r2,'$1'}.
1255
1256            L -> '*' R : {r3,'$2'}.
1257            L -> id : {r4,'$1'}.
1258
1259            R -> L : {r5,'$1'}.
1260
1261            Erlang code.
1262
1263            -export([t/0]).
1264
1265            t() ->
1266               {ok,{r1,{r3,{r5,{r4,{id,1}}}},{r5,{r4,{id,3}}}}} =
1267                   parse([{'*',0},{id,1},{'=',2},{id,3}]),
1268               ok.
1269           ">>,
1270           default,
1271           ok}],
1272    ?line run(Config, Ts),
1273    ok.
1274
1275old_yecc(doc) ->
1276    "The old interface yecc:yecc/2,3,4.";
1277old_yecc(suite) -> [];
1278old_yecc(Config) when is_list(Config) ->
1279    Dir = ?privdir,
1280    Filename = filename:join(Dir, "file.yrl"),
1281    Parserfile = filename:join(Dir, "file.erl"),
1282    Mini = <<"Nonterminals nt.
1283              Terminals t.
1284              Rootsymbol nt.
1285              nt -> t.">>,
1286    ?line ok = file:write_file(Filename, Mini),
1287    ?line {_, _} = yecc:yecc(Filename, Parserfile),
1288    ?line {_, _} = yecc:yecc(Filename, Parserfile, true),
1289    ?line {_, _} = yecc:yecc(Filename, Parserfile, true),
1290    TE = process_flag(trap_exit, true),
1291    ?line {'EXIT', error} =
1292        (catch yecc:yecc(Filename, Parserfile, false, Parserfile)),
1293    _ = process_flag(trap_exit, TE),
1294    ok.
1295
1296other_examples(doc) ->
1297    "Misc examples.";
1298other_examples(suite) -> [];
1299other_examples(Config) when is_list(Config) ->
1300    Ts = [{empty, <<"
1301            %% G1 from the 1974 article.
1302
1303            Nonterminals LIST ELEMENT.
1304            Terminals ',' a b.
1305            Rootsymbol LIST.
1306
1307            LIST -> LIST ',' ELEMENT : {'$1', '$3'}.
1308            LIST -> ELEMENT : '$1'.
1309
1310            ELEMENT -> a : '$1'.
1311            ELEMENT -> b : '$1'.
1312
1313            Erlang code.
1314
1315            -export([t/0]).
1316
1317            t() ->
1318                L = [{a, 1}, {',', 2}, {b, 3}],
1319                {ok,{{a,1},{b,3}}} = parse(L),
1320                ok.
1321            ">>,
1322           default,
1323           ok}],
1324    ?line run(Config, Ts),
1325    ok.
1326
1327
1328otp_5369(doc) ->
1329    "OTP-5369. A bug in parse_and_scan reported on erlang questions.";
1330otp_5369(suite) -> [];
1331otp_5369(Config) when is_list(Config) ->
1332    Ts = [{otp_5369,<<"
1333        Nonterminals list.
1334        Terminals element.
1335        Rootsymbol list.
1336
1337        list -> element : {single, '$1'}.
1338        list -> list element : {pair, '$1', '$2'}.
1339
1340        Erlang code.
1341
1342        -export([t/0, scan/1]).
1343
1344        scan(Lexer) ->
1345            Lexer ! {scan, self()},
1346            receive
1347                {ok, Lexer, [Token], Position} ->
1348                    {ok, [Token], Position};
1349                {eof, Lexer, Position} ->
1350                    {eof, Position}
1351            end.
1352
1353        make_scanner(L) ->
1354            spawn_link(fun() ->
1355                               loop(L)
1356                       end).
1357
1358        loop([]) ->
1359            receive
1360                {scan, Pid} ->
1361                    Pid ! {eof, self(), 1000}
1362            end;
1363        loop([Token = {_, P}|T]) ->
1364            receive
1365                {scan, Pid} ->
1366                    Pid ! {ok, self(), [Token], P},
1367                    loop(T)
1368            end.
1369
1370        t(L) ->
1371            case parse_and_scan({yecc_test, scan, [make_scanner(L)]}) of
1372                {ok, _Result} ->
1373                    ok;
1374                {error, {_LineNumber, Module, Message}} ->
1375                    _M = apply(Module, format_error, [Message]),
1376                    not_ok
1377            end.
1378
1379        t() ->
1380            not_ok = t([]), %% This test has been added afterwards.
1381                            %% OTP-5369 did not fix this bug!
1382            L = [{element, 1},
1383                 {element, 2},
1384                 {element, 3}],
1385            t(L).
1386      ">>,
1387      default,
1388      ok}],
1389    ?line run(Config, Ts),
1390    ok.
1391
1392otp_6362(doc) ->
1393    "OTP-6362. A precedence declaration bug reported on erlang questions.";
1394otp_6362(suite) -> [];
1395otp_6362(Config) when is_list(Config) ->
1396    Ts = [{otp_6362_1,<<"
1397        Nonterminals cmp compare expr.
1398        Terminals 'string' '>' '='.
1399        Rootsymbol compare.
1400        Nonassoc 250 cmp.
1401        compare -> expr cmp expr     : {cmp, '$2', '$1', '$3'}.
1402        compare -> expr              : {cmp, '==', '$1', {string, \"TRUE\"}}.
1403        cmp -> '>' '='               : '>='.
1404        cmp -> '>'                   : '>'.
1405        expr -> 'string'             : '$1'.
1406
1407        Erlang code.
1408
1409        -export([t/0]).
1410
1411        t() ->
1412            {ok,{cmp,'>',{string,1},{string,3}}} =
1413                parse([{string,1}, {'>', 2}, {string,3}]),
1414            ok.
1415      ">>,
1416      default,
1417      ok}],
1418    ?line run(Config, Ts),
1419
1420    Dir = ?privdir,
1421    %% Report errors. Very simple test of format_error/1.
1422    Ret = [return, {report, true}],
1423    Filename = filename:join(Dir, "file.yrl"),
1424
1425    %% An error introduced due to this ticket. Terminals can be
1426    %% assigned conflicting precedences, which cannot be resolved.
1427    ?line ok = file:write_file(Filename,<<"
1428            Nonterminals cmp compare expr fopp.
1429            Terminals string '>' '='.
1430            Rootsymbol compare.
1431            Nonassoc 250 cmp.
1432            Left 300 '>'.
1433
1434            compare -> expr cmp expr	: {cmp, '$2', '$1', '$3'}.
1435            compare -> expr fopp expr	: {cmp, '$2', '$1', '$3'}.
1436            compare -> expr '=' expr        : '$1'.
1437            compare -> expr 		: {cmp, '==', '$1', {string, foo}}.
1438            cmp -> '>' '='			: '>='.
1439            cmp -> '>'			: '>'.
1440            expr -> string  		: '$1'.
1441
1442            fopp -> '>' '='			: '>='.
1443            fopp -> '>'			: '>'.">>),
1444
1445    Ret = [return, {report, true}],
1446    ?line {error,[{_,[{none,yecc,{conflict,_}}]}],[]} =
1447        yecc:file(Filename, Ret),
1448    file:delete(Filename),
1449    ok.
1450
1451my_yeccpre() ->
1452  %% Version 1.1.
1453  <<"parse(Tokens) ->
1454         yeccpars0(Tokens, false).
1455
1456     parse_and_scan({F, A}) -> % Fun or {M, F}
1457         yeccpars0([], {F, A});
1458     parse_and_scan({M, F, A}) ->
1459         yeccpars0([], {{M, F}, A}).
1460
1461     format_error(Message) ->
1462         case io_lib:deep_char_list(Message) of
1463             true ->
1464                 Message;
1465             _ ->
1466                 io_lib:write(Message)
1467         end.
1468
1469     % To be used in grammar files to throw an error message to the parser
1470     % toplevel. Doesn't have to be exported!
1471     -compile({nowarn_unused_function,{return_error,2}}).
1472     return_error(Line, Message) ->
1473         throw({error, {Line, yecc_test, Message}}).
1474
1475     yeccpars0(Tokens, MFA) ->
1476         try yeccpars1(Tokens, MFA, 0, [], [])
1477         catch
1478             throw: {error, {_Line, yecc_test, _M}} = Error ->
1479                        Error % probably from return_error/1
1480         end.
1481
1482     % Don't change yeccpars1/6 too much, it is called recursively by yeccpars2/8!
1483    yeccpars1([Token | Tokens], Tokenizer, State, States, Vstack) ->
1484        yeccpars2(State, element(1, Token), States, Vstack, Token, Tokens,
1485                  Tokenizer);
1486    yeccpars1([], {F, A}, State, States, Vstack) ->
1487        case apply(F, A) of
1488            {ok, Tokens, _Endline} ->
1489                yeccpars1(Tokens, {F, A}, State, States, Vstack);
1490            {eof, _Endline} ->
1491                yeccpars1([], false, State, States, Vstack);
1492            {error, Descriptor, _Endline} ->
1493                {error, Descriptor}
1494        end;
1495    yeccpars1([], false, State, States, Vstack) ->
1496        yeccpars2(State, '$end', States, Vstack, {'$end', 999999}, [], false).
1497
1498     % For internal use only.
1499     yeccerror(Token) ->
1500         {error,
1501          {element(2, Token), yecc_test,
1502           [\"syntax error before: \", yecctoken2string(Token)]}}.
1503
1504     yecctoken2string({atom, _, A}) -> io_lib:write(A);
1505     yecctoken2string({integer,_,N}) -> io_lib:write(N);
1506     yecctoken2string({float,_,F}) -> io_lib:write(F);
1507     yecctoken2string({char,_,C}) -> io_lib:write_char(C);
1508     yecctoken2string({var,_,V}) -> io_lib:format('~s', [V]);
1509     yecctoken2string({string,_,S}) -> io_lib:write_string(S);
1510     yecctoken2string({reserved_symbol, _, A}) -> io_lib:format('~w', [A]);
1511     yecctoken2string({_Cat, _, Val}) -> io_lib:format('~w', [Val]);
1512     yecctoken2string({'dot', _}) -> io_lib:format('~w', ['.']);
1513     yecctoken2string({'$end', _}) ->
1514         [];
1515     yecctoken2string({Other, _}) when is_atom(Other) ->
1516         io_lib:format('~w', [Other]);
1517     yecctoken2string(Other) ->
1518         io_lib:write(Other).
1519">>.
1520
1521otp_7945(doc) ->
1522    "OTP-7945. A bug introduced in R13A.";
1523otp_7945(suite) -> [];
1524otp_7945(Config) when is_list(Config) ->
1525    A2 = erl_anno:new(2),
1526    A3 = erl_anno:new(3),
1527    {error,_} = erl_parse:parse([{atom,A3,foo},{'.',A2,9,9}]),
1528    ok.
1529
1530otp_8483(doc) ->
1531    "OTP-8483. reduce/accept conflict";
1532otp_8483(suite) -> [];
1533otp_8483(Config) when is_list(Config) ->
1534    Dir = ?privdir,
1535    Input = filename:join(Dir, "bug.yrl"),
1536
1537    Bug1 = <<"Nonterminals elem seq.
1538              Terminals 'foo'.
1539              Rootsymbol elem.
1540              elem -> 'foo'.
1541              elem -> seq.
1542              seq -> elem.
1543              seq -> seq elem.">>,
1544    ?line ok = file:write_file(Input, Bug1),
1545    Ret = [return, {report, true}],
1546    ?line {error,[{_,[{none,yecc,{conflict,_}},
1547                      {none,yecc,{conflict,_}},
1548                      {none,yecc,{conflict,_}}]}],
1549           [{_,[{none,yecc,{conflicts,1,3}}]}]} =
1550        yecc:file(Input, Ret),
1551    file:delete(Input),
1552    ok.
1553
1554otp_8486(doc) ->
1555    "OTP-8486.";
1556otp_8486(suite) -> [];
1557otp_8486(Config) when is_list(Config) ->
1558    Ts = [{otp_8486,<<"
1559           Nonterminals boolean command.
1560           Terminals '(' ')' if then else true and or skip while do.
1561           Rootsymbol command.
1562           Left 100 or.
1563           Left 200 and.
1564           boolean -> '(' boolean ')' : '$2'.
1565           boolean -> 'true' : b.
1566           boolean -> boolean 'and' boolean : {a,'$1','$3'}.
1567           boolean -> boolean 'or' boolean : {o,'$1','$3'}.
1568           command -> 'skip' : s.
1569           command -> 'if' boolean 'then' command 'else' command :
1570                                  {i,'$2','$4','$6'}.
1571           command -> 'while' boolean 'do' command : {w,'$2','$4'}.
1572
1573           Erlang code.
1574           -export([t/0]).
1575           t() ->
1576               {ok,{i,{o,b,b},s,s}} =
1577                   parse([{'if',1},{'true',1},{'or',1},{'true',1},
1578                          {'then',1},{'skip',1},{'else',1},{'skip',1}]),
1579               ok.
1580          ">>,default,ok}],
1581    ?line run(Config, Ts),
1582    ok.
1583
1584otp_7292(doc) ->
1585    "OTP-7292. Header declarations for edoc.";
1586otp_7292(suite) -> [];
1587otp_7292(Config) when is_list(Config) ->
1588    Dir = ?privdir,
1589    Filename = filename:join(Dir, "file.yrl"),
1590    Parserfile1 = filename:join(Dir, "a file"),
1591
1592    Contents =  <<"Nonterminals nt.
1593                   Terminals t.
1594                   Rootsymbol nt.
1595                   Endsymbol e.
1596                   nt -> t : a bad code.
1597
1598                   Header \"%% copyright bla bla bla\"
1599                   \"%% @private\" \"%% foo\"
1600                   \"%% @author X.Y.\".
1601
1602                   Erlang code.
1603
1604                   %% @private
1605                   %% etc.
1606
1607                   foo() ->
1608                       bar. ">>,
1609
1610    %% Check that correct line number is used in messages.
1611    ?line ok = file:write_file(Filename, Contents),
1612    ParserFile3 = [{parserfile, Parserfile1}],
1613    Ret = [return, {report, true}],
1614    ?line {ok, _, []} = yecc:file(Filename, ParserFile3 ++ Ret),
1615
1616    %% Note: checking the line numbers. Changes when yeccpre.hrl changes.
1617    fun() ->
1618            SzYeccPre = yeccpre_size(),
1619            ?line {error,
1620                   [{_,[{5,_,["syntax error before: ","bad"]}]},
1621                    {_,[{L1,_,{undefined_function,{yeccpars2_2_,1}}},
1622                        {L2,_,{bad_inline,{yeccpars2_2_,1}}}]}],
1623                   [{_,[{16,_,{unused_function,{foo,0}}}]}]} =
1624                compile:file(Parserfile1, [basic_validation, return]),
1625            L1 = 41 + SzYeccPre,
1626            L2 = 49 + SzYeccPre
1627    end(),
1628
1629    YeccPre = filename:join(Dir, "yeccpre.hrl"),
1630    ?line ok = file:write_file(YeccPre,
1631       [<<"-export([parse/1, parse_and_scan/1, format_error/1]).\n">>,
1632        yeccpre_v1_2()]),
1633    Inc = [{includefile,YeccPre}],
1634    ?line {ok, _, []} = yecc:file(Filename, ParserFile3 ++ Inc ++ Ret),
1635    fun() ->
1636            SzYeccPre = yeccpre_size(YeccPre),
1637            ?line {error,
1638                   [{_,[{5,_,["syntax error before: ","bad"]}]},
1639                    {_,[{L1,_,{undefined_function,{yeccpars2_2_,1}}},
1640                        {L2,_,{bad_inline,{yeccpars2_2_,1}}}]}],
1641                   [{_,[{16,_,{unused_function,{foo,0}}}]}]} =
1642                compile:file(Parserfile1, [basic_validation, return]),
1643            ?line L1 = 40 + SzYeccPre,
1644            ?line L2 = 48 + SzYeccPre
1645    end(),
1646
1647    file:delete(YeccPre),
1648    file:delete(Parserfile1 ++ ".erl"),
1649    file:delete(Filename),
1650
1651    ok.
1652
1653yeccpre_v1_2() ->
1654    <<"
1655parse(Tokens) ->
1656    yeccpars0(Tokens, false).
1657
1658parse_and_scan({F, A}) ->
1659    yeccpars0([], {F, A});
1660parse_and_scan({M, F, A}) ->
1661    Arity = length(A),
1662    yeccpars0([], {fun M:F/Arity, A}).
1663
1664format_error(Message) ->
1665    case io_lib:deep_char_list(Message) of
1666	true ->
1667	    Message;
1668	_ ->
1669	    io_lib:write(Message)
1670    end.
1671
1672-define(CODE_VERSION, \"1.2\").
1673
1674yeccpars0(Tokens, MFA) ->
1675    try yeccpars1(Tokens, MFA, 0, [], [])
1676    catch
1677        error: Error : Stacktrace ->
1678            try yecc_error_type(Error, Stacktrace) of
1679                {syntax_error, Token} ->
1680                    yeccerror(Token);
1681                {missing_in_goto_table=Tag, State} ->
1682                    Desc = {State, Tag},
1683                    erlang:raise(error, {yecc_bug, ?CODE_VERSION, Desc},
1684                                Stacktrace);
1685                {missing_in_goto_table=Tag, Symbol, State} ->
1686                    Desc = {Symbol, State, Tag},
1687                    erlang:raise(error, {yecc_bug, ?CODE_VERSION, Desc},
1688                                Stacktrace)
1689            catch _:_ -> erlang:raise(error, Error, Stacktrace)
1690            end;
1691        throw: {error, {_Line, ?MODULE, _M}} = Error ->
1692            Error % probably from return_error/2
1693    end.
1694
1695yecc_error_type(function_clause, [{?MODULE,F,[_,_,_,_,Token,_,_]} | _]) ->
1696    \"yeccpars2\" ++ _ = atom_to_list(F),
1697    {syntax_error, Token};
1698yecc_error_type({case_clause,{State}}, [{?MODULE,yeccpars2,_}|_]) ->
1699    %% Inlined goto-function
1700    {missing_in_goto_table, State};
1701yecc_error_type(function_clause, [{?MODULE,F,[State]}|_]) ->
1702    \"yeccgoto_\" ++ SymbolL = atom_to_list(F),
1703    {ok,[{atom,_,Symbol}]} = erl_scan:string(SymbolL),
1704    {missing_in_goto_table, Symbol, State}.
1705
1706yeccpars1([Token | Tokens], Tokenizer, State, States, Vstack) ->
1707    yeccpars2(State, element(1, Token), States, Vstack, Token, Tokens,
1708              Tokenizer);
1709yeccpars1([], {F, A}, State, States, Vstack) ->
1710    case apply(F, A) of
1711        {ok, Tokens, _Endline} ->
1712	    yeccpars1(Tokens, {F, A}, State, States, Vstack);
1713        {eof, _Endline} ->
1714            yeccpars1([], false, State, States, Vstack);
1715        {error, Descriptor, _Endline} ->
1716            {error, Descriptor}
1717    end;
1718yeccpars1([], false, State, States, Vstack) ->
1719    yeccpars2(State, '$end', States, Vstack, {'$end', 999999}, [], false).
1720
1721yeccpars1(State1, State, States, Vstack, Stack1, [Token | Tokens],
1722          Tokenizer) ->
1723    yeccpars2(State, element(1, Token), [State1 | States],
1724              [Stack1 | Vstack], Token, Tokens, Tokenizer);
1725yeccpars1(State1, State, States, Vstack, Stack1, [], {F, A}) ->
1726    case apply(F, A) of
1727        {ok, Tokens, _Endline} ->
1728	    yeccpars1(State1, State, States, Vstack, Stack1, Tokens, {F, A});
1729        {eof, _Endline} ->
1730            yeccpars1(State1, State, States, Vstack, Stack1, [], false);
1731        {error, Descriptor, _Endline} ->
1732            {error, Descriptor}
1733    end;
1734yeccpars1(State1, State, States, Vstack, Stack1, [], false) ->
1735    yeccpars2(State, '$end', [State1 | States], [Stack1 | Vstack],
1736              {'$end', 999999}, [], false).
1737
1738yeccerror(Token) ->
1739    {error,
1740     {element(2, Token), ?MODULE,
1741      [\"syntax error before: \", yecctoken2string(Token)]}}.
1742
1743yecctoken2string({atom, _, A}) -> io_lib:write(A);
1744yecctoken2string({integer,_,N}) -> io_lib:write(N);
1745yecctoken2string({float,_,F}) -> io_lib:write(F);
1746yecctoken2string({char,_,C}) -> io_lib:write_char(C);
1747yecctoken2string({var,_,V}) -> io_lib:format('~s', [V]);
1748yecctoken2string({string,_,S}) -> io_lib:write_string(S);
1749yecctoken2string({reserved_symbol, _, A}) -> io_lib:format('~w', [A]);
1750yecctoken2string({_Cat, _, Val}) -> io_lib:format('~w', [Val]);
1751yecctoken2string({'dot', _}) -> io_lib:format('~w', ['.']);
1752yecctoken2string({'$end', _}) ->
1753    [];
1754yecctoken2string({Other, _}) when is_atom(Other) ->
1755    io_lib:format('~w', [Other]);
1756yecctoken2string(Other) ->
1757    io_lib:write(Other).
1758">>.
1759
1760run(Config, Tests) ->
1761    F = fun({N,P,Pre,E}) ->
1762                case catch run_test(Config, P, Pre) of
1763                    E ->
1764                        ok;
1765                    Bad ->
1766                        ?t:format("~nTest ~p failed. Expected~n  ~p~n"
1767                                  "but got~n  ~p~n", [N, E, Bad]),
1768			fail()
1769                end
1770        end,
1771    lists:foreach(F, Tests).
1772
1773otp_7969(doc) ->
1774    "OTP-7969. Interface to the I/O protocol..";
1775otp_7969(suite) -> [];
1776otp_7969(Config) when is_list(Config) ->
1777    ?line {ok,Ts1,_} =
1778        erl_scan:string("'foo\nbar'", {1,1}, [text]),
1779    ?line {error,{2,_,["syntax error before: ",[]]}} = erl_parse:parse(Ts1),
1780
1781    ?line {ok,Ts1_1,_} = erl_scan:string("'foo\nbar'", 1, [text]),
1782    ?line {error,{2,_,["syntax error before: ",[]]}} = erl_parse:parse(Ts1_1),
1783
1784    ?line {ok,Ts2,_EndLocation} =
1785        erl_scan:string("'foo\nbar'", {1,1}, []),
1786    %% Can't do better than report possibly wrong line:
1787    ?line {error,{1,_,["syntax error before: ",[]]}} = erl_parse:parse(Ts2),
1788
1789    ?line {ok, Ts11, _}=R1 = erl_scan:string("f() -> a."),
1790    ?line F1 = fun() -> {ok,Ts11 ++ [{'$end',2}],2} end,
1791    A1 = erl_anno:new(1),
1792    {ok,{function,A1,f,0,[{clause,A1,[],[],[{atom,A1,a}]}]}} =
1793        erl_parse:parse_and_scan({F1, []}),
1794    ?line F2 = fun() -> erl_scan:string("f() -> ,") end,
1795    ?line {error,{1,erl_parse,_}} = erl_parse:parse_and_scan({F2, []}),
1796    ?line F3 = fun() -> case erase(foo) of
1797                            bar ->
1798                                {ok,[{'$end',2}],3};
1799                            undefined ->
1800                                put(foo,bar), R1
1801                        end
1802               end,
1803    {ok,{function,A1,f,0,[{clause,A1,[],[],[{atom,A1,a}]}]}} =
1804        erl_parse:parse_and_scan({F3,[]}),
1805    F4 = fun() -> {error, {1, ?MODULE, bad}, 2} end,
1806    ?line {error, {1,?MODULE,bad}} = erl_parse:parse_and_scan({F4, []}),
1807    F5 = fun() -> {eof, 3} end,
1808    ?line {error,{3,erl_parse,_}} = erl_parse:parse_and_scan({F5, []}),
1809    ?line {error,{999999,erl_parse,_}} = erl_parse:parse([]),
1810    ?line {ok, Ts21, EL} = erl_scan:string("f() -> a; g() -> b. ", {1,1}),
1811    ?line F6 = fun() -> {ok, Ts21, EL} end,
1812    ?line {error,{{1,11},erl_parse,_}} = erl_parse:parse_and_scan({F6, []}),
1813    ok.
1814
1815otp_8919(doc) ->
1816    "OTP-8919. Improve formating of Yecc error messages.";
1817otp_8919(suite) -> [];
1818otp_8919(Config) when is_list(Config) ->
1819    A1 = erl_anno:new(1),
1820    {error,{1,Mod,Mess}} = erl_parse:parse([{cat,A1,"hello"}]),
1821    "syntax error before: \"hello\"" = lists:flatten(Mod:format_error(Mess)),
1822    ok.
1823
1824otp_10302(doc) ->
1825    "OTP-10302. Unicode characters scanner/parser.";
1826otp_10302(suite) -> [];
1827otp_10302(Config) when is_list(Config) ->
1828    Dir = ?privdir,
1829    Filename = filename:join(Dir, "OTP-10302.yrl"),
1830    Ret = [return, {report, true}],
1831    Mini1 = <<"%% coding: utf-8
1832               Nonterminals Häpp.
1833               nt -> t.">>,
1834    ok = file:write_file(Filename, Mini1),
1835    %% This could (and should) be refined:
1836    {error,[{Filename,[{2,Mod1,Err1}]}],[]} =
1837        yecc:file(Filename, Ret),
1838    "cannot translate from UTF-8" = Mod1:format_error(Err1),
1839
1840    Mini2 = <<"%% coding: Utf-8
1841               Nonterminals Hopp.
1842               Terminals t.
1843               Rootsymbol Hopp.
1844
1845               Hopp -> t.
1846
1847               Erlang code.
1848
1849               t() ->
1850                   Häpp.">>,
1851    ok = file:write_file(Filename, Mini2),
1852    {error,[{Filename,[{11,Mod2,Err2}]}],[]} =
1853        yecc:file(Filename, Ret),
1854    "cannot parse; possibly encoding mismatch" = Mod2:format_error(Err2),
1855
1856    Mini3 = <<"%% coding: latin-1
1857               Nonterminals Hopp.
1858               Terminals t.
1859               Rootsymbol Hopp.
1860
1861               Hopp -> t.
1862
1863               Erlang code.
1864
1865               t() ->
1866                   Häpp.">>,
1867    ok = file:write_file(Filename, Mini3),
1868    YeccPre = filename:join(Dir, "yeccpre.hrl"),
1869    ok = file:write_file(YeccPre, [<<"%% coding: UTF-8\n ä.\n">>]),
1870    Inc = [{includefile,YeccPre}],
1871    {error,[{_,[{2,yecc,cannot_parse}]}],[]} =
1872        yecc:file(Filename, Inc ++ Ret),
1873
1874    ok = file:write_file(Filename,
1875     <<"%% coding: UTF-8
1876        Nonterminals Hopp.
1877        Terminals t.
1878        Rootsymbol \"örn_Ѐ\".
1879        Hopp -> t : '$1'.">>),
1880    {error,[{Filename,[{4,yecc,{bad_symbol,"örn_"++[1024]}}]}],[]} =
1881        yecc:file(Filename, Ret),
1882
1883    ok = file:write_file(Filename,
1884     <<"%% coding: UTF-8
1885        Nonterminals Hopp.
1886        Terminals t.
1887        Rootsymbol Hopp.
1888        Endsymbol \"örn_Ѐ\".
1889        Hopp -> t : '$1'.">>),
1890    {error,[{Filename,[{5,yecc,{bad_symbol,"örn_"++[1024]}}]}],[]} =
1891        yecc:file(Filename, Ret),
1892
1893    ok = file:write_file(Filename,
1894     <<"%% coding: UTF-8
1895        Nonterminals Hopp.
1896        Terminals t.
1897        Rootsymbol Hopp.
1898        Expect \"örn_Ѐ\".
1899        Hopp -> t : '$1'.">>),
1900    {error,[{Filename,[{5,yecc,{bad_symbol,"örn_"++[1024]}}]}],[]} =
1901        yecc:file(Filename, Ret),
1902
1903    ok = file:write_file(Filename,
1904     <<"%% coding: UTF-8
1905        Nonterminals Hopp.
1906        Terminals t.
1907        Rootsymbol Hopp.
1908        States \"örn_Ѐ\".
1909        Hopp -> t : '$1'.">>),
1910    {error,[{Filename,[{5,yecc,{bad_symbol,"örn_"++[1024]}}]}],[]} =
1911        yecc:file(Filename, Ret),
1912
1913    Ts = [{otp_10302_1,<<"
1914           %% coding: UTF-8
1915           Header \"%% örn_Ѐ\" \"%% \\x{400}B\".
1916           Nonterminals Häpp list.
1917           Terminals element.
1918           Rootsymbol Häpp.
1919
1920           Häpp -> list : '$1'.
1921
1922           list -> element : '$1'.
1923           list -> list element :
1924                       begin
1925                           Häpp = foo,
1926                           {Häpp, 'Häpp',\"\\x{400}B\",\"örn_Ѐ\"}
1927                       end.
1928
1929           Erlang code.
1930
1931           -export([t/0]).
1932
1933           t() ->
1934               L = [{element, 1}, {element,2}],
1935               {ok, R} = parse(L),
1936               Häpp = foo,
1937               {_,_,[1024,66],[246,114,110,95,1024]} = R,
1938               {Häpp,'Häpp',\"\\x{400}B\",\"örn_Ѐ\"} = R,
1939               ok.
1940          ">>,default,ok},
1941          {otp_10302_2,<<"
1942           %% coding: Latin-1
1943           Nonterminals Häpp list.
1944           Terminals element.
1945           Rootsymbol Häpp.
1946
1947           Häpp -> list : '$1'.
1948
1949           list -> element : '$1'.
1950           list -> list element :
1951                       begin
1952                           Häpp = foo,
1953                           {Häpp, 'Häpp',\"\\x{400}B\",\"örn_Ѐ\"}
1954                       end.
1955
1956           Erlang code.
1957
1958           -export([t/0]).
1959
1960           t() ->
1961               L = [{element, 1}, {element,2}],
1962               {ok, R} = parse(L),
1963               Häpp = foo,
1964               {_,_,[1024,66],[195,182,114,110,95,208,128]} = R,
1965               {Häpp,'Häpp',\"\\x{400}B\",\"örn_Ѐ\"} = R,
1966               ok.
1967          ">>,default,ok}],
1968    run(Config, Ts),
1969    ok.
1970
1971otp_11269(doc) ->
1972    "OTP-11269. A bug.";
1973otp_11269(suite) -> [];
1974otp_11269(Config) when is_list(Config) ->
1975    Dir = ?privdir,
1976    Filename = filename:join(Dir, "OTP-11269.yrl"),
1977    Ret = [return, {report, false}],
1978    Pai = <<"Nonterminals
1979             list list0 list1 newline_list.
1980
1981             Terminals
1982             '\n' semi.
1983
1984             Rootsymbol  list.
1985
1986             Endsymbol '$end'.
1987
1988             list ->   newline_list list0 : '$2'.
1989
1990             list0 -> list1 '\n' newline_list : '$1'.
1991
1992             list1 -> list1 semi newline_list list1 :
1993                           {command_connect, '$1', '$4', semi}.
1994
1995             newline_list -> newline_list '\n' : nil.">>,
1996    ok = file:write_file(Filename, Pai),
1997    {ok,ErlFile,[{_YrlFile,[{none,yecc,{conflicts,1,0}}]}]} =
1998        yecc:file(Filename, Ret),
1999    Opts = [return, warn_unused_vars,{outdir,Dir}],
2000    {ok,'OTP-11269',_Warnings} = compile:file(ErlFile, Opts),
2001    ok.
2002
2003otp_11286(doc) ->
2004    "OTP-11286. A Unicode filename bug; both Leex and Yecc.";
2005otp_11286(suite) -> [];
2006otp_11286(Config) when is_list(Config) ->
2007    Node = start_node(otp_11286, "+fnu"),
2008    Dir = ?privdir,
2009    UName = [1024] ++ "u",
2010    UDir = filename:join(Dir, UName),
2011    _ = rpc:call(Node, file, make_dir, [UDir]),
2012
2013    %% Note: Cannot use UName as filename since the filename is used
2014    %% as module name. To be fixed in R18.
2015    Filename = filename:join(UDir, 'OTP-11286.yrl'),
2016    Ret = [return, {report, false}, time],
2017
2018    Mini1 = <<"%% coding: utf-8
2019               Terminals t.
2020               Nonterminals nt.
2021               Rootsymbol  nt.
2022               nt -> t.">>,
2023    ok = rpc:call(Node, file, write_file, [Filename, Mini1]),
2024    {ok,ErlFile,[]} = rpc:call(Node, yecc, file, [Filename, Ret]),
2025    Opts = [return, warn_unused_vars,{outdir,Dir}],
2026    {ok,_,_Warnings} = rpc:call(Node, compile, file, [ErlFile, Opts]),
2027
2028    Mini2 = <<"Terminals t.
2029               Nonterminals nt.
2030               Rootsymbol  nt.
2031               nt -> t.">>,
2032    ok = rpc:call(Node, file, write_file, [Filename, Mini2]),
2033    {ok,ErlFile,[]} = rpc:call(Node, yecc, file, [Filename, Ret]),
2034    Opts = [return, warn_unused_vars,{outdir,Dir}],
2035    {ok,_,_Warnings} = rpc:call(Node, compile, file, [ErlFile, Opts]),
2036
2037    Mini3 = <<"%% coding: latin-1
2038               Terminals t.
2039               Nonterminals nt.
2040               Rootsymbol  nt.
2041               nt -> t.">>,
2042    ok = rpc:call(Node, file, write_file, [Filename, Mini3]),
2043    {ok,ErlFile,[]} = rpc:call(Node, yecc, file, [Filename, Ret]),
2044    Opts = [return, warn_unused_vars,{outdir,Dir}],
2045    {ok,_,_Warnings} = rpc:call(Node, compile, file, [ErlFile, Opts]),
2046
2047    true = test_server:stop_node(Node),
2048    ok.
2049
2050otp_14285(Config) ->
2051    Dir = ?privdir,
2052    YeccPre = filename:join(Dir, "yeccpre.hrl"),
2053    ?line ok = file:write_file(YeccPre,
2054                               [<<"-export([t/0]).\n">>,my_yeccpre()]),
2055
2056    T0 = <<"
2057        Nonterminals '\\x{400}'.
2058        Terminals t.
2059        Rootsymbol '\\x{400}'.
2060       '\\x{400}' -> t : '$1'.
2061       Erlang code.
2062       t() ->
2063           L = [{t, 1}],
2064           {ok, R} = parse(L),
2065           {t, 1} = R,
2066           ok.">>,
2067    Ts0 = [{otp_14285_1,
2068           [<<"%% coding: Latin-1\n">>,T0],YeccPre,ok},
2069         {otp_14285_2,
2070           [<<"%% coding: coding: UTF-8\n">>,T0],YeccPre,ok}],
2071    run(Config, Ts0),
2072    file:delete(YeccPre),
2073
2074    T1 = <<"
2075        Nonterminals '1\\x{400}' list 'unused\\x{400}'.
2076        Terminals '2\\x{400}'.
2077        Rootsymbol '1\\x{400}'.
2078
2079        '1\\x{400}' -> list : '$1'.
2080
2081        list -> '2\\x{400}' : '$1'.
2082        list -> list '2\\x{400}' : {foo,'\\x{400}'}.
2083
2084        Erlang code.
2085
2086        -export([t/0]).
2087
2088        t() ->
2089            L = [{'2\\x{400}', 1}, {'2\\x{400}',2}],
2090            {ok, R} = parse(L),
2091            {foo,A} = R,
2092            '\\x{400}' = A,
2093            [1024] = atom_to_list(A),
2094            ok.">>,
2095
2096    Ts1 = [{otp_14285_3,
2097            [<<"%% coding: Latin-1\n">>,T1],default,ok},
2098           {otp_14285_4,
2099            [<<"%% coding: UTF-8\n">>,T1],default,ok}],
2100    run(Config, Ts1),
2101
2102    T2 = <<"
2103        Nonterminals E.
2104        Terminals '-' '+' '=' id.
2105        Rootsymbol E.
2106        Endsymbol '\\x{400}'.
2107
2108        E -> E '=' E : {op, '=', '$1', '$3'}.
2109        E -> E '+' E  : {op, '+', '$1', '$3'}.
2110        E -> '-' E : {op, '-', '$2'}.
2111        E -> id : '$1'.
2112
2113        Nonassoc 100 '='.
2114        Right 200 '+' '-'.
2115
2116        Erlang code.
2117
2118        -export([t/0]).
2119
2120        t() ->
2121            {ok,{op,'=',{id,1},{op,'-',{op,'+',{id,4},{id,6}}}}} =
2122                parse([{id,1},{'=',2},{'-',3},{id,4},{'+',5},{id,6},
2123                      {'\\x{400}',1}]),
2124            ok.">>,
2125
2126    Ts2 = [{otp_14285_5,
2127            [<<"%% coding: Latin-1\n">>,T2],default,ok},
2128           {otp_14285_6,
2129            [<<"%% coding: UTF-8\n">>,T2],default,ok}],
2130    run(Config, Ts2),
2131
2132    ok.
2133
2134start_node(Name, Args) ->
2135    [_,Host] = string:tokens(atom_to_list(node()), "@"),
2136    ct:log("Trying to start ~w@~s~n", [Name,Host]),
2137    case test_server:start_node(Name, peer, [{args,Args}]) of
2138	{error,Reason} ->
2139	    test_server:fail(Reason);
2140	{ok,Node} ->
2141	    ct:log("Node ~p started~n", [Node]),
2142	    Node
2143    end.
2144
2145yeccpre_size() ->
2146    yeccpre_size(default_yeccpre()).
2147
2148yeccpre_size(File) ->
2149    n_lines(File).
2150
2151default_yeccpre() ->
2152    filename:join([code:lib_dir(parsetools),"include","yeccpre.hrl"]).
2153
2154n_lines(File) ->
2155    {ok, Bin} = file:read_file(File),
2156    length([C || C=$\n <- binary_to_list(Bin)]).
2157
2158run_test(Config, Def, Pre) ->
2159    %% io:format("testing ~s~n", [binary_to_list(Def)]),
2160    DefFile = 'yecc_test.yrl',
2161    Filename = 'yecc_test.erl',
2162    DataDir = ?privdir,
2163    YrlFile = filename:join(DataDir, DefFile),
2164    ErlFile = filename:join(DataDir, Filename),
2165    Opts = [return, warn_unused_vars,{outdir,DataDir}],
2166    ok = file:write_file(YrlFile, Def),
2167    YOpts = [return, {report, false} |
2168             case Pre of
2169                 default ->
2170                     [];
2171                 _ ->
2172                     [{includefile,Pre}]
2173             end],
2174    P0 = pps(),
2175    YRet = yecc:file(YrlFile, [verbose | YOpts]),
2176    case {pps(), YRet} of
2177        {P0, {ok, _Outfile, _YWs}} ->
2178                 case compile:file(ErlFile, Opts) of
2179                     {ok, _M, _Ws} ->
2180                         AbsFile = filename:rootname(ErlFile, ".erl"),
2181                         Mod = yecc_test,
2182                         code:purge(Mod),
2183                         code:load_abs(AbsFile, Mod),
2184                         Mod:t();
2185                         %% warnings(ErlFile, Ws);
2186                     {error, [{ErlFile,Es}], []} -> {error, Es, []};
2187                     {error, [{ErlFile,Es}], [{ErlFile,Ws}]} -> {error, Es, Ws};
2188                     Error  -> Error
2189                 end;
2190        {P0, {error, [{YrlFile,YEs}], []}} -> {error, YEs, []};
2191        {P0, {error, [{YrlFile,YEs}], [{YrlFile,YWs}]}} -> {error, YEs, YWs};
2192        {P0, YError} -> YError;
2193        {P, _} ->
2194            io:format("failure, got ~p~n, expected ~p\n", [P, P0]),
2195            fail()
2196    end.
2197
2198extract(File, {error, Es, Ws}) ->
2199    {errors, extract(File, Es), extract(File, Ws)};
2200extract(File, Ts) ->
2201    lists:append([T || {F, T} <- Ts,  F =:= File]).
2202
2203pps() ->
2204    {port_list(), process_list()}.
2205
2206port_list() ->
2207    [{P,safe_second_element(erlang:port_info(P, name))} || P <- erlang:ports()].
2208
2209process_list() ->
2210    [{P,process_info(P, registered_name),
2211      safe_second_element(process_info(P, initial_call))} ||
2212        P <- processes(), is_process_alive(P)].
2213
2214safe_second_element({_,Info}) -> Info;
2215safe_second_element(Other) -> Other.
2216
2217fail() ->
2218    ?t:fail().
2219