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.erl190
1 files changed, 150 insertions, 40 deletions
diff --git a/lib/parsetools/src/leex.erl b/lib/parsetools/src/leex.erl
index b764678516..c5e61b8149 100644
--- a/lib/parsetools/src/leex.erl
+++ b/lib/parsetools/src/leex.erl
@@ -119,6 +119,8 @@ file(File) -> file(File, []).
| {'verbose', boolean()}
| {'warnings_as_errors', boolean()}
| {'deterministic', boolean()}
+ | {'error_location', line | column}
+ | {'tab_size', pos_integer()}
| 'dfa_graph'
| 'report_errors' | 'report_warnings' | 'report'
| 'return_errors' | 'return_warnings' | 'return'
@@ -281,6 +283,12 @@ check_options([{Option, Boolean} | Options], AllOptions, L)
false ->
badarg
end;
+check_options([{error_location, Loc}=O | Options], AllOptions, L)
+ when Loc =:= line; Loc =:= column ->
+ check_options(Options, AllOptions, [O | L]);
+check_options([{tab_size, S}=O | Options], AllOptions, L)
+ when is_integer(S) andalso S>0 ->
+ check_options(Options, AllOptions, [O | L]);
check_options([], _AllOptions, L) ->
L;
check_options(_Options, _, _L) ->
@@ -289,7 +297,7 @@ check_options(_Options, _, _L) ->
all_options() ->
[dfa_graph,includefile,report_errors,report_warnings,
return_errors,return_warnings,scannerfile,verbose,
- warnings_as_errors, deterministic].
+ warnings_as_errors,deterministic,error_location,tab_size].
default_option(dfa_graph) -> false;
default_option(includefile) -> [];
@@ -300,7 +308,9 @@ default_option(return_warnings) -> false;
default_option(scannerfile) -> [];
default_option(verbose) -> false;
default_option(warnings_as_errors) -> false;
-default_option(deterministic) -> false.
+default_option(deterministic) -> false;
+default_option(error_location) -> line;
+default_option(tab_size) -> 8.
atom_option(dfa_graph) -> {dfa_graph,true};
atom_option(report_errors) -> {report_errors,true};
@@ -596,7 +606,9 @@ parse_rule(S, Line, Atoks, Ms, N, St) ->
TokenChars = var_used('TokenChars', Atoks),
TokenLen = var_used('TokenLen', Atoks),
TokenLine = var_used('TokenLine', Atoks),
- {ok,{R,N},{N,Atoks,TokenChars,TokenLen,TokenLine},St};
+ TokenCol = var_used('TokenCol', Atoks),
+ TokenLoc = var_used('TokenLoc', Atoks),
+ {ok,{R,N},{N,Atoks,TokenChars,TokenLen,TokenLine,TokenCol,TokenLoc},St};
{error,E} ->
add_error({Line,leex,E}, St)
end.
@@ -1415,6 +1427,10 @@ out_file(Ifile, Ofile, St, DFA, DF, Actions, Code, L) ->
case string:slice(Line, 0, 5) of
"##mod" -> out_module(Ofile, St);
"##cod" -> out_erlang_code(Ofile, St, Code, L);
+ "##str" -> out_string(Ofile, St#leex.opts);
+ "##tkn" -> out_token(Ofile, St#leex.opts);
+ "##tks" -> out_tokens(Ofile, St#leex.opts);
+ "##tab" -> out_tab_size(Ofile, St#leex.opts);
"##dfa" -> out_dfa(Ofile, St, DFA, Code, DF, L);
"##act" -> out_actions(Ofile, St#leex.xfile, Deterministic, Actions);
_ -> io:put_chars(Ofile, Line)
@@ -1440,6 +1456,92 @@ out_erlang_code(File, St, Code, L) ->
io:nl(File),
output_file_directive(File, St#leex.ifile, Deterministic, L).
+out_tab_size(File, Opts) ->
+ Size = proplists:get_value(tab_size, Opts),
+ io:fwrite(File, "tab_size() -> ~p.\n", [Size]).
+
+%% Exclude column number if needed
+out_string(File, Opts) ->
+ out_string_1(File, Opts),
+ out_string_2(File, Opts),
+ Vars = lists:join(", ",["Ics","L0","C0","Tcs","Ts"]),
+ out_head(File,string,Vars),
+ EL = proplists:get_value(error_location, Opts),
+ case EL of
+ column ->
+ io:fwrite(File," do_string(~s).\n",[Vars]);
+ line ->
+ io:fwrite(File," case do_string(~s) of\n",[Vars]),
+ io:fwrite(File," {ok, T, {L,_}} -> {ok, T, L};\n",[]),
+ io:fwrite(File," {error, {{EL,_},M,D}, {L,_}} ->\n",[]),
+ io:fwrite(File," EI = {EL,M,D},\n",[]),
+ io:fwrite(File," {error, EI, L}\n",[]),
+ io:fwrite(File," end.\n",[])
+ end.
+
+out_string_1(File, Opts) ->
+ out_head(File,string,"Ics"),
+ EL = proplists:get_value(error_location, Opts),
+ DefLoc = case EL of
+ column -> "{1,1}";
+ line -> "1"
+ end,
+ io:fwrite(File," string(~s).\n",["Ics,"++DefLoc]).
+
+out_string_2(File, Opts) ->
+ EL = proplists:get_value(error_location, Opts),
+ case EL of
+ column ->
+ out_head(File,string,"Ics,{L0,C0}"),
+ CallVars = lists:join(", ", ["Ics","L0","C0","Ics","[]"]),
+ io:fwrite(File," string(~s).\n",[CallVars]);
+ line ->
+ out_head(File,string,"Ics,L0"),
+ CallVars = lists:join(", ", ["Ics","L0","1","Ics","[]"]),
+ io:fwrite(File," string(~s).\n",[CallVars])
+ end.
+
+out_token(File, Opts) ->
+ out_tokens_wrapper(File, Opts, token).
+
+out_tokens(File, Opts) ->
+ out_tokens_wrapper(File, Opts, tokens).
+
+out_tokens_wrapper(File, Opts, Fun) ->
+ out_token_2(File, Opts, Fun),
+ EL = proplists:get_value(error_location, Opts),
+ case EL of
+ column ->
+ VarsCol = lists:join(", ",["Cont","Chars","{Line,Col}"]),
+ out_head(File, Fun, VarsCol),
+ io:fwrite(File," do_~s(~s).\n",[Fun,"Cont,Chars,Line,Col"]);
+ line ->
+ VarsCol = lists:join(", ",["Cont","Chars","Line"]),
+ out_head(File, Fun, VarsCol),
+ io:fwrite(File," case do_~s(~s) of\n",[Fun,"Cont,Chars,Line,1"]),
+ io:fwrite(File," {more, _} = C -> C;\n",[]),
+ io:fwrite(File," {done, Ret0, R} ->\n",[]),
+ io:fwrite(File," Ret1 = case Ret0 of\n",[]),
+ io:fwrite(File," {ok, T, {L,_}} -> {ok, T, L};\n",[]),
+ io:fwrite(File," {eof, {L,_}} -> {eof, L};\n",[]),
+ io:fwrite(File," {error, {{EL,_},M,D},{L,_}} -> {error, {EL,M,D},L}\n",[]),
+ io:fwrite(File," end,\n",[]),
+ io:fwrite(File," {done, Ret1, R}\n",[]),
+ io:fwrite(File," end.\n",[])
+ end.
+
+out_token_2(File, Opts, Fun) ->
+ out_head(File, Fun, "Cont,Chars"),
+ EL = proplists:get_value(error_location, Opts),
+ DefLoc = case EL of
+ column -> "{1,1}";
+ line -> "1"
+ end,
+ io:fwrite(File," ~s(~s).\n",[Fun,"Cont,Chars,"++DefLoc]).
+
+out_head(File, Fun, Vars) ->
+ io:fwrite(File, "~s(~s) -> \n",[Fun,Vars]).
+
file_copy(From, To) ->
case io:get_line(From, leex) of
eof -> ok;
@@ -1455,36 +1557,36 @@ out_dfa(File, St, DFA, Code, DF, L) ->
output_file_directive(File, St#leex.efile, Deterministic, L+(NCodeLines-1)+3),
io:fwrite(File, "yystate() -> ~w.~n~n", [DF]),
foreach(fun (S) -> out_trans(File, S) end, DFA),
- io:fwrite(File, "yystate(S, Ics, Line, Tlen, Action, Alen) ->~n", []),
- io:fwrite(File, " {Action,Alen,Tlen,Ics,Line,S}.~n", []).
+ io:fwrite(File, "yystate(S, Ics, Line, Col, Tlen, Action, Alen) ->~n", []),
+ io:fwrite(File, " {Action,Alen,Tlen,Ics,Line,Col,S}.~n", []).
out_trans(File, #dfa_state{no=N,trans=[],accept={accept,A}}) ->
%% Accepting end state, guaranteed done.
- io:fwrite(File, "yystate(~w, Ics, Line, Tlen, _, _) ->~n", [N]),
- io:fwrite(File, " {~w,Tlen,Ics,Line};~n", [A]);
+ io:fwrite(File, "yystate(~w, Ics, Line, Col, Tlen, _, _) ->~n", [N]),
+ io:fwrite(File, " {~w,Tlen,Ics,Line,Col};~n", [A]);
out_trans(File, #dfa_state{no=N,trans=Tr,accept={accept,A}}) ->
%% Accepting state, but there maybe more.
foreach(fun (T) -> out_accept_tran(File, N, A, T) end, pack_trans(Tr)),
- io:fwrite(File, "yystate(~w, Ics, Line, Tlen, _, _) ->~n", [N]),
- io:fwrite(File, " {~w,Tlen,Ics,Line,~w};~n", [A,N]);
+ io:fwrite(File, "yystate(~w, Ics, Line, Col, Tlen, _, _) ->~n", [N]),
+ io:fwrite(File, " {~w,Tlen,Ics,Line,Col,~w};~n", [A,N]);
out_trans(File, #dfa_state{no=N,trans=Tr,accept=noaccept}) ->
%% Non-accepting transition state.
foreach(fun (T) -> out_noaccept_tran(File, N, T) end, pack_trans(Tr)),
- io:fwrite(File, "yystate(~w, Ics, Line, Tlen, Action, Alen) ->~n", [N]),
- io:fwrite(File, " {Action,Alen,Tlen,Ics,Line,~w};~n", [N]).
+ io:fwrite(File, "yystate(~w, Ics, Line, Col, Tlen, Action, Alen) ->~n", [N]),
+ io:fwrite(File, " {Action,Alen,Tlen,Ics,Line,Col,~w};~n", [N]).
out_accept_tran(File, N, A, {{Cf,maxchar},S}) ->
out_accept_head_max(File, N, Cf),
- out_accept_body(File, S, "Line", A);
+ out_accept_body(File, S, "Line", "Col", A);
out_accept_tran(File, N, A, {{Cf,Cl},S}) ->
out_accept_head_range(File, N, Cf, Cl),
- out_accept_body(File, S, "Line", A);
+ out_accept_body(File, S, "Line", "Col", A);
out_accept_tran(File, N, A, {$\n,S}) ->
out_accept_head_1(File, N, $\n),
- out_accept_body(File, S, "Line+1", A);
+ out_accept_body(File, S, "Line+1", "1", A);
out_accept_tran(File, N, A, {C,S}) ->
out_accept_head_1(File, N, C),
- out_accept_body(File, S, "Line", A).
+ out_accept_body(File, S, "Line", "Col", A).
out_accept_head_1(File, State, Char) ->
out_head_1(File, State, Char, "_", "_").
@@ -1495,21 +1597,21 @@ out_accept_head_max(File, State, Min) ->
out_accept_head_range(File, State, Min, Max) ->
out_head_range(File, State, Min, Max, "_", "_").
-out_accept_body(File, Next, Line, Action) ->
- out_body(File, Next, Line, io_lib:write(Action), "Tlen").
+out_accept_body(File, Next, Line, Col, Action) ->
+ out_body(File, Next, Line, Col, io_lib:write(Action), "Tlen").
out_noaccept_tran(File, N, {{Cf,maxchar},S}) ->
out_noaccept_head_max(File, N, Cf),
- out_noaccept_body(File, S, "Line");
+ out_noaccept_body(File, S, "Line", "Col");
out_noaccept_tran(File, N, {{Cf,Cl},S}) ->
out_noaccept_head_range(File, N, Cf, Cl),
- out_noaccept_body(File, S, "Line");
+ out_noaccept_body(File, S, "Line", "Col");
out_noaccept_tran(File, N, {$\n,S}) ->
out_noaccept_head_1(File, N, $\n),
- out_noaccept_body(File, S, "Line+1");
+ out_noaccept_body(File, S, "Line+1", "1");
out_noaccept_tran(File, N, {C,S}) ->
out_noaccept_head_1(File, N, C),
- out_noaccept_body(File, S, "Line").
+ out_noaccept_body(File, S, "Line", "Col").
out_noaccept_head_1(File, State, Char) ->
out_head_1(File, State, Char, "Action", "Alen").
@@ -1520,24 +1622,27 @@ out_noaccept_head_max(File, State, Min) ->
out_noaccept_head_range(File, State, Min, Max) ->
out_head_range(File, State, Min, Max, "Action", "Alen").
-out_noaccept_body(File, Next, Line) ->
- out_body(File, Next, Line, "Action", "Alen").
+out_noaccept_body(File, Next, Line, Col) ->
+ out_body(File, Next, Line, Col, "Action", "Alen").
+out_head_1(File, State, Char = $\n, Action, Alen) ->
+ io:fwrite(File, "yystate(~w, [~w|Ics], Line, _, Tlen, ~s, ~s) ->\n",
+ [State,Char,Action,Alen]);
out_head_1(File, State, Char, Action, Alen) ->
- io:fwrite(File, "yystate(~w, [~w|Ics], Line, Tlen, ~s, ~s) ->\n",
+ io:fwrite(File, "yystate(~w, [~w|Ics], Line, Col, Tlen, ~s, ~s) ->\n",
[State,Char,Action,Alen]).
out_head_max(File, State, Min, Action, Alen) ->
- io:fwrite(File, "yystate(~w, [C|Ics], Line, Tlen, ~s, ~s) when C >= ~w ->\n",
+ io:fwrite(File, "yystate(~w, [C|Ics], Line, Col, Tlen, ~s, ~s) when C >= ~w ->\n",
[State,Action,Alen,Min]).
out_head_range(File, State, Min, Max, Action, Alen) ->
- io:fwrite(File, "yystate(~w, [C|Ics], Line, Tlen, ~s, ~s) when C >= ~w, C =< ~w ->\n",
+ io:fwrite(File, "yystate(~w, [C|Ics], Line, Col, Tlen, ~s, ~s) when C >= ~w, C =< ~w ->\n",
[State,Action,Alen,Min,Max]).
-out_body(File, Next, Line, Action, Alen) ->
- io:fwrite(File, " yystate(~w, Ics, ~s, Tlen+1, ~s, ~s);\n",
- [Next,Line,Action,Alen]).
+out_body(File, Next, Line, Col, Action, Alen) ->
+ io:fwrite(File, " yystate(~w, Ics, ~s, ~s, Tlen+1, ~s, ~s);\n",
+ [Next,Line,Col,Action,Alen]).
%% pack_trans([{Crange,State}]) -> [{Crange,State}] when
%% Crange = {Char,Char} | Char.
@@ -1581,31 +1686,32 @@ pack_trans([], Pt) -> Pt.
out_actions(File, XrlFile, Deterministic, As) ->
As1 = prep_out_actions(As),
foreach(fun (A) -> out_action(File, A) end, As1),
- io:fwrite(File, "yyaction(_, _, _, _) -> error.~n", []),
+ io:fwrite(File, "yyaction(_, _, _, _, _) -> error.~n", []),
foreach(fun (A) -> out_action_code(File, XrlFile, Deterministic, A) end, As1).
prep_out_actions(As) ->
map(fun ({A,empty_action}) ->
{A,empty_action};
- ({A,Code,TokenChars,TokenLen,TokenLine}) ->
+ ({A,Code,TokenChars,TokenLen,TokenLine,TokenCol,TokenLoc}) ->
Vs = [{TokenChars,"TokenChars"},
{TokenLen,"TokenLen"},
- {TokenLine,"TokenLine"},
+ {TokenLine or TokenLoc,"TokenLine"},
+ {TokenCol or TokenLoc,"TokenCol"},
{TokenChars,"YYtcs"},
{TokenLen or TokenChars,"TokenLen"}],
Vars = [if F -> S; true -> "_" end || {F,S} <- Vs],
Name = list_to_atom(lists:concat([yyaction_,A])),
- [Chars,Len,Line,_,_] = Vars,
- Args = [V || V <- [Chars,Len,Line], V =/= "_"],
+ [Chars,Len,Line,Col,_,_] = Vars,
+ Args = [V || V <- [Chars,Len,Line,Col], V =/= "_"],
ArgsChars = lists:join(", ", Args),
- {A,Code,Vars,Name,Args,ArgsChars}
+ {A,Code,Vars,Name,Args,ArgsChars, TokenLoc}
end, As).
out_action(File, {A,empty_action}) ->
- io:fwrite(File, "yyaction(~w, _, _, _) -> skip_token;~n", [A]);
-out_action(File, {A,_Code,Vars,Name,_Args,ArgsChars}) ->
- [_,_,Line,Tcs,Len] = Vars,
- io:fwrite(File, "yyaction(~w, ~s, ~s, ~s) ->~n", [A,Len,Tcs,Line]),
+ io:fwrite(File, "yyaction(~w, _, _, _, _) -> skip_token;~n", [A]);
+out_action(File, {A,_Code,Vars,Name,_Args,ArgsChars,_TokenLoc}) ->
+ [_,_,Line,Col,Tcs,Len] = Vars,
+ io:fwrite(File, "yyaction(~w, ~s, ~s, ~s, ~s) ->~n", [A,Len,Tcs,Line,Col]),
if
Tcs =/= "_" ->
io:fwrite(File, " TokenChars = yypre(YYtcs, TokenLen),~n", []);
@@ -1615,13 +1721,17 @@ out_action(File, {A,_Code,Vars,Name,_Args,ArgsChars}) ->
out_action_code(_File, _XrlFile, _Deterministic, {_A,empty_action}) ->
ok;
-out_action_code(File, XrlFile, Deterministic, {_A,Code,_Vars,Name,Args,ArgsChars}) ->
+out_action_code(File, XrlFile, Deterministic, {_A,Code,_Vars,Name,Args,ArgsChars, TokenLoc}) ->
%% Should set the file to the .erl file, but instead assumes that
%% ?LEEXINC is syntactically correct.
io:fwrite(File, "\n-compile({inline,~w/~w}).\n", [Name, length(Args)]),
L = erl_scan:line(hd(Code)),
output_file_directive(File, XrlFile, Deterministic, L-2),
io:fwrite(File, "~s(~s) ->~n", [Name, ArgsChars]),
+ if
+ TokenLoc -> io:fwrite(File," TokenLoc={TokenLine,TokenCol},~n",[]);
+ true -> ok
+ end,
io:fwrite(File, " ~ts\n", [pp_tokens(Code, L, File)]).
%% pp_tokens(Tokens, Line, File) -> [char()].