Skip to content

Latest commit

 

History

History
96 lines (86 loc) · 2.66 KB

README.md

File metadata and controls

96 lines (86 loc) · 2.66 KB

pg_brainfuck

-- Hello, World!
select brainfuck('+[-->-[>>+>-----<<]<--<---]>-.>>>+.>>..+++[.>]<<<<.+++.------.<<-.>>>>+.');

-- test from stdin
select brainfuck(',[.,]', 'test from stdin'::bytea);
select brainfuck(',[.[-],]', 'test from stdin'::bytea);
select brainfuck(',[>,]<[.<]', 'nidts morf tset'::bytea);
create or replace function brainfuck(
  in program text,
  in stdin bytea default ''::bytea,
  out stdout text
) as $$
  declare
    commands text[] := regexp_split_to_array(program, '');
    commands_size int := array_upper(commands, 1);

    cells int[] := array[]::int[];
    jumps int[] := array[]::int[];
    stack int[] := array[]::int[];

    depth int;
    index int := 1;
    pointer int := 0;
    read int := 0;
    subindex int;
  begin
    while index <= commands_size loop
      case commands[index]
      when '>' then
        pointer = pointer + 1;
      when '<' then
        pointer = pointer - 1;
      when '+' then
        cells[pointer] = coalesce(cells[pointer], 0) + 1;
        cells[pointer] = coalesce(nullif(cells[pointer], 256), 0);
      when '-' then
        cells[pointer] = coalesce(cells[pointer], 0) - 1;
        cells[pointer] = coalesce(nullif(cells[pointer], -1), 255);
      when '.' then
        continue when coalesce(cells[pointer], 0) = 0;
        stdout = coalesce(stdout, '') || chr(cells[pointer]);
      when ',' then
        begin
          cells[pointer] = get_byte(stdin, read);
          read = read + 1;
        exception when array_subscript_error then
          index = index + 1;
        end;
      when ']' then
        if array_length(stack, 1) > 0 then
          subindex = stack[array_upper(stack, 1)];
          stack = array_remove(stack, subindex);
          jumps[subindex] = index;
          index = subindex - 1;
        end if;
      when '[' then
        if coalesce(cells[pointer], 0) != 0 then
          stack = array_append(stack, index);
        elsif jumps[index] is not null then
          index = jumps[index];
        else
          depth = 1;
          index = index + 1;
          subindex = index;

          while subindex <= commands_size loop
            case commands[subindex]
            when '[' then depth = depth + 1;
            when ']' then depth = depth - 1;
            else end case;

            if depth = 0 then
              jumps[index] = subindex;
              index = subindex;
              exit;
            end if;

            subindex = subindex + 1;
          end loop;
        end if;
      else end case;

      index = index + 1;
    end loop;
  end;
$$ language plpgsql immutable;