Why? I don't know, why not?
Paradigm(s) | esoteric |
---|---|
Appeared in | 1993 |
Designed by | Urban Müller |
Influenced by | P′′, FALSE |
Usual filename extensions | .b, .bf |
The brainfuck programming language is an esoteric programming language noted for its extreme minimalism. It is a Turing tarpit, designed to challenge and amuseprogrammers, and is not suitable for practical use.[1] It was created in 1993 by Urban Müller.
The name of the language is generally not capitalized except at the start of a sentence, although it is a proper noun.
The eight language commands, each consisting of a single character:
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 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.
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;
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]
I've produced a more complete implementation that supports most portably written brainfuck programs:
New features
Fixes & minor optimisations
/**************************************************************************************************/
/* 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;
Nicely done, I'm surprised to see this come back after such a long time. Hope you enjoyed working on it.
Join us for SAS Innovate April 16-19 at the Aria in Las Vegas. Bring the team and save big with our group pricing for a limited time only.
Pre-conference courses and tutorials are filling up fast and are always a sellout. Register today to reserve your seat.
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.