From 3c6ce827a002c54deb88e40cbddddb03866e695b Mon Sep 17 00:00:00 2001 From: Case Duckworth Date: Wed, 6 Jul 2022 22:00:30 -0500 Subject: Big update --- COPYING | 15 ++ LICENSE | 15 -- Makefile | 20 ++ README.md | 9 +- examples/add2.tf | 500 ++++++++++++++++++++++++++++++++++++++++++++++++ examples/hello-world.bf | 55 +++--- examples/hello-world.tf | 388 +++++++++++++++++++++++++++++++++++++ examples/printchar.bf | 5 + examples/printchar.tf | 10 + examples/rot13.tf | 215 +++++++++++++++++++++ fucktrain | 53 +++-- fucktrain.awk | 97 ++++++++++ trainfuck | 19 +- trainfuck.awk | 53 ++++- 14 files changed, 1366 insertions(+), 88 deletions(-) create mode 100644 COPYING delete mode 100644 LICENSE create mode 100644 Makefile create mode 100644 examples/add2.tf create mode 100644 examples/hello-world.tf create mode 100644 examples/printchar.bf create mode 100644 examples/printchar.tf create mode 100644 examples/rot13.tf create mode 100755 fucktrain.awk diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..0f6c35a --- /dev/null +++ b/COPYING @@ -0,0 +1,15 @@ +Copyright 2020 Case Duckworth and licensed under the terms of the + + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + Version 2, December 2004 + + Copyright (C) 2004 Sam Hocevar + + Everyone is permitted to copy and distribute verbatim or modified + copies of this license document, and changing it is allowed as long + as the name is changed. + + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. You just DO WHAT THE FUCK YOU WANT TO. diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 0f6c35a..0000000 --- a/LICENSE +++ /dev/null @@ -1,15 +0,0 @@ -Copyright 2020 Case Duckworth and licensed under the terms of the - - DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE - Version 2, December 2004 - - Copyright (C) 2004 Sam Hocevar - - Everyone is permitted to copy and distribute verbatim or modified - copies of this license document, and changing it is allowed as long - as the name is changed. - - DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. You just DO WHAT THE FUCK YOU WANT TO. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ebe8bf4 --- /dev/null +++ b/Makefile @@ -0,0 +1,20 @@ +# TRAINFUCK MOTHER CHOO-ER +# Version #9 + +PREFIX = /usr/local + +.PHONY: help install uninstall + +help: + @echo "TRAINFUCK!" + @echo " make install Install to $(PREFIX)" + @echo " make uninstall Remove from $(PREFIX)" + +install: trainfuck trainfuck.awk fucktrain fucktrain.awk + install -Dt $(DESTDIR)$(PREFIX)/bin/ $? + +uninstall: + rm $(DESTDIR)$(PREFIX)/trainfuck + rm $(DESTDIR)$(PREFIX)/trainfuck.awk + rm $(DESTDIR)$(PREFIX)/fucktrain + rm $(DESTDIR)$(PREFIX)/fucktrain.awk diff --git a/README.md b/README.md index c552d91..bf4da7b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ # TRAINFUCK -an esolang that transpiles to everyone's favorite esolange +an esolang that transpiles to everyone's favorite esolang (so basically an awk script) +**NOW WITH MORE SCRIPTING CAPABILITIES!** ## LANGUAGE @@ -33,19 +34,19 @@ because fuck you, that's why. ## INVOKING ``` -trainfuck FILE | BRAINFUCK_INTERPRETER +trainfuck FILE.tf ``` Or, for round-tripping ... ``` -fucktrain FILE | trainfuck | BRAINFUCK_INTERPRETER +fucktrain FILE.bf | trainfuck ``` ## INSTALL ``` -cp trainfuck /usr/sbin/ +make install ``` ## UNINSTALL diff --git a/examples/add2.tf b/examples/add2.tf new file mode 100644 index 0000000..3c1529b --- /dev/null +++ b/examples/add2.tf @@ -0,0 +1,500 @@ + Add two values +from https://en.wikipedia.org/wiki/Brainfuck#Adding_two_values + + + + +ALL ABOARD +chug chug +END OF THE LINE + Cell c0 = 2 + +ALL ABOARD +choo + +END OF THE LINE + +ALL ABOARD +chug chug chug chug chug +END OF THE LINE + Cell c1 = 5 + + +ALL ABOARD +tickets please +END OF THE LINE + Start your loops with your cell pointer on the loop counter (c1 in our case) + +ALL ABOARD +choo choo + +END OF THE LINE + +ALL ABOARD +chug +END OF THE LINE + Add 1 to c0 + +ALL ABOARD +choo + +END OF THE LINE + +ALL ABOARD +chugga +END OF THE LINE + Subtract 1 from c1 + +ALL ABOARD +your ticket please +END OF THE LINE + End your loops with the cell pointer on the loop counter + +At this point our program has added 5 to 2 leaving 7 in c0 and 0 in c1 +but we cannot output this value to the terminal since it is not ASCII encoded + +To display the ASCII character "7" we must add 48 to the value 7 +We use a loop to compute 48 = 6 * 8 + + +ALL ABOARD +chug chug chug chug +END OF THE LINE + +ALL ABOARD +chug chug chug chug +END OF THE LINE + c1 = 8 and this will be our loop counter again + +ALL ABOARD +tickets please +choo choo + +END OF THE LINE + +ALL ABOARD +chug chug chug +END OF THE LINE + +ALL ABOARD +chug chug chug +END OF THE LINE + Add 6 to c0 + +ALL ABOARD +choo + +END OF THE LINE + +ALL ABOARD +chugga +END OF THE LINE + Subtract 1 from c1 + +ALL ABOARD +your ticket please +choo choo + +END OF THE LINE + +ALL ABOARD +click +END OF THE LINE + Print out c0 which has the value 55 which translates to "7"! + +Finally print a newline: + +ALL ABOARD +chugga chugga chugga chugga chugga chugga chugga chugga chugga chugga chugga +chugga chugga chugga chugga chugga chugga chugga chugga chugga chugga chugga +chugga chugga chugga chugga chugga chugga chugga chugga chugga chugga chugga +chugga chugga chugga chugga chugga chugga chugga chugga chugga chugga chugga +chugga click + This program prints "Hello World!" and a newline to the screen, its +length is 106 active command characters. [It is not the shortest.] + +This loop is an "initial comment loop", a simple way of adding a comment +to a BF program such that you don't have to worry about any command +characters. Any ".", ",", "+", "-", "<" and ">" characters are simply +ignored, the "[" and "]" characters just have to be balanced. This +loop and the commands it contains are ignored because the current cell +defaults to a value of 0; the 0 value causes this loop to be skipped. + +from https://en.wikipedia.org/wiki/Brainfuck#Hello_World! + + +ALL ABOARD +chug chug chug chug chug chug chug chug +END OF THE LINE + Set Cell #0 to 8 + +ALL ABOARD +tickets please +choo +chug chug chug chug +END OF THE LINE + Add 4 to Cell #1; this will always set Cell #1 to 4 + +ALL ABOARD +tickets please +END OF THE LINE + as the cell will be cleared by the loop + +ALL ABOARD +choo +chug chug +END OF THE LINE + Add 2 to Cell #2 + +ALL ABOARD +choo +chug chug chug +END OF THE LINE + Add 3 to Cell #3 + +ALL ABOARD +choo +chug chug chug +END OF THE LINE + Add 3 to Cell #4 + +ALL ABOARD +choo +chug +END OF THE LINE + Add 1 to Cell #5 + +ALL ABOARD +choo choo +choo choo +choo choo +choo choo +chugga +END OF THE LINE + Decrement the loop counter in Cell #1 + +ALL ABOARD +your ticket please +END OF THE LINE + Loop until Cell #1 is zero; number of iterations is 4 + +ALL ABOARD +choo +chug +END OF THE LINE + Add 1 to Cell #2 + +ALL ABOARD +choo +chug +END OF THE LINE + Add 1 to Cell #3 + +ALL ABOARD +choo +chugga +END OF THE LINE + Subtract 1 from Cell #4 + +ALL ABOARD +choo +choo +chug +END OF THE LINE + Add 1 to Cell #6 + +ALL ABOARD +tickets please choo choo +your ticket please +END OF THE LINE + Move back to the first zero cell you find; this will + be Cell #1 which was cleared by the previous loop + +ALL ABOARD +choo choo +chugga +END OF THE LINE + Decrement the loop Counter in Cell #0 + +ALL ABOARD +your ticket please +END OF THE LINE + Loop until Cell #0 is zero; number of iterations is 8 + +The result of this is: +Cell no : 0 1 2 3 4 5 6 +Contents: 0 0 72 104 88 32 8 +Pointer : ^ + + +ALL ABOARD +choo +choo +click +END OF THE LINE + Cell #2 has value 72 which is 'H' + +ALL ABOARD +choo +chugga chugga chugga click +END OF THE LINE + Subtract 3 from Cell #3 to get 101 which is 'e' + +ALL ABOARD +chug chug chug chug chug chug chug clickety click chug chug chug click + +END OF THE LINE + Likewise for 'llo' from Cell #3 + +ALL ABOARD +choo +choo +click +END OF THE LINE + Cell #5 is 32 for the space + +ALL ABOARD +choo choo +chugga clickety +END OF THE LINE + Subtract 1 from Cell #4 for 87 to give a 'W' + +ALL ABOARD +choo choo +clickety +END OF THE LINE + Cell #3 was set to 'o' from the end of 'Hello' + +ALL ABOARD +chug chug chug click chugga chugga chugga chugga chugga chugga clickety +chugga chugga chugga chugga chugga chugga chugga chugga click +END OF THE LINE + Cell #3 for 'rl' and 'd' + +ALL ABOARD +choo +choo +chug click +END OF THE LINE + Add 1 to Cell #5 gives us an exclamation point + +ALL ABOARD +choo +chug chug click +END OF THE LINE + And finally a newline from Cell #6 + ROT13 in Brainfuck +from https://en.wikipedia.org/wiki/Brainfuck#ROT13 + + + + +ALL ABOARD +chugga clack chug tickets please +END OF THE LINE + Read first character and start outer character reading loop + +ALL ABOARD +chugga tickets please +END OF THE LINE + Skip forward if character is 0 + +ALL ABOARD +choo +choo +chug chug chug chug tickets please choo +chug chug chug chug chug chug chug chug +choo choo +chugga your ticket please +END OF THE LINE + Set up divisor (32) for division loop +(MEMORY LAYOUT: dividend copy remainder divisor quotient zero zero) + +ALL ABOARD +choo choo +chug choo choo +chugga tickets please +END OF THE LINE + Set up dividend (x minus 1) and enter division loop + +ALL ABOARD +choo +chug choo +chug choo +chugga tickets please choo +choo +choo +your ticket please +END OF THE LINE + Increase copy and remainder / reduce divisor / Normal case: skip forward + +ALL ABOARD +choo choo +tickets please tickets please choo +chug choo choo +chugga your ticket please choo +choo +chug choo +your ticket please + +END OF THE LINE + Special case: move remainder back to divisor and increase quotient + +ALL ABOARD +choo choo +choo choo +choo choo +choo choo +choo choo +chugga +END OF THE LINE + Decrement dividend + +ALL ABOARD +your ticket please +END OF THE LINE + End division loop + +ALL ABOARD +your ticket please choo +choo +choo +tickets please chugga your ticket please chug +END OF THE LINE + End skip loop; zero former divisor and reuse space for a flag + +ALL ABOARD +choo +chugga chugga tickets please chugga tickets please choo choo +chugga choo +chug chug chug +tickets please chugga your ticket please your ticket please your ticket please +choo choo +tickets please +END OF THE LINE + Zero that flag unless quotient was 2 or 3; zero quotient; check flag + +ALL ABOARD +chug chug chug chug chug chug chug chug chug chug chug chug choo choo +tickets please + +END OF THE LINE + If flag then set up divisor (13) for second division loop +(MEMORY LAYOUT: zero copy dividend divisor remainder quotient zero zero) + +ALL ABOARD +choo +chugga tickets please choo +chug choo +choo +your ticket please +END OF THE LINE + Reduce divisor; Normal case: increase remainder + +ALL ABOARD +choo +tickets please chug tickets please choo choo +chug choo +chugga your ticket please choo +chug +choo +choo +your ticket please +END OF THE LINE + Special case: increase remainder / move it back to divisor / increase quotient + +ALL ABOARD +choo choo +choo choo +choo choo +choo choo +choo choo +chugga +END OF THE LINE + Decrease dividend + +ALL ABOARD +your ticket please +END OF THE LINE + End division loop + +ALL ABOARD +choo +choo +tickets please choo choo +chug choo +chugga your ticket please +END OF THE LINE + Add remainder back to divisor to get a useful 13 + +ALL ABOARD +choo +tickets please +END OF THE LINE + Skip forward if quotient was 0 + +ALL ABOARD +chugga tickets please +END OF THE LINE + Decrement quotient and skip forward if quotient was 1 + +ALL ABOARD +chugga choo choo +choo choo +tickets please chugga your ticket please choo +choo + +END OF THE LINE + Zero quotient and divisor if quotient was 2 + +ALL ABOARD +your ticket please choo choo +choo choo +tickets please choo choo +choo choo +chugga choo +choo +chugga your ticket please choo +choo + +END OF THE LINE + Zero divisor and subtract 13 from copy if quotient was 1 + +ALL ABOARD +your ticket please choo choo +choo choo +tickets please choo choo +choo choo +chug choo +choo +chugga your ticket please +END OF THE LINE + Zero divisor and add 13 to copy if quotient was 0 + +ALL ABOARD +your ticket please +END OF THE LINE + End outer skip loop (jump to here if ((character minus 1)/32) was not 2 or 3) + +ALL ABOARD +choo choo +tickets please chugga your ticket please +END OF THE LINE + Clear remainder from first division if second division was skipped + +ALL ABOARD +choo choo +click tickets please chugga your ticket please +END OF THE LINE + Output ROT13ed character from copy and clear it + +ALL ABOARD +choo choo +chugga clack chug +END OF THE LINE + Read next character + +ALL ABOARD +your ticket please +END OF THE LINE + End character reading loop diff --git a/examples/hello-world.bf b/examples/hello-world.bf index dce24e2..eab99ed 100644 --- a/examples/hello-world.bf +++ b/examples/hello-world.bf @@ -8,38 +8,37 @@ ignored, the "[" and "]" characters just have to be balanced. This loop and the commands it contains are ignored because the current cell defaults to a value of 0; the 0 value causes this loop to be skipped. -from https://en.wikipedia.org/wiki/Brainfuck#Hello_World! -] -++++++++ Set Cell #0 to 8 +from https://en.wikipedia.org/wiki/Brainfuck#Hello_World! ] +++++++++ Set Cell #0 to 8 [ ->++++ Add 4 to Cell #1; this will always set Cell #1 to 4 -[ as the cell will be cleared by the loop ->++ Add 2 to Cell #2 ->+++ Add 3 to Cell #3 ->+++ Add 3 to Cell #4 ->+ Add 1 to Cell #5 -<<<<- Decrement the loop counter in Cell #1 -] Loop until Cell #1 is zero; number of iterations is 4 ->+ Add 1 to Cell #2 ->+ Add 1 to Cell #3 ->- Subtract 1 from Cell #4 ->>+ Add 1 to Cell #6 -[<] Move back to the first zero cell you find; this will -be Cell #1 which was cleared by the previous loop -<- Decrement the loop Counter in Cell #0 -] Loop until Cell #0 is zero; number of iterations is 8 +>++++ Add 4 to Cell #1; this will always set Cell #1 to 4 +[ as the cell will be cleared by the loop +>++ Add 2 to Cell #2 +>+++ Add 3 to Cell #3 +>+++ Add 3 to Cell #4 +>+ Add 1 to Cell #5 +<<<<- Decrement the loop counter in Cell #1 +] Loop until Cell #1 is zero; number of iterations is 4 +>+ Add 1 to Cell #2 +>+ Add 1 to Cell #3 +>- Subtract 1 from Cell #4 +>>+ Add 1 to Cell #6 +[<] Move back to the first zero cell you find; this will + be Cell #1 which was cleared by the previous loop +<- Decrement the loop Counter in Cell #0 +] Loop until Cell #0 is zero; number of iterations is 8 The result of this is: Cell no : 0 1 2 3 4 5 6 Contents: 0 0 72 104 88 32 8 Pointer : ^ ->>. Cell #2 has value 72 which is 'H' ->---. Subtract 3 from Cell #3 to get 101 which is 'e' -+++++++..+++. Likewise for 'llo' from Cell #3 ->>. Cell #5 is 32 for the space -<-. Subtract 1 from Cell #4 for 87 to give a 'W' -<. Cell #3 was set to 'o' from the end of 'Hello' -+++.------.--------. Cell #3 for 'rl' and 'd' ->>+. Add 1 to Cell #5 gives us an exclamation point ->++. And finally a newline from Cell #6 +>>. Cell #2 has value 72 which is 'H' +>---. Subtract 3 from Cell #3 to get 101 which is 'e' ++++++++..+++. Likewise for 'llo' from Cell #3 +>>. Cell #5 is 32 for the space +<-. Subtract 1 from Cell #4 for 87 to give a 'W' +<. Cell #3 was set to 'o' from the end of 'Hello' ++++.------.--------. Cell #3 for 'rl' and 'd' +>>+. Add 1 to Cell #5 gives us an exclamation point +>++. And finally a newline from Cell #6 diff --git a/examples/hello-world.tf b/examples/hello-world.tf new file mode 100644 index 0000000..397bc43 --- /dev/null +++ b/examples/hello-world.tf @@ -0,0 +1,388 @@ + This program prints "Hello World!" and a newline to the screen, its +length is 106 active command characters. [It is not the shortest.] + +This loop is an "initial comment loop", a simple way of adding a comment +to a BF program such that you don't have to worry about any command +characters. Any ".", ",", "+", "-", "<" and ">" characters are simply +ignored, the "[" and "]" characters just have to be balanced. This +loop and the commands it contains are ignored because the current cell +defaults to a value of 0; the 0 value causes this loop to be skipped. + +from https://en.wikipedia.org/wiki/Brainfuck#Hello_World! + + +ALL ABOARD +chug chug chug chug chug chug chug chug +END OF THE LINE + Set Cell #0 to 8 + +ALL ABOARD +tickets please +choo +chug chug chug chug +END OF THE LINE + Add 4 to Cell #1; this will always set Cell #1 to 4 + +ALL ABOARD +tickets please +END OF THE LINE + as the cell will be cleared by the loop + +ALL ABOARD +choo +chug chug +END OF THE LINE + Add 2 to Cell #2 + +ALL ABOARD +choo +chug chug chug +END OF THE LINE + Add 3 to Cell #3 + +ALL ABOARD +choo +chug chug chug +END OF THE LINE + Add 3 to Cell #4 + +ALL ABOARD +choo +chug +END OF THE LINE + Add 1 to Cell #5 + +ALL ABOARD +choo choo +choo choo +choo choo +choo choo +chugga +END OF THE LINE + Decrement the loop counter in Cell #1 + +ALL ABOARD +your ticket please +END OF THE LINE + Loop until Cell #1 is zero; number of iterations is 4 + +ALL ABOARD +choo +chug +END OF THE LINE + Add 1 to Cell #2 + +ALL ABOARD +choo +chug +END OF THE LINE + Add 1 to Cell #3 + +ALL ABOARD +choo +chugga +END OF THE LINE + Subtract 1 from Cell #4 + +ALL ABOARD +choo +choo +chug +END OF THE LINE + Add 1 to Cell #6 + +ALL ABOARD +tickets please choo choo +your ticket please +END OF THE LINE + Move back to the first zero cell you find; this will + be Cell #1 which was cleared by the previous loop + +ALL ABOARD +choo choo +chugga +END OF THE LINE + Decrement the loop Counter in Cell #0 + +ALL ABOARD +your ticket please +END OF THE LINE + Loop until Cell #0 is zero; number of iterations is 8 + +The result of this is: +Cell no : 0 1 2 3 4 5 6 +Contents: 0 0 72 104 88 32 8 +Pointer : ^ + + +ALL ABOARD +choo +choo +click +END OF THE LINE + Cell #2 has value 72 which is 'H' + +ALL ABOARD +choo +chugga chugga chugga click +END OF THE LINE + Subtract 3 from Cell #3 to get 101 which is 'e' + +ALL ABOARD +chug chug chug chug chug chug chug clickety click chug chug chug click + +END OF THE LINE + Likewise for 'llo' from Cell #3 + +ALL ABOARD +choo +choo +click +END OF THE LINE + Cell #5 is 32 for the space + +ALL ABOARD +choo choo +chugga clickety +END OF THE LINE + Subtract 1 from Cell #4 for 87 to give a 'W' + +ALL ABOARD +choo choo +clickety +END OF THE LINE + Cell #3 was set to 'o' from the end of 'Hello' + +ALL ABOARD +chug chug chug click chugga chugga chugga chugga chugga chugga clickety +chugga chugga chugga chugga chugga chugga chugga chugga click +END OF THE LINE + Cell #3 for 'rl' and 'd' + +ALL ABOARD +choo +choo +chug click +END OF THE LINE + Add 1 to Cell #5 gives us an exclamation point + +ALL ABOARD +choo +chug chug click +END OF THE LINE + And finally a newline from Cell #6 + ROT13 in Brainfuck +from https://en.wikipedia.org/wiki/Brainfuck#ROT13 + + + + +ALL ABOARD +chugga clack chug tickets please +END OF THE LINE + Read first character and start outer character reading loop + +ALL ABOARD +chugga tickets please +END OF THE LINE + Skip forward if character is 0 + +ALL ABOARD +choo +choo +chug chug chug chug tickets please choo +chug chug chug chug chug chug chug chug +choo choo +chugga your ticket please +END OF THE LINE + Set up divisor (32) for division loop +(MEMORY LAYOUT: dividend copy remainder divisor quotient zero zero) + +ALL ABOARD +choo choo +chug choo choo +chugga tickets please +END OF THE LINE + Set up dividend (x minus 1) and enter division loop + +ALL ABOARD +choo +chug choo +chug choo +chugga tickets please choo +choo +choo +your ticket please +END OF THE LINE + Increase copy and remainder / reduce divisor / Normal case: skip forward + +ALL ABOARD +choo choo +tickets please tickets please choo +chug choo choo +chugga your ticket please choo +choo +chug choo +your ticket please + +END OF THE LINE + Special case: move remainder back to divisor and increase quotient + +ALL ABOARD +choo choo +choo choo +choo choo +choo choo +choo choo +chugga +END OF THE LINE + Decrement dividend + +ALL ABOARD +your ticket please +END OF THE LINE + End division loop + +ALL ABOARD +your ticket please choo +choo +choo +tickets please chugga your ticket please chug +END OF THE LINE + End skip loop; zero former divisor and reuse space for a flag + +ALL ABOARD +choo +chugga chugga tickets please chugga tickets please choo choo +chugga choo +chug chug chug +tickets please chugga your ticket please your ticket please your ticket please +choo choo +tickets please +END OF THE LINE + Zero that flag unless quotient was 2 or 3; zero quotient; check flag + +ALL ABOARD +chug chug chug chug chug chug chug chug chug chug chug chug choo choo +tickets please + +END OF THE LINE + If flag then set up divisor (13) for second division loop +(MEMORY LAYOUT: zero copy dividend divisor remainder quotient zero zero) + +ALL ABOARD +choo +chugga tickets please choo +chug choo +choo +your ticket please +END OF THE LINE + Reduce divisor; Normal case: increase remainder + +ALL ABOARD +choo +tickets please chug tickets please choo choo +chug choo +chugga your ticket please choo +chug +choo +choo +your ticket please +END OF THE LINE + Special case: increase remainder / move it back to divisor / increase quotient + +ALL ABOARD +choo choo +choo choo +choo choo +choo choo +choo choo +chugga +END OF THE LINE + Decrease dividend + +ALL ABOARD +your ticket please +END OF THE LINE + End division loop + +ALL ABOARD +choo +choo +tickets please choo choo +chug choo +chugga your ticket please +END OF THE LINE + Add remainder back to divisor to get a useful 13 + +ALL ABOARD +choo +tickets please +END OF THE LINE + Skip forward if quotient was 0 + +ALL ABOARD +chugga tickets please +END OF THE LINE + Decrement quotient and skip forward if quotient was 1 + +ALL ABOARD +chugga choo choo +choo choo +tickets please chugga your ticket please choo +choo + +END OF THE LINE + Zero quotient and divisor if quotient was 2 + +ALL ABOARD +your ticket please choo choo +choo choo +tickets please choo choo +choo choo +chugga choo +choo +chugga your ticket please choo +choo + +END OF THE LINE + Zero divisor and subtract 13 from copy if quotient was 1 + +ALL ABOARD +your ticket please choo choo +choo choo +tickets please choo choo +choo choo +chug choo +choo +chugga your ticket please +END OF THE LINE + Zero divisor and add 13 to copy if quotient was 0 + +ALL ABOARD +your ticket please +END OF THE LINE + End outer skip loop (jump to here if ((character minus 1)/32) was not 2 or 3) + +ALL ABOARD +choo choo +tickets please chugga your ticket please +END OF THE LINE + Clear remainder from first division if second division was skipped + +ALL ABOARD +choo choo +click tickets please chugga your ticket please +END OF THE LINE + Output ROT13ed character from copy and clear it + +ALL ABOARD +choo choo +chugga clack chug +END OF THE LINE + Read next character + +ALL ABOARD +your ticket please +END OF THE LINE + End character reading loop diff --git a/examples/printchar.bf b/examples/printchar.bf new file mode 100644 index 0000000..e0d73ad --- /dev/null +++ b/examples/printchar.bf @@ -0,0 +1,5 @@ +[ printchar is a small example input/output trainfuck program. +it waits for the user to press a key, then prints that key +and a newline to the screen. +] +,.>++++++++++. diff --git a/examples/printchar.tf b/examples/printchar.tf new file mode 100644 index 0000000..c9092be --- /dev/null +++ b/examples/printchar.tf @@ -0,0 +1,10 @@ +printchar is a small example input/output trainfuck program. +it waits for the user to press a key, then prints that key +and a newline to the screen. +ALL ABOARD +clack clickety +choo +chug chug chug chug chug +chug chug chug chug chug +click +END OF THE LINE diff --git a/examples/rot13.tf b/examples/rot13.tf new file mode 100644 index 0000000..f7c24df --- /dev/null +++ b/examples/rot13.tf @@ -0,0 +1,215 @@ + ROT13 in Brainfuck +from https://en.wikipedia.org/wiki/Brainfuck#ROT13 + + + + +ALL ABOARD +chugga clack chug tickets please +END OF THE LINE + Read first character and start outer character reading loop + +ALL ABOARD +chugga tickets please +END OF THE LINE + Skip forward if character is 0 + +ALL ABOARD +choo +choo +chug chug chug chug tickets please choo +chug chug chug chug chug chug chug chug +choo choo +chugga your ticket please +END OF THE LINE + Set up divisor (32) for division loop +(MEMORY LAYOUT: dividend copy remainder divisor quotient zero zero) + +ALL ABOARD +choo choo +chug choo choo +chugga tickets please +END OF THE LINE + Set up dividend (x minus 1) and enter division loop + +ALL ABOARD +choo +chug choo +chug choo +chugga tickets please choo +choo +choo +your ticket please +END OF THE LINE + Increase copy and remainder / reduce divisor / Normal case: skip forward + +ALL ABOARD +choo choo +tickets please tickets please choo +chug choo choo +chugga your ticket please choo +choo +chug choo +your ticket please + +END OF THE LINE + Special case: move remainder back to divisor and increase quotient + +ALL ABOARD +choo choo +choo choo +choo choo +choo choo +choo choo +chugga +END OF THE LINE + Decrement dividend + +ALL ABOARD +your ticket please +END OF THE LINE + End division loop + +ALL ABOARD +your ticket please choo +choo +choo +tickets please chugga your ticket please chug +END OF THE LINE + End skip loop; zero former divisor and reuse space for a flag + +ALL ABOARD +choo +chugga chugga tickets please chugga tickets please choo choo +chugga choo +chug chug chug +tickets please chugga your ticket please your ticket please your ticket please +choo choo +tickets please +END OF THE LINE + Zero that flag unless quotient was 2 or 3; zero quotient; check flag + +ALL ABOARD +chug chug chug chug chug chug chug chug chug chug chug chug choo choo +tickets please + +END OF THE LINE + If flag then set up divisor (13) for second division loop +(MEMORY LAYOUT: zero copy dividend divisor remainder quotient zero zero) + +ALL ABOARD +choo +chugga tickets please choo +chug choo +choo +your ticket please +END OF THE LINE + Reduce divisor; Normal case: increase remainder + +ALL ABOARD +choo +tickets please chug tickets please choo choo +chug choo +chugga your ticket please choo +chug +choo +choo +your ticket please +END OF THE LINE + Special case: increase remainder / move it back to divisor / increase quotient + +ALL ABOARD +choo choo +choo choo +choo choo +choo choo +choo choo +chugga +END OF THE LINE + Decrease dividend + +ALL ABOARD +your ticket please +END OF THE LINE + End division loop + +ALL ABOARD +choo +choo +tickets please choo choo +chug choo +chugga your ticket please +END OF THE LINE + Add remainder back to divisor to get a useful 13 + +ALL ABOARD +choo +tickets please +END OF THE LINE + Skip forward if quotient was 0 + +ALL ABOARD +chugga tickets please +END OF THE LINE + Decrement quotient and skip forward if quotient was 1 + +ALL ABOARD +chugga choo choo +choo choo +tickets please chugga your ticket please choo +choo + +END OF THE LINE + Zero quotient and divisor if quotient was 2 + +ALL ABOARD +your ticket please choo choo +choo choo +tickets please choo choo +choo choo +chugga choo +choo +chugga your ticket please choo +choo + +END OF THE LINE + Zero divisor and subtract 13 from copy if quotient was 1 + +ALL ABOARD +your ticket please choo choo +choo choo +tickets please choo choo +choo choo +chug choo +choo +chugga your ticket please +END OF THE LINE + Zero divisor and add 13 to copy if quotient was 0 + +ALL ABOARD +your ticket please +END OF THE LINE + End outer skip loop (jump to here if ((character minus 1)/32) was not 2 or 3) + +ALL ABOARD +choo choo +tickets please chugga your ticket please +END OF THE LINE + Clear remainder from first division if second division was skipped + +ALL ABOARD +choo choo +click tickets please chugga your ticket please +END OF THE LINE + Output ROT13ed character from copy and clear it + +ALL ABOARD +choo choo +chugga clack chug +END OF THE LINE + Read next character + +ALL ABOARD +your ticket please +END OF THE LINE + End character reading loop diff --git a/fucktrain b/fucktrain index 7ade621..1c25aff 100755 --- a/fucktrain +++ b/fucktrain @@ -1,37 +1,30 @@ -#!/bin/awk -f -# FUCKTRAIN: FUCKAMUTHA CHOO CHOO -*- awk -*- +#!/bin/sh +# TRAINFUCK: CHOO CHOO MUTHAFUCKA -*- sh -*- # Author: Case Duckworth # License: WTFPL # Version: #9 -BEGIN { - print "ALL ABOARD" -} -{ - gsub(/[^-+<>.,\[\]]/, "", $0) - gsub(/+/, "chug ", $0) - gsub(/-/, "chugga ", $0) - gsub(/>/, "choo\n", $0) - gsub(/ +# License: WTFPL +# Version: #9 + +### Commentary: + +# FUCKTRAIN turns brainfuck code into trainfuck code. + +### Code: +BEGIN { + buffer = "" + fold_width = 70 + width = 0 +} + +{ + buffer = buffer $0 "\n" +} + +END { + sub(/^[ \t\n\r\f]+/, "", buffer) + sub(/[ \t\n\r\f]+$/, "", buffer) + split(buffer, bufa, "") + boarded = 0 + header = 1 + for (c in bufa) { + if (bufa[c] == "[" && header) { + header++ + if (header == 2) { + c++ + } + } + if (bufa[c] == "]" && header) { + header-- + if (header == 1) { + header = 0 + c++ + } + } + if (! boarded && ! header && bufa[c] ~ /[-+<>.,\[\]]/) { + printf "\n%s\n", "ALL ABOARD" + boarded = 1 + } + if (boarded) { + if (width > fold_width) { + print "" + width = 0 + } + if (bufa[c] == ">") { + printf "%s", "choo\n" + } else if (bufa[c] == "<") { + printf "%s", "choo choo\n" + } else if (bufa[c] == "+") { + printf "%s", "chug " + width += 5 + } else if (bufa[c] == "-") { + printf "%s", "chugga " + width += 7 + } else if (bufa[c] == ".") { + click = clickety_click() + printf "%s", click + width += length(click) + } else if (bufa[c] == ",") { + printf "%s", "clack " + width += 6 + } else if (bufa[c] == "[") { + printf "%s", "tickets please " + width += 15 + } else if (bufa[c] == "]") { + printf "%s", "your ticket please " + width += 19 + } else if (bufa[c] ~ /[\n]/) { + printf "%s", bufa[c] + width = 0 + } else { + printf "\n%s\n%s", "END OF THE LINE", bufa[c] + boarded = 0 + } + } else { + width = 0 + printf "%s", bufa[c] + } + } + print "" +} + + +function clickety_click() +{ + if (rand() <= 0.5) { + return "clickety " + } else { + return "click " + } +} diff --git a/trainfuck b/trainfuck index 22d1009..dec743b 100755 --- a/trainfuck +++ b/trainfuck @@ -10,6 +10,21 @@ ### Code: -TRAINFUCK=trainfuck.awk +TRAINFUCK="$(dirname "$0")/trainfuck.awk" -gawk -v EXE_NAME="$(basename $0)" -f "$TRAINFUCK" -- "$@" +case "$(realpath "$(command -v awk)")" in +*gawk) + AWK=gawk + EXTRA_AWK_ARGS="--characters-as-bytes" # --posix overrides + ;; +*mawk) + AWK=mawk + EXTRA_AWK_ARGS="-Wposix" + ;; +*) + AWK=awk + EXTRA_AWK_ARGS= + ;; +esac + +"$AWK" -v EXE_NAME="$(basename $0)" -f "$TRAINFUCK" $EXTRA_AWK_ARGS -- "$@" diff --git a/trainfuck.awk b/trainfuck.awk index df89821..1a6c19c 100755 --- a/trainfuck.awk +++ b/trainfuck.awk @@ -39,6 +39,7 @@ BEGIN { # Constants EXE_NAME = (EXE_NAME ? EXE_NAME : "trainfuck") ERR_SYNTAX = 1 + ERR_ARGUMENT = 2 } BEGIN { @@ -46,6 +47,7 @@ BEGIN { ABOARD = 0 FIRST_LINE = 1 OFS = "\t" + header = 0 } BF_MODE == "brainfuck" { @@ -54,14 +56,16 @@ BF_MODE == "brainfuck" { } FIRST_LINE { - if (BF_PRINT_COMMENTS && first_line != "[") { - eprint("[") + if (BF_PRINT_COMMENTS && $0 !~ /^[ \t]\[/) { + eprint("[ ", 1) } - eprint(first_line) FIRST_LINE = 0 } /^ALL ABOARD$/ { + if (NR == 1) { + eprint(ARGV[1] " ", 1) + } if (! header && BF_PRINT_COMMENTS) { eprint("]") } @@ -94,6 +98,7 @@ END { exit dead } printbuf() + print "" if (BF_EXECUTE) { brainfuck(bf_program) } @@ -108,8 +113,11 @@ function brainfuck(buffer) for (n = 1; n < 30000; n++) { tape[n] = 0 } - while (c <= length(bf)) { - # print i, tape[i], c, bf[c] + len_bf = 0 + for (i in bf) { + len_bf++ + } + while (c <= len_bf) { if (bf[c] == "<" && c > 1) { i-- } else if (bf[c] == ">") { @@ -163,10 +171,32 @@ function brainfuck(buffer) } } -function die(message, errnum) +function char2number(ch) +{ + ascii = "" # NUL is undefined in POSIX awk ... XXX: + ascii = ascii "\001\002\003\004\005\006\a\b\t\n\v\f\r\016\017" + ascii = ascii "\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" + ascii = ascii " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO" + ascii = ascii "PQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\177" + ascii = ascii "\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217" + ascii = ascii "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237" + ascii = ascii "\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257" + ascii = ascii "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277" + ascii = ascii "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317" + ascii = ascii "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337" + ascii = ascii "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357" + ascii = ascii "\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377" + # print ch + return index(ascii, ch) +} + +function die(message, errnum, now) { print(message) > "/dev/stderr" dead = errnum + if (now) { + exit errnum + } } function eprint(message, suppress_newline) @@ -177,9 +207,9 @@ function eprint(message, suppress_newline) function getchar() { system("stty raw") - cmd = "dd bs=1 count=1 2>/dev/null" - cmd | getline ch - close(cmd) + chcmd = "dd bs=1 count=1 2>/dev/null" + chcmd | getline ch + close(chcmd) system("stty cooked") return ch } @@ -236,6 +266,11 @@ function process_commandline() BF_MODE = "brainfuck" BF_MODE_FORCE = 1 delete ARGV[a] + } else if (ARGV[a] == "-q" || ARGV[a] == "--quiet") { + BF_OUTPUT = "/dev/null" + delete ARGV[a] + } else if (ARGV[a] ~ /^-/) { + die("Unknown option '" ARGV[a] "'", ERR_ARGUMENT, 1) } } if (! BF_MODE_FORCE) { -- cgit 1.4.1-21-gabe81