git @ Cat's Eye Technologies pibfi / master src / pibfi_parser.erl
master

Tree @master (Download .tar.gz)

pibfi_parser.erl @masterraw · history · blame

%%% BEGIN pibfi_parser.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 Brainf*ck parser for <code>pibfi</code>.
%%
%% @end

-module(pibfi_parser).
-vsn('2003.0426').
-copyright('Copyright (c)2003 Cat`s Eye Technologies. All rights reserved.').

-export([parse/2]).

%% @spec parse(string() | binary(), Options) -> {tuple(), string()}
%% @doc Transforms a string into a nested tuple data structure
%% suitable for interpretation.

parse(Binary, Options) when is_binary(Binary) ->
  parse(binary_to_list(Binary), Options);
parse(Source, Options) ->
  {DocBody, Source0} =
   case pibfi_options:get_option(Options, heredoc, undefined) of
    undefined ->
      {"", Source};
    [Marker] ->
      extract_heredoc(Source, Marker, false, [], [])
  end,
  Program = parse0(Source0),
  Exclude =  pibfi_options:get_option(Options, dontstrip, ""),
  Program0 = pibfi_stripper:strip(Program, Exclude),
  Program1 = case pibfi_options:get_option(Options, optimize, 1) of
    0 ->
      Program0;
    1 ->
      pibfi_optimizer:optimize(Program0)
  end,
  % ce_log:write("~p", [Program1]),
  {Program1, DocBody}.
  
parse0(String) ->
  TupleList = annotate(String),
  parse0({}, TupleList).

parse0(Tuple, []) -> Tuple;
parse0(Tuple, [{$], R, C} | Tail]) -> {Tuple, Tail};
parse0(Tuple, [{$[, R, C} | Tail]) ->
  {NewTuple, NewTail} = parse0({}, Tail),
  parse0(erlang:append_element(Tuple, {while, R, C, NewTuple}), NewTail);
parse0(Tuple, [{Head, R, C} | Tail]) ->
  parse0(erlang:append_element(Tuple, {instruction, R, C, Head}), Tail).

annotate(String) ->
  annotate(String, 1, 1, []).

annotate("", R, C, Acc) ->
  lists:reverse(Acc);
annotate("\n" ++ Tail, R, C, Acc) ->
  annotate(Tail, R+1, 1, Acc);
annotate([Head | Tail], R, C, Acc) ->
  annotate(Tail, R, C+1, [{Head, R, C} | Acc]).

extract_heredoc("", Marker, Found, AccD, AccS) ->
  {lists:reverse(AccD), lists:reverse(AccS)};
extract_heredoc([Marker | Tail], Marker, Found, AccD, AccS) ->
  extract_heredoc(Tail, Marker, true, AccD, AccS);
extract_heredoc([Head | Tail], Marker, true, AccD, AccS) ->
  extract_heredoc(Tail, Marker, true, [Head | AccD], AccS);
extract_heredoc([Head | Tail], Marker, false, AccD, AccS) ->
  extract_heredoc(Tail, Marker, false, AccD, [Head | AccS]).

%%% END of pibfi_parser.erl %%%