summaryrefslogtreecommitdiff
path: root/lib/parsetools/src/leex.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/parsetools/src/leex.erl')
-rw-r--r--lib/parsetools/src/leex.erl228
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]);