Today's treat: Thue, pronounced two-ay, after a mathematician named Axel Thue.
Thue is a language based on semi-Thue grammars. semi-Thue grammars are equivalent to Chosmky-0 grammars, except that they're even more confusing: a semi-Thue grammar doesn't distinguish between terminal and non-terminal symbols. (Since Chomsky-0 is equivalent to a turing machine, we know that Thue is turing complete.) The basic idea of it is that a program is a set of rewrite rules that tell you how to convert one string into another. The language itself is incredibly simple; programs written in it are positively mind-warping.
There are two parts to a Thue program. First is a set of grammar rules, which are written in what looks like pretty standard BNF: "<lhs> ::= <rhs>". After that, there is a section which is the initial input string for the program. The two parts are separated by the "::=" symbol by itself on a line.
As I said, the rules are pretty much basic BNF: whatever is on the left-hand side can be replaced with whatever is on the right-hand side of the rule, whenever a matching substring is found. There are two exceptions, for input and output. Any rule whose right hand side is ":::" reads a line of input from the user, and replaces its left-hand-side with whatever it read from the input. And any rule that has "~" after the "::=" prints whatever follows the "~" to standard out.
So, a hello world program:
x ::=~ Hello world::=xPretty simple: the input string is "x"; there's a replacement for "x" which replaces "x" with nothing, and prints out "Hello world".
How about something much more interesting. Adding one in binary. This assumes that the binary number starts off surrounded by underscore characters to mark the beginning and end of a line.
1_::=1++0_::=101++::=1011++::=1++0_0::=__1++::=10//::=:::::=_//_Let's tease that apart a bit.
Let's trace this on a couple of smallish numbers.
Not so hard, eh?
Decrement is the same sort of thing; here's decrement with an argument hardcoded instead of reading from input:
0_::=0--1_::=010--::=0100--::=0--1_1--::=@_0--::=1_0::=::=_1000000000000_Now, something more complicated. From here, a very nicely documented program that computes fibonacci numbers. It's an interesting mess - it converts things into a unary form, does the computation in unary, then converts back. This program uses a fairly neat trick to get comments. Thue doesn't have any comment syntax. But they use "#" on the left hand side as a comment marker, and then make sure that it never appears anywhere else - so none of the comment rules can ever be invoked.
#::= fibnth.t - Print the nth fibonacci number, n input in decimal#::= (C) 2003 Laurent Vogel#::= GPL version 2 or later (http://www.gnu.org/copyleft/gpl.html)#::= Thue info at: http://www.catseye.mb.ca/esoteric/thue/#::= This is modified thue where only foo::=~ outputs a newline.#::= 'n' converts from decimal to unary-coded decimal (UCD).n9::=*********,nn8::=********,nn7::=*******,nn6::=******,nn5::=*****,nn4::=****,nn3::=***,nn2::=**,nn1::=*,nn0::=,nn-::=-#::= '.' prints an UCD number and eats it..*********,::=.~9.********,::=.~8.*******,::=.~7.******,::=.~6.*****,::=.~5.****,::=.~4.***,::=.~3.**,::=.~2.*,::=.~1.,::=.~0~9::=~9~8::=~8~7::=~7~6::=~6~5::=~5~4::=~4~3::=~3~2::=~2~1::=~1~0::=~0#::= messages moving over ',', '*', '|'*<::=<*,<::=<,|<::=<|0>*::=*0>0>,::=,0>0>|::=|0>1>*::=*1>1>,::=,1>1>|::=|1>2>*::=*2>2>,::=,2>2>|::=|2>#::= Decrement n. if n is >= 0, send message '2>';#::= when n becomes negative, we delete the garbage using 'z' and#::= print the left number using '.'.*,-::=,2>,,-::=,-*********,|,-::=zz*::=zz,::=zz|::=.#::= move the left number to the right, reversing it (0 becomes 9, ...)#::= reversal is performed to help detect the need for carry. As the #::= order of rule triggering is undetermined in Thue, a rule matching #::= nine consecutive * would not work.*c<::=c<0>,c<::=c<1>|c<::=2>0>d*::=d1>d::=d*********,#::= when the copy is done, 'd' is at the right place to begin the sum.2>d::=f<|#::= add left to right. 'f' moves left char by char when prompted by a '<'.#::= it tells 'g' to its right what the next char is.*f<::=f*0>,f<::=f,1>#::= when done for this sum, decrement nth.|f<::=-|#::= upon receiving '0>' 'g' drops an 'i' that increments the current digit.0>g::=ig*i::=<,i::=i,*********|i::=<|********,*********#::= '1>' tells 'g' to move left to the next decimal position, #::= adding digit 0 if needed (i.e. nine '*' in reversed UCD)*1>g::=1>g*,1>g::=<g,|1>g::=|<*********g,#::= '2>' tells 'g' that the sum is done. We then prepare for copy (moving #::= a copy cursor 'c' to the correct place at the beginning of the left #::= number) and reverse (using 'j') the right number back.*2>g::=2>g*,2>g::=2>g,|2>g::=c|*********j#::= 'j' reverses the right number back, then leaves a copy receiver 'd'#::= and behind it a sum receiver 'g'.*j*::=jj,*::=,********jj,,::=,*********j,j,|::=<,dg|#::= '?' used to input n?::=:::#::= the initial data is set up, so that after reading n ('?'), converting #::= it to UCD ('n') and decrementing it (-), message '2>' sent by '-' #::= will start when hitting 'g' the first swap + sum cycle#::= for numbers 0 (left) and 1 (reversed, right).::=|n?-|,|********g,|Ok. Now, here's where we go really pathological. Here, in all it's wonderful glory, is a Brainfuck interpreter written in Thue, written by Mr. Frederic van der Plancke. (You can get the original version, with documentation and example programs, along with a Thue interpreter written in Python from here)
#::=# BRAINFUNCT interpreter in THUE#::=# by Frederic van der Plancke; released to the Public Domain.o0::=0oi0::=0io1::=1oi1::=1io]::=]oi]::=]io[::=[oi[::=[ioz::=zooZ::=Zoiz::=ziiZ::=Zi0z::=z01z::=z1]z::=z][z::=z[_z::=z_0Z::=Z01Z::=Z1]Z::=Z][Z::=Z[_Z::=Z_}}]::=}]}&}]::=]&}&]::=]^}[::=[{&[::=[&{&0::=0&&1::=1&}0::=0}{1::=1{?Z[::=[&?z[::=[^?z]::=\]?Z]::=]^[{{::={[{[{\::=\[[\::=[^]{::={]]\::={\]0\::=\01\::=\10{::={01{::={1^[::=?[iii^]::=?]iii}|::=}]|WARN]WARN&|::=&]|WARN]WARNWARN]WARN::=~ERROR: missing ']' in brainfunct program; inserted at end^000::=000^ooo^001::=001^ooi^010::=010^oio^011::=011^oii^100::=100^ioo^101::=101^ioiooo|::=|oooooi|::=|ooioio|::=iio|oiooii|::=|oiiioo|::=|iooioi|::=|ioiiii|::=|iiiiio|!::=||z::=z||Z::=Z|o_::=_oi_::=_i0!::=!01!::=!1_!::=!_/!::=!/oooX!::=XooooooY::=$Y0$::=!11$::=$0X$::=X!1ooiX!::=XooiooiY::=@1Y1@1::=@000@1::=@111@0::=@010@0::=@00X@1::=X!WARNDEC0WARNWARNDEC0WARN::=~WARNING: attempt at decrementing zero (result is still zero)X@00::=X@0X@01::=X!1X@0Y::=X!0YoioX!::=LLYLR0LL::=LL01LL::=LL1_LL::=!X!|LL::=|!0X!LR0::=0LRLR1::=1LRLRY::=_oiiX!::=_oiioiiY::=X!%%0::=0%%1::=1%%_0::=Y0%_1::=Y1%_/::=Y0_/iooX!::=X(in)(in)0::=(in)(in)1::=(in)(in)Y::=Yii/0::=Zi/i/1::=zi/i/_::=!/XY!::=X!0Y0Y!::=0!Y1Y!::=1!YYZ::=0YYz::=1YioiX!::=X(out)(out)0::=0(out)O0(out)1::=1(out)O1(out)Y::=OO!YO0::=~0O1::=~1OO::=~_iiiX!0::=ZX!0iiiX!1::=zX!1+::=000-::=001<::=010>::=011,::=100.::=101:::=|X!0Y0_/::=^* Read the rest of this post... | Read the comments on this post...
Add to del.icio.us
Digg this
Post to Furl
Add to reddit
Add to myYahoo!
Powered by blogdig.net