This commit is contained in:
Miloslav Ciz 2024-08-25 01:56:24 +02:00
parent 4bff69ec4a
commit 8e2f22bfc7
20 changed files with 1913 additions and 1808 deletions

View file

@ -94,8 +94,6 @@ int main(void)
}
```
TODO: brainfuck to C translator
TODO: comun implementation
Advanced Brainfuck implementations may include [optimizations](optimization.md), for example things like `>>><<>` may be reduced to `>>` etc.
@ -167,7 +165,9 @@ Read two 0-9 numbers (as ASCII digits) and add them:
,>,[<+>-]<------------------------------------------------.
```
TODO: more
## Variants
TODO
## Making Brainfuck Usable: Defining Macrofucker
@ -180,7 +180,7 @@ Hmmm okay, what name do we give the language? Let's call it **Macrofucker**. It
- Vanilla Brainfuck commands work normally, they'll be simply copied.
- Additionally we introduce macros. A macro will be defined as: `:M<commands>;`. `:` and `;` are simply keywords separating the macro definition, `M` is the macro name, which we'll for simplicity sake limit to single uppercase letters only (so we won't be able to make more macros than there are letters), and `<commands>` are just commands that will be copy-pasted wherever the macro is used.
- A macro will be used by simply writing its name, i.e. if we have macro `M` defined (anywhere in the source code), we can use it by simply writing `M`. Optionally we may call it with numeric parameter as `MX`, where `X` is a decimal number. If no parameter is given, we consider it 0. Macro may be invoked even inside another macro.
- Inside a macro definition we may use the symbol `$` that will repeat the next character by the macro's parameter number of times.
- Inside a macro definition we may use the symbol `$` that will make the next character be repeated the macro's argument number of times -- i.e. if the macro was called with let's argument 3, then `$>` will output `>>>`. This symbol can also be used in the same sense in front of macro invocation.
For example consider the following piece of code:
@ -237,9 +237,8 @@ void process(const char *c, int topLevel)
char f = *c; // macro name to search
unsigned int n = 0; // macro argument
if (!topLevel)
if (!topLevel) // read the argument
{
// read argument
c++;
while (*c >= '0' && *c <= '9')
@ -249,13 +248,14 @@ void process(const char *c, int topLevel)
}
}
#define IS_MACRO(x) ((x) >= 'A' && (x) <= 'Z')
c = program;
while (*c) // search for the macro
while (*c) // search for the macro definition
{
if (topLevel || (c[0] == ':' && c[1] == f))
{
c += topLevel ? 0 : 2; // skip the beginning macro chars
c += topLevel ? 0 : 2; // skip the beginning macro chars
while (*c && *c != ';')
{
@ -264,13 +264,13 @@ void process(const char *c, int topLevel)
else if (*c == '+' || *c == '-' || *c == '<' || *c == '>' ||
*c == '[' || *c == ']' || *c == '.' || *c == ',')
putchar(*c); // normal BF commands
else if (*c >= 'A' && *c <= 'Z')
else if (IS_MACRO(*c))
process(c,0); // macro
else if (*c == '$')
{
c++;
for (unsigned int i = 0; i < n; ++i)
putchar(*c);
IS_MACRO(*c) ? process(c,0) : putchar(*c);
}
c++;
@ -286,19 +286,97 @@ void process(const char *c, int topLevel)
int main(int argc, char **argv)
{
process(program,1);
putchar(0); // allows separating program on stdin from program input
// puts("013"); // program input may go here
putchar(0); // allows separating program on stdin from program input
//puts("013"); // program input may go here
return 0;
}
```
The main program we have here is the example program from the [algorithm](algorithm.md) article: it reads a number, prints the number of its divisors and says if the number is [prime](prime.md). Code of the Brainfuck program will be simply printed out on standard output and it can then be run using our Brainfuck interpreter above. Unlike "hello world" this is already a pretty cool problem we've solved with Brainfuck, and we didn't even need that much code to make it happen. Improving this further could allow us to make a completely usable (though, truth be said, probably slow) language. Isn't this just beautiful? Yes, it is :)
## Variants
So just for completeness, here is a Macrofucker program that prints out the first 10 [Fibonacci numbers](fibonacci_number.md):
TODO
```
:Z[-]; zero the cell
:L$<; go left by n
:R$>; go right by n
:XZ$+; store constant n
:N>Z+<[Z>-<]>[<$++>Z]<; not
:CZ>Z<<$<[-$>>+>+<$<<]$>>>[-<$<<+>>$>]<; copy
:F>Z<[->+<]<$<[->$>+<$<]$>>>[-<<$<+>>$>]<; flip
:A>C1[-<+>]<; add
:S>C1[-<->]<; subtract
:GZ>C2>C2+<[->->CN[L3+R3Z]<<]<; greater
:B>C1>C1<<Z>>>GN[L3+>>S>GN]<F<; divide
:P>X100>C1BF>X48A.L3X10>BF>X48A.<F>X48A.L4; print
main program
>X10 loop counter
>X0 first number
>X1 second number
<<
[- loop
R3
C1 A copy and add
P > X10 . print number and newline
< F < F << go back and shift numbers
]
```
which translates to:
```
>[-]++++++++++>[-]>[-]+<<[->>>[-]>[-]<<<[->>+>+<<<]>>>[-<<<
+>>>]<>[-]>[-]<<<[->>+>+<<<]>>>[-<<<+>>>]<[-<+>]<>[-]++++++
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++++++>[-]>[-]<<<[->>+>+<<<]>>
>[-<<<+>>>]<>[-]>[-]<<<[->>+>+<<<]>>>[-<<<+>>>]<>[-]>[-]<<<
[->>+>+<<<]>>>[-<<<+>>>]<<<[-]>>>[-]>[-]>[-]<<<<[->>>+>+<<<
<]>>>>[-<<<<+>>>>]<>[-]>[-]<<<<[->>>+>+<<<<]>>>>[-<<<<+>>>>
]<+<[->->[-]>[-]<<[->+>+<<]>>[-<<+>>]<>[-]+<[[-]>-<]>[<+>[-
]]<[<<<+>>>[-]]<<]<>[-]+<[[-]>-<]>[<+>[-]]<[<<<+>>>[-]>[-]<
<<[->>+>+<<<]>>>[-<<<+>>>]<[-<->]<>[-]>[-]>[-]<<<<[->>>+>+<
<<<]>>>>[-<<<<+>>>>]<>[-]>[-]<<<<[->>>+>+<<<<]>>>>[-<<<<+>>
>>]<+<[->->[-]>[-]<<[->+>+<<]>>[-<<+>>]<>[-]+<[[-]>-<]>[<+>
[-]]<[<<<+>>>[-]]<<]<>[-]+<[[-]>-<]>[<+>[-]]<]<>[-]<[->+<]<
[->+<]>>[-<<+>>]<<>[-]<[->+<]<[->+<]>>[-<<+>>]<>[-]++++++++
++++++++++++++++++++++++++++++++++++++++>[-]>[-]<<<[->>+>+<
<<]>>>[-<<<+>>>]<[-<+>]<.<<<[-]++++++++++>>[-]>[-]<<<[->>+>
+<<<]>>>[-<<<+>>>]<>[-]>[-]<<<[->>+>+<<<]>>>[-<<<+>>>]<<<[-
]>>>[-]>[-]>[-]<<<<[->>>+>+<<<<]>>>>[-<<<<+>>>>]<>[-]>[-]<<
<<[->>>+>+<<<<]>>>>[-<<<<+>>>>]<+<[->->[-]>[-]<<[->+>+<<]>>
[-<<+>>]<>[-]+<[[-]>-<]>[<+>[-]]<[<<<+>>>[-]]<<]<>[-]+<[[-]
>-<]>[<+>[-]]<[<<<+>>>[-]>[-]<<<[->>+>+<<<]>>>[-<<<+>>>]<[-
<->]<>[-]>[-]>[-]<<<<[->>>+>+<<<<]>>>>[-<<<<+>>>>]<>[-]>[-]
<<<<[->>>+>+<<<<]>>>>[-<<<<+>>>>]<+<[->->[-]>[-]<<[->+>+<<]
>>[-<<+>>]<>[-]+<[[-]>-<]>[<+>[-]]<[<<<+>>>[-]]<<]<>[-]+<[[
-]>-<]>[<+>[-]]<]<>[-]<[->+<]<[->+<]>>[-<<+>>]<<>[-]<[->+<]
<[->+<]>>[-<<+>>]<>[-]+++++++++++++++++++++++++++++++++++++
+++++++++++>[-]>[-]<<<[->>+>+<<<]>>>[-<<<+>>>]<[-<+>]<.<>[-
]<[->+<]<[->+<]>>[-<<+>>]<>[-]+++++++++++++++++++++++++++++
+++++++++++++++++++>[-]>[-]<<<[->>+>+<<<]>>>[-<<<+>>>]<[-<+
>]<.<<<<>[-]++++++++++.<>[-]<[->+<]<[->+<]>>[-<<+>>]<<>[-]<
[->+<]<[->+<]>>[-<<+>>]<<<]
```
which outputs:
```
001
001
002
003
005
008
013
021
034
055
```
## See Also
- [False](false.md) (a very similar esolang)
- [comun](comun.md)
- [comun](comun.md)