false.txt - brcon2024-hackathons - Bitreichcon 2024 Hackathons
(HTM) 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