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