DATA Step, Macro, Functions and more

Brainf**k interpreter for SAS

Reply
Trusted Advisor
Posts: 1,301

Brainf**k interpreter for SAS

Why?  I don't know, why not?

Brainfuck

From Wikipedia, the free encyclopedia

brainfuck
Paradigm(s)esoteric
Appeared in1993
Designed byUrban Müller
Influenced byP′′, FALSE
Usual filename extensions.b, .bf

Commands

The eight language commands, each consisting of a single character:

CharacterMeaning
>increment the data pointer (to point to the next cell to the right).
<decrement the data pointer (to point to the next cell to the left).
+increment (increase by one) the byte at the data pointer.
-decrement (decrease by one) the byte at the data pointer.
.output a character, the ASCII value of which being the byte at the data pointer.
,accept one byte of input, storing its value in the byte at the data pointer.
[if the byte at the data pointer is zero, then instead of moving the instruction pointer forward to the next command, jump it forward to the command after the matching ] command*.
]if the byte at the data pointer is nonzero, then instead of moving the instruction pointer forward to the next command, jump it back to the command after the matching [ command*.

%let program=++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.;

*this is not complete.  I am not implementing ability for ',' brainfuck operation;

data _null_;

file print;

*compatibility check;

if findc("&program",',')>0then

  do;

   putlog '4552524f523a20'x 'Illegal operation , operation not supported';

   stop;

  end;

*initialize data;

array data[30000] (30000*0);

data_pointer=1;

i=1;

*initialize and slurp program;

array program[5000] $;

program_pointer=1;

prog=strip(compress("&program",'+-.[]<>','k'));

if length(prog) gt 5000 then

  do;

   putlog '4552524f523a20'x 'Programcannot exceed 5000 operations';

   stop;

  end;

do p=1 to length(prog);

  program

=substr(prog,p,1);

end;

do while(program_pointer<length(prog));

  c=program[program_pointer];

  select(c);

   when('<') data_pointer=data_pointer-1;

   when('>') data_pointer+1;

   when('+') data[data_pointer]+1;

   when('-') data[data_pointer]=data[data_pointer]-1;

   when('.') do; put #1@i data[data_pointer] pib3. @@; i+1; end;

   when('[') do;

               if data[data_pointer]=0 then

                do;

                 bracket_count=1;

                 do while(program_pointer<length(prog));

          program_pointer+1;

                   select(program[program_pointer]);

                    when('[') bracket_count+1;

                    when(']') bracket_count=bracket_count-1;

                    otherwise;

                  end;

                  if bracket_count=0 then leave;

                         end;

                end;

              end;

   when(']') do;

               bracket_count=bracket_count-1;

               do while(program_pointer<length(prog));

               program_pointer=program_pointer-1;

                select(program[program_pointer]);

                 when('[') bracket_count+1;

                 when(']') bracket_count=bracket_count-1;

                 otherwise;

                end;

                if bracket_count=0 then leave;

               end;

               program_pointer=program_pointer-1;

              end;

   otherwise;

  end;

  program_pointer+1;

end;

run;

The result is: Hello World!

At the very least I would consider this program thouroughly untested, it appears to work for the 1 example I have provided but I have tested no further.  This should be viewed as a program strictly for fun.

Trusted Advisor
Posts: 1,301

Brainf**k interpreter for SAS

Upon some further testing I have determined that the above program does not work well for deeply nested loops.  Back to the drawing board.  Anyone else have some input on this?  Here is one minor tweak to help with multiline outputs:

%let program=++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.;

*this is not complete.  I am not implementing ability for ',' brainfuck operation;

data _null_;

file print;

*compatibility check;

if findc("&program",',')>0then

  do;

   putlog '4552524f523a20'x 'Illegal operation , operation not supported';

   stop;

  end;

*initialize data;

array data[30000] (30000*0);

data_pointer=1;

i=1;

*initialize and slurp program;

array program[5000] $;

program_pointer=1;

prog=strip(compress("&program",'+-.[]<>','k'));

if length(prog) gt 5000 then

  do;

   putlog '4552524f523a20'x 'Programcannot exceed 5000 operations';

   stop;

  end;

do p=1 to length(prog);

  program

=substr(prog,p,1);

end;

l=1;

do while(program_pointer<length(prog));

  c=program[program_pointer];

  select(c);

   when('<') data_pointer=data_pointer-1;

   when('>') data_pointer+1;

   when('+') data[data_pointer]+1;

   when('-') data[data_pointer]=data[data_pointer]-1;

   when('.') do;

            put #l @i data[data_pointer] pib3. @@;

            if data[data_pointer] ne 10 then i+1;

                        else

                         do;

                          l+1; i=1;

                         end;

           end;

   when('[') do;

               if data[data_pointer]=0 then

                do;

                 bracket_count=1;

                 do while(program_pointer<length(prog));

          program_pointer+1;

                   select(program[program_pointer]);

                    when('[') bracket_count+1;

                    when(']') bracket_count=bracket_count-1;

                    otherwise;

                  end;

                  if bracket_count=0 then leave;

                         end;

                end;

              end;

   when(']') do;

               bracket_count=bracket_count-1;

               do while(program_pointer<length(prog));

               program_pointer=program_pointer-1;

                select(program[program_pointer]);

                 when('[') bracket_count+1;

                 when(']') bracket_count=bracket_count-1;

                 otherwise;

                end;

                if bracket_count=0 then leave;

               end;

               program_pointer=program_pointer-1;

              end;

   otherwise;

  end;

  program_pointer+1;

end;

run;

Trusted Advisor
Posts: 1,301

Brainf**k interpreter for SAS

Here is a quick tutorial of how this strange language works.

++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.

This program does the following

++++++++++     In the first array cell increment value from default 0 to 10

[                        Start of a loop

>+++++++         Move to second array cell, Increment second array cell by 7

>++++++++++   Move to third array cell, Increment third array cell by 10

>+++                 Move to fourth array cell, Increment fourth array cell by 3

>+                     Move to fifth array cell, Increment fifth array cell by 1

<<<<-                Move to first array cell, decrement value by 1

]                        End of Loop (do until first cell = 0, 10 interations)

>++.                  Move to second array cell, increment by 2, print (7x10+2=72, format pib3. = H)

>+.                    Move to third array cell, increment by 2, print (10x10+1=111 = e)

+++++++.          Stay in third cell, increment by 7, print (10x10+1+7 = 118 = l )

.                        Stay in third cell, print (118=l)

+++.                  Stay in third cell, increment by 3, print (118+3 = 121 = o)

>++.                  Move to fourth cell, increment by 2, print (3x10+2=32= [space])

<<+++++++++++++++.      Move to second cell, increment by 15, print (72+15=87=W)

>.                      Move to third cell, print (121 = o)

+++.                  Stay in third cell, increment by 3, print (121+3 = 124 = r)

------.                  Stay in third cell, decrement by 6, print (124-6=118=l)

--------.                Stay in third cell, decrement by 8, print (118-8=110=d)

>+.                    Move to fourth cell, increment by 1, print (32+1=33=!)

>.                      Move to fifth cell, print (1x10=10= [\n - unix newline - line feed]

Occasional Learner
Posts: 1

Re: Brainf**k interpreter for SAS

I've produced a more complete implementation that supports most portably written brainfuck programs:

New features

  • Support for the comma operator
  • Choice of EOF behaviour (i.e. what happens to the byte under the pointer if you try to read past the end)
  • Support for tabs and newlines in output
  • Cells wrap around within the interval [-128,+127]
  • Program and input are given in the title above the output.

Fixes & minor optimisations

  • The last character of the input program is now correctly executed
  • ] operator only triggers if the active cell is non-zero
  • Array variables set to minimal length

/**************************************************************************************************/ 
/* Program        * bf.sas (macro)                                                                */ 
/**************************************************************************************************/ 
/* Suite          * Global SAS Macro                                                              */ 
/**************************************************************************************************/ 
/* Description    * A brainfuck interpreter for SAS                                               */ 
/**************************************************************************************************/ 
/* Inputs         * A valid brainfuck progam                                                      */ 
/*                * Optional input string                                                         */ 
/**************************************************************************************************/ 
/* Usage notes    * The program and input string should be quoted using %nrstr if they contain any*/ 
/*                * commas.                                                                       */ 
/*                * The default EOF behaviour in this implementation is to do nothing, but you can*/ 
/*                * change this to set the pointer to 0 or -1 if desired, via the EOF parameter.  */ 
/**************************************************************************************************/ 
/* Outputs        * Text output by the brainfuck program is printed to the output window.         */ 
/**************************************************************************************************/ 
/*                                      Change History                                            */ 
/*     Date       * Initials  *  Details                                                   *  QA  */ 
/*  16 Aug 2013   * KZIG      *  Added support for , operation (reading next char of input)*      */ 
/*  23 Aug 2013   * KZIG      *  Added support for newline and tab characters in output    *      */ 
/**************************************************************************************************/

/* 
        A Brainfuck interpreter for SAS, based on the one found here: 
        https://communities.sas.com/thread/32165

        == Character Meaning == 
        >               increment the data pointer (to point to the next cell to the right). 
        <               decrement the data pointer (to point to the next cell to the left). 
        +               increment (increase by one) the byte at the data pointer. 
        -               decrement (decrease by one) the byte at the data pointer. 
        .               output the byte at the data pointer. 
        ,               accept one byte of input, storing its value in the byte at the data pointer. 
        [               if the byte at the data pointer is zero,  
                                then instead of moving the instruction pointer forward to the next command,  
                                jump it forward to the command after the matching ] command. 
        ]               if the byte at the data pointer is nonzero,  
                                then instead of moving the instruction pointer forward to the next command, 
                                jump it back to the command after the matching [ command. 
*/

%macro bf(PROGRAM=,/*      A valid brainfuck program - quote using %nrstr if it contains commas*/

                    INPUT  =%sysget(username), /*  ASCII input string - quote if necessary*/

                    EOF    =/*      Optional value to return on EOF (reading past the end of INPUT)*/

                   );

        %local INPUT_LENGTH KEEP_SYNTAX_HIGHLIGHTING;

        %let KEEP_SYNTAX_HIGHLIGHTING = %nrstr(%mend); 
        %let INPUT_LENGTH = %length(&INPUT);

        %if "&PROGRAM" = "" %then %do; 
                %let PROGRAM = %nrstr(++++++++++[>+++++++>++++++++++>+++<<<-]>++.>+.+++++++..+++.>++.>,[.[-],]<+.); 
        %end;

        option nodate; 
        title "Program: %unquote(&PROGRAM)"; 
        title2 "Input: &INPUT";

       data _null_; 
                file print; 
                *initialize and slurp input; 
                length input_str: 3; 
                array input_str[&INPUT_LENGTH]; 
                do i = 1 to &INPUT_LENGTH; 
                        input_str = min(127,rank(substr("&INPUT",i,1))); 
                end; 
                input_pointer = 1; 
                *initialize data; 
                length data: 3; 
                array data[30000] (30000*0); 
                data_pointer=1; 
                *initialize output line and column pointers; 
                i=1; 
                j=1;  
                *initialize and slurp program; 
                length program: c $1; 
                array program[5000] $; 
                program_pointer=1; 
                prog=strip(compress("&PROGRAM",'+-.,[]<>','k')); 
                if length(prog) gt 5000 then do; 
                        putlog '4552524f523a20'x 'Program cannot exceed 5000 operations'; 
                        stop; 
                end; 
                do p=1 to length(prog); 
                  program

=substr(prog,p,1); 
                end; 
                do while(program_pointer<=length(prog)); 
                        c=program[program_pointer]; 
                        select(c); 
                                when('<') data_pointer+ -1; 
                                when('>') data_pointer+1; 
                                when('+') do; 
                                        if data[data_pointer] < 127 then data[data_pointer]+1; 
                                                                                              else data[data_pointer]= -128;

                                end; 
                                when('-') do; 
                                        if data[data_pointer] > -128   then data[data_pointer]+ -1; 
                                                                                                       else data[data_pointer]= 127;

                                end; 
                                when('.') do; 
                                        /*Line feed or carriage return*/ 
                                        if data[data_pointer] in (10 13) then do; 
                                                put #j@i; /*Cancels @@ (line hold) from any previous output*/ 
                                                j+1; 
                                                i=1;  
                                        end; 
                                        /*Tab (4 spaces)*/ 
                                        else if data[data_pointer] = 9 then do k = 1 to (4-mod(i-1,4)); 
                                                put #j@i ' ' @@; 
                                                i+1; 
                                        end; 
                                        /*Any other character*/ 
                                        else do; 
                                                put #j@i data[data_pointer] pib3. @@;  
                                                i+1; 
                                        end; 
                                end; 
                                when(',') do;  
                                        if input_pointer <= &INPUT_LENGTH then do; 
                                                data[data_pointer]=input_str[input_pointer];  
                                                input_pointer+1;  
                                        end; 
                                        %if "&EOF" ne "" %then %do; 
                                        else data[data_pointer]=&EOF; 
                                        %end; 
                                end; 
                                when('[') do; 
                                        if data[data_pointer]=0 then do; 
                                                bracket_count=1; 
                                                do while(program_pointer<length(prog)); 
                                                        program_pointer+1; 
                                                        select(program[program_pointer]); 
                                                                when('[') bracket_count+1; 
                                                                when(']') bracket_count+ -1; 
                                                                otherwise; 
                                                        end; 
                                                        if bracket_count=0 then leave; 
                                                end; 
                                        end; 
                                end; 
                                when(']') do; 
                                        if data[data_pointer] ne 0 then do; 
                                                bracket_count+ -1; 
                                                do while(1 < program_pointer < length(prog)); 
                                                        program_pointer+ -1; 
                                                        select(program[program_pointer]); 
                                                                when('[') bracket_count+1; 
                                                                when(']') bracket_count+ -1; 
                                                                otherwise; 
                                                        end; 
                                                        if bracket_count=0 then leave; 
                                                end; 
                                                program_pointer+ -1; 
                                        end; 
                                end; 
                                otherwise; 
                        end; 
                        program_pointer+1; 
                end; 
       run;

        title;

%mend bf;

 

Trusted Advisor
Posts: 1,301

Re: Brainf**k interpreter for SAS

Nicely done, I'm surprised to see this come back after such a long time.  Hope you enjoyed working on it.

Ask a Question
Discussion stats
  • 4 replies
  • 461 views
  • 0 likes
  • 2 in conversation