%%% BEGIN pibfi_options.erl %%%
%%%
%%% pibfi - Platonic Ideal Brainf*ck Interpreter
%%% Copyright (c)2003 Cat's Eye Technologies. All rights reserved.
%%%
%%% Redistribution and use in source and binary forms, with or without
%%% modification, are permitted provided that the following conditions
%%% are met:
%%%
%%% Redistributions of source code must retain the above copyright
%%% notice, this list of conditions and the following disclaimer.
%%%
%%% Redistributions in binary form must reproduce the above copyright
%%% notice, this list of conditions and the following disclaimer in
%%% the documentation and/or other materials provided with the
%%% distribution.
%%%
%%% Neither the name of Cat's Eye Technologies nor the names of its
%%% contributors may be used to endorse or promote products derived
%%% from this software without specific prior written permission.
%%%
%%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
%%% CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
%%% INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
%%% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
%%% DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
%%% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
%%% OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
%%% PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
%%% OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
%%% ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
%%% OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
%%% OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
%%% POSSIBILITY OF SUCH DAMAGE.
%% @doc Options parser for pibfi.
%%
%%
This module implements collecting options %% from the command line.
%% %%When invoking pibfi from the command line, the
%% following syntax can be used:
erl -noshell options -run pibfi run filenameThe following options are recognized.
%% %%-dontstrip s, where s is a string of
%% characters, default null (empty), specifies the set of characters
%% (beyond the 8 basic Brainf*ck instructions)
%% which
%% will not be stripped from the parsed source prior to optimization.
%% Note that if this option if given without an argument, it is assumed
%% to be the set of all applicable characters - in other words, nothing
%% at all will be stripped.-optimize n, where n is an integer,
%% default 1, sets the optimization level of the parser.
%% At optimization level 0, no optimization occurs.
%% At optimization level 1, run-length encoding is performed on the
%% instructions. Further optimization levels may be defined in the
%% future. Note that if this option if given without an argument,
%% it is assumed to be asking for the most thorough yet quickly
%% available optimization.-statuscmd c, where c may be
%% any single-character string of the term undefined,
%% default "#" (octalthorpe), specifies
%% which symbol, when encountered, is treated
%% as a debugging instruction which displays a status report.-heredoc c, where c may be
%% a single-character string or the term undefined,
%% default undefined, specifies which symbol when encountered,
%% is treated as the marker that signifies that input is embedded in
%% the program source code following it. This input will be stripped
%% from the source (even if it contains valid Brainf*ck instructions)
%% and will be made available to -infile heredoc (see
%% below.) Note that if this option is given with no argument,
%% "!" (exclamation point) is assumed.-tapemodule m, where n is the name of
%% an Erlang module conforming to the pibfi_tape behaviour,
%% defaulting to whatever pibfi determines would be optimal
%% for the given sourcecode, (currently always pibfi_tape_ets),
%% names the module which implements the backing for the simulated tape.-maxcell n, where n is any integer or the
%% term infinity, default infinity, sets the
%% highest value that can be placed into a cell on the tape.-mincell n, where n is any integer or the
%% term infinity, default 0, sets the
%% lowest value that can be placed into a cell on the tape.
%% (Note that infinity actually represents negative infinity
%% here.)-wrapcell b, where b is a boolean
%% (true or false), default false,
%% determines what happens when either limit of any cell in the tape is
%% exceeded. When -wrapcell is true, the limits
%% will be taken as modulus boundaries, and the value will 'wrap around'
%% to the opposite limit. When -wrapcell is false,
%% an exception will be generated. Note that if b is omitted
%% after -wrapcell, true is assumed.
%% Also note that -wrapcell true is not compatible with
%% either -maxcell infinity or -mincell infinity
%% (for what should be obvious reasons.)-maxtape n, where n is any integer or the
%% term infinity, default infinity, sets the
%% rightmost position to which the tape head can move. Note that the initial
%% position of the tape head is considered position 0.-mintape n, where n is any integer or the
%% term infinity, default 0, sets the
%% leftmost position to which the tape head can move.
%% (Note that infinity actually represents negative infinity
%% here.)-wraptape b, where b is a boolean,
%% default false, determines what happens when either limit
%% of the tape head is exceeded. With -wraptape true,
%% the limits will be taken as modulus boundaries,
%% and the position of the tape head will 'wrap around' to the
%% opposite limit. With -wraptape false,
%% an exception will be generated when this happens.
%% Note that if b is omitted
%% after -wraptape, true is assumed. Also note
%% that -wraptape true is not compatible with either
%% -maxtape infinity or -mintape infinity.-infile s, where s is a filename or
%% one of the terms tty or heredoc,
%% default tty, sets the
%% source of the input to the Brainf*ck program.
%% tty indicates an interactive terminal session with
%% "standard input".
%% heredoc indicates input will come from the
%% "here-doc" portion of the program source code (note that the
%% -heredoc option must also be given to parse the
%% source code.)
%% Using this option is preferred
%% over redirecting standard I/O with the shell, as it is a hint to the
%% interpreter that the program is not being run interactively.-outfile s, where s is a filename or
%% the term tty, default tty, sets the
%% destination of the output of the Brainf*ck program. This is preferred
%% to redirecting standard I/O with the shell, as it is a hint to the
%% interpreter that the program is not being run interactively.-maxout n, where n is any integer or the
%% term infinity, default infinity, sets the
%% maximum character value which can be output.-minout n, where n is any integer or the
%% term infinity, default 0, sets the minimum character
%% value which can be output.
%% (Note that infinity actually represents negative infinity
%% here.)-wrapout b, where b is a boolean,
%% default false, determines what happens when either limit
%% of character output is exceeded. With -wrapout true,
%% the limits will be taken as modulus boundaries,
%% and the actual character output will be computed by 'wrapping around'
%% the rquested value to the opposite limit.
%% With -wrapout false,
%% an exception will be generated. Note that if b is omitted
%% after -wrapout, true is assumed. Also note
%% that -wrapout true is not compatible with either
%% -maxout infinity or -minout infinity.-maxin n, where n is any integer or the
%% term infinity, default infinity, sets the
%% maximum character value which can be input.-minin n, where n is any integer or the
%% term infinity, default 0, sets the minimum character
%% value which can be input.
%% (Note that infinity actually represents negative infinity
%% here.)-wrapin b, where b is a boolean,
%% default false, determines what happens when either limit
%% of character input is exceeded. With -wrapin true,
%% the limits will be taken as modulus boundaries,
%% and the actual character input will be computed by 'wrapping around'
%% the rquested value to the opposite limit.
%% With -wrapin false,
%% an exception will be generated. Note that if b is omitted
%% after -wrapin, true is assumed. Also note
%% that -wrapin true is not compatible with either
%% -maxin infinity or -minin infinity.-xlatout s, where s is string
%% in the form given below,
%% default value #10=#nl, specifies a mapping between
%% characters the Brainf*ck program sees itself as sending to output,
%% and the characters that the operating system actually receives.
%% The syntax for the mapping specification is described by this mini-grammar:
%% -xlatout option is present
%% with no argument, this means that there should be no translation
%% mapping between Brainf*ck output and operating system output.-xlatin s, where s is a string
%% in the form given above,
%% default value #nl=#10, specifies a complementary mapping between
%% characters on the operating system's input and
%% the Brainf*ck program's input.
%% Note that if the -xlatin option is present
%% with no argument, this means that there should be no translation
%% mapping of input.-eof i, where i is any integer
%% or one of the terms halt, stop,
%% or nop, default 0,
%% determines the single ASCII character that will be given repeatedly to
%% the Brainf*ck program during execution of the , instruction
%% at and after the end of input is encountered.
%% If halt is given for eof, the Brainf*ck
%% program will be halted with an error
%% if it attempts to read past the end of user input.
%% If stop is given for eof, the Brainf*ck
%% program will be terminated normally if it attempts to read past
%% the end of user input.
%% If nop is given for eof, the Brainf*ck
%% program will act as if nothing at all happened if it attempts
%% to read past the end of user input (the tape will not be altered in
%% any way.)-quiet, if given, suppresses all startup
%% output generated by the interpreter. It does not suppress
%% status reports.-autopsy, if given, causes the interpreter to
%% issue a status report after the program terminates normally.-statusevery n, where n is an
%% integer specifying a duration or the term undefined,
%% default undefined, tells pibfi
%% to generate periodic status reports at the given interval,
%% if it is not undefined. If the duration is given
%% as a plain integer, units of milliseconds are assumed. The
%% duration may also be given as an integer followed immediately
%% by s, m, or h, in which
%% case the units of measurement will be taken to be seconds,
%% minutes, or hours, respectively.pibfi can work with internally.
convert(dontstrip, String) -> unescape(String);
convert(optimize, Integer) -> list_to_integer(Integer);
convert(statuscmd, "undefined") -> undefined;
convert(statuscmd, String) -> unescape(String);
convert(heredoc, "undefined") -> undefined;
convert(heredoc, String) -> unescape(String);
convert(tapemodule, String) -> list_to_atom(String);
convert(maxcell, "infinity") -> infinity;
convert(maxcell, Else) -> list_to_integer(Else);
convert(mincell, "infinity") -> infinity;
convert(mincell, Else) -> list_to_integer(Else);
convert(wrapcell, "true") -> true;
convert(wrapcell, "false") -> false;
convert(maxtape, "infinity") -> infinity;
convert(maxtape, Else) -> list_to_integer(Else);
convert(mintape, "infinity") -> infinity;
convert(mintape, Else) -> list_to_integer(Else);
convert(wraptape, "true") -> true;
convert(wraptape, "false") -> false;
convert(infile, "tty") -> tty;
convert(infile, "heredoc") -> heredoc;
convert(infile, Else) -> Else;
convert(outfile, "tty") -> tty;
convert(outfile, Else) -> Else;
convert(maxout, "infinity") -> infinity;
convert(maxout, Else) -> list_to_integer(Else);
convert(minout, "infinity") -> infinity;
convert(minout, Else) -> list_to_integer(Else);
convert(wrapout, "true") -> true;
convert(wrapout, "false") -> false;
convert(maxin, "infinity") -> infinity;
convert(maxin, Else) -> list_to_integer(Else);
convert(minin, "infinity") -> infinity;
convert(minin, Else) -> list_to_integer(Else);
convert(wrapin, "true") -> true;
convert(wrapin, "false") -> false;
convert(xlatin, String) -> parse_xlat(String, []);
convert(xlatout, String) -> parse_xlat(String, []);
convert(eof, "halt") -> halt;
convert(eof, "nop") -> nop;
convert(eof, "stop") -> stop;
convert(eof, Else) -> list_to_integer(Else);
convert(statusevery, "undefined") -> undefined;
convert(statusevery, Else) ->
Factor = case lists:last(Else) of
$s -> 1000;
$m -> 60*1000;
$h -> 60*60*1000;
_ -> 1
end,
Root = case Factor of
1 -> Else;
_ -> lists:reverse(tl(lists:reverse(Else)))
end,
% ce_log:write("~p ~p", [Root, Factor]),
list_to_integer(Root) * Factor.
parse_xlat(String, Acc) ->
{First, String0} = parse_lstring(String, ""),
{Second, String1} = parse_rstring(String0, ""),
pibfi:assert(First =/= "", {lefthand_string_in_xlat_may_not_be_null, String}),
Acc0 = [{unescape(First), unescape(Second)} | Acc],
case String1 of
"," ++ String2 ->
parse_xlat(String2, Acc0);
_ ->
Acc0
end.
parse_lstring("=" ++ Tail, Acc) ->
{lists:reverse(Acc), Tail};
parse_lstring([Head | Tail], Acc) ->
parse_lstring(Tail, [Head | Acc]).
parse_rstring("", Acc) ->
{lists:reverse(Acc), ""};
parse_rstring("," ++ Tail, Acc) ->
{lists:reverse(Acc), "," ++ Tail};
parse_rstring([Head | Tail], Acc) ->
parse_rstring(Tail, [Head | Acc]).
%% @spec unescape(string()) -> string()
%% @doc Transforms escape codes in a string into embedded characters.
%% The escape code #i where i is a
%% decimal integer of from one to three digits is converted into an
%% ASCII character of that value.
unescape(String) ->
unescape(String, []).
unescape([], Acc) ->
lists:reverse(Acc);
unescape([$#, $n, $l | Tail], Acc) ->
unescape(Tail, lists:reverse(pibfi:os_eol()) ++ Acc);
unescape([$#, D1, D2, D3 | Tail], Acc)
when D1 >= $0, D1 =< $9, D2 >= $0, D2 =< $9, D3 >= $0, D3 =< $9 ->
unescape(Tail, [(D1 - $0) * 100 + (D2 - $0) * 10 + (D3 - $0) | Acc]);
unescape([$#, D1, D2 | Tail], Acc)
when D1 >= $0, D1 =< $9, D2 >= $0, D2 =< $9 ->
unescape(Tail, [(D1 - $0) * 10 + (D2 - $0) | Acc]);
unescape([$#, D | Tail], Acc)
when D >= $0, D =< $9 ->
unescape(Tail, [(D - $0) | Acc]);
unescape([Head | Tail], Acc) ->
unescape(Tail, [Head | Acc]).
%% @spec get_option(Options::[{atom(), term()}], Option::atom(), Default::term()) -> term()
%% @doc Gets an option from a list of (already parsed) option tuples.
get_option(TupleList, Option, Default) ->
case lists:keysearch(Option, 1, TupleList) of
{value, {Option, Value}} ->
Value;
_ ->
Default
end.
%%% END of pibfi_options.erl %%%