diff options
Diffstat (limited to 'lib/parsetools/src/leex.erl')
-rw-r--r-- | lib/parsetools/src/leex.erl | 228 |
1 files changed, 132 insertions, 96 deletions
diff --git a/lib/parsetools/src/leex.erl b/lib/parsetools/src/leex.erl index fd494eaf06..cdf20461d9 100644 --- a/lib/parsetools/src/leex.erl +++ b/lib/parsetools/src/leex.erl @@ -35,7 +35,7 @@ -export([compile/3,file/1,file/2,format_error/1]). -import(lists, [member/2,reverse/1,sort/1,delete/2, - keysearch/3,keysort/2,keydelete/3,keyfind/3, + keysort/2,keydelete/3, map/2,foldl/3,foreach/2,flatmap/2]). -import(string, [substr/2,substr/3,span/2]). -import(ordsets, [is_element/2,add_element/2,union/2]). @@ -58,7 +58,7 @@ gfile=[], % Graph file module, % Module name opts=[], % Options - posix=false, % POSIX regular expressions + % posix=false, % POSIX regular expressions errors=[], warnings=[] }). @@ -73,12 +73,15 @@ %%% Interface to erl_compile. compile(Input0, Output0, - #options{warning = WarnLevel, verbose=Verbose, includes=Includes}) -> + #options{warning = WarnLevel, verbose=Verbose, includes=Includes, + specific=Specific}) -> Input = assure_extension(shorten_filename(Input0), ".xrl"), Output = assure_extension(shorten_filename(Output0), ".erl"), Includefile = lists:sublist(Includes, 1), + Werror = proplists:get_bool(warnings_as_errors, Specific), Opts = [{scannerfile,Output},{includefile,Includefile},{verbose,Verbose}, - {report_errors,true},{report_warnings,WarnLevel > 0}], + {report_errors,true},{report_warnings,WarnLevel > 0}, + {warnings_as_errors, Werror}], case file(Input, Opts) of {ok, _} -> ok; @@ -107,10 +110,15 @@ file(File, Opts0) -> St = try {ok,REAs,Actions,Code,St2} = parse_file(St1), {DFA,DF} = make_dfa(REAs, St2), - St3 = out_file(St2, DFA, DF, Actions, Code), - case lists:member(dfa_graph, St3#leex.opts) of - true -> out_dfa_graph(St3, DFA, DF); - false -> St3 + case werror(St2) of + false -> + St3 = out_file(St2, DFA, DF, Actions, Code), + case lists:member(dfa_graph, St3#leex.opts) of + true -> out_dfa_graph(St3, DFA, DF); + false -> St3 + end; + true -> + St2 end catch #leex{}=St4 -> St4 @@ -131,8 +139,8 @@ format_error({regexp,E})-> "unterminated " ++ Cs; {illegal_char,Cs} -> "illegal character " ++ Cs; - {posix_cc,What} -> - ["illegal POSIX character class ",io_lib:write_string(What)]; +%% {posix_cc,What} -> +%% ["illegal POSIX character class ",io_lib:write_string(What)]; {char_class,What} -> ["illegal character class ",io_lib:write_string(What)] end, @@ -163,7 +171,8 @@ options(Options0) when is_list(Options0) -> (T) -> [T] end, Options0), options(Options, [scannerfile,includefile,report_errors, - report_warnings,return_errors,return_warnings, + report_warnings,warnings_as_errors, + return_errors,return_warnings, verbose,dfa_graph], []) catch error: _ -> badarg end; @@ -182,18 +191,18 @@ options(Options0, [Key|Keys], L) when is_list(Options0) -> false -> Options0 end, - V = case keysearch(Key, 1, Options) of - {value, {Key, Filename0}} when Key =:= includefile; - Key =:= scannerfile -> + V = case lists:keyfind(Key, 1, Options) of + {Key, Filename0} when Key =:= includefile; + Key =:= scannerfile -> case is_filename(Filename0) of no -> badarg; Filename -> {ok,[{Key,Filename}]} end; - {value,{Key,Bool}} when Bool; not Bool -> - {ok,[{Key, Bool}]}; - {value,{Key, _}} -> + {Key, Bool} = KB when is_boolean(Bool) -> + {ok, [KB]}; + {Key, _} -> badarg; false -> {ok,[{Key,default_option(Key)}]} @@ -217,6 +226,7 @@ default_option(dfa_graph) -> false; default_option(includefile) -> []; default_option(report_errors) -> true; default_option(report_warnings) -> true; +default_option(warnings_as_errors) -> false; default_option(return_errors) -> false; default_option(return_warnings) -> false; default_option(scannerfile) -> []; @@ -225,14 +235,14 @@ default_option(verbose) -> false. atom_option(dfa_graph) -> {dfa_graph,true}; atom_option(report_errors) -> {report_errors,true}; atom_option(report_warnings) -> {report_warnings,true}; +atom_option(warnings_as_errors) -> {warnings_as_errors,true}; atom_option(return_errors) -> {return_errors,true}; atom_option(return_warnings) -> {return_warnings,true}; atom_option(verbose) -> {verbose,true}; atom_option(Key) -> Key. is_filename(T) -> - try filename:flatten(T) of - Filename -> Filename + try filename:flatten(T) catch error: _ -> no end. @@ -252,19 +262,29 @@ leex_ret(St) -> report_warnings(St), Es = pack_errors(St#leex.errors), Ws = pack_warnings(St#leex.warnings), + Werror = werror(St), if + Werror -> + do_error_return(St, Es, Ws); Es =:= [] -> case member(return_warnings, St#leex.opts) of true -> {ok, St#leex.efile, Ws}; false -> {ok, St#leex.efile} end; - true -> - case member(return_errors, St#leex.opts) of - true -> {error, Es, Ws}; - false -> error - end + true -> + do_error_return(St, Es, Ws) + end. + +do_error_return(St, Es, Ws) -> + case member(return_errors, St#leex.opts) of + true -> {error, Es, Ws}; + false -> error end. +werror(St) -> + St#leex.warnings =/= [] + andalso member(warnings_as_errors, St#leex.opts). + pack_errors([{File,_} | _] = Es) -> [{File, flatmap(fun({_,E}) -> [E] end, sort(Es))}]; pack_errors([]) -> @@ -287,16 +307,26 @@ report_errors(St) -> end, report_errors, St#leex.opts). report_warnings(St) -> - when_opt(fun () -> - foreach(fun({File,{none,Mod,W}}) -> - io:fwrite("~s: Warning: ~s\n", - [File,Mod:format_error(W)]); - ({File,{Line,Mod,W}}) -> - io:fwrite("~s:~w: Warning: ~s\n", - [File,Line,Mod:format_error(W)]) - end, sort(St#leex.warnings)) - end, report_warnings, St#leex.opts). - + Werror = member(warnings_as_errors, St#leex.opts), + Prefix = case Werror of + true -> ""; + false -> "Warning: " + end, + ReportWerror = Werror andalso member(report_errors, St#leex.opts), + ShouldReport = member(report_warnings, St#leex.opts) orelse ReportWerror, + when_bool(fun () -> + foreach(fun({File,{none,Mod,W}}) -> + io:fwrite("~s: ~s~s\n", + [File,Prefix, + Mod:format_error(W)]); + ({File,{Line,Mod,W}}) -> + io:fwrite("~s:~w: ~s~s\n", + [File,Line,Prefix, + Mod:format_error(W)]) + end, sort(St#leex.warnings)) + end, ShouldReport). + +-spec add_error(_, #leex{}) -> no_return(). add_error(E, St) -> add_error(St#leex.xfile, E, St). @@ -320,10 +350,10 @@ filenames(File, Opts, St0) -> St1 = St0#leex{xfile=Xfile, opts=Opts, module=Module}, - {value,{includefile,Ifile0}} = keysearch(includefile, 1, Opts), + {includefile,Ifile0} = lists:keyfind(includefile, 1, Opts), Ifile = inc_file_name(Ifile0), %% Test for explicit scanner file. - {value,{scannerfile,Ofile}} = keysearch(scannerfile, 1, Opts), + {scannerfile,Ofile} = lists:keyfind(scannerfile, 1, Opts), if Ofile =:= [] -> St1#leex{efile=filename:join(Dir, Efile), @@ -342,6 +372,12 @@ when_opt(Do, Opt, Opts) -> false -> ok end. +when_bool(Do, Bool) -> + case Bool of + true -> Do(); + false -> ok + end. + verbose_print(St, Format, Args) -> when_opt(fun () -> io:fwrite(Format, Args) end, verbose, St#leex.opts). @@ -495,7 +531,7 @@ parse_rule(S, Line, Atoks, Ms, N, St) -> end. var_used(Name, Toks) -> - case keyfind(Name, 3, Toks) of + case lists:keyfind(Name, 3, Toks) of {var,_,Name} -> true; %It's the var we want _ -> false end. @@ -629,7 +665,7 @@ re_seq(Cs0, Sn0, St) -> {Rs,Sn1,Cs1} -> {{seq,Rs},Sn1,Cs1} end. -re_seq1([C|_]=Cs0, Sn0, St) when C /= $|, C /= $) -> +re_seq1([C|_]=Cs0, Sn0, St) when C =/= $|, C =/= $) -> {L,Sn1,Cs1} = re_repeat(Cs0, Sn0, St), {Rs,Sn2,Cs2} = re_seq1(Cs1, Sn1, St), {[L|Rs],Sn2,Cs2}; @@ -645,14 +681,14 @@ re_repeat1([$*|Cs], Sn, S, St) -> re_repeat1(Cs, Sn, {kclosure,S}, St); re_repeat1([$+|Cs], Sn, S, St) -> re_repeat1(Cs, Sn, {pclosure,S}, St); re_repeat1([$?|Cs], Sn, S, St) -> re_repeat1(Cs, Sn, {optional,S}, St); %% { only starts interval when ere is true, otherwise normal character. -re_repeat1([${|Cs0], Sn, S, #leex{posix=true}=St) -> % $} - case re_interval_range(Cs0) of - {Min,Max,[$}|Cs1]} when is_integer(Min), is_integer(Max), Min =< Max -> - re_repeat1(Cs1, Sn, {interval,S,Min,Max}, St); - {Min,Max,[$}|Cs1]} when is_integer(Min), is_atom(Max) -> - re_repeat1(Cs1, Sn, {interval,S,Min,Max}, St); - {_,_,Cs1} -> parse_error({interval_range,string_between([${|Cs0], Cs1)}) - end; +%% re_repeat1([${|Cs0], Sn, S, #leex{posix=true}=St) -> % $} +%% case re_interval_range(Cs0) of +%% {Min,Max,[$}|Cs1]} when is_integer(Min), is_integer(Max), Min =< Max -> +%% re_repeat1(Cs1, Sn, {interval,S,Min,Max}, St); +%% {Min,Max,[$}|Cs1]} when is_integer(Min), is_atom(Max) -> +%% re_repeat1(Cs1, Sn, {interval,S,Min,Max}, St); +%% {_,_,Cs1} -> parse_error({interval_range,string_between([${|Cs0], Cs1)}) +%% end; re_repeat1(Cs, Sn, S, _) -> {S,Sn,Cs}. %% re_single(Chars, SubNumber, State) -> {RegExp,SubNumber,Chars}. @@ -734,7 +770,7 @@ special_char($|, _) -> true; special_char($*, _) -> true; special_char($+, _) -> true; special_char($?, _) -> true; -special_char(${, #leex{posix=true}) -> true; % Only when POSIX set +%% special_char(${, #leex{posix=true}) -> true; % Only when POSIX set special_char($\\, _) -> true; special_char(_, _) -> false. @@ -745,15 +781,15 @@ re_char_class([$]|Cs], St) -> % Must special case this. re_char_class(Cs, [$]], St); re_char_class(Cs, St) -> re_char_class(Cs, [], St). -re_char_class("[:" ++ Cs0, Cc, #leex{posix=true}=St) -> - %% POSIX char class only. - case posix_cc(Cs0) of - {Pcl,":]" ++ Cs1} -> re_char_class(Cs1, [{posix,Pcl}|Cc], St); - {_,Cs1} -> parse_error({posix_cc,string_between(Cs0, Cs1)}) - end; -re_char_class([C1|Cs0], Cc, St) when C1 /= $] -> +%% re_char_class("[:" ++ Cs0, Cc, #leex{posix=true}=St) -> +%% %% POSIX char class only. +%% case posix_cc(Cs0) of +%% {Pcl,":]" ++ Cs1} -> re_char_class(Cs1, [{posix,Pcl}|Cc], St); +%% {_,Cs1} -> parse_error({posix_cc,string_between(Cs0, Cs1)}) +%% end; +re_char_class([C1|Cs0], Cc, St) when C1 =/= $] -> case re_char(C1, Cs0) of - {Cf,[$-,C2|Cs1]} when C2 /= $] -> + {Cf,[$-,C2|Cs1]} when C2 =/= $] -> case re_char(C2, Cs1) of {Cl,Cs2} when Cf < Cl -> re_char_class(Cs2, [{range,Cf,Cl}|Cc], St); @@ -767,19 +803,19 @@ re_char_class(Cs, Cc, _) -> {reverse(Cc),Cs}. % Preserve order %% posix_cc(String) -> {PosixClass,RestString}. %% Handle POSIX character classes. -posix_cc("alnum" ++ Cs) -> {alnum,Cs}; -posix_cc("alpha" ++ Cs) -> {alpha,Cs}; -posix_cc("blank" ++ Cs) -> {blank,Cs}; -posix_cc("cntrl" ++ Cs) -> {cntrl,Cs}; -posix_cc("digit" ++ Cs) -> {digit,Cs}; -posix_cc("graph" ++ Cs) -> {graph,Cs}; -posix_cc("lower" ++ Cs) -> {lower,Cs}; -posix_cc("print" ++ Cs) -> {print,Cs}; -posix_cc("punct" ++ Cs) -> {punct,Cs}; -posix_cc("space" ++ Cs) -> {space,Cs}; -posix_cc("upper" ++ Cs) -> {upper,Cs}; -posix_cc("xdigit" ++ Cs) -> {xdigit,Cs}; -posix_cc(Cs) -> parse_error({posix_cc,substr(Cs, 1, 5)}). +%% posix_cc("alnum" ++ Cs) -> {alnum,Cs}; +%% posix_cc("alpha" ++ Cs) -> {alpha,Cs}; +%% posix_cc("blank" ++ Cs) -> {blank,Cs}; +%% posix_cc("cntrl" ++ Cs) -> {cntrl,Cs}; +%% posix_cc("digit" ++ Cs) -> {digit,Cs}; +%% posix_cc("graph" ++ Cs) -> {graph,Cs}; +%% posix_cc("lower" ++ Cs) -> {lower,Cs}; +%% posix_cc("print" ++ Cs) -> {print,Cs}; +%% posix_cc("punct" ++ Cs) -> {punct,Cs}; +%% posix_cc("space" ++ Cs) -> {space,Cs}; +%% posix_cc("upper" ++ Cs) -> {upper,Cs}; +%% posix_cc("xdigit" ++ Cs) -> {xdigit,Cs}; +%% posix_cc(Cs) -> parse_error({posix_cc,substr(Cs, 1, 5)}). escape_char($n) -> $\n; % \n = LF escape_char($r) -> $\r; % \r = CR @@ -798,24 +834,24 @@ escape_char(C) -> C. % Pass it straight through %% Int, -> Int,any %% Int1,Int2 -> Int1,Int2 -re_interval_range(Cs0) -> - case re_number(Cs0) of - {none,Cs1} -> {none,none,Cs1}; - {N,[$,|Cs1]} -> - case re_number(Cs1) of - {none,Cs2} -> {N,any,Cs2}; - {M,Cs2} -> {N,M,Cs2} - end; - {N,Cs1} -> {N,none,Cs1} - end. +%% re_interval_range(Cs0) -> +%% case re_number(Cs0) of +%% {none,Cs1} -> {none,none,Cs1}; +%% {N,[$,|Cs1]} -> +%% case re_number(Cs1) of +%% {none,Cs2} -> {N,any,Cs2}; +%% {M,Cs2} -> {N,M,Cs2} +%% end; +%% {N,Cs1} -> {N,none,Cs1} +%% end. -re_number([C|Cs]) when C >= $0, C =< $9 -> - re_number(Cs, C - $0); -re_number(Cs) -> {none,Cs}. +%% re_number([C|Cs]) when C >= $0, C =< $9 -> +%% re_number(Cs, C - $0); +%% re_number(Cs) -> {none,Cs}. -re_number([C|Cs], Acc) when C >= $0, C =< $9 -> - re_number(Cs, 10*Acc + (C - $0)); -re_number(Cs, Acc) -> {Acc,Cs}. +%% re_number([C|Cs], Acc) when C >= $0, C =< $9 -> +%% re_number(Cs, 10*Acc + (C - $0)); +%% re_number(Cs, Acc) -> {Acc,Cs}. string_between(Cs1, Cs2) -> substr(Cs1, 1, length(Cs1)-length(Cs2)). @@ -998,7 +1034,7 @@ pack_crs([{C1,C2},{C3,C4}|Crs]) when C2 >= C3, C2 < C4 -> %% C1 C2 %% C3 C4 pack_crs([{C1,C4}|Crs]); -pack_crs([{C1,C2},{C3,C4}|Crs]) when C2 + 1 == C3 -> +pack_crs([{C1,C2},{C3,C4}|Crs]) when C2 + 1 =:= C3 -> %% C1 C2 %% C3 C4 pack_crs([{C1,C4}|Crs]); @@ -1055,7 +1091,7 @@ build_dfa(Set, Us, N, Ts, Ms, NFA) -> %% List of all transition sets. Crs0 = [Cr || S <- Set, {Crs,_St} <- (element(S, NFA))#nfa_state.edges, - Crs /= epsilon, % Not an epsilon transition + Crs =/= epsilon, % Not an epsilon transition Cr <- Crs ], Crs1 = lists:usort(Crs0), % Must remove duplicates! %% Build list of disjoint test ranges. @@ -1072,7 +1108,7 @@ disjoint_crs([{_C1,C2}=Cr1,{C3,_C4}=Cr2|Crs]) when C2 < C3 -> %% C1 C2 %% C3 C4 [Cr1|disjoint_crs([Cr2|Crs])]; -disjoint_crs([{C1,C2},{C3,C4}|Crs]) when C1 == C3 -> +disjoint_crs([{C1,C2},{C3,C4}|Crs]) when C1 =:= C3 -> %% C1 C2 %% C3 C4 [{C1,C2}|disjoint_crs(add_element({C2+1,C4}, Crs))]; @@ -1080,7 +1116,7 @@ disjoint_crs([{C1,C2},{C3,C4}|Crs]) when C1 < C3, C2 >= C3, C2 < C4 -> %% C1 C2 %% C3 C4 [{C1,C3-1}|disjoint_crs(union([{C3,C2},{C2+1,C4}], Crs))]; -disjoint_crs([{C1,C2},{C3,C4}|Crs]) when C1 < C3, C2 == C4 -> +disjoint_crs([{C1,C2},{C3,C4}|Crs]) when C1 < C3, C2 =:= C4 -> %% C1 C2 %% C3 C4 [{C1,C3-1}|disjoint_crs(add_element({C3,C4}, Crs))]; @@ -1093,7 +1129,7 @@ disjoint_crs([]) -> []. build_dfa([Cr|Crs], Set, Us, N, Ts, Ms, NFA) -> case eclosure(move(Set, Cr, NFA), NFA) of - S when S /= [] -> + S when S =/= [] -> case dfa_state_exist(S, Us, Ms) of {yes,T} -> build_dfa(Crs, Set, Us, N, store(Cr, T, Ts), Ms, NFA); @@ -1110,11 +1146,11 @@ build_dfa([], _, Us, N, Ts, _, _) -> %% dfa_state_exist(Set, Unmarked, Marked) -> {yes,State} | no. dfa_state_exist(S, Us, Ms) -> - case keysearch(S, #dfa_state.nfa, Us) of - {value,#dfa_state{no=T}} -> {yes,T}; + case lists:keyfind(S, #dfa_state.nfa, Us) of + #dfa_state{no=T} -> {yes,T}; false -> - case keysearch(S, #dfa_state.nfa, Ms) of - {value,#dfa_state{no=T}} -> {yes,T}; + case lists:keyfind(S, #dfa_state.nfa, Ms) of + #dfa_state{no=T} -> {yes,T}; false -> no end end. @@ -1129,7 +1165,7 @@ eclosure(Sts, NFA) -> eclosure(Sts, NFA, []). eclosure([St|Sts], NFA, Ec) -> #nfa_state{edges=Es} = element(St, NFA), eclosure([ N || {epsilon,N} <- Es, - not is_element(N, Ec) ] ++ Sts, + not is_element(N, Ec) ] ++ Sts, NFA, add_element(St, Ec)); eclosure([], _, Ec) -> Ec. @@ -1137,7 +1173,7 @@ move(Sts, Cr, NFA) -> %% io:fwrite("move1: ~p\n", [{Sts,Cr}]), [ St || N <- Sts, {Crs,St} <- (element(N, NFA))#nfa_state.edges, - Crs /= epsilon, % Not an epsilon transition + Crs =/= epsilon, % Not an epsilon transition in_crs(Cr, Crs) ]. in_crs({C1,C2}, [{C3,C4}|_Crs]) when C1 >= C3, C2 =< C4 -> true; @@ -1436,7 +1472,7 @@ pack_trans([{{$\n,Cl},S}|Trs], Pt) -> pack_trans([{{Cf,Cl},S}|Trs], Pt) when Cf < $\n, Cl > $\n -> pack_trans([{{Cf,$\n-1},S},{{$\n+1,Cl},S}|Trs], [{$\n,S}|Pt]); %% Small ranges become singletons. -pack_trans([{{Cf,Cl},S}|Trs], Pt) when Cl == Cf + 1 -> +pack_trans([{{Cf,Cl},S}|Trs], Pt) when Cl =:= Cf + 1 -> pack_trans(Trs, [{Cf,S},{Cl,S}|Pt]); pack_trans([Tr|Trs], Pt) -> % The default uninteresting case pack_trans(Trs, Pt ++ [Tr]); |