false.txt - brcon2024-hackathons - Bitreichcon 2024 Hackathons HTML git clone git://bitreich.org/brcon2024-hackathons git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/brcon2024-hackathons DIR Log DIR Files DIR Refs DIR Tags DIR Submodules --- false.txt (21173B) --- 1 2 The FALSE Programming Language 3 4 by Wouter van Oortmerssen 5 6 Manual 7 8 9 WHAT'S NEW in v1.3 10 - lots of new and exciting example source code by lots of people! 11 (have a look in `contrib/' for some amazing code) 12 - documentation in french too 13 - minor fixes and enhancements to the portable interpreter 14 (read comments in the source) 15 - new infos, ftp/www sites etc., read the last chapter 16 17 WHAT'S NEW in v1.1 18 - one bug fix in the 68k version 19 - other example sources (mainly written by Eelko, in the "other" dir.) 20 - Portable False Interpreter/Debugger! 21 (read comments in the source) 22 23 24 +-------------------------------+ 25 | Introduction: | 26 +-------------------------------+ 27 28 The language FALSE and it's compiler were designed for only two reasons: 29 - building a working compiler in just 1k (!) 30 - designing a language that looks cryptic and fuzzy (in the APL tradition) 31 32 the result is a language that is quite powerfull (for it's size). 33 It's a Forth type language with lambda abstraction and lots of other goodies. 34 I named the language after my favourite truthvalue. 35 36 NOTE: a) the compiler as well as the generated code need kickstart v37+ 37 b) You're strongly advised to read this entire manual before 38 trying to operate the compiler. 39 40 +-------------------------------+ 41 | The implementation: | 42 +-------------------------------+ 43 44 To compile a FALSE program, type "false" followed by the source-code 45 name, like: 46 47 1> false helloworld.f 48 49 the compiler produces an executable called "a.out" in the same dir: 50 51 1> a.out 52 Hello, World! 53 1> 54 55 To squeeze the real compilation functions for all language elements in 56 1024 bytes, some things had to go: there are no error messages, and even 57 worse: there are no syntax error checks. Luckily, the language is 58 designed so that it's hard to make compile-time errors. 59 60 the compiler only signals an error in the following events: 61 - it could not allocate memory 62 - it could not read the source file 63 - it could not write the executable 64 - it could not open dos.library (very unlikely) 65 - it found a symbol in the source, which isn't part of the language. 66 67 an error is signalled by returning value 10 instead of 0, it is 68 therefore wise to have your cli-prompt display return values ("%R") 69 70 note: the compiler will start acting weird as soon as you try 71 to compile sources or produce executables >32k 72 73 Working with FALSE 74 ------------------ 75 It is actually possible to write small utilities and stuff in FALSE, 76 and quite powerfull too once you see how to use stacks and lambda 77 functions etc. However, with a minimal compiler like this it's hard to 78 find errors, and I suppose you really have to be a Forth hacker or a 79 hardcore programmer to get the most of it. 80 81 Helloworld in FALSE: 82 -------------------- 83 84 "Hello, World! 85 " 86 87 (yes, that's all...). 88 And this is the fac() function definition in FALSE: 89 90 [$1=$[\%1\]?~[$1-f;!*]?]f: 91 92 (fuzzy eh? we'll explain that later...) 93 94 95 +-------------------------------+ 96 | FALSE: The Language. | 97 +-------------------------------+ 98 99 Format of the language: 100 ----------------------- 101 FALSE sources are totally free-format, i.e you may have any number 102 of tabs/spaces/lf's between two symbols. comments start with "{", 103 end with "}" and may not be nested. 104 105 106 evaluation: 107 ----------- 108 FALSE inherits its way of evaluating expressions from Forth, so it 109 really helps if you know that language, but for those who don't: 110 111 All elements in the language are defined by what they push on and/or 112 pop from the stack. for example, a number like "1" or "100" simply 113 pushes it's own value on the stack. An operator like "+" takes the 114 two top elements of the stack, adds them, and pushes back the result: 115 116 1 2 + 4 * { (1+2)*4 } 117 118 the result of this expression is "12". We will use the notation 119 (<pops>-<pushes>) to signify what a function does, so "1" does (-num) 120 and "+" does (n1,n2-result) 121 122 complex expressions will keep lots of intermediate results on the stack, 123 so mostly there's no need for local variables. FALSE doesn't even 124 have expressions or statements; more likely a program is one stream 125 of symbols that manipulate the stack. It's very helpfull when you 126 can imagine what the stack looks like in a particular part of the program 127 when programming. 128 129 130 elementary functions: 131 --------------------- 132 133 available are: 134 135 "+" "-" "*" "/" "_" 136 137 these function as usual. "_" is the unary minus. 138 139 140 "=" ">" 141 142 these result in 0 (false) or -1 (true) 143 144 unequal is "=~", and smaller than etc. can be made by swapping arguments 145 and/or using "~" 146 147 example: a;1_=~ { a<>-1 } 148 149 150 "&" "|" "~" 151 152 "and", "or" and "not", as usual. 153 154 example: a;0>a;99>~& { (a>0) and (a<100) } 155 156 157 values: 158 ------- 159 160 values are either integers like discussed before ("1", "100" etc.), 161 or characters precede by a quote: 'A (equals 65) (do not mix up with 162 backquote "`" !) 163 note that the 1k parser only parses integers up to 320000, it uses 164 full 32bit representation for them, however. 165 166 167 global variables: 168 ----------------- 169 variables to store values are less needed in FALSE than in other 170 languages. in FALSE they are used mostly for functions, explained 171 below. 172 173 a variable is a character "a" to "z" (just these). 174 ":" is the assignment function, and ";" is contrary: it gets the 175 variable's value: 176 177 1a: { a:=1 } 178 a;1+b: { b:=a+1 } 179 180 i.e: "a;" is used where in other languages you would just write "a" 181 182 all variables (and also stack-items) are 32bits. 183 184 lambda functions: 185 ----------------- 186 a FALSE lambda function is a piece of code between []. for example: 187 188 [1+] 189 190 is a function that adds 1 to it's argument. A function is really defined 191 by what it takes from the stack (in this case the first arg to "+"), and 192 what it puts back, just like builtin functions. Note that FALSE lambda 193 functions are not restricted to just one return value. 194 195 what a [] expression really does, is push the function. this means in 196 practise that it can be given to yet another function as argument etc., 197 just like in functional languages. The symbol "!" is called "apply", 198 and applies a function to it's arguments, for example: 199 200 2[1+]! 201 202 would result in "3" 203 This wouldn't make much sense, since what you really want is define the 204 function once, and then use it all-over. this is easy: 205 206 [1+]i: 207 208 this defines the function "i" (actually, it assigns the function to "i"), 209 so that it can be used simply by applying "i" to it's arguments: 210 211 2i;! 212 213 WARNING: as with all other elements in FALSE, but even more important 214 with functions: the 1k compiler does not check if symbols like 215 "!" really get a function as argument (so "1!" means trouble), 216 the compiler may even crash if you don't balance your [ and ]. 217 218 219 stack functions: 220 ---------------- 221 222 "$" (x-x,x) dup: duplicate topmost stackitem 223 "%" (x-) drop: delete topmost stack item 224 "\" (x1,x2-x2,x1) swap: swap to topmost stack-items. 225 "@" (x,x1,x2-x1,x2,x) rot: rotate 3rd stack item to top. 226 "ø" (n-x) pick: copy n-th item to top (0ø equals $) 227 228 examples: 229 230 1$ equals 1 1 231 1 2% equals 1 232 1 2\ equals 2 1 233 1 2 3@ equals 2 3 1 234 7 8 9 2ø equals 7 8 9 7 235 236 237 control structure: 238 ------------------ 239 FALSE only has an IF and a WHILE. 240 if is "?", and looks like this: (bool,fun-). example: 241 242 a;1=["hello!"]? { if a=1 then print "hello!" } 243 244 the first argument is a boolean value, the second the lambda function 245 to be executed (see below for "") 246 there's no "else", so you'll have to mimic this with a second "?". 247 this can be easily done by copying the truthvalue: 248 249 a;1=$["true"]?~["false"]? 250 251 after the first "?" (wether it's executed or not), a copy of the truthvalue 252 is still on the stack, and we negate it for the else part. 253 Beware that if the first "if" needs arguments on the stack from before 254 the boolean expression, it's top is still the truthvalue. 255 256 While is a "#", and gets two lambda functions as args, one that results in 257 a boolean, and the second as body: 258 259 [a;1=][2f;!]# { while a=1 do f(2) } 260 261 note that with while, if and lambda's, you can build virtually 262 any other control structure. 263 264 265 Input/Output: 266 ------------- 267 watch out: all these are BUFFERED. 268 269 - strings printing: strings simply print themselves. Special: strings in FALSE 270 may contain <lf>'s, that explains why in the helloworld program, the second 271 " is on the next line: 272 273 "Hello, World! 274 " 275 276 - integers: "." prints the topmost stack item as integer value: 277 278 123. { prints string "123" on console } 279 280 - characters: "," 281 282 65, { prints "A" } 283 284 - reading a character from stdin: "^" 285 286 ^ { top stack is char read } 287 288 - flush: "ß" 289 when stdin and stdout are different (i.e. you started your compiled 290 FALSE program with <infile >outfile you will hardly need to flush, however, 291 if you both use "^" and the output operations on the same console, 292 you may need to flush between input and output. 293 "ß" flushes both input and output. 294 295 ß[^$1_=~][,]# { while c:=getc()<>EOF do putc(c) } 296 297 for example, above program copies input to output until eof, 298 so no flushing is needed after every read when used with two 299 files, however: 300 301 "press return:"ß^%ß"continuing..." 302 303 it is, since we get input on the same console as the output. 304 305 306 +-------------------------------+ 307 | Example programming | 308 +-------------------------------+ 309 310 How the $#%! am I going to write a decent program with all this, you may ask. 311 Well, the first barrier one has to take into account, is that FALSE doesn't 312 support any amiga-specific programming, some io-functions is as far as 313 it gets. However, with those, you can create some stunningly compact 314 utilities, for example the FALSE version of the "copy" command we saw above, 315 in just 13 bytes! 316 317 ß[^$1_=~][,]# 318 319 ok, what happens: first recognise the four main parts in this program, 320 we have a flush, then two arguments and then a while. The first [] 321 function is supposed to deliver the boolean for the while: it reads 322 a character, duplicates it, the compares it it with -1 (EOF). at the end 323 of this function, we do not only have a boolean, but also an extra copy 324 of the character we read. This immediately demonstrates a powerfull 325 feature of FALSE: we can have any number of interim-results on the 326 stack. the body of the while loop [,] just prints the character to 327 stdout. 328 Note that if the body is not executed, we leave with a non-empty stack. 329 This is no problem at the end of a program, however, doing this within an 330 iteration would be fatal. 331 332 333 another example of FALSE programming: the fac() function. 334 335 [$1=$[\%1\]?~[$1-f;!*]?]f: 336 337 thus we call fac(6) (=720) like: 338 339 6f;! 340 341 no range checking is done by the "f" function, that is what 342 is done by the fac.f example program. 343 344 Well, how does it work? (does it?) First recognise the f;! within 345 the function implementation: that's the recursion. Let us recall what 346 fac() looks like in a hypotheticall procedural/functional programming 347 language: 348 349 fac(n) = if n=1 then 1 else n*fac(n-1) 350 351 our FALSE code goes just along these lines, only we use two "if"'s (hence 352 the two [] blocks) insteas of one if-then-else. 353 we start with (n-) on the stack: 354 355 $1=$ 356 357 duplicate the n, and compare it with 1, and leave a second truthvalue (t), 358 thus: (n,t,t-) 359 360 [\%1\]? 361 362 first push the [], and after the "if" (=?) we have (n,t-). we won't 363 be needing the lower n anymore, so we swap and drop. then we push the 364 final result "1", and swap it below the truthvalue for the second "if". 365 (1,t-) 366 367 ~[$1-f;!*]? 368 369 we first have to negate the truthvalue, because this is the else part. 370 in the "if"-body, we have just (n-), and we add a "n-1" to that as argument 371 for the recusive call. after f;! we have (n,r-) (r is result of the call), 372 and we simply multiply the two together as result of the whole. 373 374 this may look all awfully complicated, but infact, it isn't. it's 375 just a very different style of programming. once you fully understand 376 it's power, you won't want to live without it :-) 377 378 if by now you haven't understood zip of how FALSE works, this probably 379 isn't the language for you. however, if you got the slightest feeling 380 that some things are getting clear to you, try understanding the examples, 381 and your on your way of becoming a real FALSE programmer ! :-). however, 382 the examples are not heavily commented, as that is considered bad-taste 383 in FALSE (see some section below). 384 385 386 +-------------------------------+ 387 | FALSE wizards corner | 388 +-------------------------------+ 389 390 "Inline assembly" in FALSE: 391 --------------------------- 392 393 one topic has been kept undiscussed (on purpose), and it's the 394 possibility to add assembly code to a FALSE program, to allow it to 395 be extended with custom functions. 396 397 syntax: <integer>` 398 399 any integer value 0..65535 folowed by a backquote. an expression like 400 this causes the a 16bit value to be put directly into the code. 401 A series of backquoted values may allow you a primitive form of 402 inline assembly. for example: 403 404 [8221`29184`9336`4`50510`20142`65338`50510`11008`]a: { allocmem (size-mem) } 405 [8221`8797`9336`4`50510`20142`65326`50510`]f: { freemem (mem,size-) } 406 407 are two assembly functions that allow you to allocate memory 408 from within FALSE (see example alloc.f) 409 410 register conventions: 411 when writing assembly code for use with FALSE, use following registers: 412 413 A6 = dosbase 414 A5 = evaluation stack. use MOVE.L (A5)+,D0 to read a paramenter into D0, 415 and MOVE.L D0,-(A5) to write one. 416 A4 = variables. 0(A4) = a, 4(A4) = b etc. 417 D6 = stdout 418 D5 = stdin 419 420 example code for allocmem/freemem above: 421 422 alloc: move.l (a5)+,d0 423 moveq #0,d1 424 move.l 4.w,a2 425 exg a2,a6 ; we need to restore dosbase later. 426 jsr -198(a6) 427 exg a2,a6 428 move.l d0,-(a5) ; no rts, that's done by [] 429 430 free: move.l (a5)+,d0 ; second argument first! 431 move.l (a5)+,a1 432 move.l 4.w,a2 433 exg a2,a6 434 jsr -210(a6) 435 exg a2,a6 436 437 438 peek/poke: 439 ---------- 440 441 ":" and ";" are operators to read and write variables, but they can be 442 (mis-)used to do arbitrary peek and poking, even array-indexing! 443 (see vcheck.f for an example: we read execbase) 444 445 array indexing and structure reading: 446 if p is a pointer to an array/structure, then: 447 448 p;<index>+; 449 450 reads p[<index>]. 451 452 unfortunately, this way you can only read 32bit values. 453 454 cli arguments: 455 -------------- 456 457 reading files is mostly done with redirection on the commandline, however, 458 for future extensability, a pointer to the command-line arguments is 459 passed in var a. see also "command line tips" below. 460 461 stack: 462 ------ 463 464 you can use the stack as a buffer, and reverse-indexing the values 465 on it with ø. however, the FALSE stack is the lower-half of the normal 466 amigados stack, and thus normally only 2k. You can write programs 467 that need arbitrarily large stack-buffers by increasing the stack 468 size before running. 469 470 command line tips: 471 ------------------ 472 473 - make sure you write an input redirection when testing some 474 programs: if the program simply does "nothing", than the 475 computer is not hung, but it's simply waiting for input. 476 - if you do not write a flush (ß) at the start of a program that 477 processes the input to the output, you will get a <lf> as 478 first input: this is actually the commandline. example: 479 480 a.out blabla <in >out 481 482 then a.out will first read "blabla" as a line, then the contents 483 of "in". 484 485 486 good style: 487 ----------- 488 489 programming in FALSE has a certain kind of taste: it's not easy, but 490 when it works, it works good, and the resulting sources look great. 491 Therefore, it may be tempting to "indent" while-loops in larger 492 programs, but remember: 493 - indentation, spacing and comments are for wimps :-) 494 - real FALSE programmmers: 495 - write dense code 496 - write only very "global" comments. 497 - use the stack intensively, and thus dislike to use variables 498 for other purposes than function definitions. 499 500 501 502 +---------------------------------------+ 503 | FALSE language overview. | 504 +---------------------------------------+ 505 506 syntax: pops: pushes: example: 507 -->top -->top 508 --------------- --------------- --------------- ------------------------------- 509 510 {comment} - - { this is a comment } 511 [code] - function [1+] { (lambda (x) (+ x 1)) } 512 a .. z - varadr a { use a: or a; } 513 integer - value 1 514 'char - value 'A { 65 } 515 num` - - 0` { emitword(0) } 516 517 : n,varadr - 1a: { a:=1 } 518 ; varadr varvalue a; { a } 519 ! function - f;! { f() } 520 521 + n1,n1 n1+n2 1 2+ { 1+2 } 522 - n1,n2 n1-n2 1 2- 523 * n1,n2 n1*n2 1 2* 524 / n1,n2 n1/n2 1 2/ 525 _ n -n 1_ { -1 } 526 527 = n1,n1 n1=n2 1 2=~ { 1<>2 } 528 > n1,n2 n1>n2 1 2> 529 530 & n1,n2 n1 and n2 1 2& { 1 and 2 } 531 | n1,n2 n1 or n2 1 2| 532 ~ n not n 0~ { -1,TRUE } 533 534 $ n n,n 1$ { dupl. top stack } 535 % n - 1% { del. top stack } 536 \ n1,n2 n2,n1 1 2\ { swap } 537 @ n,n1,n2 n1,n2,n 1 2 3@ { rot } 538 ø (alt-o) n v 1 2 1ø { pick } 539 540 541 ? bool,fun - a;2=[1f;!]? 542 { if a=2 then f(1) } 543 # boolf,fun - 1[$100<][1+]# 544 { while a<100 do a:=a+1 } 545 546 . n - 1. { printnum(1) } 547 "string" - - "hi!" { printstr("hi!") } 548 , ch - 10, { putc(10) } 549 ^ - ch ^ { getc() } 550 ß (alt-s) - - ß { flush() } 551 552 553 554 +-----------------------------------------------+ 555 | additional infos & thank you's | 556 +-----------------------------------------------+ 557 558 FALSE was created for fun, just to see how small a compiler I could 559 write while still compiling a relatively powerfull language. 560 The result is even better than I thought: it's great fun to 561 program in FALSE, and it looks even better. 562 563 about the compiler source: note that throughout the program ALL 564 variables reside in registers without saving on the stack! 565 please: don't come and tell me you found a way to reduce 566 the size of the executable by 4 more bytes... I think it's small 567 enough as it is now. 568 569 False has inspired other people to implement similarly perverse 570 languages. Some of them are: 571 572 * "Brainfuck" by Urban Mueller. If you enjoy compilers just because 573 of their lenght, make sure you get a look at the this! (an 574 executable in less than 256 bytes!) [aminet:dev/lang/brainfuck2.lha] 575 This is helloworld: 576 577 >+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.[-]>++++++++[<++++>-] 578 <.#>+++++++++++[<+++++>-]<.>++++++++[<+++>-]<.+++.------.--------.[-]>++++++++[ 579 <++++>-]<+.[-]++++++++++. 580 581 * "Y" by Thomas Fischbacher. Very similar to False (syntax too), yet 582 with some more powerful constructs. Comes with (portable) interpreter 583 in C++ [aminet:dev/lang/Y.lha] 584 585 * "Befunge" by Chris Pressey. Comes with interpreter and debugger in C. 586 Code is different from False, but looks equally beautiful. [bef.zip, 587 have a look at http://www.cats-eye.com/cet/soft/lang/befunge/]. 588 factorial looks like this: 589 590 v 591 >v"Please enter a number (1-16) : "0< 592 ,: >$*99g1-:99p#v_.25*,@ 593 ^_&:1-99p>:1-:!|10 < 594 ^ < 595 596 * "Bloop" by Ben Schaeffer <Yaxman@nesbbx.rain.com>. An as yet unreleased 597 language with features from False (and another pet language of mine, 598 "Yax"). Ben also made a true x86 version of False (by translating the 599 68k code), but I lost the code (silly me). 600 601 602 Steinar Knutsen has been so friendly to set up an FTP site so 603 all you people can put your False related products there! 604 605 ftp://ftp.nvg.unit.no/pub/lang/false/ for the distribution. 606 ftp://ftp.nvg.unit.no/pub/lang/false/src/ for sources not in the 607 distribution. 608 609 610 Chris Pressey has a False homepage at: 611 612 http://www.cats-eye.com/cet/soft/lang/false/ 613 614 615 616 I want to thank the people who contributed sourcecode, 617 among others: 618 619 Ben Schaeffer, Ed Mackey, Eelko de Vos (and the rest of The TU-Delft 620 False Fanclub, Maarten and Rene), Herb Wollman, Lionel Vintenat, 621 Marcel van Kervinck, Peter Bengtsson, Steinar Knutsen, Thomas Fischbacher, 622 and Tomas Partl 623 624 and the many more people that have shown their interest 625 in the language. one of them put it like this: 626 627 #define FLAME ON 628 Dear Mr. Wouter van Oortmerssen, Sir, Bwana! 629 630 We (FORTH enthusiasts of Southern German Banana Republic 631 of Bavaria) are not amused by your FALSE language. 632 633 No Sir, not at all. 634 635 Some of us are still jumping up and down in the coconut tree 636 muttering obscenities like "DUP RECURSE that *@! Oortmerssen!". 637 (Some are say even things like "'Oortmerssen EXECUTE") 638 639 You have had the intention of writing an absolutely cryptic 640 while extreme terse & powerful language. In that you've 641 succeeded marvelously. 642 Yet why, Great Moore! have you taken FORTH for the template? 643 Forth is quite cryptic already, yet you must you render it 644 completely unreadable. In Bavaria this is regarded as a 645 grave public offense, sentenceable to not below of 3 years 646 of pure K&R C programming. You could plead for clemency by 647 pointing out your having introduced the lambda computational 648 concept into FORTH, though. 649 I will grant you that much. 650 651 Donations? who would want to give something for a program that 652 has the size of a bootblock virus? anyway, the only thing I'd 653 like to receive is large and complex FALSE sources (of working 654 applications, of course). Please always put a comment at the 655 top of your source, otherwise you'll give me a hard time guessing 656 if it's FALSE or uuencoded. don't ask me to debug your code, as 657 understanding other peoples FALSE programs is horrible. 658 659 If you want to contact me: 660 661 662 Wouter van Oortmerssen 663 Levendaal 87 664 2311 JG Leiden 665 HOLLAND 666 667 or better if you have access to Email: 668 669 Wouter@mars.let.uva.nl 670 W.v.Oortmerssen@let.uva.nl 671 Oortmers@fwi.uva.nl 672