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;
... View more