diff --git a/.gitignore b/.gitignore index 062bbd1..de247ab 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ -references +# references .env +references/processed_visuals diff --git a/references/FORTH_NOTES.csv b/references/FORTH_NOTES.csv new file mode 100644 index 0000000..10c2926 --- /dev/null +++ b/references/FORTH_NOTES.csv @@ -0,0 +1,71 @@ +"Anchor Text","URL" +"Original Inspiration for these notes","https://x.com/Richard6044392/status/1926097042029363270" +"Substack Article","https://edsabode.substack.com/p/onats-kyra-compiled-forths-a-new" +"Wikipedia Page","https://en.wikipedia.org/wiki/Forth_(programming_language)" +"Homepage","https://colorforth.github.io/index.html" +"Forth- The Early Years","https://colorforth.github.io/HOPL.html" +"C2-Wiki: Chuck Moore","https://wiki.c2.com/?ChuckMoore" +"C2-Wiki: colorFORTH","https://wiki.c2.com/?ColorForth" +"cmFORTH","https://github.com/ForthHub/cmFORTH" +"Archived Website","https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/index.html" +"Metaprogramming VAMP in KYRA, a Next-gen Forth-like language --- Onat Türkçüoğlu -- 2025-04-26","https://www.youtube.com/watch?v=J9U_5tjdegY" +"Website - Bit Test Complement","https://onatto.github.io/lang.html" +"Forth Day 2020 - Preview of x64 & ColorForth & SPIR V - Onat","https://www.youtube.com/watch?v=ajZAECYdJvE" +"Jonesforth.git","http://git.annexia.org/?p=jonesforth.git;a=summary" +"jombloforth (x64 Jonesforth)","https://github.com/matematikaadit/jombloforth" +"JonesForth-arm","https://github.com/M2IHP13-admin/JonesForth-arm" +"guitarvydas/forthish","https://github.com/guitarvydas/forthish" +"Smithforth workings","https://youtu.be/9MSJGzYELBA" +"A Forth for x86-64 personal computers","https://dacvs.neocities.org/SF/" +"SmithForth_RISC-V","https://github.com/AndreiDuma/SmithForth_RISC-V" +"2022-08-27 --- NEW LINUX FORTH --- DAVID SMITH","https://youtu.be/a1UWxa2g9Us" +"Starting FORTH","https://www.forth.com/wp-content/uploads/2018/01/Starting-FORTH.pdf" +"THINKING FORTH","https://www.forth.com/wp-content/uploads/2018/11/thinking-forth-color.pdf" +"The Evolution of Forth","https://www.forth.com/resources/forth-programming-language/" +"Website","https://wiki.c2.com" +"c2-for-me","http://marc.tries.fed.wiki/view/c2-for-me/ward.eu.wiki.org/c2-for-me" +"Forth Landing","https://wiki.c2.com/?ForthLanguage" +"Forth Values","https://wiki.c2.com/?ForthValues" +"Website","https://muforth.dev" +"Threaded code","https://muforth.dev/threaded-code/" +"Variations","https://muforth.dev/threaded-code-variations/" +"Literals, ifs, and loops","https://muforth.dev/threaded-code-literals-ifs-and-loops/" +"call versus branch-and-link","https://muforth.dev/call-versus-branch-and-link/" +"Repo","https://github.com/nimblemachines/muforth#under-active-development" +"Bootstrap yourself into conviviality by writing your own Forth","https://vimeo.com/859408" +"Website","https://www.forth.org/svfig/" +"Youtube","https://www.youtube.com/@siliconvalleyforthinterest1736" +"Forth","https://www.taygeta.com/forth.html" +"Website","https://www.ultratechnology.com" +"Building a tiny FORTH for an Arduino UNO in one week","https://www.thanassis.space/miniforth.html" +"J.V. Noble: A Beginners Guide to Forth","https://galileo.phys.virginia.edu/classes/551.jvn.fall01/primer.htm" +"wiki.laptop: Forth Lessons","https://wiki.laptop.org/go/Forth_Lessons" +"Building A Simple Forth Interpreter (in python)","https://peerdh.com/blogs/programming-insights/building-a-simple-forth-interpreter" +"HN post on concatenative language interpreter","https://news.ycombinator.com/item?id=13082825" +"PYCON UK 2017: What I learned building Forth in 64 bit Intel assembly","https://youtu.be/iZ-5rBQS_p4" +"Color","https://github.com/AshleyF/Color/tree/master" +"easyforth","https://github.com/skilldrick/easyforth" +"libforth","https://github.com/howerj/libforth" +"luaforth","https://github.com/vifino/luaforth" +"foth (forth in go)","https://github.com/skx/foth" +"lbForth","https://github.com/larsbrinkhoff/lbForth" +"milliForth","https://github.com/fuzzballcat/milliForth" +"MiniForth","https://github.com/ttsiodras/MiniForth" +"pforth","https://github.com/philburk/pforth" +"StoneKnifeForth","https://github.com/kragen/stoneknifeforth" +"zForth","https://github.com/zevv/zForth" +"Concatenative language","https://concatenative.org/wiki/view/Concatenative%20language" +"A FOUNDATION FOR TYPED CONCATENATIVE LANGUAGES","https://www2.ccs.neu.edu/racket/pubs/dissertation-kleffner.pdf" +"Wikipedia","https://en.wikipedia.org/wiki/Concatenative_programming_language" +"b4 virtual machine","https://github.com/tangentstorm/b4" +"Callisto","https://github.com/callisto-lang/compiler" +"Cognate","https://cognate-lang.github.io" +"deckload","https://github.com/JosephOziel/deckload" +"Factor","https://factorcode.org" +"fiveth","https://github.com/dramforever/fiveth" +"formic","https://formic.id" +"GDForth","https://github.com/yumaikas/GDForth" +"iNet","https://inet.run" +"kcats","https://github.com/skyrod-vactai/kcats" +"kitten","https://kittenlang.org" +"meow5","https://ratfactor.com/meow5/" \ No newline at end of file diff --git a/references/Forth Day 2020 - Preview of x64 & ColorForth & SPIR V - Onat.txt b/references/Forth Day 2020 - Preview of x64 & ColorForth & SPIR V - Onat.txt new file mode 100644 index 0000000..bc4835e --- /dev/null +++ b/references/Forth Day 2020 - Preview of x64 & ColorForth & SPIR V - Onat.txt @@ -0,0 +1,484 @@ +0:00 +you got 10 minutes you're on awesome +0:03 +thank you I'll try to share the screen +0:05 +from the another account because like on +0:07 +that I don't have um I hope you can see +0:10 +it can you see the +0:12 +screen +0:14 +yes okay I I I assume you can see yes +0:17 +you can see the screen so um yes uh my +0:22 +adventure fors actually started back +0:25 +like four years ago and uh I just +0:27 +recently understood for them by just I +0:30 +mean like around uh like three months or +0:33 +something like that like and uh this +0:36 +like this iteration of Fort I I've done +0:39 +like 10 20 fors by now like uh this is +0:42 +like a month old and um yeah this is +0:47 +like this is a uh actually like +0:52 +Fort defined by like inspired by color +0:55 +Fort and uh I first saw it from Timothy +0:59 +lattes and like I really liked it and I +1:01 +uh implemented and I thought like uh I'm +1:05 +I'm very happy with it and um I can like +1:09 +maybe showcase something interesting +1:11 +about the editor like uh I care a lot +1:14 +about like uh programmer comfort so I I +1:18 +sort of um did like an editor from +1:21 +scratch and c and won and like +1:25 +um and like in three like screens uh +1:29 +like there's like this uh x64 assembler +1:33 +and um yeah this this test on the right +1:38 +side that you see it's it's like +1:41 +um generating assembly from uh Define +1:45 +with in this language basically So like +1:50 +um basically some like +1:54 +um oops oh yeah I mean I can maybe +1:57 +showcase the editor I guess the editor +1:59 +is the most interesting part so it it +2:02 +has like uh undo and redo and um it can +2:08 +also yeah can also like tus words um and +2:14 +it doesn't matter if they're like um you +2:18 +can hear me right I assume okay yes yeah +2:23 +yes uh so I can hear you yes great so um +2:29 +I don't know if this is new maybe uh +2:31 +some someone can tell me but like the +2:33 +way I do this look up is not by search +2:36 +but instead when I'm compiling I have +2:39 +another four bytes uh per character for +2:42 +a block um that gives the source +2:46 +location for the currently compiled word +2:49 +and like uh like that it's you can just +2:52 +search right inside this block for uh +2:56 +the next iteration uh I mean the next +2:59 +occurrence of of of that value and then +3:01 +like it it finds the word perfectly +3:03 +which uh I thought would be only +3:05 +possible with uh like binary encoded +3:08 +fors you know with specific like IDs for +3:11 +Words um but yeah I I found that with +3:15 +the simple extension uh like four bytes +3:17 +per character um it's it actually allows +3:22 +to look up that and also go to the +3:23 +definition like uh instantly without uh +3:28 +like making okay a having to +3:30 +about and like um another thing I found +3:34 +like uh interesting was that +3:40 +um like I added a word called this and +3:44 +now it gives me all theur all the +3:46 +calling um it traces the word basically +3:50 +so you can look up all uh execution of +3:54 +this word in order of execution that it +3:58 +happen so it's okay first execute here +4:00 +and then here and then like goes on like +4:03 +this so sort of gives like a um +4:06 +intuition about like what happens in the +4:08 +program without having to execute it or +4:11 +like do like uh print test or whatever +4:14 +like um you know this I mean this this +4:17 +might seem maybe yeah it's it's too fast +4:21 +right uh but uh I hope people get the +4:24 +idea like +4:27 +um so actually another interesting thing +4:31 +is like with Ford I found like because +4:33 +it's so free it's uh we can even go one +4:36 +level up right what is this word getting +4:41 +like where is this word getting called +4:43 +in order and where is that like where is +4:46 +the word that is getting called from is +4:49 +like uh is called right so it gives like +4:53 +oh we're compiling like three times in +4:55 +this like uh we're executing that verbs +4:57 +three times over here one time over here +5:00 +and so on like um basically like a +5:04 +compile time +5:07 +um idea of like what what gets executed +5:11 +um without having to do print like +5:15 +[Music] +5:17 +um I'm really underprepared for this I I +5:21 +use this for to uh like to do games and +5:25 +Graphics uh at least that's what I will +5:27 +use it for um right now I'm compiling +5:30 +spr and um like I got some of this stuff +5:36 +maybe x64 will be much more interesting +5:39 +like the Syntax for the x64 looks like +5:42 +this actually um so there's this like +5:46 +Direction register I'm just going to +5:48 +turn off the examples and I'm going to +5:50 +turn off uh +5:53 +oops turn off spe also so +5:58 +yeah all right +6:01 +so um yeah basically +6:04 +like with with this assem you can just +6:07 +change the direction and like +6:11 +um uh it's it's it was it reads as uh +6:16 +from Ax to BX register let's move uh and +6:20 +unsign which I Define as 32 bits you can +6:23 +change this to Long which makes it like +6:25 +RBX to +6:27 +uh oh wait +6:30 +what okay this is this is somehow broken +6:34 +I'm +6:35 +sorry oh no +6:37 +it's yes yes yes of course not of course +6:40 +yeah it's it's it's exactly I mean you +6:44 +could instead like reading I mean +6:46 +writing from uh RX +6:49 +to register RBX you could uh write to +6:52 +memory RB RBX or uh maybe like have like +6:57 +an offset here uh +7:00 +um or you could even do like s bites +7:05 +like um like S 4 c one c 2 uh C +7:11 +8 uh Al or C with +7:15 +offset so um all of that works and again +7:19 +like with this um like Direction uh like +7:24 +so yeah basically um we can have +7:28 +variables like +7:30 +oh sorry do we have questions or +7:33 +comments Tomatoes I don't know so +7:39 +um yeah or we could do like an add you +7:43 +like unsign ad like long at or bat +7:46 +without having to change like um the +7:50 +registers as we usually do in the +7:52 +assembly so I yeah I um +8:00 +and what +8:01 +else I mean +8:04 +uh yeah there's also jumps and uh what +8:08 +not like um over here that looks like +8:12 +this like labels um I mean this is the +8:15 +x64 assembler um then I also use this to +8:21 +compile like where is it oh +8:26 +sorry Compass per V which is is the um +8:30 +intermediate representation for um +8:32 +shaders in welcome and like um actually +8:37 +I I was expecting x64 to be a lot like +8:41 +um a lot +8:43 +more complicated but turned out +8:46 +to be actually uh a bit more complicated +8:50 +because um I'm also doing things like +8:54 +having like type checked um variables +8:57 +and whatnot in this language it's it's +8:59 +still work can you can you complete that +9:02 +sentence it's not complicated because +9:04 +it's less complicated +9:06 +because oh +9:08 +x64 uh is less complicated because like +9:13 +um x64 is a machine language right uh +9:16 +machine languages are in my opinion +9:19 +easier to compile than like standards +9:21 +which like I can't there has to be like +9:24 +you know a specific order to these like +9:28 +um like definitions inside the standard +9:30 +right like the capability has the +9:32 +capability Ops have to come first and +9:34 +then the type of operations and then uh +9:37 +the uh function deficients and whatnot +9:39 +so instead of just compiling right I had +9:42 +to introduce the concept of like um okay +9:45 +where is that sections yeah there it is +9:48 +uh the concept of sections uh to compile +9:53 +into like a binary with uh multiple +9:55 +sections and then I had to assemble that +9:57 +versus on x64 it's it was like +10:02 +um yeah a lot less complicated when like +10:06 +um I +10:09 +mean yeah apart from a few things +10:15 +um like can you say it in +10:19 +words with like without showing us just +10:21 +your general +10:23 +impression uh general impression +10:26 +regarding what sorry regarding this +10:29 +less complex to use x I'm gonna have to +10:33 +ask you to to wrap it up in the next +10:35 +minute or two and uh perhaps back next +10:40 +month and give us a more uh +10:45 +expanded uh yeah version of this but +10:48 +thank you I appreciate your willingness +10:51 +to +10:52 +present uh I want to encourage you to to +10:55 +uh work something up in a more orderly +10:59 +organized presentation yes yes yes yes +11:02 +this is like completely impris right now +11:05 +and I'm not doing like a good job of it +11:07 +I hope +11:08 +like this looks like St folks would be +11:11 +interested in and uh thank you +11:16 +uh so you want to take another minute or +11:19 +you you done um I I like thanks for +11:24 +listening to this like very um you know +11:28 +okay un share your +11:30 +and we'll move on +11:37 +yes oh maybe one thing one last thing I +11:39 +could showcas is like I just +11:42 +added +11:55 +yes okay +12:02 +hey +12:03 +Masa hi who are you where are you from +12:08 +where are you and uh say something about +12:11 +Force okay +12:13 +well uh I I'm actually joining the +12:17 +meeting from +12:18 +Sunnyville and um I'm pting things uh C4 +12:23 +uh version 2.3 to uh LPC +12:27 +2148 uh board so uh once I'm success +12:30 +successful I'm going to probably present +12:32 +that the my +12:35 +experience that's +12:37 +it that sounds great so uh I noticed +12:42 +that somebody I did not +12:45 +uh Poll for the +12:48 +introductions is this guy uh +12:55 +Moore and +12:57 +uh I was was thinking I would run a +13:00 +YouTube video of the uh Fireside so +13:03 +you're just going to have to uh +13:06 +imagine a YouTube video of a Fireside +13:09 +running for 30 seconds uh while I +13:12 +blather uh because uh I feel that if I +13:16 +try to do that it'll it'll +13:19 +uh it'll cause me it'll kick me off the +13:22 +air again so uh Chuck boore needs to +13:25 +unmute and deliver his fireside chat at +13:28 +this time +13:32 +you diff --git a/references/ForthNotes/A_Forth_for_x86-64_personal_computers.md b/references/ForthNotes/A_Forth_for_x86-64_personal_computers.md new file mode 100644 index 0000000..702095f --- /dev/null +++ b/references/ForthNotes/A_Forth_for_x86-64_personal_computers.md @@ -0,0 +1,322 @@ +# A Forth for x86-64 personal computers + +**Source:** https://dacvs.neocities.org/SF/ + +SmithForth + + +# A Forth for x86-64 personal computers + +``` +David Smith 2022 david.a.c.v.smith@gmail.com +``` + +***New:*** Check out **[Andrei Duma's explanation of SmithForth](https://github.com/AndreiDuma/SmithForth_RISC-V)!** He has implemented in **RISC-V** the machine-code part of SmithForth and more! + +* SmithForth runs on Linux x86-64 systems. +* I believe some other Unix x86-64 systems can run Linux ELF binaries. SmithForth should run on these. +* SmithForth should run on your Windows system if you have installed the Windows Subsystem for Linux. I haven't tried it. + +## SmithForth design + +SmithForth is an implementation of the Forth programming language for x86-64 desktop computers. +SmithForth is a text interpreter that runs in a Linux text console. + +You can use SmithForth as you would use any other standard Forth system. +SmithForth follows the [the Forth standard of 2012](https://forth-standard.org/). +The Forth standard describes some optional word sets concerning features like floating-point arithmetic and dynamic memory allocation that most programmers today would regard as standard, but the Forth community considers optional, perhaps because Forth runs on modest machines like microcontrollers. +SmithForth does not yet have floating-point arithmetic, local variables, or file access. + +When I consider using a programming environment, I expect it to work on my hardware, and I expect it to be concrete and simple as possible. +Good luck finding tools that meet this standard. +So I wrote SmithForth. +Please take a look at the source code and the comments. +SmithForth is implemented in the subroutine-threaded style, which I think is the most straightforward way. +The [Intel manual](https://software.intel.com/content/www/us/en/develop/articles/intel-sdm.html) is our source of information on the x86 architecture. + +We use none of the usual tools from the world of C, not even an assembler. +SmithForth is implemented in two source files: + +1. **[SForth.dmp](SForth220711dmp.txt)** contains a primitive Forth system in 1000 hand-written bytes of annotated machine code. +2. **[system.fs](system220711fs.txt)** contains 1000 lines of system Forth to complete a standard Forth system. + +## How to run SmithForth + +1. ### Combine SForth.dmp and system.fs into one binary file. + + Machine code is converted from a human-readable format "DMP" to binary by `xxd` + (hex dump) `-r` (reverse). + + ``` + $ cut -d'#' -f1 SForth.dmp | xxd -p -r > SForth + $ cat system.fs >> SForth + ``` + + The Forth source text is grafted onto the binary. +2. ### Turn the binary file into a proper executable. + + Grant permission to execute the file on the Linux system. + + ``` + $ chmod +x SForth + ``` + + You should now have a working executable (if your system is similar enough to mine). + + (*Optional:*) + Advanced users might edit the kernel or system.fs. + You must ensure that the ELF segment header entry `p_filesz` contains the number of bytes of the segment that appear in binary file `SForth`. + In my design, that's the whole file, including ELF header, machine code, and system Forth. + We prefer not to count those bytes by hand. + An easy solution is: + 1. Make the binary as above. Don't run the binary yet. + 2. Ask the system for the size of the binary file. + 3. Write the result into field `p_filesz` of `dmqc.dmp`. + 4. Remake the binary. The binary is ready to run. + + My script [make.sh](make220711sh.txt) does these steps automatically: + + ``` + $ ./make.sh # if and only if you modified SForth.dmp or system.fs + ``` +3. ### Run the SmithForth executable. + + You can use SmithForth interactively, or you can feed your program into the standard input stream. + + ``` + $ ./SForth + $ ./SForth < YourProgram.fs + $ cat YourProgram.fs - | ./SForth + ``` + + The last command allows you to use SmithForth interactively after your programs. + +--- + +## Numbers in machines + +If you aren't an experienced programmer, here are some things to know before you read the DMP source file. + +### Hexadecimal + +Numbers in machine-code listings are often written in hexadecimal, +the base-sixteen number system with numerals 0123456789ABCDEF. In +hexadecimal, the nonnegative integers are: +> 0, 1, 2, ..., 9, A, B, C, D, E, F, 10, 11, ..., 1F, 20, ..., FF, 100, 101, ... + +### Bytes + +A byte is eight bits. The eight bits of a byte have 28 different states, +but our alphabet has fewer symbols. Instead we write these +states in base sixteen (=24) using a pair of hexadecimal numerals. The +states of a byte are: +> 00, 01, 02, ..., FE, FF. + +### Binary + +Sometimes we need to convert hexadecimal numbers to and from binary (base 2). +Conveniently, one base is the fourth power of the other, and the conversion +can be done in one-to-four fashion, repeatedly, independently. For example: +> 3E hexadecimal = 0011 1110 binary, + +as 3 = 0011 and E = 1110. +You may see bits of a binary number grouped in various ways. For example, +x86 instruction "sub r/m32, r32" has a ModR/M byte written: +> 11 111 000. + +Bits 11 select an access mode for argument r/m32, and bits 000 select +register EAX for that argument. The middle three bits 111 select +register EDI. To convert this into hexadecimal, we regroup the eight bits: +> 1111 1000 binary = F8 hexadecimal (as 1111 = F and 1000 = 8). + +### Endianness + +In hexadecimal, and in our usual decimal system, numbers with more than one +numeral are written with more significant numerals first: + +* Decimal has hundreds before tens before ones. +* Hexadecimal has two hundred fifty-sixes before sixteens before ones. + +Such systems are *big-endian*. *Little-endian* is the reverse order, with +less significant numerals first. + +### The little-endian x86 + +The x86 architecture is **little-endian in bytes** (that is, little-endian in base 28) ... +> When an integer is moved from a CPU register into memory, for example, the +> least significant byte appears first in memory. + +... but each byte is written as a **big-endian pair** of hexadecimal numerals. +This custom is observed: + +* in Intel's manuals, +* in the output of tools (like xxd) that convert binary files to text, and +* in the input of tools that convert text (like our DMP file) to binary files. + +For example, + +* hexadecimal 12 is eighteen, +* hexadecimal 12 00 is eighteen (= 0012 big-endian), and +* hexadecimal 12 00 00 00 is eighteen (= 00000012 big-endian). + +### Machine arithmetic is modular + +There are infinitely many integers, but digital machines have finitely many states. +Integers processed by the Arithmetic Logic Unit (ALU) of the machine are more aptly +called congruence classes, as the ALU performs modular arithmetic for addition, +subtraction, and multiplication, where the modulus of the congruence relation is a +power of 2, like 28. However, some operations involve a particular representative +of a congruence class. + +Two rules are commonly used to select a representative. They are: + +1. **unsigned**, where the representatives are + > 0, 1, 2, ..., modulus - 1, and +2. **signed**, where the representatives are + > 0, 1, ..., modulus/2 - 1, (*nonnegative*) and + + > -1, -2, ..., modulus/2 (*negative*); + + but the machine has no "minus sign," so instead we use + > modulus - 1, modulus - 2, ..., modulus/2 (*negative*). + +For example, if the modulus is 28, the signed representatives are +> 00, 01, ..., 7F, (nonnegative) +> FF, FE, ..., 80 (negative). + +We can tell negative from nonnegative by the most significant bit. + +* Nonnegatives have most significant bit 0. +* Negatives have most significant bit 1. + +Watch for "unsigned" and "signed" in the Intel manual. + +## Implementing Forth + +If you aren't an experienced Forth programmer, here are some things to know before you read the Forth system file. + +### Conditionals + +Compiling in Forth is simple. The compiler sees a word W, looks it up in the dictionary, +and appends to the body of the current dictionary entry a CALL instruction. The target of +the CALL is the address of the body of the dictionary entry of word W. + +CALL facilitates the use of subroutines, which normally return control to the point in the instruction +stream where CALL occurred. There are other forms of flow control, mainly conditionals +and loops. + +``` +: X ... flag IF ... ( do this if flag is nonzero ) ... THEN ... ; + \ / + -->-- ( skip to THEN if flag is zero ) ---->--- +``` + +Forth has words IF and THEN for conditional execution. They are used in compilation mode. +Normally IF is paired with an instance of THEN later in a word definition. +When the interpreter reaches IF at run time, it examines the number at the top of the stack. +If the number is nonzero, execution continues past IF. +If the number is zero, execution jumps past THEN. + +The microprocessor has flow-control features including jumps and conditional jumps. +The Forth compiler, when it sees IF, might emit a conditional jump. +A likely instruction of this kind in x86 is JZ, jump if zero. JZ has a parameter that +indicates where to jump to, *past THEN* in this case. However, when the compiler +first sees IF, it has not yet seen any THEN. So the plan is: + +1. Upon IF, reserve space in the compiler's output for instruction JZ and produce (push) a reference. +2. Continue compiling as usual. +3. Upon THEN, consume (pop) a reference and finish formulating instruction JZ. + In the Forth standard, this is *resolving a forward reference*. + +Forth implements this plan by using the data stack during compilation: + +* IF ( flag -- ) Compilation: ( -- orig ) ... ; +* THEN ( -- ) Compilation: ( orig -- ) ... ; + +Stack-effect comments like ( bef -- aft ) describe the end of the stack before and after the word is executed. +The LIFO property of the stack allows IF-THEN statements to be nested. + +### Loops + +Forth offers several ways to write loops. +One is BEGIN-WHILE-REPEAT. + +``` + --------------------------------<--------------------------- + / \ +: X ... BEGIN ... flag WHILE ... ( do this if flag is nonzero ) ... REPEAT ... ; + \ / + --->-- ( skip to REPEAT if flag is zero ) ---->---- +``` + +* BEGIN ( -- ) Compilation: ( -- dest ) ... ; +* WHILE ( flag -- ) Compilation: ( dest -- orig dest ) ... ; +* REPEAT ( -- ) Compilation: ( orig dest -- ) + +BEGIN-WHILE-REPEAT is versatile, allowing to exit from the middle of a loop body. +BEGIN-WHILE-REPEAT can emulate other control structures: + +IF-THEN: +: flag BEGIN WHILE ... 0 REPEAT + +IF-ELSE-THEN: +: flag DUP BEGIN WHILE DROP ... 1 0 REPEAT 0= BEGIN WHILE ... 0 REPEAT + +BEGIN-UNTIL: +: BEGIN ... flag 0= WHILE REPEAT + +--- + +## Simpler software + +Here are my opinions and motivations for this project. +**Forth** is a simple programming language that achieved some fame back when personal computers were young. +What else would run on such modest computers? +Nowadays computers and languages are fancy and complex. +I say Forth is still a good choice. Forth is simple enough that we may reason about it and understand it. +Forth provides: + +* features found in most programming languages: + + conditionals (if-else) + + loops + + variables + + user-defined functions +* and more: + + CREATE + + DOES> + +A good system helps us to solve our problems quickly. +Some systems try to be comprehensive. + +Others keep it simple. +SmithForth is small and flat enough that a programmer can understand it all. +SmithForth has only a couple files. +We use none of the usual tools from the world of C. +You might argue that C makes programming simpler by insulating us from the workings of the machine. +I might agree if: + +* in our daily work, we are allowed to focus on a small number of layers, and +* each layer is well documented, + +but this has not been my experience. +C is intentionally vague about the dimensions of machines -- *an irritation the programmer* -- so that programs are portable -- *a feature I never use*. +There is always one kind of machine available, usually x86. +The Intel architecture is fairly well documented, and although the Intel manual is huge, we can find the few parts we need. +For an introduction to x86 machine-language programming (without Forth), please see +[my video series](https://www.youtube.com/playlist?list=PLZCIHSjpQ12woLj0sjsnqDH8yVuXwTy3p) on that topic. + +I can imagine a system that contains its own documentation and C source code and tailors these to the computer on which it is installed in such a way that the user can study them and be unconcerned with other computers. No one does this, as far as I know. + +Forth has been implemented many times. +Some Forths have a small kernel so that the system can be ported easily to other architectures (by implementing only a small number of kernel words in machine code). +But if you want the system to run well, you have to write more machine code anyway, don't you? +My goal with SmithForth is not to stop writing machine code early, but to start writing Forth early. +In SmithForth, our early Forth contains a lot of machine code. + +I believe SmithForth is a good first Forth to learn and a good first programming environment. +The shortened presentation may appeal to mathematicians. + +If you want to know my ideas for the direction of this project, I would like to write extensions so that SmithForth becomes +fast and suitable for scientific computing; +and to add enough features of Lisp, Python, Awk, and Tcl that I wouldn't think to use those languages. +I would like to adapt it to other machines and make it usable without an underlying operating system like Linux. \ No newline at end of file diff --git a/references/ForthNotes/Archived_Website.md b/references/ForthNotes/Archived_Website.md new file mode 100644 index 0000000..ae3a0c4 --- /dev/null +++ b/references/ForthNotes/Archived_Website.md @@ -0,0 +1,380 @@ +# Archived Website + +**Source:** https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/index.html + +``` + + \\\\\\` \\\\\\\\\\`\\\`\\\\\\\\\`\\\\\\\\\` \```\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ + \\\\\ `\\` ``\`\\\\` `\ \ \\`` `\\\` ``\` ``\`\\\\`\\ + `, , o `, ` ` + . .oo.. . . o ... ' .o + OO. ...ooOO..... o . ooOOoooo.. . O o . . + OOOo..OOOOOOOo... ....OOo.... .o..... oOOOOOOOOoooo.... Oo. oO + OOOOOOOOOOOOOOO .Ooo. OOOOo......oo. ..ooOO..OOOOOOOOOO......oo.OOo... ..OOO + OOOOO.OOOOOOo.. oOOOOoo. .OO..OOOOOOOOOOOo.......OOO......OOOOOOOOOOoo.OOOOOO + OOOOOo.OOOOOOOoOOOOOOOOOOO.OOOOOOO|OOOOOOOOOO...||||oo.OOOOOOOOOOOoOOOOOooOOO + ||oooOOOOOOOOOOOOOOOOOOO|||||ooOOOO|OOOOO|||||oooOOOOOO|OOO|OOOOOOOOOOOOOOOOO +. OOO''||''OOOOOOOOOOOO|||||''||''OO|||o|||||||''||OOOOOO''OOO''OOO|||ooooOO|OO . +O OOO ||..||OO||||||||||OOo || ||||||||||||| ||||OO|| |o| ||||||||OO||OOO O +' o| |''|' '' '|' '| | '| | |||| |' '| | |' '|' 'OO ' + ||| || | . . | . || || . | | ||/| | . || |oO || ' | ||||| + /|| || | | | | | || || | | | |//| | | || ||| || ...||.. '|| + //| || | | | | ' || || | | ' |//| | ' || ||| || '''|''' |/ + ///..//../../../..//.../....//../../... ////..//...///..///..///....//.../// + /////////////../////////////.//////////..///////////././///////.///////////// + ////.//.//. ..//...././/. ///////..//////.///.//.... ././//...//..//////// + //.... . ./ /////. ...//. ./////... . ... .. ./.// + .. .. . .// . ... + / +``` + + + +# 20161121 - Index - [RSS](index.rss) + + + + +*TimothyLottes.github.io - Welcome to this Online Blog and Archive.* + +[![](20161114-D.bmp)](20161114-D.bmp) + +**Recently Changed** + +[20161121 - Moving Beyond Rendering With Triangles](20161121.html) +[20161117 - Mechanics of Vulkan SPIR-V Specialization](20161117.html) +[20161114 - Believing in an Image](20161114.html) +[20161113 - Vintage Programming 2](20161113.html) + +**Updates** + +RSS feed is done manually, so only the minimal note that a page was added. +Switched over to using [protonmail.com](https://protonmail.com/) for my email. +To contact me, email TimothyLottes at that domain. +Using [duckduckgo.com](https://duckduckgo.com/) for search personally, +*added the duckduckgo widget to this site for direct site search, but the site is too new to get picked up yet*. +Slowly migrating everything else to this site, +and attempting to restore what I can from prior lost images. + + + +* 190 pages left to sort through on blogger* 60 docs left to sort through on drive + + +**2016** +[20161121 - Moving Beyond Rendering With Triangles](20161121.html) +[20161117 - Mechanics of Vulkan SPIR-V Specialization](20161117.html) +[20161114 - Believing in an Image](20161114.html) +[20161113 - Vintage Programming 2](20161113.html) +[20161112 - Plasma Displays](20161112.html) +[20161109 - CreamTracker](20161109.html) +[20161108 - Linux Link Farm](20161108.html) +[20161105 - Owlboy via CRT](20161105.html) +[20161104 - Is OpenVR Actually Open?](20161104.html) +[20161103 - Game List](20161103.html) +[20161102 - Frequent Web Travels](20161102.html) +[20161101 - Linear Dithering Before Transfer Function](20161101.html) + +[20161031 - FPGA Links](20161031.html) +[20161030 - Demo Tube Mega List](20161030.html) +[20161029 - Program Per Clock](20161029.html) +[20161028 - Rotated View Vs Rotated Sample Grid In Pixel](20161028.html) +[20161027 - FXAA Pixel Width Contrast Reduction](20161027.html) +[20161023 - Sphere Tracing AA](20161023.html) +[20161022 - Variation on Branching Design - Return Only](20161022.html) +[20161018 - Fixed Point Rounding](20161018.html) +[20161017 - Notes from Attempting to Understand FPGA Timing Limits](20161017.html) +[20161016 - Instruction Fetch Optimization](20161016.html) +[20161015 - Atomic Scatter-Only Gather-Free Machines](20161015.html) +[20161014 - Possible Directional Routing Hoplite Variant?](20161014.html) +[20161013 - SymbOS - 8-bit OS Awesome Sause](20161013.html) +[20161012 - Technical Evaluation of Traditional vs New "HDR" Encoding Crossed With Display Capability](20161012.html) +[20161011 - Forth Hardware Thoughts](20161011.html) +[20161005 - Epiphany-V Taped Out](20161005.html) +[20161004 - T4K Try 3](20161004.html) +[20161003 - T4K Try 2](20161003.html) +[20161001 - T4K Try 1](20161001.html) + +[20160921 - Parallel Noise Generation](20160921.html) +[20160912 - The Great MacOS 9](20160912.html) +[20160909 - Thinking "Clearly" About 4K](20160909.html) +[20160908 - Transistor Count Thoughts](20160908.html) +[20160905 - GPU Parking Lot](20160905.html) + +[20160806 - Uber Shader Unrolling](20160806.html) + +[20160731 - Vulkan From Scratch Part 2](20160731.html) +[20160728 - Blink Mechanic for Fast View Switch for VR](20160728.html) +[20160727 - Vulkan - How to Deal With the Layouts of Presentable Images](20160727.html) +[20160726 - On Killing WIN32?](20160726.html) +[20160724 - Simplified Vulkan Rapid Prototyping](20160724.html) +[20160723 - Why Motion Blur Trivially Breaks Tone-Mapping - Part 2](20160723.html) +[20160721 - Why Motion Blur Trivially Breaks Tone-Mapping - Part 1](20160721.html) +[20160720 - Re Twitter: Thoughts on Vulkan Command Buffers](20160720.html) +[20160715 - LED Displays](20160715.html) +[20160706 - Low Cost Branching to Factoring Out Loop Exit Check](20160706.html) +[20160705 - CPU Threading to Hide Pipelining](20160705.html) +[20160704 - Relative Addressing With XOR - Removing an Adder](20160704.html) + +[20160331 - Instant Soft-Reboot to Prior Machine Snapshot](20160331.html) + +[20160127 - Temporal AA Neighborhood Clamp](20160127.html) +[20160126 - Local/Global Dimming, Blooming, Contrast Ratios - CRT/LCD/Plasma/OLED](20160126.html) + +**2015** +[20151222 - Random Holiday 2015](20151222.html) + +[20151123 - Cross-Invocation Data Sharing Portability](20151123.html) +[20151122 - CRT Inventory](20151122.html) +[20151121 - ISA Toolbox](20151121.html) +[20151116 - Mixing Temporal AA and Transparency](20151116.html) +[20151113 - Rethinking the Symbolic Dictionary](20151113.html) + +[20151025 - Finer Points of Living in the Raleigh North Carolina Area](20151025.html) +[20151021 - Thoughts on Minimal Filesystem Design](20151021.html) + +[20150930 - Tonemapping and Slot Mask Simulation](20150930.html) +[20150915 - Bacon Wrapped Sour Cream](20150915.html) +[20150914 - Tearaway Unfolded PS4 on Wega CRT HDTV](20150914.html) +[20150913 - Minimal Operand CPU ISA For IPC](20150913.html) +[20150912 - Self-Correcting Part 2 or Rather a Rant on Why Extreme DoD](20150912.html) +[20150911 - Self-Correcting CPU Pipelines](20150911.html) +[20150910 - September Trip to Iceland](20150910.html) + +[20150829 - Ketogenic Diet Working on Year 2](20150829.html) +[20150828 - Atari Shock Reloaded?](20150828.html) +[20150814 - The Written Word](20150814.html) +[20150810 - 1536-5 : Keys](20150810.html) +[20150809 - 1536-4 : Coloring](20150809.html) + +[20150722 - 1536-3 : Simplify, Repeat](20150722.html) +[20150719 - CRT Shadow Masks vs LCD](20150719.html) +[20150718 - Stochastic 1 Sample/Pixel Lit Fog stills](20150718.html) +[20150715 - 1536-2 : Assembling From the Nothing](20150715.html) +[20150714 - 1536-1 : The Programmer Addiction = Feedback](20150714.html) +[20150713 - Great Tube: Old computers did it better!](20150713.html) +[20150712 - Oh How Programming Has Changed](20150712.html) +[20150710 - Inspiration Reboot](20150710.html) +[20150709 - GPU Unchained ASCII Notes](20150709.html) + +[20150630 - Sugar Free Peppermint Chocolate Chip Custard Ice Cream](20150630.html) +[20150624 - AMD Fury X (aka Fiji) is a Beast of a GPU Compute Platform](20150624.html) +[20150623 - BenQ XL2730Z Blur Reduction vs CRT](20150623.html) +[20150604 - Panasonic CT-34WX59 = Piece of Junk](20150604.html) + +[20150525 - OS Project : 7 - PS/2 and Misc](20150525.html) +[20150522 - The Other Project Cleaned Up](20150522.html) +[20150509 - OS Project : 6 - Hashing](20150509.html) + +[20150430 - The Other Project Getting Wired](20150430.html) +[20150426 - Source-Less Programming : 5](20150426.html) +[20150424 - Source-Less Programming : 4](20150424.html) +[20150423 - Source-Less Programming : 3](20150423.html) +[20150422 - Source-Less Programming : 2](20150422.html) +[20150421 - Look No Triangles : Scatter vs Gather](20150421.html) +[20150420 - From Scratch Bug 2 : Source-Less Programming](20150420.html) +[20150416 - Pixel Art and Slot Mask Pitch](20150416.html) +[20150415 - Indie vs Real Slug Fest](20150415.html) +[20150414 - From Scratch Bug](20150414.html) +[20150406 - End of an Era](20150406.html) +[20150403 - Why I'm Using Fedex From Now On](20150403.html) + +[20150328 - Stills From My Talk](20150328.html) +[20150309 - Quick Thoughts on Strobbed LCD Displays for VR Perf Proxy](20150309.html) +[20150327 - Other CRT Options](20150327.html) +[20150308 - CRTs](20150308.html) + +[20150221 - Great Example of Horrible API Interface Design](20150221.html) +[20150220 - The Order 1886!](20150220.html) + +[20150111 - Leaving Something for the Imagination](20150111.html) + +**2014** +[20141231 - Continued Notes on Custom Language](20141231.html) +[20141223 - Transparency/OIT Thoughts](20141223.html) +[20141211 - AMD64 Assembly Porting Between Linux and Windows](20141211.html) + +[20141010 - The Source of the Strange "Win7" Color Distortion?](20141010.html) +[20141006 - Driving NTSC TV from GTX 880M](20141006.html) + +[20140926 - Post Depth Coverage](20140926.html) +[20140921 - Using GDB Without Source and With Runtime Changing of Code](20140921.html) +[20140920 - Interlacing at High Frame Rates and Low Persistence?](20140920.html) + +[20140830 - HDFury Nano GX: Part 2](20140830.html) +[20140828 - HDFury Nano GX: HDMI to VGA](20140828.html) +[20140826 - Scifi Reading Suggestion List From Twitters](20140826.html) +[20140823 - MinWM](20140823.html) +[20140819 - Scanlines](20140819.html) +[20140816 - Vintage Programming](20140816.html) +[20140814 - HRAA And Coverage and Related Topics](20140814.html) +[20140810 - Front Buffer Rendering](20140810.html) +[20140809 - Strict Aliasing](20140809.html) + +[20140730 - Scanlines and Vintage TVs](20140730.html) +[20140723 - Body Hacking Running on Oil](20140723.html) +[20140717 - Bad Industry Humor: Computer Engineering Hall of Shame](20140717.html) +[20140715 - Infinte Projection Matrix Notes](20140715.html) +[20140712 - VR Topics : Racing Scan-Out + Filtering/Noise](20140712.html) + +[20140627 - CG Anti-Aliasing in 1984](20140627.html) +[20140621 - Filtering and Reconstruction : Points and Filtered Raster Without MSAA](20140621.html) +[20140606 - Easy Understanding of Natural Draw Rate Limiters and The Route To Zero Overhead](20140606.html) + +[20140506 - The Other Project](20140506.html) + +[20140413 - Minimal Single Symbol ELF For Using GL](20140413.html) + +[20140328 - Related to Filtering for VR](20140328.html) + +[20140110 - Portable Read-Only Thumb Linux](20140110.html) +[20140104 - GL Idea Listing](20140104.html) +[20140103 - Killzone Shadow Fall Multiplayer After 50 Hours](20140103.html) + +**2013** +[20131126 - Random Next Generation Notes](20131126.html) + +[20130825 - Modern Memory Mapping](20130825.html) +[20130808 - Runtime Recompile Reloaded](20130808.html) + +[20130707 - Slab Hash](20130707.html) + +[20130524 - AMD GCN GPU Scaling : Tablet To Desktop](20130524.html) + +[20130325 - Understanding WIN32 GetRawInputBuffer()](20130325.html) + +[20130226 - Shader Aliasing and Small Triangles](20130226.html) + +[20130119 - Understanding the Speed of Light of Game Input Latency](20130119.html) + +**2012** +[20121229 - Practical Non-Atomic CPU/GPU Communication](20121229.html) +[20121203 - Simple Custom Web Server Tricks](20121203.html) +[20121202 - Winged Doom: Stealer](20121202.html) + +[20121001 - Linux Distros and Compression](20121001.html) + +[20120903 - Linux Threading Via Syscalls](20120903.html) + +[20120802 - DX Camera Motion from Depth](20120802.html) + +[20120706 - Exposure Render](20120706.html) + +[20120513 - Frame Stutter Reduction Via Time Smoothing](20120513.html) + +[20120414 - Engine Scaling on April 2012 GPUs](20120414.html) + +[20120211 - Old School: Modems](20120211.html) + +**2011** +[20111031 - Exclusive Core Access](20111031.html) + +[20110907 - Parallel Programming With Clones](20110907.html) + +[20110331 - DX11 Tessellation and Level Building Blocks](20110331.html) + +**2010** +[20101005 - MSVC Optimizing Static Constant Data Copy?](20101005.html) +[20101004 - MSVC Optimizing Static Constant Function Tables?](20101004.html) + +[20100108 - AntiPlanet2](20100108.html) +[20100105 - Game Engine Architecture](20100105.html) +[20100104 - OnLive Notes](20100104.html) +[20100102 - PC CPU Task Parallelism Limits](20100102.html) + +**2009** +[20091229 - DirectCompute 3D Fluid Simulation Tube](20091229.html) + +[20090917 - Food-For-Thought Supermarket Aisle](20090917.html) +[20090909 - L1 Misses](20090909.html) + +[20090812 - Stochastic Visibility in Distorted Fisheye](20090812.html) +[20090804 - Aras's Compact Normal Storage](20090804.html) + +[20090728 - Morphological AA Part II](20090728.html) +[20090714 - Hybrid Cached Raycast and Reproject Raster](20090714.html) +[20090710 - Video of Particles via L-System and Stochastic Visibility](20090710.html) +[20090709 - Stochastic Visibility Update](20090709.html) +[20090708 - GPU Ray Traversal Efficiency](20090708.html) +[20090705 - Odd Transparent Rendering Ideas](20090705.html) + +[20090611 - Factoring Out the Job Scheduler](20090611.html) +[20090606 - Thread Scheduling Part 3](20090606.html) +[20090605 - SIMD Binning And Caches](20090605.html) +[20090604 - Thread Scheduling Part 2](20090604.html) +[20090602 - Thread Scheduling Part 1](20090602.html) + +[20090519 - GPU REYES](20090519.html) +[20090513 - Gaussian KD Trees](20090513.html) +[20090506 - Electromagnetic Spectrum and Rendering](20090506.html) +[20090505 - Compute Mega Post](20090505.html) +[20090501 - 32bpp HDR Blending Idea](20090501.html) + +[20090422 - WFA Image Compression](20090422.html) +[20090407 - DXT Tip](20090407.html) + +[20090318 - Reattachable Code](20090318.html) + +[20090110 - Hole Filling](20090110.html) + +**2008** +[20081218 - Reprojection 2](20081218.html) +[20081216 - Reprojection 0](20081216.html) +[20081209 - Atom Updates](20081209.html) + +[20081030 - Parallel Rapid Development Architecture](20081030.html) +[20081020 - Temporal Binned Ring Buffers](20081020.html) +[20081014 - Octahedron Mapping](20081014.html) +[20081010 - Temporal Locality](20081010.html) + +[20080918 - General Purpose](20080918.html) + +[20080709 - Anti-Aliasing](20080709.html) +[20080704 - Micro Polygons II](20080704.html) + +[20080628 - Micro Polygons](20080628.html) + +**2007** +[20071126 - Optimization and More](20071126.html) +[20071121 - Deferred Shading III](20071121.html) +[20071116 - Deferred Shading II](20071116.html) + +[20071026 - Transform Feedback](20071026.html) +[20071025 - Motion Cards](20071025.html) +[20071024 - Geometry Shader Woes](20071024.html) +[20071018 - Cubemap Concepts](20071018.html) +[20071015 - Drawing in Reverse II](20071015.html) + +[20070926 - Drawing in Reverse](20070926.html) +[20070921 - Assembler in Atom4th](20070921.html) +[20070919 - Editor Working](20070919.html) +[20070915 - Building the Chicken Without an Egg](20070915.html) +[20070912 - The Making of a Font](20070912.html) +[20070910 - 2 4th | !2 4th](20070910.html) + +[20070822 - New Pipeline Progress](20070822.html) +[20070819 - High Dynamic Range](20070819.html) +[20070818 - Deferred Fractal Environment Shading](20070818.html) +[20070817 - Videos Update](20070817.html) +[20070816 - CFD Videos](20070816.html) +[20070810 - Graphics Engine Lighting](20070810.html) +[20070809 - Graphics Engine Videos](20070809.html) + +[20070731 - High Resolution Screen Shots](20070731.html) +[20070730 - Computational Fluid Dynamics Code](20070730.html) +[20070715 - Self Healing](20070715.html) +[20070713 - Micro Imposters](20070713.html) +[20070712 - Fragment Raytracer](20070712.html) +[20070711 - Infinite Level of Detail](20070711.html) +[20070710 - Graphics Engine Introduction](20070710.html) +[20070709 - 3D Audio and KEMAR Data](20070709.html) +[20070708 - Breaking Firewalls](20070708.html) +[20070707 - Management Server](20070707.html) +[20070706 - 510 Players on Screen at 128 Kbps](20070706.html) +[20070705 - UDP Player Bandwidth](20070705.html) +[20070704 - Network Latency](20070704.html) +[20070703 - Cost of Bandwidth](20070703.html) +[20070702 - Market Research](20070702.html) + +**2004** +[20040101 - Simple IP Reference](20040101.html) \ No newline at end of file diff --git a/references/ForthNotes/Bootstrap_yourself_into_conviviality_by_writing_your_own_Forth.md b/references/ForthNotes/Bootstrap_yourself_into_conviviality_by_writing_your_own_Forth.md new file mode 100644 index 0000000..3587e3b --- /dev/null +++ b/references/ForthNotes/Bootstrap_yourself_into_conviviality_by_writing_your_own_Forth.md @@ -0,0 +1,23 @@ +# Bootstrap yourself into conviviality by writing your own Forth + +**Source:** https://vimeo.com/859408 + +Bootstrap yourself into conviviality by writing your own Forth + + + + + + + + + + +# Verify to continue + +To continue, please confirm that you're a human (and not a spambot). + +## Checking if the site connection is secure + +vimeo.com needs to review the security of your connection before +proceeding. \ No newline at end of file diff --git a/references/ForthNotes/Building_A_Simple_Forth_Interpreter_in_python.md b/references/ForthNotes/Building_A_Simple_Forth_Interpreter_in_python.md new file mode 100644 index 0000000..2e64942 --- /dev/null +++ b/references/ForthNotes/Building_A_Simple_Forth_Interpreter_in_python.md @@ -0,0 +1,2237 @@ +# Building A Simple Forth Interpreter (in python) + +**Source:** https://peerdh.com/blogs/programming-insights/building-a-simple-forth-interpreter + +Building A Simple Forth Interpreter +– peerdh.com + + +[Skip to content](#MainContent) + +* [Stock Images](/blogs/stock-images) +* [Blogs](/blogs/programming-insights) + +EUR + +Region and language + +Search + +## Country/Region + +No results found* Afghanistan + + AFN + ؋ +* Åland Islands + + EUR + € +* Albania + + ALL + L +* Algeria + + DZD + د.ج +* Andorra + + EUR + € +* Angola + + EUR + € +* Anguilla + + XCD + $ +* Antigua & Barbuda + + XCD + $ +* Argentina + + EUR + € +* Armenia + + AMD + դր. +* Aruba + + AWG + ƒ +* Ascension Island + + SHP + £ +* Australia + + AUD + $ +* Austria + + EUR + € +* Azerbaijan + + AZN + ₼ +* Bahamas + + BSD + $ +* Bahrain + + EUR + € +* Bangladesh + + BDT + ৳ +* Barbados + + BBD + $ +* Belarus + + EUR + € +* Belgium + + EUR + € +* Belize + + BZD + $ +* Benin + + XOF + Fr +* Bermuda + + USD + $ +* Bhutan + + EUR + € +* Bolivia + + BOB + Bs. +* Bosnia & Herzegovina + + BAM + КМ +* Botswana + + BWP + P +* Brazil + + EUR + € +* British Indian Ocean Territory + + USD + $ +* British Virgin Islands + + USD + $ +* Brunei + + BND + $ +* Bulgaria + + EUR + € +* Burkina Faso + + XOF + Fr +* Burundi + + BIF + Fr +* Cambodia + + KHR + ៛ +* Cameroon + + XAF + CFA +* Canada + + CAD + $ +* Cape Verde + + CVE + $ +* Caribbean Netherlands + + USD + $ +* Cayman Islands + + KYD + $ +* Central African Republic + + XAF + CFA +* Chad + + XAF + CFA +* Chile + + EUR + € +* China + + CNY + ¥ +* Christmas Island + + AUD + $ +* Cocos (Keeling) Islands + + AUD + $ +* Colombia + + EUR + € +* Comoros + + KMF + Fr +* Congo - Brazzaville + + XAF + CFA +* Congo - Kinshasa + + CDF + Fr +* Cook Islands + + NZD + $ +* Costa Rica + + CRC + ₡ +* Côte d’Ivoire + + XOF + Fr +* Croatia + + EUR + € +* Curaçao + + ANG + ƒ +* Cyprus + + EUR + € +* Czechia + + CZK + Kč +* Denmark + + DKK + kr. +* Djibouti + + DJF + Fdj +* Dominica + + XCD + $ +* Dominican Republic + + DOP + $ +* Ecuador + + USD + $ +* Egypt + + EGP + ج.م +* El Salvador + + USD + $ +* Equatorial Guinea + + XAF + CFA +* Eritrea + + EUR + € +* Estonia + + EUR + € +* Eswatini + + EUR + € +* Ethiopia + + ETB + Br +* Falkland Islands + + FKP + £ +* Faroe Islands + + DKK + kr. +* Fiji + + FJD + $ +* Finland + + EUR + € +* France + + EUR + € +* French Guiana + + EUR + € +* French Polynesia + + XPF + Fr +* French Southern Territories + + EUR + € +* Gabon + + XOF + Fr +* Gambia + + GMD + D +* Georgia + + EUR + € +* Germany + + EUR + € +* Ghana + + EUR + € +* Gibraltar + + GBP + £ +* Greece + + EUR + € +* Greenland + + DKK + kr. +* Grenada + + XCD + $ +* Guadeloupe + + EUR + € +* Guatemala + + GTQ + Q +* Guernsey + + GBP + £ +* Guinea + + GNF + Fr +* Guinea-Bissau + + XOF + Fr +* Guyana + + GYD + $ +* Haiti + + EUR + € +* Honduras + + HNL + L +* Hong Kong SAR + + HKD + $ +* Hungary + + HUF + Ft +* Iceland + + ISK + kr +* India + + INR + ₹ +* Indonesia + + IDR + Rp +* Iraq + + EUR + € +* Ireland + + EUR + € +* Isle of Man + + GBP + £ +* Israel + + ILS + ₪ +* Italy + + EUR + € +* Jamaica + + JMD + $ +* Japan + + JPY + ¥ +* Jersey + + EUR + € +* Jordan + + EUR + € +* Kazakhstan + + KZT + ₸ +* Kenya + + KES + KSh +* Kiribati + + EUR + € +* Kosovo + + EUR + € +* Kuwait + + EUR + € +* Kyrgyzstan + + KGS + som +* Laos + + LAK + ₭ +* Latvia + + EUR + € +* Lebanon + + LBP + ل.ل +* Lesotho + + EUR + € +* Liberia + + EUR + € +* Libya + + EUR + € +* Liechtenstein + + CHF + CHF +* Lithuania + + EUR + € +* Luxembourg + + EUR + € +* Macao SAR + + MOP + P +* Madagascar + + EUR + € +* Malawi + + MWK + MK +* Malaysia + + MYR + RM +* Maldives + + MVR + MVR +* Mali + + XOF + Fr +* Malta + + EUR + € +* Martinique + + EUR + € +* Mauritania + + EUR + € +* Mauritius + + MUR + ₨ +* Mayotte + + EUR + € +* Mexico + + EUR + € +* Moldova + + MDL + L +* Monaco + + EUR + € +* Mongolia + + MNT + ₮ +* Montenegro + + EUR + € +* Montserrat + + XCD + $ +* Morocco + + MAD + د.م. +* Mozambique + + EUR + € +* Myanmar (Burma) + + MMK + K +* Namibia + + EUR + € +* Nauru + + AUD + $ +* Nepal + + NPR + Rs. +* Netherlands + + EUR + € +* New Caledonia + + XPF + Fr +* New Zealand + + NZD + $ +* Nicaragua + + NIO + C$ +* Niger + + XOF + Fr +* Nigeria + + NGN + ₦ +* Niue + + NZD + $ +* Norfolk Island + + AUD + $ +* North Macedonia + + MKD + ден +* Norway + + EUR + € +* Oman + + EUR + € +* Pakistan + + PKR + ₨ +* Palestinian Territories + + ILS + ₪ +* Panama + + USD + $ +* Papua New Guinea + + PGK + K +* Paraguay + + PYG + ₲ +* Peru + + PEN + S/ +* Philippines + + PHP + ₱ +* Pitcairn Islands + + NZD + $ +* Poland + + PLN + zł +* Portugal + + EUR + € +* Qatar + + QAR + ر.ق +* Réunion + + EUR + € +* Romania + + RON + Lei +* Russia + + EUR + € +* Rwanda + + RWF + FRw +* Samoa + + WST + T +* San Marino + + EUR + € +* São Tomé & Príncipe + + STD + Db +* Saudi Arabia + + SAR + ر.س +* Senegal + + XOF + Fr +* Serbia + + RSD + РСД +* Seychelles + + EUR + € +* Sierra Leone + + SLL + Le +* Singapore + + SGD + $ +* Sint Maarten + + ANG + ƒ +* Slovakia + + EUR + € +* Slovenia + + EUR + € +* Solomon Islands + + SBD + $ +* Somalia + + EUR + € +* South Africa + + EUR + € +* South Georgia & South Sandwich Islands + + GBP + £ +* South Korea + + KRW + ₩ +* South Sudan + + EUR + € +* Spain + + EUR + € +* Sri Lanka + + LKR + ₨ +* St. Barthélemy + + EUR + € +* St. Helena + + SHP + £ +* St. Kitts & Nevis + + XCD + $ +* St. Lucia + + XCD + $ +* St. Martin + + EUR + € +* St. Pierre & Miquelon + + EUR + € +* St. Vincent & Grenadines + + XCD + $ +* Sudan + + EUR + € +* Suriname + + EUR + € +* Svalbard & Jan Mayen + + EUR + € +* Sweden + + SEK + kr +* Switzerland + + CHF + CHF +* Taiwan + + TWD + $ +* Tajikistan + + TJS + ЅМ +* Tanzania + + TZS + Sh +* Thailand + + THB + ฿ +* Timor-Leste + + USD + $ +* Togo + + XOF + Fr +* Tokelau + + NZD + $ +* Tonga + + TOP + T$ +* Trinidad & Tobago + + TTD + $ +* Tristan da Cunha + + GBP + £ +* Tunisia + + EUR + € +* Türkiye + + EUR + € +* Turkmenistan + + EUR + € +* Turks & Caicos Islands + + USD + $ +* Tuvalu + + AUD + $ +* U.S. Outlying Islands + + USD + $ +* Uganda + + UGX + USh +* Ukraine + + UAH + ₴ +* United Arab Emirates + + AED + د.إ +* United Kingdom + + GBP + £ +* United States + + USD + $ +* Uruguay + + UYU + $U +* Uzbekistan + + UZS + so'm +* Vanuatu + + VUV + Vt +* Vatican City + + EUR + € +* Venezuela + + USD + $ +* Vietnam + + VND + ₫ +* Wallis & Futuna + + XPF + Fr +* Western Sahara + + MAD + د.م. +* Yemen + + YER + ﷼ +* Zambia + + EUR + € +* Zimbabwe + + USD + $ + + + + +* More + +- [Stock Images](/blogs/stock-images) +- [Blogs](/blogs/programming-insights) +- More + +[peerdh.com](/) + +Open region and language selector +EUR + +Search + +## Country/Region + +No results found* Afghanistan + + AFN + ؋ +* Åland Islands + + EUR + € +* Albania + + ALL + L +* Algeria + + DZD + د.ج +* Andorra + + EUR + € +* Angola + + EUR + € +* Anguilla + + XCD + $ +* Antigua & Barbuda + + XCD + $ +* Argentina + + EUR + € +* Armenia + + AMD + դր. +* Aruba + + AWG + ƒ +* Ascension Island + + SHP + £ +* Australia + + AUD + $ +* Austria + + EUR + € +* Azerbaijan + + AZN + ₼ +* Bahamas + + BSD + $ +* Bahrain + + EUR + € +* Bangladesh + + BDT + ৳ +* Barbados + + BBD + $ +* Belarus + + EUR + € +* Belgium + + EUR + € +* Belize + + BZD + $ +* Benin + + XOF + Fr +* Bermuda + + USD + $ +* Bhutan + + EUR + € +* Bolivia + + BOB + Bs. +* Bosnia & Herzegovina + + BAM + КМ +* Botswana + + BWP + P +* Brazil + + EUR + € +* British Indian Ocean Territory + + USD + $ +* British Virgin Islands + + USD + $ +* Brunei + + BND + $ +* Bulgaria + + EUR + € +* Burkina Faso + + XOF + Fr +* Burundi + + BIF + Fr +* Cambodia + + KHR + ៛ +* Cameroon + + XAF + CFA +* Canada + + CAD + $ +* Cape Verde + + CVE + $ +* Caribbean Netherlands + + USD + $ +* Cayman Islands + + KYD + $ +* Central African Republic + + XAF + CFA +* Chad + + XAF + CFA +* Chile + + EUR + € +* China + + CNY + ¥ +* Christmas Island + + AUD + $ +* Cocos (Keeling) Islands + + AUD + $ +* Colombia + + EUR + € +* Comoros + + KMF + Fr +* Congo - Brazzaville + + XAF + CFA +* Congo - Kinshasa + + CDF + Fr +* Cook Islands + + NZD + $ +* Costa Rica + + CRC + ₡ +* Côte d’Ivoire + + XOF + Fr +* Croatia + + EUR + € +* Curaçao + + ANG + ƒ +* Cyprus + + EUR + € +* Czechia + + CZK + Kč +* Denmark + + DKK + kr. +* Djibouti + + DJF + Fdj +* Dominica + + XCD + $ +* Dominican Republic + + DOP + $ +* Ecuador + + USD + $ +* Egypt + + EGP + ج.م +* El Salvador + + USD + $ +* Equatorial Guinea + + XAF + CFA +* Eritrea + + EUR + € +* Estonia + + EUR + € +* Eswatini + + EUR + € +* Ethiopia + + ETB + Br +* Falkland Islands + + FKP + £ +* Faroe Islands + + DKK + kr. +* Fiji + + FJD + $ +* Finland + + EUR + € +* France + + EUR + € +* French Guiana + + EUR + € +* French Polynesia + + XPF + Fr +* French Southern Territories + + EUR + € +* Gabon + + XOF + Fr +* Gambia + + GMD + D +* Georgia + + EUR + € +* Germany + + EUR + € +* Ghana + + EUR + € +* Gibraltar + + GBP + £ +* Greece + + EUR + € +* Greenland + + DKK + kr. +* Grenada + + XCD + $ +* Guadeloupe + + EUR + € +* Guatemala + + GTQ + Q +* Guernsey + + GBP + £ +* Guinea + + GNF + Fr +* Guinea-Bissau + + XOF + Fr +* Guyana + + GYD + $ +* Haiti + + EUR + € +* Honduras + + HNL + L +* Hong Kong SAR + + HKD + $ +* Hungary + + HUF + Ft +* Iceland + + ISK + kr +* India + + INR + ₹ +* Indonesia + + IDR + Rp +* Iraq + + EUR + € +* Ireland + + EUR + € +* Isle of Man + + GBP + £ +* Israel + + ILS + ₪ +* Italy + + EUR + € +* Jamaica + + JMD + $ +* Japan + + JPY + ¥ +* Jersey + + EUR + € +* Jordan + + EUR + € +* Kazakhstan + + KZT + ₸ +* Kenya + + KES + KSh +* Kiribati + + EUR + € +* Kosovo + + EUR + € +* Kuwait + + EUR + € +* Kyrgyzstan + + KGS + som +* Laos + + LAK + ₭ +* Latvia + + EUR + € +* Lebanon + + LBP + ل.ل +* Lesotho + + EUR + € +* Liberia + + EUR + € +* Libya + + EUR + € +* Liechtenstein + + CHF + CHF +* Lithuania + + EUR + € +* Luxembourg + + EUR + € +* Macao SAR + + MOP + P +* Madagascar + + EUR + € +* Malawi + + MWK + MK +* Malaysia + + MYR + RM +* Maldives + + MVR + MVR +* Mali + + XOF + Fr +* Malta + + EUR + € +* Martinique + + EUR + € +* Mauritania + + EUR + € +* Mauritius + + MUR + ₨ +* Mayotte + + EUR + € +* Mexico + + EUR + € +* Moldova + + MDL + L +* Monaco + + EUR + € +* Mongolia + + MNT + ₮ +* Montenegro + + EUR + € +* Montserrat + + XCD + $ +* Morocco + + MAD + د.م. +* Mozambique + + EUR + € +* Myanmar (Burma) + + MMK + K +* Namibia + + EUR + € +* Nauru + + AUD + $ +* Nepal + + NPR + Rs. +* Netherlands + + EUR + € +* New Caledonia + + XPF + Fr +* New Zealand + + NZD + $ +* Nicaragua + + NIO + C$ +* Niger + + XOF + Fr +* Nigeria + + NGN + ₦ +* Niue + + NZD + $ +* Norfolk Island + + AUD + $ +* North Macedonia + + MKD + ден +* Norway + + EUR + € +* Oman + + EUR + € +* Pakistan + + PKR + ₨ +* Palestinian Territories + + ILS + ₪ +* Panama + + USD + $ +* Papua New Guinea + + PGK + K +* Paraguay + + PYG + ₲ +* Peru + + PEN + S/ +* Philippines + + PHP + ₱ +* Pitcairn Islands + + NZD + $ +* Poland + + PLN + zł +* Portugal + + EUR + € +* Qatar + + QAR + ر.ق +* Réunion + + EUR + € +* Romania + + RON + Lei +* Russia + + EUR + € +* Rwanda + + RWF + FRw +* Samoa + + WST + T +* San Marino + + EUR + € +* São Tomé & Príncipe + + STD + Db +* Saudi Arabia + + SAR + ر.س +* Senegal + + XOF + Fr +* Serbia + + RSD + РСД +* Seychelles + + EUR + € +* Sierra Leone + + SLL + Le +* Singapore + + SGD + $ +* Sint Maarten + + ANG + ƒ +* Slovakia + + EUR + € +* Slovenia + + EUR + € +* Solomon Islands + + SBD + $ +* Somalia + + EUR + € +* South Africa + + EUR + € +* South Georgia & South Sandwich Islands + + GBP + £ +* South Korea + + KRW + ₩ +* South Sudan + + EUR + € +* Spain + + EUR + € +* Sri Lanka + + LKR + ₨ +* St. Barthélemy + + EUR + € +* St. Helena + + SHP + £ +* St. Kitts & Nevis + + XCD + $ +* St. Lucia + + XCD + $ +* St. Martin + + EUR + € +* St. Pierre & Miquelon + + EUR + € +* St. Vincent & Grenadines + + XCD + $ +* Sudan + + EUR + € +* Suriname + + EUR + € +* Svalbard & Jan Mayen + + EUR + € +* Sweden + + SEK + kr +* Switzerland + + CHF + CHF +* Taiwan + + TWD + $ +* Tajikistan + + TJS + ЅМ +* Tanzania + + TZS + Sh +* Thailand + + THB + ฿ +* Timor-Leste + + USD + $ +* Togo + + XOF + Fr +* Tokelau + + NZD + $ +* Tonga + + TOP + T$ +* Trinidad & Tobago + + TTD + $ +* Tristan da Cunha + + GBP + £ +* Tunisia + + EUR + € +* Türkiye + + EUR + € +* Turkmenistan + + EUR + € +* Turks & Caicos Islands + + USD + $ +* Tuvalu + + AUD + $ +* U.S. Outlying Islands + + USD + $ +* Uganda + + UGX + USh +* Ukraine + + UAH + ₴ +* United Arab Emirates + + AED + د.إ +* United Kingdom + + GBP + £ +* United States + + USD + $ +* Uruguay + + UYU + $U +* Uzbekistan + + UZS + so'm +* Vanuatu + + VUV + Vt +* Vatican City + + EUR + € +* Venezuela + + USD + $ +* Vietnam + + VND + ₫ +* Wallis & Futuna + + XPF + Fr +* Western Sahara + + MAD + د.م. +* Yemen + + YER + ﷼ +* Zambia + + EUR + € +* Zimbabwe + + USD + $ + + + + + + + + + + + + + + + + + +Account + +[Other sign in options + +Sign in](/customer_authentication/login?return_to=%2Fblogs%2Fprogramming-insights%2Fbuilding-a-simple-forth-interpreter&locale=en&ui_hint=full) + +* [Orders](/account) +* [Profile](/account/addresses) + + + + + + + + + + + + + + +Account + +[Other sign in options + +Sign in](/customer_authentication/login?return_to=%2Fblogs%2Fprogramming-insights%2Fbuilding-a-simple-forth-interpreter&locale=en&ui_hint=full) + +* [Orders](/account) +* [Profile](/account/addresses) + + + + + + + + + +Total items in cart: 0 + +0 + + + +Your cart is empty + +Have an account? [Log in](https://peerdh.com/customer_authentication/redirect?locale=en®ion_country=NL) to check out faster. + +[Continue shopping](/collections/all) + +# Building A Simple Forth Interpreter + +Creating a Forth interpreter from scratch can be a rewarding experience. Forth is a stack-based programming language that emphasizes simplicity and efficiency. It is unique because it allows you to define new words (functions) easily, making it a great choice for embedded systems and low-level programming. This article will guide you through the process of building a simple Forth interpreter. + +## Understanding Forth Basics + +Forth operates on a stack, where data is pushed and popped. The language uses postfix notation, meaning operators follow their operands. For example, to add two numbers, you would write: + +``` +3 4 + +``` + +This pushes 3 and 4 onto the stack, then applies the `+` operator. The result, 7, remains on the stack. + +### Forth Basics + +## Setting Up the Environment + +Before writing the interpreter, you need a programming environment. You can use any language, but Python is a good choice for its readability. Start by creating a new Python file named `forthand.py`. + +### Basic Structure + +Begin by defining the main structure of your interpreter. You will need a stack to hold values and a dictionary to store defined words. + +``` +class Forth: + def __init__(self): + self.stack = [] + self.words = {} + + def run(self, command): + for token in command.split(): + self.execute(token) + + def execute(self, token): + # Execution logic will go here + pass +``` + +### Setting Up + +## Implementing Stack Operations + +Next, implement basic stack operations: `push`, `pop`, and `add`. These operations will be the foundation of your interpreter. + +``` +def push(self, value): + self.stack.append(value) + +def pop(self): + if not self.stack: + raise Exception("Stack underflow") + return self.stack.pop() + +def add(self): + b = self.pop() + a = self.pop() + self.push(a + b) +``` + +### Stack Operations + +## Defining Words + +Forth allows you to define new words. This is done by adding them to the dictionary. Here’s how to implement a simple word definition. + +``` +def define_word(self, name, definition): + self.words[name] = definition + +def execute(self, token): + if token.isdigit(): + self.push(int(token)) + elif token in self.words: + self.words[token]() + elif token == '+': + self.add() + else: + raise Exception(f"Unknown command: {token}") +``` + +### Defining Words + +## Handling Input + +Now, you need to handle user input. You can create a simple loop that reads commands from the user. + +``` +def repl(self): + while True: + command = input("> ") + if command == "exit": + break + self.run(command) +``` + +### Handling Input + +## Putting It All Together + +Now that you have the basic components, you can put everything together. Here’s the complete code for your Forth interpreter. + +``` +class Forth: + def __init__(self): + self.stack = [] + self.words = {} + + def run(self, command): + for token in command.split(): + self.execute(token) + + def execute(self, token): + if token.isdigit(): + self.push(int(token)) + elif token in self.words: + self.words[token]() + elif token == '+': + self.add() + else: + raise Exception(f"Unknown command: {token}") + + def push(self, value): + self.stack.append(value) + + def pop(self): + if not self.stack: + raise Exception("Stack underflow") + return self.stack.pop() + + def add(self): + b = self.pop() + a = self.pop() + self.push(a + b) + + def define_word(self, name, definition): + self.words[name] = definition + + def repl(self): + while True: + command = input("> ") + if command == "exit": + break + self.run(command) + +if __name__ == "__main__": + forth = Forth() + forth.repl() +``` + +## Testing Your Interpreter + +After implementing the interpreter, it’s time to test it. Run your script and try some commands: + +``` +> 3 4 + +> 5 6 + +> 10 2 + +``` + +You should see the results on the stack. If you want to define a new word, you can extend the interpreter further. + +## Conclusion + +Building a Forth interpreter is a great way to understand stack-based programming and language design. You can expand this interpreter by adding more operations, error handling, and even file input. The simplicity of Forth makes it an excellent choice for learning about interpreters and programming languages. + +### Author - [LinkedIn LinkedIn](https://www.linkedin.com/in/peerdh/) - [GitHub GitHub](https://github.com/birdhouses) + +## 1 comment + +You could’ve implemented + as a word. I don’t think you could call this a Forth, it’s a RPN calculator. It’s missing conditionals and loops. + +Martyn Buttersmere +• +May 31, 2025 + +## Leave a comment + +Name + +Email + +Message + +Post comment + +[View my Adobe Stock](https://stock.adobe.com/nl/contributor/212241211/Peer) + +## Related + + + + +Learn + +Learn + +* [Stock Images](/blogs/stock-images) +* [Blogs](/blogs/programming-insights) + +### Sign up for our newsletter + +Email + +peerdh.com + +* [Privacy policy](/policies/privacy-policy) +* [Contact information](/policies/contact-information) + + + + + + + + + + +Search + + + + + + + + + +Clear + +No results found. + +View all \ No newline at end of file diff --git a/references/ForthNotes/Building_a_tiny_FORTH_for_an_Arduino_UNO_in_one_week.md b/references/ForthNotes/Building_a_tiny_FORTH_for_an_Arduino_UNO_in_one_week.md new file mode 100644 index 0000000..3cd6e81 --- /dev/null +++ b/references/ForthNotes/Building_a_tiny_FORTH_for_an_Arduino_UNO_in_one_week.md @@ -0,0 +1,291 @@ +# Building a tiny FORTH for an Arduino UNO in one week + +**Source:** https://www.thanassis.space/miniforth.html + +Building a tiny FORTH for an Arduino UNO in one week + + +Building a tiny FORTH for an Arduino UNO in one week + +*(July 2021)* + +[![Fork me on GitHub](forkme_right_darkblue_121621.png)](https://github.com/ttsiodras/MiniForth/) + +It was raining hard, a week ago. + +And what could you possibly do on a rainy Saturday afternoon? + +Well... I was inspired by [a series of articles on Hackaday](https://hackaday.com/2017/01/27/forth-the-hackers-language/) to... + +*...make a Forth interpreter/compiler from scratch... +...then put it inside a 1.5$ Blue Pill microcontroller... +...then repeatedly squash it until it fits inside an Arduino UNO... +...i.e. inside 2K of RAM!* + +I haven't done anything even *remotely* close to this in decades. +I *loved* building it :-) + +The rainy afternoon turned into a week-long hackfest *(was looking +forward every day to the post-work FORTH-tinkering in the afternoon...)* + +The result: [a tiny, mini-Forth](https://github.com/ttsiodras/MiniForth/). In portable C++ :-) +It has... + +* basic arithmetic +* star-slash (double-word accurate muldiv) +* literals +* constants +* variables +* direct memory access +* string printing +* reseting +* comments +* nested DO/LOOP +* comparisons +* nested IF/ELSE/THEN +* ...and of course, functions (Forth words) + +Here's a recording of it in action: + +...and another one, where a small Forth program blinks the Arduino LED: + +# ArduinoSTL and Valgrind / AddressSanitizer checks + +I meant it when I said "portable" - the [source code](https://github.com/ttsiodras/MiniForth/) +compiles as-is for both native and Arduino builds. + +Another part of my reasoning was that +in addition to targeting multiple platforms (e.g. BluePill and +Arduino) I wanted to be able to use Valgrind and AddressSanitizer +to detect - in the host! - any issues I have with my memory handling. +And just as important, debugging with GDB in the native host is much easier/faster. + +Since I had embedded targets in mind, I tried ArduinoSTL - but it was too +wasteful memory-wise. It also made the build process significantly slower. +I therefore built my own [memory pool, as well as list, tuple and string-like C++ templates](https://github.com/ttsiodras/MiniForth/tree/master/src/mini_stl.h). It was a nice challenge, re-inventing a tiny C++ STL... + +And I understand STL a lot better now, after building small pieces of it myself :-) + +# Simulation / Debugging + +I setup simulation via [simavr](https://github.com/buserror/simavr.git). +This tremendously improved my developing speed, since a simulator +spawns and runs much faster than the real board. Due to the code +being portable, debugging took place mostly in the host GDB; +and after Valgrind and AddressSanitizer gave their blessing, I usually +found out that the simulator (and the real board) worked fine as well. + +# BluePill vs Arduino UNO + +Thanks to ArduinoSTL, I quickly reached the point of running inside the BluePill. The 1.5$ mini-monster has 10 times more SRAM than an Arduino UNO; +so in a couple of days, I had a [working branch](https://github.com/ttsiodras/MiniForth/tree/BluePill-STM32F103C). + +![Before the Arduino UNO, I run my mini-FORTH inside the 1.5$ Blue Pill](BluePill.jpg) + +*Before the Arduino UNO, I run my mini-FORTH inside the 1.5$ Blue Pill* + +But as said above, that wasn't nearly enough to make it work in my +Arduino UNO. That required far more work *(see below)*. + +As for the BluePill, I should note that, as in all my other embedded targets, +I prefer a development workflow that is based on normal bootloaders +*(not on programmers)*. I therefore burned the +[stm32duino](https://github.com/rogerclarkmelbourne/STM32duino-bootloader) +bootloader on the BluePill, which allowed me to easily program it +in subsequent iterations via the USB connection (and a simple `make upload`). + +The same USB connection would then function as a serial port immediately +afterwards - allowing me to interact with the newly uploaded Forth in the +BluePill. + +The screenshot below is from a `tmux`: on the left, the output from `make upload`; +and on the right, I used `picocom` to interact with my mini-Forth +over the serial port: + +![Compiling, uploading and testing](itworks.jpg) +*Compiling, uploading and testing* + +# Memory - the final frontier + +That covered the first two days. + +But when I tried compiling for the Arduino UNO, I realised that the ArduinoSTL +was not enough. I run out of memory... + +So I built my own [mini-STL](https://github.com/ttsiodras/MiniForth/tree/master/src/mini_stl.h), +and tightly controlled *all* memory utilisation. + +I also used macro-magic to move all strings to Flash at compile-time +(see `dprintf` in the code)... And saved memory everywhere I could, +re-using error messages across various operations - and storing the +entire array of native operations in Flash. + +Nothing flexes your coding muscles as much as optimising; whether it is +for speed or for space. See the implementation of ".S" for example, +where the (obvious) stack reversal code is also the most wasteful... +Changing it to a slower but memory-preserving algorithm allowed me +to use ".S" even when almost all my memory is full. + +# C++ vs C + +I know that many developers hate C++. I even wrote a +[blog post](cpp.html) about it. + +And I understand why - they see code like this... + +``` +#include "mini_stl.h" + +template +typename forward_list::box *forward_list::_freeList = NULL; +``` + +...and they start screaming - "what the hell is that", "incomprehensible +madness", etc. + +But there are very important benefits in using C++ - and templates +in particular. You write less code, with no additional run-time or +memory overhead compared to C, and with a lot more compile-time checks +that watch your back (for things that would otherwise blow up in your face). + +See my Optional for example, that emulates (badly) the optional +type of Rust/OCaml/F#/Scala/Kotlin etc. It **forces** you to check +your returned error codes: + +``` +Optional Forth::needs_a_number(const __FlashStringHelper *msg) +{ + if (_stack.empty()) + return error(emptyMsgFlash, msg); + auto topVal = *_stack.begin(); + if (topVal._kind == StackNode::LIT) + return topVal._u.intVal; + else + return FAILURE; +} +``` + +You can't "forget" to check the potential for a failure coded inside +your returned value - because your code has to "unwrap" it. I could have +done this better, but I chose to implement it via simple tuples +(this was a one-weeks-afternoons hack, after all :-) + +As for the template "magic" incantation above - it *is* true magic: My +`forward_list` template is using free-lists to store the `pop_front`-ed +elements and reuse them in subsequent allocations. I wanted these free-lists to +be global (i.e. static members) because lists of the same type must re-use a +single, commonly-shared free-list. The magic spell tells the compiler I want to +instantiate these globals *once*, for each type T that I use in any +lists in my code. + +# My Forth test scenario - including a FizzBuzz! + +Yep, FizzBuzz - we are fully Turing complete. And would surely pass +Joel's interview :-) + +``` +." Reset... " RESET +." Check comments... " \ Yes, we support the new-style comments :-) +." Computing simple addition of 3 + 4... " 3 4 + . +." Is 1 = 2 ?... " 1 2 = . +." Is 1 > 2 ?... " 1 2 > . +." Is 1 < 2 ?... " 1 2 < . +." Define pi at double-word precision... " : pi 355 113 */ ; +." Use definition to compute 10K times PI... " 10000 pi . +." Check: 23 mod 7... " 23 7 MOD . +." Defining 1st level function1... " : x2 2 * ; +." Defining 1st level function2... " : p4 4 + ; +." 2nd level word using both - must print 24... " 10 x2 p4 . +." Defining a variable with value 123... " 123 variable ot3 +." Printing variable's value... " ot3 @ . +." Defining The Constant (TM)... " 42 constant lifeUniverse +." Printing The Constant (TM)... " lifeUniverse . +." Setting the variable to The Constant (TM)... " lifeUniverse ot3 ! +." Printing variable's value... " ot3 @ . +." Setting the variable to hex 0x11... " $11 ot3 ! +." Printing variable's value... " ot3 @ . +." Defining helper... " : p5 5 U.R . ; +." Defining 3 times loop... " : x3lp 3 0 DO I p5 LOOP ; +." Calling loop... " x3lp +." Defining loop calling loop 2 times... " : x6lp 2 0 DO x3lp LOOP ; +." Nested-looping 2x3 times... " x6lp +." Inline: " : m 3 1 DO 3 1 DO CR J p5 I p5 ." = " J I * p5 LOOP LOOP ; +." Use inline loops with two indexes... " m +." Make multiples of 7 via DUP... " : m7s 10 0 DO DUP I * . LOOP DROP ; +." Print them and DROP the 7... " 7 m7s +." Reset... " RESET +\ Time for Turing completeness... +." Let's do Fizz-Buzz! " \ Turing Completeness check... +\ fizz ( n -- 0_or_1 n ) +." Define fizz... " : fizz DUP 3 MOD 0 = IF ." fizz " 1 ELSE 0 THEN SWAP ; +\ buzz ( n -- 0_or_1 n ) +." Define buzz... " : buzz DUP 5 MOD 0 = IF ." buzz " 1 ELSE 0 THEN SWAP ; +\ emitNum ( 0_or_1 0_or_1 n -- ) +." Define emitNum... " : emitNum ROT ROT + 0 = if . ELSE DROP THEN ; +\ mainloop ( n -- ) +." Define mainloop... " : mainloop fizz buzz emitNum ; +\ fb ( -- ) +." Define fizzbuzz... " : fb 37 1 DO I mainloop LOOP ; +." Run it! " fb +." Report memory usage... " .S +``` + +# Automation + +I am a strong believer in automation. The final form of my `Makefile` +therefore has many rules - e.g. `make arduino-sim` - that automate +various parts of the workflow. + +Here's what they do: + +* **arduino**: Compiles the code for Arduino UNO - builds `src/tmp/myforth.ino.{elf,hex}` +* **arduino-sim**: After building, launches the compiled mini-Forth in `simduino`. +* **upload**: After building, uploads to an Arduino attached to the port + configured inside `config.mk`. +* **terminal**: After uploading, launches a `picocom` terminal with + all appropriate settings to interact with my Forth. +* **x86**: Builds for x86. Actually, should easily build for any native target (ARM, etc). +* **test-address-sanitizer**: Uses the x86 binary to test the code, executing + all steps of the scenario shown above. The binary is built with the + address sanitizer enabled (to detect memory issues). +* **test-valgrind**: Same, but with Valgrind. +* **test-simulator**: Spawns `simavr` and sends the entire test scenario shown + above to it - while showing the responses received from it. +* **test-arduino**: Sends the entire test scenario shown above to an + Arduino Uno connected to the port specified in `config.mk` + and shows the responses received over that serial port. + +Another example of automation - the complete test scenario shown in the +previous section, is not just an example in the documentation; it is +extracted automatically from this text and fed into the Valgrind and +AddressSanitizer tests... and also into the Python testing script that +sends the data to the board in real-time. + +[DRY](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself), folks. + +# Conclusion + +I thoroughly enjoyed building this. I know full well that Forths are not +supposed to be built in C++; they are supposed to be built in assembly, +and also, utilise the Flash to store the user-compiled code at run-time. + +But that wasn't the point of this - the point was to have fun and learn Forth. +What better way to learn a language... than to actually implement it! :-) + +And... as a child of the 80s... I now know first-hand what +[Jupiter Ace](https://en.wikipedia.org/wiki/Jupiter_Ace) was about :-) + +Fork the code, and enjoy tinkering with it! + + + + +--- + +[![profile for ttsiodras at Stack Overflow, Q&A for professional and enthusiast programmers](382050.png "profile for ttsiodras at Stack Overflow, Q&A for professional and enthusiast programmers")](https://stackoverflow.com/users/382050/ttsiodras) + +[![GitHub member ttsiodras](github.png "GitHub member ttsiodras")](https://github.com/ttsiodras) + +| | | | +| --- | --- | --- | +| [Index](index.html) | [CV](cv.pdf) | *Updated: Sun Nov 19 23:06:10 2023* | \ No newline at end of file diff --git a/references/ForthNotes/C2-Wiki_Chuck_Moore.md b/references/ForthNotes/C2-Wiki_Chuck_Moore.md new file mode 100644 index 0000000..392d7b3 --- /dev/null +++ b/references/ForthNotes/C2-Wiki_Chuck_Moore.md @@ -0,0 +1,17 @@ +# C2-Wiki: Chuck Moore + +**Source:** https://wiki.c2.com/?ChuckMoore + +**notice** + +javascript required to view this site + +**why** + +measured improvement in server performance + +awesome incremental search + +![](spin.gif) + +This site uses features not available in older browsers. \ No newline at end of file diff --git a/references/ForthNotes/C2-Wiki_colorFORTH.md b/references/ForthNotes/C2-Wiki_colorFORTH.md new file mode 100644 index 0000000..b37f79d --- /dev/null +++ b/references/ForthNotes/C2-Wiki_colorFORTH.md @@ -0,0 +1,17 @@ +# C2-Wiki: colorFORTH + +**Source:** https://wiki.c2.com/?ColorForth + +**notice** + +javascript required to view this site + +**why** + +measured improvement in server performance + +awesome incremental search + +![](spin.gif) + +This site uses features not available in older browsers. \ No newline at end of file diff --git a/references/ForthNotes/Callisto.md b/references/ForthNotes/Callisto.md new file mode 100644 index 0000000..d1a099c --- /dev/null +++ b/references/ForthNotes/Callisto.md @@ -0,0 +1,422 @@ +# Callisto + +**Source:** https://github.com/callisto-lang/compiler + +GitHub - callisto-lang/compiler: The Callisto compiler of the 13th month, and other language extras + + + +[Skip to content](#start-of-content) + + + + + + + + + + + + + +## Navigation Menu + +Toggle navigation + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2Fcallisto-lang%2Fcompiler) + +Appearance settings + +* Platform + + + AI CODE CREATION + - [GitHub CopilotWrite better code with AI](https://github.com/features/copilot) + - [GitHub SparkBuild and deploy intelligent apps](https://github.com/features/spark) + - [GitHub ModelsManage and compare prompts](https://github.com/features/models) + - [MCP RegistryNewIntegrate external tools](https://github.com/mcp) + + DEVELOPER WORKFLOWS + - [ActionsAutomate any workflow](https://github.com/features/actions) + - [CodespacesInstant dev environments](https://github.com/features/codespaces) + - [IssuesPlan and track work](https://github.com/features/issues) + - [Code ReviewManage code changes](https://github.com/features/code-review) + + APPLICATION SECURITY + - [GitHub Advanced SecurityFind and fix vulnerabilities](https://github.com/security/advanced-security) + - [Code securitySecure your code as you build](https://github.com/security/advanced-security/code-security) + - [Secret protectionStop leaks before they start](https://github.com/security/advanced-security/secret-protection) + + EXPLORE + - [Why GitHub](https://github.com/why-github) + - [Documentation](https://docs.github.com) + - [Blog](https://github.blog) + - [Changelog](https://github.blog/changelog) + - [Marketplace](https://github.com/marketplace) + + [View all features](https://github.com/features) +* Solutions + + + BY COMPANY SIZE + - [Enterprises](https://github.com/enterprise) + - [Small and medium teams](https://github.com/team) + - [Startups](https://github.com/enterprise/startups) + - [Nonprofits](https://github.com/solutions/industry/nonprofits) + + BY USE CASE + - [App Modernization](https://github.com/solutions/use-case/app-modernization) + - [DevSecOps](https://github.com/solutions/use-case/devsecops) + - [DevOps](https://github.com/solutions/use-case/devops) + - [CI/CD](https://github.com/solutions/use-case/ci-cd) + - [View all use cases](https://github.com/solutions/use-case) + + BY INDUSTRY + - [Healthcare](https://github.com/solutions/industry/healthcare) + - [Financial services](https://github.com/solutions/industry/financial-services) + - [Manufacturing](https://github.com/solutions/industry/manufacturing) + - [Government](https://github.com/solutions/industry/government) + - [View all industries](https://github.com/solutions/industry) + + [View all solutions](https://github.com/solutions) +* Resources + + + EXPLORE BY TOPIC + - [AI](https://github.com/resources/articles?topic=ai) + - [Software Development](https://github.com/resources/articles?topic=software-development) + - [DevOps](https://github.com/resources/articles?topic=devops) + - [Security](https://github.com/resources/articles?topic=security) + - [View all topics](https://github.com/resources/articles) + + EXPLORE BY TYPE + - [Customer stories](https://github.com/customer-stories) + - [Events & webinars](https://github.com/resources/events) + - [Ebooks & reports](https://github.com/resources/whitepapers) + - [Business insights](https://github.com/solutions/executive-insights) + - [GitHub Skills](https://skills.github.com) + + SUPPORT & SERVICES + - [Documentation](https://docs.github.com) + - [Customer support](https://support.github.com) + - [Community forum](https://github.com/orgs/community/discussions) + - [Trust center](https://github.com/trust-center) + - [Partners](https://github.com/partners) +* Open Source + + + COMMUNITY + - [GitHub SponsorsFund open source developers](https://github.com/sponsors) + + PROGRAMS + - [Security Lab](https://securitylab.github.com) + - [Maintainer Community](https://maintainers.github.com) + - [Accelerator](https://github.com/accelerator) + - [Archive Program](https://archiveprogram.github.com) + + REPOSITORIES + - [Topics](https://github.com/topics) + - [Trending](https://github.com/trending) + - [Collections](https://github.com/collections) +* Enterprise + + + ENTERPRISE SOLUTIONS + - [Enterprise platformAI-powered developer platform](https://github.com/enterprise) + + AVAILABLE ADD-ONS + - [GitHub Advanced SecurityEnterprise-grade security features](https://github.com/security/advanced-security) + - [Copilot for BusinessEnterprise-grade AI features](https://github.com/features/copilot/copilot-business) + - [Premium SupportEnterprise-grade 24/7 support](https://github.com/premium-support) +* [Pricing](https://github.com/pricing) + +Search or jump to... + + +# Search code, repositories, users, issues, pull requests... + +Search + +Clear + +[Search syntax tips](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax) + +# Provide feedback + +We read every piece of feedback, and take your input very seriously. + + +Include my email address so I can be contacted + +Cancel + Submit feedback + + + + + +# Saved searches + +## Use saved searches to filter your results more quickly + +Name + +Query + +To see all available qualifiers, see our [documentation](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax). + +Cancel + Create saved search + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2Fcallisto-lang%2Fcompiler) + +[Sign up](/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E&source=header-repo&source_repo=callisto-lang%2Fcompiler) + +Appearance settings + +Resetting focus + +You signed in with another tab or window. Reload to refresh your session. +You signed out in another tab or window. Reload to refresh your session. +You switched accounts on another tab or window. Reload to refresh your session. + + + +Dismiss alert + +{{ message }} + +[callisto-lang](/callisto-lang) +/ +**[compiler](/callisto-lang/compiler)** +Public + +* [Notifications](/login?return_to=%2Fcallisto-lang%2Fcompiler) You must be signed in to change notification settings +* [Fork + 8](/login?return_to=%2Fcallisto-lang%2Fcompiler) +* [Star + 76](/login?return_to=%2Fcallisto-lang%2Fcompiler) + +The Callisto compiler of the 13th month, and other language extras + +[callisto.mesyeti.uk](https://callisto.mesyeti.uk "https://callisto.mesyeti.uk") + +### License + +[MIT license](/callisto-lang/compiler/blob/main/LICENSE) + +[76 +stars](/callisto-lang/compiler/stargazers) [8 +forks](/callisto-lang/compiler/forks) [Branches](/callisto-lang/compiler/branches) [Tags](/callisto-lang/compiler/tags) [Activity](/callisto-lang/compiler/activity) + +[Star](/login?return_to=%2Fcallisto-lang%2Fcompiler) + +[Notifications](/login?return_to=%2Fcallisto-lang%2Fcompiler) You must be signed in to change notification settings + +* [Code](/callisto-lang/compiler) +* [Issues + 0](/callisto-lang/compiler/issues) +* [Pull requests + 0](/callisto-lang/compiler/pulls) +* [Actions](/callisto-lang/compiler/actions) +* [Projects + 0](/callisto-lang/compiler/projects) +* [Security + 0](/callisto-lang/compiler/security) +* [Insights](/callisto-lang/compiler/pulse) + +Additional navigation options + + +* [Code](/callisto-lang/compiler) +* [Issues](/callisto-lang/compiler/issues) +* [Pull requests](/callisto-lang/compiler/pulls) +* [Actions](/callisto-lang/compiler/actions) +* [Projects](/callisto-lang/compiler/projects) +* [Security](/callisto-lang/compiler/security) +* [Insights](/callisto-lang/compiler/pulse) + +# callisto-lang/compiler + +main + +[Branches](/callisto-lang/compiler/branches)[Tags](/callisto-lang/compiler/tags) + +Go to file + +Code + +Open more actions menu + +## Folders and files + +| Name | | Name | Last commit message | Last commit date | +| --- | --- | --- | --- | --- | +| Latest commit History[474 Commits](/callisto-lang/compiler/commits/main/) 474 Commits | | | +| [.gitub-temp-disabled/workflows](/callisto-lang/compiler/tree/main/.gitub-temp-disabled/workflows "This path skips through empty directories") | | [.gitub-temp-disabled/workflows](/callisto-lang/compiler/tree/main/.gitub-temp-disabled/workflows "This path skips through empty directories") | | | +| [docs](/callisto-lang/compiler/tree/main/docs "docs") | | [docs](/callisto-lang/compiler/tree/main/docs "docs") | | | +| [editors](/callisto-lang/compiler/tree/main/editors "editors") | | [editors](/callisto-lang/compiler/tree/main/editors "editors") | | | +| [examples](/callisto-lang/compiler/tree/main/examples "examples") | | [examples](/callisto-lang/compiler/tree/main/examples "examples") | | | +| [source](/callisto-lang/compiler/tree/main/source "source") | | [source](/callisto-lang/compiler/tree/main/source "source") | | | +| [std @ 4c0918c](/callisto-lang/std/tree/4c0918cfa12a9b80f65732b044a0a0c11365204e "std") | | [std @ 4c0918c](/callisto-lang/std/tree/4c0918cfa12a9b80f65732b044a0a0c11365204e "std") | | | +| [.gitattributes](/callisto-lang/compiler/blob/main/.gitattributes ".gitattributes") | | [.gitattributes](/callisto-lang/compiler/blob/main/.gitattributes ".gitattributes") | | | +| [.gitignore](/callisto-lang/compiler/blob/main/.gitignore ".gitignore") | | [.gitignore](/callisto-lang/compiler/blob/main/.gitignore ".gitignore") | | | +| [.gitmodules](/callisto-lang/compiler/blob/main/.gitmodules ".gitmodules") | | [.gitmodules](/callisto-lang/compiler/blob/main/.gitmodules ".gitmodules") | | | +| [LICENSE](/callisto-lang/compiler/blob/main/LICENSE "LICENSE") | | [LICENSE](/callisto-lang/compiler/blob/main/LICENSE "LICENSE") | | | +| [README.md](/callisto-lang/compiler/blob/main/README.md "README.md") | | [README.md](/callisto-lang/compiler/blob/main/README.md "README.md") | | | +| [STYLE.md](/callisto-lang/compiler/blob/main/STYLE.md "STYLE.md") | | [STYLE.md](/callisto-lang/compiler/blob/main/STYLE.md "STYLE.md") | | | +| [TODO.md](/callisto-lang/compiler/blob/main/TODO.md "TODO.md") | | [TODO.md](/callisto-lang/compiler/blob/main/TODO.md "TODO.md") | | | +| [dub.json](/callisto-lang/compiler/blob/main/dub.json "dub.json") | | [dub.json](/callisto-lang/compiler/blob/main/dub.json "dub.json") | | | +| [flake.nix](/callisto-lang/compiler/blob/main/flake.nix "flake.nix") | | [flake.nix](/callisto-lang/compiler/blob/main/flake.nix "flake.nix") | | | +| View all files | | | + +## Repository files navigation + +* [README](#) +* [MIT license](#) + +[![](https://camo.githubusercontent.com/4bdb739c0513e67abf8868948c01b60d12189f18d85f06ebb6abd6cf6e156804/68747470733a2f2f63616c6c6973746f2e6d6573796574692e756b2f6c6f676f5f736861646f772e706e67)](https://camo.githubusercontent.com/4bdb739c0513e67abf8868948c01b60d12189f18d85f06ebb6abd6cf6e156804/68747470733a2f2f63616c6c6973746f2e6d6573796574692e756b2f6c6f676f5f736861646f772e706e67) + +# The Callisto Programming Language + +[Website](https://callisto.mesyeti.uk/) | +[Docs](https://callisto.mesyeti.uk/docs) | +[Awesome List](https://github.com/callisto-lang/awesome-callisto) | +[Discord](https://discord.com/invite/QHAtc4GWq7) + +**Callisto** is a stack-based imperative programming language with stack safety enforced +by the compiler (which is optional). + +It also has a subset called CallistoScript made to compile to scripting languages like +Lua, while keeping its low level features (like direct access to memory). + +## Supported targets + +* x86 real mode - MS-DOS, bare metal +* x86\_64 - Linux, macOS, FreeBSD (partial) +* ARM64 - Linux, macOS +* Uxn - Varvara +* Lua + +## Build + +``` +dub build --compiler=ldc +``` + +The compiler executable will be called `cac` + +Warning + +Compilation may freeze due to a bug in the Digital Mars D compiler. If this happens, +compile with this command: `dub build --compiler=ldc`. + +If that doesn't work, then run with `--compiler=ldc2` instead. + +## Run example programs + +Make sure you get the standard library + +``` +git submodule update --remote +``` + +Then compile example programs like this + +``` +cac examples/exampleNameHere.cal -i std +``` + +The output executable will be called `out`. Any example programs that require extra flags +for compilation will have a compile command in a comment at the top of the source file. + +## IRC Channel + +Join `#callisto-lang` on irc.libera.chat. + +## About + +The Callisto compiler of the 13th month, and other language extras + +[callisto.mesyeti.uk](https://callisto.mesyeti.uk "https://callisto.mesyeti.uk") + +### Topics + +[programming-language](/topics/programming-language "Topic: programming-language") +[compiler](/topics/compiler "Topic: compiler") +[x86-64](/topics/x86-64 "Topic: x86-64") +[concatenative](/topics/concatenative "Topic: concatenative") +[concatenative-language](/topics/concatenative-language "Topic: concatenative-language") +[concatenative-programming-language](/topics/concatenative-programming-language "Topic: concatenative-programming-language") +[uxn](/topics/uxn "Topic: uxn") +[uxntal](/topics/uxntal "Topic: uxntal") + +### Resources + +[Readme](#readme-ov-file) + +### License + +[MIT license](#MIT-1-ov-file) + +### Uh oh! + +There was an error while loading. Please reload this page. + +[Activity](/callisto-lang/compiler/activity) + +[Custom properties](/callisto-lang/compiler/custom-properties) + +### Stars + +[**76** +stars](/callisto-lang/compiler/stargazers) + +### Watchers + +[**1** +watching](/callisto-lang/compiler/watchers) + +### Forks + +[**8** +forks](/callisto-lang/compiler/forks) + +[Report repository](/contact/report-content?content_url=https%3A%2F%2Fgithub.com%2Fcallisto-lang%2Fcompiler&report=callisto-lang+%28user%29) + +## [Releases 23](/callisto-lang/compiler/releases) + +[Beta 0.13.0 - Modules part 1 + +Latest + +Nov 15, 2025](/callisto-lang/compiler/releases/tag/b0.13.0) + +[+ 22 releases](/callisto-lang/compiler/releases) + +## [Packages 0](/orgs/callisto-lang/packages?repo_name=compiler) + +No packages published + +### Uh oh! + +There was an error while loading. Please reload this page. + +## [Contributors 7](/callisto-lang/compiler/graphs/contributors) + +### Uh oh! + +There was an error while loading. Please reload this page. + +## Languages + +* [D + 99.6%](/callisto-lang/compiler/search?l=d) +* [Nix + 0.4%](/callisto-lang/compiler/search?l=nix) + +## Footer + +© 2026 GitHub, Inc. + +### Footer navigation + +* [Terms](https://docs.github.com/site-policy/github-terms/github-terms-of-service) +* [Privacy](https://docs.github.com/site-policy/privacy-policies/github-privacy-statement) +* [Security](https://github.com/security) +* [Status](https://www.githubstatus.com/) +* [Community](https://github.community/) +* [Docs](https://docs.github.com/) +* [Contact](https://support.github.com?tags=dotcom-footer) +* Manage cookies +* Do not share my personal information + + + +You can’t perform that action at this time. \ No newline at end of file diff --git a/references/ForthNotes/Cognate.md b/references/ForthNotes/Cognate.md new file mode 100644 index 0000000..ce6b72d --- /dev/null +++ b/references/ForthNotes/Cognate.md @@ -0,0 +1,98 @@ +# Cognate + +**Source:** https://cognate-lang.github.io + +Cognate: Readable and concise concatenative programming + + + + +# Cognate + +## Readable and concise concatenative programming + +``` +~~ Fizzbuzz in Cognate + +Def Fizzbuzz ( + Let N be Of (Integer?); + Def Multiple as (Zero? Modulo Swap N); + + If Multiple of 15 then "fizzbuzz" + If Multiple of 3 then "fizz" + If Multiple of 5 then "buzz" + else N +); + +For each in Range 1 to 100 (Print Fizzbuzz); +``` + +Cognate is a project aiming to create a human readable programming language with as little syntax as possible. Where natural language programming usually uses many complex syntax rules, instead Cognate takes them away. What it adds is simple, a way to embed comments into statements. + +``` +~~ Towers of Hanoi in Cognate + +Def Move discs as ( + + Let N be number of discs; + Let A be first rod; + Let B be second rod; + Let C be third rod; + + Unless Zero? N ( + Move - 1 N discs from A via C to B; + Prints ("Move disc " N " from " A " to " C); + Move - 1 N discs from B via A to C; + ) +); + +Move 5 discs from "a" via "b" to "c"; +``` + +As you can see, Cognate ignores words starting with lowercase letters, allowing them to be used to describe functionality and enhance readability. This makes Cognate codebases intuitive and maintainable. + +``` +~~ Square numbers in Cognate + +Def Square as (* Twin); +Map (Square) over Range 1 to 10; +Print; +``` + +Cognate is a stack-oriented programming language similar to Forth or Factor, except statements are evaluated right to left. This gives the expressiveness of concatenative programming as well as the readability of prefix notation. Statements can be delimited at arbitrary points, allowing them to read as sentences would in English. + +``` +~~ Prime numbers in Cognate + +Def Factor (Zero? Modulo Swap); + +Def Primes ( + Fold ( + Let I be our potential prime; + Let Primes are the found primes; + Let To-check be Take-while (<= Sqrt I) Primes; + When None (Factor of I) To-check + (Append List (I)) to Primes; + ) from List () over Range from 2 +); + +Print Primes up to 1000; +``` + +Cognate borrows from other concatenative languages, but also adds unique features of its own. + +* Point-free functions +* Operation chaining +* Multiple return values +* Combinator oriented programming +* Predicate pattern matching +* Natural language programming + +Interested? Read the [tutorial](/learn/), and check out one of Cognate’s implementations: + +* [CognaC](https://github.com/cognate-lang/cognate) is the original compiler – it performs type inference and produces efficient binaries. +* [Cognate Playground](https://cognate-playground.hedy.dev/) (developed by [hedyhli](https://github.com/hedyhli)) runs Cognate programs in a web browser. +* [Cogni](https://github.com/dragoncoder047/cogni) (developed by [dragoncoder047](https://github.com/dragoncoder047)) interprets Cognate programs and is optimised to run on microcontrollers. + + + \ No newline at end of file diff --git a/references/ForthNotes/Color.md b/references/ForthNotes/Color.md new file mode 100644 index 0000000..523aee2 --- /dev/null +++ b/references/ForthNotes/Color.md @@ -0,0 +1,389 @@ +# Color + +**Source:** https://github.com/AshleyF/Color/tree/master + +GitHub - AshleyF/Color: Fun playing around with colorForth and GreenArrays architecture. + + + +[Skip to content](#start-of-content) + + + + + + + + + + + + + +## Navigation Menu + +Toggle navigation + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2FAshleyF%2FColor%2Ftree%2Fmaster) + +Appearance settings + +* Platform + + + AI CODE CREATION + - [GitHub CopilotWrite better code with AI](https://github.com/features/copilot) + - [GitHub SparkBuild and deploy intelligent apps](https://github.com/features/spark) + - [GitHub ModelsManage and compare prompts](https://github.com/features/models) + - [MCP RegistryNewIntegrate external tools](https://github.com/mcp) + + DEVELOPER WORKFLOWS + - [ActionsAutomate any workflow](https://github.com/features/actions) + - [CodespacesInstant dev environments](https://github.com/features/codespaces) + - [IssuesPlan and track work](https://github.com/features/issues) + - [Code ReviewManage code changes](https://github.com/features/code-review) + + APPLICATION SECURITY + - [GitHub Advanced SecurityFind and fix vulnerabilities](https://github.com/security/advanced-security) + - [Code securitySecure your code as you build](https://github.com/security/advanced-security/code-security) + - [Secret protectionStop leaks before they start](https://github.com/security/advanced-security/secret-protection) + + EXPLORE + - [Why GitHub](https://github.com/why-github) + - [Documentation](https://docs.github.com) + - [Blog](https://github.blog) + - [Changelog](https://github.blog/changelog) + - [Marketplace](https://github.com/marketplace) + + [View all features](https://github.com/features) +* Solutions + + + BY COMPANY SIZE + - [Enterprises](https://github.com/enterprise) + - [Small and medium teams](https://github.com/team) + - [Startups](https://github.com/enterprise/startups) + - [Nonprofits](https://github.com/solutions/industry/nonprofits) + + BY USE CASE + - [App Modernization](https://github.com/solutions/use-case/app-modernization) + - [DevSecOps](https://github.com/solutions/use-case/devsecops) + - [DevOps](https://github.com/solutions/use-case/devops) + - [CI/CD](https://github.com/solutions/use-case/ci-cd) + - [View all use cases](https://github.com/solutions/use-case) + + BY INDUSTRY + - [Healthcare](https://github.com/solutions/industry/healthcare) + - [Financial services](https://github.com/solutions/industry/financial-services) + - [Manufacturing](https://github.com/solutions/industry/manufacturing) + - [Government](https://github.com/solutions/industry/government) + - [View all industries](https://github.com/solutions/industry) + + [View all solutions](https://github.com/solutions) +* Resources + + + EXPLORE BY TOPIC + - [AI](https://github.com/resources/articles?topic=ai) + - [Software Development](https://github.com/resources/articles?topic=software-development) + - [DevOps](https://github.com/resources/articles?topic=devops) + - [Security](https://github.com/resources/articles?topic=security) + - [View all topics](https://github.com/resources/articles) + + EXPLORE BY TYPE + - [Customer stories](https://github.com/customer-stories) + - [Events & webinars](https://github.com/resources/events) + - [Ebooks & reports](https://github.com/resources/whitepapers) + - [Business insights](https://github.com/solutions/executive-insights) + - [GitHub Skills](https://skills.github.com) + + SUPPORT & SERVICES + - [Documentation](https://docs.github.com) + - [Customer support](https://support.github.com) + - [Community forum](https://github.com/orgs/community/discussions) + - [Trust center](https://github.com/trust-center) + - [Partners](https://github.com/partners) +* Open Source + + + COMMUNITY + - [GitHub SponsorsFund open source developers](https://github.com/sponsors) + + PROGRAMS + - [Security Lab](https://securitylab.github.com) + - [Maintainer Community](https://maintainers.github.com) + - [Accelerator](https://github.com/accelerator) + - [Archive Program](https://archiveprogram.github.com) + + REPOSITORIES + - [Topics](https://github.com/topics) + - [Trending](https://github.com/trending) + - [Collections](https://github.com/collections) +* Enterprise + + + ENTERPRISE SOLUTIONS + - [Enterprise platformAI-powered developer platform](https://github.com/enterprise) + + AVAILABLE ADD-ONS + - [GitHub Advanced SecurityEnterprise-grade security features](https://github.com/security/advanced-security) + - [Copilot for BusinessEnterprise-grade AI features](https://github.com/features/copilot/copilot-business) + - [Premium SupportEnterprise-grade 24/7 support](https://github.com/premium-support) +* [Pricing](https://github.com/pricing) + +Search or jump to... + + +# Search code, repositories, users, issues, pull requests... + +Search + +Clear + +[Search syntax tips](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax) + +# Provide feedback + +We read every piece of feedback, and take your input very seriously. + + +Include my email address so I can be contacted + +Cancel + Submit feedback + + + + + +# Saved searches + +## Use saved searches to filter your results more quickly + +Name + +Query + +To see all available qualifiers, see our [documentation](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax). + +Cancel + Create saved search + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2FAshleyF%2FColor%2Ftree%2Fmaster) + +[Sign up](/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E&source=header-repo&source_repo=AshleyF%2FColor) + +Appearance settings + +Resetting focus + +You signed in with another tab or window. Reload to refresh your session. +You signed out in another tab or window. Reload to refresh your session. +You switched accounts on another tab or window. Reload to refresh your session. + + + +Dismiss alert + +{{ message }} + +[AshleyF](/AshleyF) +/ +**[Color](/AshleyF/Color)** +Public + +* [Notifications](/login?return_to=%2FAshleyF%2FColor) You must be signed in to change notification settings +* [Fork + 22](/login?return_to=%2FAshleyF%2FColor) +* [Star + 135](/login?return_to=%2FAshleyF%2FColor) + +Fun playing around with colorForth and GreenArrays architecture. + +### License + +[Unlicense license](/AshleyF/Color/blob/master/LICENSE) + +[135 +stars](/AshleyF/Color/stargazers) [22 +forks](/AshleyF/Color/forks) [Branches](/AshleyF/Color/branches) [Tags](/AshleyF/Color/tags) [Activity](/AshleyF/Color/activity) + +[Star](/login?return_to=%2FAshleyF%2FColor) + +[Notifications](/login?return_to=%2FAshleyF%2FColor) You must be signed in to change notification settings + +* [Code](/AshleyF/Color) +* [Issues + 0](/AshleyF/Color/issues) +* [Pull requests + 0](/AshleyF/Color/pulls) +* [Actions](/AshleyF/Color/actions) +* [Projects + 0](/AshleyF/Color/projects) +* [Wiki](/AshleyF/Color/wiki) +* [Security + 0](/AshleyF/Color/security) +* [Insights](/AshleyF/Color/pulse) + +Additional navigation options + + +* [Code](/AshleyF/Color) +* [Issues](/AshleyF/Color/issues) +* [Pull requests](/AshleyF/Color/pulls) +* [Actions](/AshleyF/Color/actions) +* [Projects](/AshleyF/Color/projects) +* [Wiki](/AshleyF/Color/wiki) +* [Security](/AshleyF/Color/security) +* [Insights](/AshleyF/Color/pulse) + +# AshleyF/Color + +master + +[Branches](/AshleyF/Color/branches)[Tags](/AshleyF/Color/tags) + +Go to file + +Code + +Open more actions menu + +## Folders and files + +| Name | | Name | Last commit message | Last commit date | +| --- | --- | --- | --- | --- | +| Latest commit History[67 Commits](/AshleyF/Color/commits/master/) 67 Commits | | | +| [Assembler](/AshleyF/Color/tree/master/Assembler "Assembler") | | [Assembler](/AshleyF/Color/tree/master/Assembler "Assembler") | | | +| [Blocks](/AshleyF/Color/tree/master/Blocks "Blocks") | | [Blocks](/AshleyF/Color/tree/master/Blocks "Blocks") | | | +| [Docs](/AshleyF/Color/tree/master/Docs "Docs") | | [Docs](/AshleyF/Color/tree/master/Docs "Docs") | | | +| [Editor](/AshleyF/Color/tree/master/Editor "Editor") | | [Editor](/AshleyF/Color/tree/master/Editor "Editor") | | | +| [Machine](/AshleyF/Color/tree/master/Machine "Machine") | | [Machine](/AshleyF/Color/tree/master/Machine "Machine") | | | +| [Synthesis](/AshleyF/Color/tree/master/Synthesis "Synthesis") | | [Synthesis](/AshleyF/Color/tree/master/Synthesis "Synthesis") | | | +| [Utility](/AshleyF/Color/tree/master/Utility "Utility") | | [Utility](/AshleyF/Color/tree/master/Utility "Utility") | | | +| [.gitignore](/AshleyF/Color/blob/master/.gitignore ".gitignore") | | [.gitignore](/AshleyF/Color/blob/master/.gitignore ".gitignore") | | | +| [Color.sln](/AshleyF/Color/blob/master/Color.sln "Color.sln") | | [Color.sln](/AshleyF/Color/blob/master/Color.sln "Color.sln") | | | +| [LICENSE](/AshleyF/Color/blob/master/LICENSE "LICENSE") | | [LICENSE](/AshleyF/Color/blob/master/LICENSE "LICENSE") | | | +| [README.md](/AshleyF/Color/blob/master/README.md "README.md") | | [README.md](/AshleyF/Color/blob/master/README.md "README.md") | | | +| View all files | | | + +## Repository files navigation + +* [README](#) +* [Unlicense license](#) + +# Color + +Having fun playing around with [colorForth](http://www.colorforth.com/cf.htm) and [GreenArrays](http://www.greenarraychips.com/) architecture. See the [demo](https://youtu.be/LYtQMmvgg6w) presented to the [Forth2020 Group](http://www.forth2020.org/) in AUG 2021 and [~~blog series~~](http://blogs.msdn.com/b/ashleyf/archive/tags/color/) - Blog series moved here to Github: + +* [Chuck Moore's Creations](/AshleyF/Color/blob/master/Docs/chuck_moores_creations.md) +* [Programming the F18](/AshleyF/Color/blob/master/Docs/programming_the_f18.md) +* [Beautiful Simplicity of colorForth](/AshleyF/Color/blob/master/Docs/beautiful_simplicity.md) +* [Multiply-step Instruction](/AshleyF/Color/blob/master/Docs/multiply_step.md) +* [Simple Variables](/AshleyF/Color/blob/master/Docs/simple_variables.md) + +[![Editor/Assembler](/AshleyF/Color/raw/master/Docs/images/editor_assembler.png)](/AshleyF/Color/blob/master/Docs/images/editor_assembler.png) + +The assembler watches for changes to the block files saved by the editor. I leave an instance of this running in one terminal window (right) while working in the editor in another (left). Later I run the machine in a third window. + +## Setup + +Everything is written in F# and uses solution (`.sln`) and project (`.fsproj`) files compatible with Visual Studio or `dotnet build`. I personally have been using plain Vim (with the [excellent F# bindings](https://github.com/fsharp/fsharpbinding)). Here's setup steps for Ubuntu: + +**Install .NET Core** + +* Install the [.NET SDK](https://docs.microsoft.com/en-us/dotnet/core/install/linux-ubuntu). For example, for *Ubuntu 21.04* in particular: + +``` +wget https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb +sudo dpkg -i packages-microsoft-prod.deb +rm packages-microsoft-prod.deb + +sudo apt-get update +sudo apt-get install -y apt-transport-https +sudo apt-get update +sudo apt-get install -y dotnet-sdk-5.0 +``` + +**Pull down the project** + +``` +git clone http://github.com/AshleyF/Color +``` + +**Build** + +``` +dotnet build Color.sln +``` + +Each project produces an executable (`Assembler.exe`, `Editor.exe`, `Machine.exe`) within `bin/` + +**Play!** + +The editor edits block files (`/Blocks/*.blk`) while the assembler waits for changes to blocks and assembles them (to block 0). Running the machine executes block 0. + +The normal way of working is to run the `./Editor` and `./Assembler` at the same time (in separate tabs or tmux splits, etc.). Each time a block is saved (by pressing `s` in the editor), it's assembled. Then run the `./Machine` to try it out. + +## About + +Fun playing around with colorForth and GreenArrays architecture. + +### Resources + +[Readme](#readme-ov-file) + +### License + +[Unlicense license](#Unlicense-1-ov-file) + +### Uh oh! + +There was an error while loading. Please reload this page. + +[Activity](/AshleyF/Color/activity) + +### Stars + +[**135** +stars](/AshleyF/Color/stargazers) + +### Watchers + +[**8** +watching](/AshleyF/Color/watchers) + +### Forks + +[**22** +forks](/AshleyF/Color/forks) + +[Report repository](/contact/report-content?content_url=https%3A%2F%2Fgithub.com%2FAshleyF%2FColor&report=AshleyF+%28user%29) + +## [Releases](/AshleyF/Color/releases) + +No releases published + +## [Packages 0](/users/AshleyF/packages?repo_name=Color) + +No packages published + +### Uh oh! + +There was an error while loading. Please reload this page. + +## [Contributors 2](/AshleyF/Color/graphs/contributors) + +### Uh oh! + +There was an error while loading. Please reload this page. + +## Languages + +* [F# + 100.0%](/AshleyF/Color/search?l=f%23) + +## Footer + +© 2026 GitHub, Inc. + +### Footer navigation + +* [Terms](https://docs.github.com/site-policy/github-terms/github-terms-of-service) +* [Privacy](https://docs.github.com/site-policy/privacy-policies/github-privacy-statement) +* [Security](https://github.com/security) +* [Status](https://www.githubstatus.com/) +* [Community](https://github.community/) +* [Docs](https://docs.github.com/) +* [Contact](https://support.github.com?tags=dotcom-footer) +* Manage cookies +* Do not share my personal information + + + +You can’t perform that action at this time. \ No newline at end of file diff --git a/references/ForthNotes/Concatenative_language.md b/references/ForthNotes/Concatenative_language.md new file mode 100644 index 0000000..66f0326 --- /dev/null +++ b/references/ForthNotes/Concatenative_language.md @@ -0,0 +1,185 @@ +# Concatenative language + +**Source:** https://concatenative.org/wiki/view/Concatenative%20language + +Concatenative language + + + +![](data:image/svg+xml;utf8,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 xmlns:xlink=%27http://www.w3.org/1999/xlink%27 width=%2724%27 height=%2716%27 viewBox=%270 0 120 100%27 fill=%27rgb(0,0,0)%27%3E%3Crect y=%270%27 width=%27120%27 height=%2720%27 rx=%2710%27 /%3E%3Crect y=%2740%27 width=%27120%27 height=%2720%27 rx=%2710%27 /%3E%3Crect y=%2780%27 width=%27120%27 height=%2720%27 rx=%2710%27 /%3E%3C/svg%3E) +[Front Page](https://concatenative.org/wiki/) +[All Articles](https://concatenative.org/wiki/articles) +[Recent Changes](https://concatenative.org/wiki/changes) +[Random Article](https://concatenative.org/wiki/random) + +## [Contents](https://concatenative.org/wiki/view/Contents) + +[Concatenative language](https://concatenative.org/wiki/view/Concatenative%20language) + +* [ACL](https://concatenative.org/wiki/view/ACL) +* [Ait](https://concatenative.org/wiki/view/Ait) +* [Aocla](https://concatenative.org/wiki/view/Aocla) +* [Breeze](https://concatenative.org/wiki/view/Breeze) +* [Callisto](https://concatenative.org/wiki/view/Callisto) +* [Cat](https://concatenative.org/wiki/view/Cat) +* [Cognate](https://concatenative.org/wiki/view/Cognate) +* [colorForth](https://concatenative.org/wiki/view/colorForth) +* [Concata](https://concatenative.org/wiki/view/Concata) +* [CoSy](https://concatenative.org/wiki/view/CoSy) +* [Deque](https://concatenative.org/wiki/view/Deque) +* [DSSP](https://concatenative.org/wiki/view/DSSP) +* [dt](https://concatenative.org/wiki/view/dt) +* [Elymas](https://concatenative.org/wiki/view/Elymas) +* [Enchilada](https://concatenative.org/wiki/view/Enchilada) +* [ERIShell](https://concatenative.org/wiki/view/ERIShell) +* [ETAC](https://concatenative.org/wiki/view/ETAC) +* [F](https://concatenative.org/wiki/view/F) +* [Factor](https://concatenative.org/wiki/view/Factor) +* [Fiveth](https://concatenative.org/wiki/view/Fiveth) +* [Forth](https://concatenative.org/wiki/view/Forth) +* [Fourth](https://concatenative.org/wiki/view/Fourth) +* [Freelang](https://concatenative.org/wiki/view/Freelang) +* [Gershwin](https://concatenative.org/wiki/view/Gershwin) +* [hex](https://concatenative.org/wiki/view/hex) +* [iNet](https://concatenative.org/wiki/view/iNet) +* [Joy](https://concatenative.org/wiki/view/Joy) +* [Joy of Postfix](https://concatenative.org/wiki/view/Joy%20of%20Postfix) *App* +* [kcats](https://concatenative.org/wiki/view/kcats) +* [Kitten](https://concatenative.org/wiki/view/Kitten) +* [lang5](https://concatenative.org/wiki/view/lang5) +* [Listack](https://concatenative.org/wiki/view/Listack) +* [LSE64](https://concatenative.org/wiki/view/LSE64) +* [Lviv](https://concatenative.org/wiki/view/Lviv) +* [Meow5](https://concatenative.org/wiki/view/Meow5) +* [min](https://concatenative.org/wiki/view/min) +* [Mirth](https://concatenative.org/wiki/view/Mirth) +* [mjoy](https://concatenative.org/wiki/view/mjoy) +* [Mlatu](https://concatenative.org/wiki/view/Mlatu) +* [Ode](https://concatenative.org/wiki/view/Ode) +* [OForth](https://concatenative.org/wiki/view/OForth) +* [Om](https://concatenative.org/wiki/view/Om) +* [Onion](https://concatenative.org/wiki/view/Onion) +* [Onyx](https://concatenative.org/wiki/view/Onyx) +* [Plorth](https://concatenative.org/wiki/view/Plorth) +* [Popr](https://concatenative.org/wiki/view/Popr) +* [Porth](https://concatenative.org/wiki/view/Porth) +* [PostScript](https://concatenative.org/wiki/view/PostScript) +* [Prowl](https://concatenative.org/wiki/view/Prowl) +* [Quackery](https://concatenative.org/wiki/view/Quackery) +* [Quadrate](https://concatenative.org/wiki/view/Quadrate) +* [Quest32](https://concatenative.org/wiki/view/Quest32) +* [r3](https://concatenative.org/wiki/view/r3) +* [Raven](https://concatenative.org/wiki/view/Raven) +* [Retro](https://concatenative.org/wiki/view/Retro) +* [RPL](https://concatenative.org/wiki/view/RPL) +* [SPL](https://concatenative.org/wiki/view/SPL) +* [Staapl](https://concatenative.org/wiki/view/Staapl) +* [Stabel](https://concatenative.org/wiki/view/Stabel) +* [Tal](https://concatenative.org/wiki/view/Tal) +* [Titan](https://concatenative.org/wiki/view/Titan) +* [Trith](https://concatenative.org/wiki/view/Trith) +* [Uiua](https://concatenative.org/wiki/view/Uiua) +* [Worst](https://concatenative.org/wiki/view/Worst) +* [xs](https://concatenative.org/wiki/view/xs) +* [XY](https://concatenative.org/wiki/view/XY) +* [5th](https://concatenative.org/wiki/view/5th) +* [8th](https://concatenative.org/wiki/view/8th) + +Concatenative topics + +* [Compilers](https://concatenative.org/wiki/view/Compilers) +* [Interpreters](https://concatenative.org/wiki/view/Interpreters) +* [Type systems](https://concatenative.org/wiki/view/Type%20systems) +* [Object systems](https://concatenative.org/wiki/view/Object%20systems) +* [Quotations](https://concatenative.org/wiki/view/Quotations) +* [Variables](https://concatenative.org/wiki/view/Variables) +* [Garbage collection](https://concatenative.org/wiki/view/Garbage%20collection) +* [Example programs](https://concatenative.org/wiki/view/Example%20programs) + +Concatenative meta + +* [People](https://concatenative.org/wiki/view/People) +* [Communities](https://concatenative.org/wiki/view/Communities) +* [Events](https://concatenative.org/wiki/view/Events) + +Other languages + +* [APL](https://concatenative.org/wiki/view/APL) +* [C++](https://concatenative.org/wiki/view/C%2B%2B) +* [Erlang](https://concatenative.org/wiki/view/Erlang) +* [FP trivia](https://concatenative.org/wiki/view/FP%20trivia) +* [Haskell](https://concatenative.org/wiki/view/Haskell) +* [Io](https://concatenative.org/wiki/view/Io) +* [Java](https://concatenative.org/wiki/view/Java) +* [JavaScript](https://concatenative.org/wiki/view/JavaScript) +* [Lisp](https://concatenative.org/wiki/view/Lisp) +* [ML](https://concatenative.org/wiki/view/ML) +* [Oberon](https://concatenative.org/wiki/view/Oberon) +* [RPL](https://concatenative.org/wiki/view/RPL) +* [Self](https://concatenative.org/wiki/view/Self) +* [Slate](https://concatenative.org/wiki/view/Slate) +* [Smalltalk](https://concatenative.org/wiki/view/Smalltalk) + +Meta + +* [**Search**](http://www.google.com/custom?hl=en&cof=&domains=concatenative.org&btnG=Search&sitesearch=concatenative.org) +* [Farkup wiki format](https://concatenative.org/wiki/view/Farkup) +* [Etiquette](https://concatenative.org/wiki/view/Etiquette) +* [Sandbox](https://concatenative.org/wiki/view/Sandbox) + +# Concatenative language + +There are many ways to categorize programming languages; one is to define them as either "concatenative" or "applicative". In an applicative language, things are evaluated by applying functions to arguments. This includes almost all programming languages in wide use, such as [C](https://concatenative.org/wiki/view/C), [Python](https://concatenative.org/wiki/view/Python), [ML](https://concatenative.org/wiki/view/ML), [Haskell](https://concatenative.org/wiki/view/Haskell), and [Java](https://concatenative.org/wiki/view/Java). In a concatenative programming language, things are evaluated by composing several functions which all operate on a single piece of data, passed from function to function. This piece of data is usually in the form of a stack. Additionally, in concatenative languages, this function composition is indicated by concatenating programs. Examples of concatenative languages include [Forth](https://concatenative.org/wiki/view/Forth), [Joy](https://concatenative.org/wiki/view/Joy), [PostScript](https://concatenative.org/wiki/view/PostScript), [Cat](https://concatenative.org/wiki/view/Cat), and [Factor](https://concatenative.org/wiki/view/Factor). + +# Concatenative and stack languages + +Although the terms *stack language* and *concatenative language* sometimes get thrown around interchangeably, they actually represent similar but distinct classes of languages. A concatenative language is not necessarily a stack language. For example, [Om](https://concatenative.org/wiki/view/Om) uses prefix notation, rather than postfix, and passes the remainder of the program as the data from function to function. See [Deque](https://concatenative.org/wiki/view/Deque) for another example of a stack-free concatenative language. + +Stacks are a pretty fundamental concept in computer science, and many languages use stacks internally in the implementation. Any language that allows recursive definitions uses some type of call stack to save return addresses between function calls, and often the same stack is used to spill values which cannot be allocated in registers. However, this is just implementation detail, and this call stack is not exposed directly to the programmer (except in languages with first-class continuations; I'll touch upon this later). + +So what makes stack languages different? The key concept here is that there are *multiple* stacks: all stack languages have a call stack to support recursion, but they also have a data stack (sometimes called an operand stack) to pass values between functions. The latter is what stack language programmers mean when they talk about "the" stack. + +Most languages in widespread use today are *applicative languages*: the central construct in the language is some form of function call, where a function is *applied* to a set of parameters, where each parameter is itself the result of a function call, the name of a variable, or a constant. In stack languages, a function call is made by simply writing the name of the function; the parameters are implicit, and they have to *already* be on the stack when the call is made. The result of the function call (if any) is then left on the stack after the function returns, for the next function to consume, and so on. Because functions are invoked simply by mentioning their name without any additional syntax, Forth and Factor refer to functions as "words", because in the syntax they really are just words. + +# One mutable stack or functions from stacks to stacks? + +Sometimes, people talk about words pushing and popping values on "the stack". Other programmers, mostly those who prefer the term "concatenative language", instead talk about words as being functions which take a stack as input, and return a whole new stack as output. The first point of view is more intuitive, and it is also how most implementations work: there really is a location in memory that is the data stack. The latter is more amenable to formal reasoning: it is easier to work with rewrite rules and type systems if your functions are pure. However, these two points of view are equivalent: because in a given thread of execution, only one stack is "live" at any given point in time, updating the stack in-place has the same semantics as the purely functional world view. More details about this can be found in [Manfred von Thun](https://concatenative.org/wiki/view/Manfred%20von%20Thun)'s paper [Mathematical Foundations of Joy](https://hypercubed.github.io/joy/html/j02maf.html). + +# Fundamentals of concatenative languages + +* [Name code not values](https://concatenative.org/wiki/view/Concatenative%20language/Name%20code%20not%20values) +* [Multiple return values](https://concatenative.org/wiki/view/Concatenative%20language/Multiple%20return%20values) +* [Concatenation is composition](https://concatenative.org/wiki/view/Concatenative%20language/Concatenation%20is%20composition) +* [Left to right evaluation](https://concatenative.org/wiki/view/Concatenative%20language/Left%20to%20right%20evaluation) + +# Concatenative idioms + +* [Keyword parameters](https://concatenative.org/wiki/view/Concatenative%20language/Keyword%20parameters) +* [Rest parameters](https://concatenative.org/wiki/view/Concatenative%20language/Rest%20parameters) +* [Pipeline style](https://concatenative.org/wiki/view/Pipeline%20style) + +# Other interesting properties + +* [Concision](https://concatenative.org/wiki/view/Concatenative%20language/Concision) +* [Simplicity](https://concatenative.org/wiki/view/Concatenative%20language/Simplicity) +* [Meta-programming](https://concatenative.org/wiki/view/Concatenative%20language/Meta-programming) +* [Continuations](https://concatenative.org/wiki/view/Concatenative%20language/Continuations) +* [Interactive development](https://concatenative.org/wiki/view/Concatenative%20language/Interactive%20development) + +# Publications + +* [Publications](https://concatenative.org/wiki/view/Concatenative%20language/Publications) + +*This revision created on Fri, 10 Sep 2021 18:36:34 by [AliAsshole](https://concatenative.org/wiki/user-edits/AliAsshole) +(Replaced dead link with live one)* + +[Latest](https://concatenative.org/wiki/view/Concatenative%20language) +[Revisions](https://concatenative.org/wiki/revisions/Concatenative%20language) +[Edit](https://concatenative.org/wiki/edit/Concatenative%20language) + + +Delete + + + +All content is © 2008-2024 by its respective authors. By adding content to this wiki, you agree to release it under the [BSD license](https://factorcode.org/license.txt). \ No newline at end of file diff --git a/references/ForthNotes/Factor.md b/references/ForthNotes/Factor.md new file mode 100644 index 0000000..7c1ed9f --- /dev/null +++ b/references/ForthNotes/Factor.md @@ -0,0 +1,71 @@ +# Factor + +**Source:** https://factorcode.org + +Factor programming language + + + +![Factor programming language](logo.png) + +# Why Factor + +The **Factor programming language** is a [concatenative](http://www.concatenative.org/), stack-based programming language with [high-level features](http://concatenative.org/wiki/view/Factor/Features/The%20language) including dynamic types, extensible syntax, macros, and garbage collection. On a practical side, Factor has a [full-featured library](http://docs.factorcode.org/content/article-vocab-index.html), supports many different platforms, and has been extensively documented. + +The implementation is [fully compiled](http://concatenative.org/wiki/view/Factor/Optimizing%20compiler) for performance, while still supporting [interactive development](http://concatenative.org/wiki/view/Factor/Interactive%20development). Factor applications are portable between all common platforms. Factor can [deploy stand-alone applications](http://concatenative.org/wiki/view/Factor/Deployment) on all platforms. Full [source code](https://github.com/factor/factor) for the Factor project is available under a [BSD license](https://factorcode.org/license.txt). + +* [Learn more about Factor](https://concatenative.org/wiki/view/Factor) +* [Get started programming with Factor](https://concatenative.org/wiki/view/Factor/Learning) +* [Get answers to frequently-asked questions](https://concatenative.org/wiki/view/Factor/FAQ) +* [Read Factor documentation online](https://docs.factorcode.org/) +* [Learn about concatenative programming](https://concatenative.org/wiki/view/Concatenative%20language) +* [See some example programs](https://concatenative.org/wiki/view/Factor/Examples) +* [Report a bug](https://github.com/factor/factor/issues) +* Screenshots on [macOS](https://factorcode.org/factor-macos.png), [Windows](https://factorcode.org/factor-windows7.png) + +``` +USING: io kernel sequences ; + +4 [ + "Happy Birthday " write + 2 = "dear NAME" "to You" ? print +] each +``` + +# Downloads + +To download a binary, follow the link for the desired OS / CPU configuration. Binary packages are the recommended route for new users who wish to try Factor. + +## Stable release: [0.101](https://re.factorcode.org/2025/12/factor-0-101-now-available.html) + +| OS/CPU | Windows | macOS | Linux | +| --- | --- | --- | --- | +| x86 | [0.101](https://builds.factorcode.org/release?os=windows&cpu=x86.32) | | [0.101](https://builds.factorcode.org/release?os=linux&cpu=x86.32) | +| x86-64 | [0.101](https://builds.factorcode.org/release?os=windows&cpu=x86.64) | [0.101](https://builds.factorcode.org/release?os=macos&cpu=x86.64) | [0.101](https://builds.factorcode.org/release?os=linux&cpu=x86.64) | + +**Source code**: +[0.101](https://downloads.factorcode.org/releases/0.101/factor-src-0.101.zip) + +## Development release + +| OS/CPU | Windows | macOS | Linux | +| --- | --- | --- | --- | +| x86 | [2025-12-17](https://builds.factorcode.org/package?os=windows&cpu=x86.32) | | [2026-02-11](https://builds.factorcode.org/package?os=linux&cpu=x86.32) | +| x86-64 | [2025-12-17](https://builds.factorcode.org/package?os=windows&cpu=x86.64) | [2026-02-09](https://builds.factorcode.org/package?os=macos&cpu=x86.64) | [2026-02-11](https://builds.factorcode.org/package?os=linux&cpu=x86.64) | + +**Source code**: available via [github](https://github.com/factor/factor/) or [gitweb](https://gitweb.factorcode.org/) or [cgit](https://cgit.factorcode.org/). + +Stable and development releases are built and uploaded by the [build farm](https://concatenative.org/wiki/view/Factor/Build%20farm). Follow [@FactorBuilds](https://twitter.com/FactorBuilds) on Twitter to receive notifications. If you're curious, take a look at the [build farm dashboard](https://builds.factorcode.org/dashboard). You can also [build Factor](https://concatenative.org/wiki/view/Factor/Building%20Factor) on your own platform from source. + +## Older releases + +[Download older releases](https://downloads.factorcode.org/releases/) from [Factor 0.29](https://downloads.factorcode.org/releases/0.29/) to the current release. + +# Community + +* [Join the mailing list](https://concatenative.org/wiki/view/Factor/Mailing%20list) +* [Join the Discord](https://discord.gg/QxJYZx3QDf) +* [Join the IRC channel](https://concatenative.org/wiki/view/Concatenative%20IRC%20channel) +* [Factor community blogs](https://planet.factorcode.org/) +* [Factor community pastebin](https://paste.factorcode.org/) - if you're in an IRC channel and want to share some code +* [Academic publications](https://concatenative.org/wiki/view/Concatenative%20language/Publications) \ No newline at end of file diff --git a/references/ForthNotes/Forth-_The_Early_Years.md b/references/ForthNotes/Forth-_The_Early_Years.md new file mode 100644 index 0000000..0bfa115 --- /dev/null +++ b/references/ForthNotes/Forth-_The_Early_Years.md @@ -0,0 +1,377 @@ +# Forth- The Early Years + +**Source:** https://colorforth.github.io/HOPL.html + +Chuck Moore: The Invention of Forth + + +# Forth - The Early Years + +Chuck Moore + +[chipchuck@colorforth.com](mailto:chipchuck@colorforth.com) + +1991 + +## Abstract + +Forth is a simple, natural computer language. It has achieved remarkable acceptance where efficiency is valued. It evolved in the 1960s on a journey from university through business to laboratory. This is the story of how a simple interpreter expanded its abilities to become a complete programming language/operating system. + +## Forward 1999 + +This paper was written for the HOPL II (History of programming languages) conference. It was summarily rejected, apparently because of its style. Much of the content was included in the accepted paper [Rather 1993]. + +This HTML version was reformatted from the original typescript. Minimal changes were made to the text. Examples of source code were suggested by reviewer Phil Koopman. They've not yet been added. + +## Contents + +Forth + +MIT, SAO, 1958 + +Stanford, SLAC, 1961 + +Free-lance, 1965 + +Mohasco, 1968 + +NRAO, 1971 + +Moral + +## Forth + +Forth evolved during the decade of the 60s, across America, within university, business and laboratory, amongst established languages. During this period, I was its only programmer and it had no name until the end. This account is retrieved from memory, prompted by sparse documentation and surviving listings. + +Forth is hardly original, but it is a unique combination of ingredients. I'm grateful to the people and organizations who permitted me to develop it - often unbeknownst to them. And to you, for being interested enough to read about it. + +Forth is a simple, natural computer language. Today it is accepted as a world-class programming language. That it has achieved this without industry, university or government support is a tribute to its efficiency, reliability and versatility. Forth is the language of choice when its efficiency outweighs the popularity of other languages. This is more often the case in real-world applications such as control and communication. + +A number of Forth organizations and a plethora of small companies provide systems, applications and documentation. Annual conferences are held in North America, Europe and Asia. A draft ANSI standard will soon be submitted [ANS 1991]. + +None of the books about Forth quite capture its flavor. I think the best is still the first, Starting Forth by Leo Brodie [Brodie 1981]. Another window is provided by JFAR's invaluable subject and author index [Martin 1987]. + +The classic Forth we are discussing provides the minimum support a programmer needs to develop a language optimized for his application. It is intended for a work-station environment: keyboard, display, computer and disk. + +Forth is a text-based language that is essentially context-free. It combines 'words' separated by spaces, to construct new words. About 150 such words constitute a system that provides (with date of introduction) + +``` + SAO 1958 Interpreter + SLAC 1961 Data stack + RSI 1966 Keyboard input + Display output, OK + Editor + Mohasco 1968 Compiler + Return stack + Dictionary + Virtual memory (disk) + Multiprogrammer + NRAO 1971 Threaded code + Fixed-point arithmetic +``` + +Such a system has 3-8K bytes of code compiled from 10-20 pages of source. It can easily be implemented by a single programmer on a small computer. + +This account necessarily follows my career. But it is intended to be the autobiography of Forth. I will discuss the features listed above; and the names of the words associated with them. The meaning of many words is obvious. Some warrant description and some are beyond the scope of this paper. + +That portion of the Forth dictionary to be mentioned is summarized here: + +``` +Interpreter + WORD NUMBER INTERPRET ABORT + HASH FIND ' FORGET + BASE OCTAL DECIMAL HEX + LOAD EXIT EXECUTE ( +Terminal + KEY EXPECT + EMIT CR SPACE SPACES DIGIT TYPE DUMP +Data stack + DUP DROP SWAP OVER + + - * / MOD NEGATE + ABS MAX MIN + AND OR XOR NOT + 0< 0= = + @ ! +! C@ C! + SQRT SIN.COS ATAN EXP LOG +Return stack + : ; PUSH POP I +Disk + BLOCK UPDATE FLUSH BUFFER PREV OLDEST +Compiler + CREATE ALLOT , SMUDGE + VARIABLE CONSTANT + [ ] LITERAL ." COMPILE + BEGIN UNTIL AGAIN WHILE REPEAT + DO LOOP +LOOP IF ELSE THEN +``` + +## MIT, SAO, 1958 + +October, 1957 was Sputnik - a most exciting time. I was a sophmore at MIT and got a part-time job with SAO (Smithsonian Astrophysical Observatory, 14 syllables) at Harvard. + +SAO was responsible for optical tracking of satellites - Moonwatch visual observations and Baker-Nunn tracking cameras. Caught off-guard by Sputnik, they hired undergraduates to compute predictions with Friden desk calculators. John Gaustad told me about MIT's IBM EDPM 704 and loaned me his Fortran II manual. My first program, Ephemeris 4, eliminated my job [Moore 1958]. + +Now a Programmer, I worked with George Veis to apply his method of least-squares fitting to determine orbital elements, station positions and ultimately the shape of Earth [Veis 1960]. Of course, this part-time job was at least 40 hours, and yes, my grades went to hell. + +At MIT, John McCarthy taught an incredible course on LISP. That was my introduction to recursion, and to the marvelous variety of computer language. Wil Baden has noted that LISP is to Lambda Calculus as Forth is to Lukasewcleicz Postfix. + +APL was also a topical language, with its weird right-left parsing. Although I admire and emulate its operators, I'm not persuaded they constitute an optimal set. + +The programming environment in the 50s was more severe than today. My source code filled 2 trays with punch cards. They had to be carried about to be put through machines, mostly by me. Compile took 30 minutes (just like C) but limited computer time meant one run per day, except maybe 3rd shift. + +So I wrote this simple interpreter to read input cards and control the program. It also directed calculations. The five orbital elements each had an empirical equation to account for atmospheric drag and the non-spherical Earth. Thus I could compose different equations for the several satellites without re-compiling. + +These equations summed terms such as P2 (polynomial of degree 2) and S (sine). 36-bit floating-point dominated calculation time so overhead was small. A data stack was unnecessary, and probably unknown to me. + +The Forth interpreter began here with the words + +``` + WORD NUMBER INTERPRET ABORT +``` + +They weren't spelled that way because they were statement numbers. + +INTERPRET uses WORD to read words separated by spaces and NUMBER to convert a word to binary (in this case, floating-point). Such free-format input was unusual, but was more efficient (smaller and faster) and reliable. Fortran input was formatted into specific columns and typographic errors had caused numerous delays. + +This interpreter used an IF ... ELSE IF construct, coded in Fortran, finding a match on a single character. Error handling consisted of terminating the run. Then, as now, ABORT asked the user what to do. Since input cards were listed as they were read, you knew where the error was. + +## Stanford, SLAC, 1961 + +In 1961 I went to Stanford to study mathematics. Although Stanford was building its computer science department, I was interested in real computing. I was impressed that they could (dared?) write their own Algol compiler. And I fatefully encountered the Burroughs B5500 computer. + +I got another 'part-time' job at SLAC (Stanford Linear Accelerator Center, 12 syllables) writing code to optimize beam steering for the pending 2-mile electron accelerator. This was a natural application of my least-squares experience to phase-space. Hal Butler was in charge of our group and the program, TRANSPORT, was quite successful. + +Another application of least-squares was the program CURVE, coded in Algol (1964). It is a general-purpose non-linear differential-corrections data-fitting program. Its statistical rigor provides insight into agreement between model and data. + +The data format and model equations were interpreted and a push-down stack used to facilitate evaluation. CURVE was an impressive precursor to Forth. It introduced these words to provide the capability to fit models much more elaborate than simple equations: + +``` + + - * NEGATE + IF ELSE THEN < + DUP DROP SWAP + : ; VARIABLE ! ( + SIN ATAN EXP LOG +``` + +Spelling was quite different: + +``` + NEGATE was MINUS + DROP ; + SWAP . + ! < + VARIABLE DECLARE + ; END + ( ...) COMMENT ...; +``` + +The interpreter used IF ... ELSE IF to identify a 6-character input word called ATOM (from LISP). DUP DROP and SWAP are 5500 instructions; I'm surprised at the spelling change. The word : was taken from the Algol label format, flipped for left-right parsing (to prevent the interpreter encountering an undefined word): + +``` + Algol - LABEL: + CURVE - : LABEL +``` + +In fact, : marked a position in the input string to be interpreted later. Interpretation was stopped by ; . A version of : was named DEFINE . + +The store operator ( ! ) appeared in connection with VARIABLE . But fetching ( @ ) was automatic. Note the input had become complex enough to warrant comments. The sometime-criticised postfix conditional dates from here: + +``` + Algol - IF expression THEN true ELSE false + CURVE - stack IF true ELSE false THEN +``` + +True is interpreted if stack is non-zero. THEN provides unique termination, the lack of which always confused me in Algol. Such expressions were interpreted: IF would scan ahead for ELSE or THEN. + +The word < introduces the convention that relations leave a truth value on the stack, 1 for true and 0 for false. The transcendental functions are, of course, library calls. + +## Free-lance + +I left Stanford in 1965 to become a free-lance programmer in the New York City area. This was not unusual, and I found work programming in Fortran, Algol, Jovial, PL/I and various assemblers. I literally carried my card deck about and recoded it as necessary. + +Minicomputers were appearing, and with them terminals. The interpreter was ideal for teletype input, and soon included code to handle output. So we aquire the words + +``` + KEY EXPECT + EMIT CR SPACE SPACES DIGIT TYPE +``` + +EXPECT is a loop calling KEY to read a keystroke. TYPE is a loop calling EMIT to display a character. + +With the TTY came paper-tape and some of the most un-friendly software imaginable - hours of editing and punching and loading and assembling and printing and loading and testing and repeating. I remember a terrible Sunday in a Manhattan skyscraper when I couldn't find splicing tape (nothing else works) and swore that 'There must be a better way'. + +I did considerable work for Bob Davis at Realtime Systems, Inc (RSI). I became a 5500 MCP guru to support his time-sharing service (remote input to a mainframe) and wrote a Fortran-Algol translator and file editing utilities. The translator taught me the value of spaces between words, not required by Fortran. + +The interpreter still accepted words with the first 6 characters significant (the 5500 had 48-bit words). The words + +``` + LIST EDIT BEGIN AGAIN EXIT +``` + +appear, with BEGIN ... AGAIN spelled START ... REPEAT and used to bracket the editor commands + +``` + T TYPE I INSERT D DELETE F FIND +``` + +later used in NRAO's editor. The word FIELD was used in the manner of Mohasco and Forth, Inc's data-base management. + +One of Forth's distinctive features comes from here. The rule is that Forth acknowledge each line of input by appending OK when interpretation is complete. This may be difficult, for when input is terminated by CR a blank must be echoed, and the CR included with OK. At RSI, OK was on the next line, but it still conveyed friendly reassurance over an intimidating communications line: + +``` + 56 INSERT ALGOL IS VERY ADAPTABLE + OK +``` + +This postfix notation suggests a data stack, but it only had to be one deep. + +## Mohasco, 1968 + +In 1968 I transformed into a business programmer at Mohasco Industries, Inc in Amsterdam NY. They are a major home-furnishing company - carpets and furniture. I had worked with Geoff Leach at RSI and he persuaded me to follow him up-state. I had just married, and Amsterdam has a lovely small-town atmosphere to contrast with NYC. + +I rewrote my code in COBOL and learned the truth about business software. Bob Rayco was in charge of Corporate data processing and assigned me two relevant projects: + +He leased an IBM 1130 minicomputer with a 2250 graphic display. The object was to see if computer graphics helped design patterned carpets. The answer was 'not without color' and the 1130 went away. + +Meanwhile I had the latest minicomputer environment: 16-bit CPU, 8K RAM, disk (my first), keyboard, printer, card reader/punch, Fortran compiler. The reader/punch provided disk backup. I ported my interpreter again (back to Fortran) and added a cross-assembler to generate code for the 2250. + +The system was a great success. It could draw animated 3-D images when IBM could barely draw static 2-D. Since this was my first real-time graphics, I coded Spacewar, that first video game. I also converted my Algol chess program into Forth and was duely impressed how much simpler it became. + +The file holding the interpreter was labeled FORTH, for 4th (next) generation software - but the operating system restricted file names to 5 characters. + +This environment for programming the 2250 was far superior to the Fortran environment, so I extended the 2250 cross-assembler into an 1130 compiler. This introduced a flock of words + +``` + DO LOOP UNTIL + BLOCK LOAD UPDATE FLUSH + BASE CONTEXT STATE INTERPRET DUMP + CREATE CODE ;CODE CONSTANT SMUDGE + @ OVER AND OR NOT 0= 0< +``` + +They were still differently spelled + +``` + LOOP was CONTINUE + UNTIL END + BLOCK GET + LOAD READ + TYPE SEND + INTERPRET QUERY + CREATE ENTER + CODE the cent symbol +``` + +The only use I've ever found for the cent symbol. The loop index and limit were on the data stack. DO and CONTINUE were meant to acknowledge Fortran. + +BLOCK manages a number of buffers to minimize disk access. LOAD reads source from a 1024-byte block. 1024 was chosen as a nice modular amount of disk, and has proven a good choice. UPDATE allows a block to be marked and later rewritten to disk, when its buffer is needed (or by FLUSH ). It implements virtual memory and is concealed in store ( ! ) words. + +BASE allows octal and hex numbers as well as decimal. CONTEXT was the first hint of vocabularies and served to isolate editor words. STATE distinguished compiling from interpreting. During compilation, the count and first 3 characters of a word were compiled for later interpretation. Strangely, words could be terminated by a special character, an aberration quickly abandoned. The fetch operator ( @ ) appeared in many guises, since fetching from variables, arrays and disk had to be distinguished. DUMP became important for examining memory. + +But most important, there was now a dictionary. Interpret code now had a name and searched a linked-list for a match. CREATE constructs the classic dictionary entry: + +``` + link to previous entry + count and 3 characters + code to be executed + parameters +``` + +The code field was an important innovation, since an indirect jump was the only overhead, once a word had been found. The value of the count in distinguishing words, I learned from the compiler writers of Stanford. + +An important class of words appeared with CODE . Machine instructions followed in the parameter field. So any word within the capability of the computer could now be defined. ;CODE specifies the code to be executed for a new class of words, and introduced what are now called objects. + +SMUDGE avoided recursion during the interpretation of a definition. Since the dictionary would be searched from newest to oldest definitions, recursion would normally occur. + +Finally, the return stack appeared. Heretofor, definitions had not been nested, or used the data stack for their return address. Altogether a time of great innovation in the punctuated evolution of Forth. + +The first paper on Forth, an internal Mohasco report, was written by Geoff and me [Moore 1970]. It would not be out of place today. + +In 1970 Bob ordered a Univac 1108. An ambitious project to support a network of leased lines for an order-entry system. I had coded a report generator in Forth and was confident I could code order-entry. I ported Forth to the 5500 (standalone!) to add credibility. But corporate software was COBOL. The marvelous compromise was to install a Forth system on the 1108 that interfaced with COBOL modules to do transaction processing. + +I vividly recall commuting to Schenectady that winter to borrow 1107 time 3rd shift. My TR4-A lacked floor and window so it became a nightly survival exercise. But the system was an incredible success. Even Univac was impressed with its efficiency (Les Sharp was project liason). The ultimate measure was response time, but I was determined to keep it maintainable (small and simple). Alas, an economic downturn led Management to cancel the 1108. I still think it was a bad call. I was the first to resign. + +1108 Forth must have been coded in assembler. It buffered input and output messages and shared the CPU among tasks handling each line. Your classic operating system. But it also interpreted the input and PERFORMed the appropriate COBOL module. It maintained drum buffers and packed/unpacked records. The words + +``` + BUFFER PREV OLDEST + TASK ACTIVATE GET RELEASE +``` + +date from here. BUFFER avoided a disk read when the desired block was known empty. PREV (previous) and OLDEST are system variables that implement least-recently-used buffer management. TASK defines a task at boot time and ACTIVATE starts it when needed. GET and RELEASE manage shared resources (drum, printer). PAUSE is how a task relinquishes control of the CPU. It is included in all I/O operations and is invisible to transaction code. It allows a simple round-robin scheduling algorithm that avoids lock-out. + +After giving notice, I wrote an angry poem and a book that has never been published. It described how to develop Forth software and encouraged simplicity and innovation. It also described indirect-threaded code, but the first implementation was at NRAO. + +I struggled with the concept of meta-language, language that talks about language. Forth could now interpret an assembler, that was assembling a compiler, that would compile the interpreter. Eventually I decided the terminology wasn't helpful, but the term Meta-compile for recompiling Forth is still used. + +## NRAO, 1971 + +George Conant offered me a position at NRAO (National Radio Astronomy Observatory, 15 syllables). I had known him at SAO and he liked Ephemeris 4. So we moved to Charlottesville VA and spent summers in Tucson AZ when the radio-telescope on Kitt Peak was available for maintainance. + +The project was to program a Honeywell 316 minicomputer to control a new filter-bank for the 36' millimeter telescope. It had a 9-track tape and Tektronix storage-tube terminal. George gave me a free hand to develop the system, though he wasn't pleased with the result. NRAO was a Fortran shop and by now I was calling Forth a language. He was right in that organizations have to standardize on a single language. Other programmers now wanted their own languages. + +Anyhow, I had coded Forth in assembler on the IBM 360/50 mainframe. Then I cross-compiled it onto the 316. Then I re-compiled it on the 316 (Although I had a terminal on the 360, response time was terrible). The application was easy once the system was available. There were two modes of observing, continuum and spectral-line. Spectral-line was the most fun, for I could display spectra as they were collected and fit line-shapes with least-squares [Moore 1973]. + +The system was well-received in Tucson, where Ned Conklin was in charge. It did advance the state-of-the-art in on-line data reduction. Astronomers used it to discover and map inter-stellar molecules just as that became hot research. + +Bess Rather was hired to provide on-site support. She had first to learn the Forth system and then explain and document it, with minimal help from me. The next year I reprogrammed the DDP-116 to optimize telescope pointing. The next, Bess and I replaced the 116 and 316 with a DEC PDP-11. + +The development that made all this possible was indirect-threaded code. It was a natural development from my work at Mohasco, though I later heard that DEC had used direct-threaded code in one of their compilers. Rather than re-interpret the text of a definition, compile the address of each dictionary entry. This improved efficiency for each reference required only 2 bytes and an address interpreter could sequence through a definition enormously faster. In fact, this interpreter was a 2-word macro on the 11: + +``` + : NEXT IP )+ W MOV W )+ ) JMP ; +``` + +Now Forth was complete. And I knew it. I could write code more quickly that was more efficient and reliable. Moreover, it was portable. I proceeded to recode the 116 pointing the 300' Green Bank telescope, and the HP mini that was inaugurating VLBI astronomy. George gave me a ModComp and I did Fourier transforms for interferometry and pulsar search (64K data). I even demonstrated that complex multiply on the 360 was 20% faster in Forth than assembler. + +NRAO appreciated what I had wrought. They had an arrangement with a consulting firm to identify spin-off technology. The issue of patenting Forth was discussed at length. But since software patents were controversial and might involve the Supreme Court, NRAO declined to pursue the matter. Whereupon, rights reverted to me. I don't think ideas should be patentable. Hindsight agrees that Forth's only chance lay in the public domain. Where it has flourished. + +Threaded-code changed the structure words (such as DO LOOP IF THEN ). They acquired an elegant implementation with addresses on the data stack during compilation. + +Now each Forth had an assembler for its particular computer. It uses post-fix op-codes and composes addresses on the data stack, with Forth-like structure words for branching. The manufacturer's mnemonics are defined as word classes by ;CODE . Might take an afternoon to code. An example is the macro for NEXT above. + +Unconventional arithmetic operators proved their value + +``` + M* */ /MOD SQRT SIN.COS ATAN EXP LOG +``` + +M\* is the usual hardware multiply of 2 16-bit numbers to a 32-bit product (arguments, of course, on the data stack). \*/ follows that with a divide to implement rational arithmetic. /MOD returns both quotient and remainder and is ideal for locating records within a file. SQRT produces a 16-bit result from a 32-bit argument. SIN.COS returns both sine and cosine as is useful for vector and complex arithmetic (FFT). ATAN is its inverse and has no quadrant ambiguity. EXP and LOG were base 2. + +These functions used fixed-point arithmetic - 14 or 30 bits right of a binary point for trig, 10 for logs. This became a characteristic of Forth since it's simpler, faster and more accurate than floating-point. But hardware and software floating-point are easy to implement. + +I'd like to applaud the invaluable work of Hart [Hart 1978] in tabulating function approximations with various accuracies. They have provided freedom from the limitations of existing libraries to those of us in the trenches. + +The word DOES> appeared (spelled ;: ). It defines a class of words (like ;CODE ) by specifying the definition to be interpreted when the word is referenced. It was tricky to invent, but particularly useful for defining op-codes. + +Nonetheless, I failed to persuade Charlottesville that Forth was suitable. I wasn't going to be allowed to program the VLA. Of any group, 25% like Forth and 25% hate it. Arguments can get violent and compromise is rare. So the friendlies joined forces and formed Forth, Inc. And that's another story. + +## Moral + +The Forth story has the making of a morality play: Persistant young programmer struggles against indifference to discover Truth and save his suffering comrades. It gets better: Watch Forth. Inc go head to head with IBM over a French banking system. + +I know Forth is the best language so far. I'm pleased at its success, especially in the ultra-conservative arena of Artificial Intelligence. I'm disturbed that people who should, don't appreciate how it embodies their own description of the ideal programming language. + +But I'm still exploring without license. Forth has led to an architecture that promises a wonderful integration of software and silicon. And another new programming environment. + +## References + +[ANS 1991] Draft Proposed ANS Forth, document number X3.215-199x, available from Global Engineering Documents, 2805 McGaw Ave., Irvine CA 92714. + +[Brodie, 1981] Brodie, Leo, Starting FORTH, Englewood Cliffs NJ: Prentice-Hall, 1981, ISBN 0 13 842930 8. + +[Hart, 1968] Hart, John F. et al, Computer Approximations. Malabar FL: Krieger, 1968; (Second Edition), 1978, ISBN 0 88275 642 7. + +[Martin, 1987] Martin, Thea, A Bibliography of Forth References, 3rd Ed, Rochester NY: Institute for Applied Forth Research, 1987, ISBN 0 914593 07 2. + +[Moore, 1958] Moore, Charles H. and Lautman, Don A., Predictions for photographic tracking stations - APO Ephemeris 4, in SAO Special Report No. 11, Schilling G. F., Ed., Cambridge MA: Smithsonian Astrophysical Observatory, 1958 March. + +[Moore, 1970] --- and Leach, Geoffrey C., FORTH - A Language for Interactive Computing, Amsterdam NY: Mohasco Industries, Inc. (internal pub.) 1970. + +[Moore, 1972] --- and Rather, Elizabeth D., The FORTH program for spectral line observing on NRAO's 36 ft telescope, Astronomy & Astrophysics Supplement Series, Vol. 15, No. 3, 1974 June, Proceedings of the Symposium on the Collection and Analysis of Astrophysical Data, Charlottesville VA, 1972 Nov. 13-15. + +[Moore, 1980] ---, The evolution of FORTH, an unusual language, Byte, 5:8, 1980 August. + +[Rather, 1993] Rather, Elizabeth D., Colburn, Donald R. and Moore, Charles H., The Evolution of Forth, in History of Programming Languages-II, Bergin T. J. and Gibson, R. G., Ed., New York NY: Addison-Wesley, 1996, ISBN 0-201-89502-1. + +[Veis, 1960] Veis, George and Moore, C. H., SAO differential orbit improvement program, in Tracking Programs and Orbit Determination Seminar Proceedings, Pasadena CA: JPL, 1960 February 23-26. \ No newline at end of file diff --git a/references/ForthNotes/Forth.md b/references/ForthNotes/Forth.md new file mode 100644 index 0000000..baf1b3e --- /dev/null +++ b/references/ForthNotes/Forth.md @@ -0,0 +1,42 @@ +# Forth + +**Source:** https://www.taygeta.com/forth.html + + Forth Information on Taygeta, Taygeta Scientific Inc. + + + + +# Forth Information on Taygeta + +*Last updated 26 November 2004* + + + + +![====](/icons/maroonbar.gif) + +Taygeta Scientific provides custom software and consulting for applications +using Forth for real-time applications, embedded systems, signal processing, +robotics, Unix scripting, and WWW CGI programs. +[Contact us](mailto:office@taygeta.com) for details. + +--- + +![](/icons/archiv.gif) [**Forth Literature and Education**](forthlit.html) + +--- + +### Software: + +![](/icons/star.gif) [**Forth Compilers**](forthcomp.html) ![](/icons/star.gif) [**TCP/IP networking with Forth**](networking/forthnet.html) + +#### Applications: + +![](/icons/pink.gif) John Hayes's ANS compiler validation program (27 Nov 95 version) (two files), [tester.fr V1.1](ftp://ftp.taygeta.com/pub/Forth/Applications/ANS/tester.fr) and [core.fr V1.2](ftp://ftp.taygeta.com/pub/Forth/Applications/ANS/core.fr) ![](/icons/pink.gif) The [Forth Scientific Library](fsl/sciforth.html) project Info ![](/icons/pink.gif) The [UUDECODE utility](ftp://ftp.taygeta.com/pub/Forth/Applications/ANS/uudecode.seq) (ANS). ![](/icons/pink.gif) The [UUENCODE utility](ftp://ftp.taygeta.com/pub/Forth/Applications/ANS/uuencode.seq) (ANS). ![](/icons/pink.gif) The **LZ77 Data Compression** utility, [Info](ftp://ftp.taygeta.com/pub/Forth/Applications/ANS/lzss.doc), and [code](ftp://ftp.taygeta.com/pub/Forth/Applications/ANS/lzss.fo). ![](/icons/pink.gif) An implementation of the [**ANS Memory-Allocation Wordset**](ftp://ftp.taygeta.com/pub/Forth/Applications/ANS/memory.fth). + +#### Development tools: + +![](/icons/pink.gif) [**Joerg Plewe**'s **ANS Debugger (From Forth Dimensions)**](ftp://ftp.taygeta.com/pub/Forth/Applications/ANS/debugger.ans) ![](/icons/pink.gif) [EMACS Forth Mode](ftp://ftp.taygeta.com/pub/Forth/Tools/forth.el) elisp file (V2.10) by **Goran Rydqvist**. ![](/icons/pink.gif) A [Condordance generator for Forth source files](ftp://ftp.taygeta.com/pub/Forth/Tools/concordance.fth) (V1.6) [(PFE version)](ftp://ftp.taygeta.com/pub/Forth/Tools/pfe/concordance.fth) ![](/icons/pink.gif) An [EMACS **TAGS** for Forth source files](ftp://ftp.taygeta.com/pub/Forth/Tools/ftags.fth) (V1.5) [(PFE version)](ftp://ftp.taygeta.com/pub/Forth/Tools/ftags.fth) ![](/icons/pink.gif) A [Forth source code obfuscator](ftp://ftp.taygeta.com/pub/Forth/Tools/gfob-0.1.0.tar.gz) (V0.1.0) by **Pierre Abbat** ([phma@trellis.net](mailto:phma@trellis.net)). + +#### Interesting Forth Applications: [Gray Forth Parser generator](ftp://ftp.complang.tuwien.ac.at/pub/forth) (ANS version) [MIX emulator, assembler, disassembler](ftp://iaehv.iaehv.nl/pub/users/mhx) by **Marcel Hendrix**. 190 MB of Forth Online ! --- Other WWW Forth resources: [The **Forth Interest Group** home page](http://www.forth.org). --- Sites: [AM Research](http://www.amresearch.com) Embedded control systems page with Forth information and software [ATHENA](ftp://ftp.uu.net/vendor/minerva/uathena.htm) Programming, Inc. [ftp.cygnus.com](ftp://ftp.cygnus.com/pub/forth) Forth directory. [Asterix FTP](ftp://ftp.dei.isep.ipp.pt/pub/forth) site (Portugal), [Asterix MIRROR FTP](ftp://col.hp.com/mirrors) site. The [**Forth Research Page at Bournemouth**](http://dec.bournemouth.ac.uk/forth). * The [**DeloSoft**](http://www.delosoft.com/) site, has **dsForth** for WindowsCE on MIPS, SH3 and Intel processors. [ForthChip](http://www.forthchip.com/), a site primarily about the F21 family of processors [**TILE** Forth](ftp://ftp.lysator.liu.se/pub/languages/forth) FTP site. Other [Forth](http://pisa.rockefeller.edu:8080/FORTH/) related info. * The [**Pocket Forth**](http://chemlab.pc.maricopa.edu/pocket.html) site. The [South Ontario FIG Chapter Library](ftp://pc-solntseff-n.dcss.mcmaster.ca) (after hours, 8:30 to 5:30 EST Mondays to Fridays, please). [ACM SIGFORTH](gopher://gopher.acm.org/11[the_files.sig_forums.sigFORTH]) directory. [Forth in French](http://perso.wanadoo.fr/mp7/forth). [ITCN](http://www.cera2.com/forth.htm) Forth Resources page * The [JForth site](http://jforth.org/) (for the Amiga) * The [Pysmatic Forth center](http://www.pysmatic.com/forth/). * The [**Russian Forth Interest Group**](http://www.forth.org.ru/) * The [**EServ (Forth Web Server) Open source site**](http://www.opensource.org.ru/eserv-src/src.html) (in Russian) * [**SP-Forth**](http://www.enet.ru/win/cherezov/) Russian site, Windows 95/NT Forth A list of [Forth applications in space](http://forth.gsfc.nasa.gov) [Transport Control Technology Ltd.](http://www.tcontec.demon.co.uk) Control system design consultants * The [Treasure Isle of Forth](http://www.stejskal.de/web/computer/forth/_index.html) --- **The Forth Webring** [[Prev](http://www.webring.org/cgi-bin/webring?ring=forth&id=10&prev)] [[Random](http://www.webring.org/cgi-bin/webring?random&ring=forth)] [[List Sites](http://www.webring.org/cgi-bin/webring?ring=forth&list)] [[Next](http://www.webring.org/cgi-bin/webring?ring=forth&id=10&next)] [[Next 5](http://www.webring.org/cgi-bin/webring?ring=forth&id=10&next5)] [Dr. Everett (Skip) F. Carter Jr.](EFCBio-General.html) [Taygeta Scientific Inc.](taygeta.html) 1340 Munras Ave., Suite 314 Monterey, CA. 93940-6140 | voice: 831.641.0645 FAX: 831.641.0647 INTERNET:[skip@taygeta.com](http://www.taygeta.com/mailme.html) WWW: | [Taygeta's home page](http://www.taygeta.com/index.html) \ No newline at end of file diff --git a/references/ForthNotes/Forth_Landing.md b/references/ForthNotes/Forth_Landing.md new file mode 100644 index 0000000..981008f --- /dev/null +++ b/references/ForthNotes/Forth_Landing.md @@ -0,0 +1,17 @@ +# Forth Landing + +**Source:** https://wiki.c2.com/?ForthLanguage + +**notice** + +javascript required to view this site + +**why** + +measured improvement in server performance + +awesome incremental search + +![](spin.gif) + +This site uses features not available in older browsers. \ No newline at end of file diff --git a/references/ForthNotes/Forth_Values.md b/references/ForthNotes/Forth_Values.md new file mode 100644 index 0000000..b5f544d --- /dev/null +++ b/references/ForthNotes/Forth_Values.md @@ -0,0 +1,17 @@ +# Forth Values + +**Source:** https://wiki.c2.com/?ForthValues + +**notice** + +javascript required to view this site + +**why** + +measured improvement in server performance + +awesome incremental search + +![](spin.gif) + +This site uses features not available in older browsers. \ No newline at end of file diff --git a/references/ForthNotes/GDForth.md b/references/ForthNotes/GDForth.md new file mode 100644 index 0000000..6f19dd9 --- /dev/null +++ b/references/ForthNotes/GDForth.md @@ -0,0 +1,311 @@ +# GDForth + +**Source:** https://github.com/yumaikas/GDForth + +GitHub - yumaikas/GDForth: A Forth-alike for better async GDScript + + + +[Skip to content](#start-of-content) + + + + + + + + + + + + + +## Navigation Menu + +Toggle navigation + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2Fyumaikas%2FGDForth) + +Appearance settings + +* Platform + + + AI CODE CREATION + - [GitHub CopilotWrite better code with AI](https://github.com/features/copilot) + - [GitHub SparkBuild and deploy intelligent apps](https://github.com/features/spark) + - [GitHub ModelsManage and compare prompts](https://github.com/features/models) + - [MCP RegistryNewIntegrate external tools](https://github.com/mcp) + + DEVELOPER WORKFLOWS + - [ActionsAutomate any workflow](https://github.com/features/actions) + - [CodespacesInstant dev environments](https://github.com/features/codespaces) + - [IssuesPlan and track work](https://github.com/features/issues) + - [Code ReviewManage code changes](https://github.com/features/code-review) + + APPLICATION SECURITY + - [GitHub Advanced SecurityFind and fix vulnerabilities](https://github.com/security/advanced-security) + - [Code securitySecure your code as you build](https://github.com/security/advanced-security/code-security) + - [Secret protectionStop leaks before they start](https://github.com/security/advanced-security/secret-protection) + + EXPLORE + - [Why GitHub](https://github.com/why-github) + - [Documentation](https://docs.github.com) + - [Blog](https://github.blog) + - [Changelog](https://github.blog/changelog) + - [Marketplace](https://github.com/marketplace) + + [View all features](https://github.com/features) +* Solutions + + + BY COMPANY SIZE + - [Enterprises](https://github.com/enterprise) + - [Small and medium teams](https://github.com/team) + - [Startups](https://github.com/enterprise/startups) + - [Nonprofits](https://github.com/solutions/industry/nonprofits) + + BY USE CASE + - [App Modernization](https://github.com/solutions/use-case/app-modernization) + - [DevSecOps](https://github.com/solutions/use-case/devsecops) + - [DevOps](https://github.com/solutions/use-case/devops) + - [CI/CD](https://github.com/solutions/use-case/ci-cd) + - [View all use cases](https://github.com/solutions/use-case) + + BY INDUSTRY + - [Healthcare](https://github.com/solutions/industry/healthcare) + - [Financial services](https://github.com/solutions/industry/financial-services) + - [Manufacturing](https://github.com/solutions/industry/manufacturing) + - [Government](https://github.com/solutions/industry/government) + - [View all industries](https://github.com/solutions/industry) + + [View all solutions](https://github.com/solutions) +* Resources + + + EXPLORE BY TOPIC + - [AI](https://github.com/resources/articles?topic=ai) + - [Software Development](https://github.com/resources/articles?topic=software-development) + - [DevOps](https://github.com/resources/articles?topic=devops) + - [Security](https://github.com/resources/articles?topic=security) + - [View all topics](https://github.com/resources/articles) + + EXPLORE BY TYPE + - [Customer stories](https://github.com/customer-stories) + - [Events & webinars](https://github.com/resources/events) + - [Ebooks & reports](https://github.com/resources/whitepapers) + - [Business insights](https://github.com/solutions/executive-insights) + - [GitHub Skills](https://skills.github.com) + + SUPPORT & SERVICES + - [Documentation](https://docs.github.com) + - [Customer support](https://support.github.com) + - [Community forum](https://github.com/orgs/community/discussions) + - [Trust center](https://github.com/trust-center) + - [Partners](https://github.com/partners) +* Open Source + + + COMMUNITY + - [GitHub SponsorsFund open source developers](https://github.com/sponsors) + + PROGRAMS + - [Security Lab](https://securitylab.github.com) + - [Maintainer Community](https://maintainers.github.com) + - [Accelerator](https://github.com/accelerator) + - [Archive Program](https://archiveprogram.github.com) + + REPOSITORIES + - [Topics](https://github.com/topics) + - [Trending](https://github.com/trending) + - [Collections](https://github.com/collections) +* Enterprise + + + ENTERPRISE SOLUTIONS + - [Enterprise platformAI-powered developer platform](https://github.com/enterprise) + + AVAILABLE ADD-ONS + - [GitHub Advanced SecurityEnterprise-grade security features](https://github.com/security/advanced-security) + - [Copilot for BusinessEnterprise-grade AI features](https://github.com/features/copilot/copilot-business) + - [Premium SupportEnterprise-grade 24/7 support](https://github.com/premium-support) +* [Pricing](https://github.com/pricing) + +Search or jump to... + + +# Search code, repositories, users, issues, pull requests... + +Search + +Clear + +[Search syntax tips](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax) + +# Provide feedback + +We read every piece of feedback, and take your input very seriously. + + +Include my email address so I can be contacted + +Cancel + Submit feedback + + + + + +# Saved searches + +## Use saved searches to filter your results more quickly + +Name + +Query + +To see all available qualifiers, see our [documentation](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax). + +Cancel + Create saved search + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2Fyumaikas%2FGDForth) + +[Sign up](/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E&source=header-repo&source_repo=yumaikas%2FGDForth) + +Appearance settings + +Resetting focus + +You signed in with another tab or window. Reload to refresh your session. +You signed out in another tab or window. Reload to refresh your session. +You switched accounts on another tab or window. Reload to refresh your session. + + + +Dismiss alert + +{{ message }} + +[yumaikas](/yumaikas) +/ +**[GDForth](/yumaikas/GDForth)** +Public + +* [Notifications](/login?return_to=%2Fyumaikas%2FGDForth) You must be signed in to change notification settings +* [Fork + 0](/login?return_to=%2Fyumaikas%2FGDForth) +* [Star + 2](/login?return_to=%2Fyumaikas%2FGDForth) + +A Forth-alike for better async GDScript + +[2 +stars](/yumaikas/GDForth/stargazers) [0 +forks](/yumaikas/GDForth/forks) [Branches](/yumaikas/GDForth/branches) [Tags](/yumaikas/GDForth/tags) [Activity](/yumaikas/GDForth/activity) + +[Star](/login?return_to=%2Fyumaikas%2FGDForth) + +[Notifications](/login?return_to=%2Fyumaikas%2FGDForth) You must be signed in to change notification settings + +* [Code](/yumaikas/GDForth) +* [Issues + 0](/yumaikas/GDForth/issues) +* [Pull requests + 0](/yumaikas/GDForth/pulls) +* [Actions](/yumaikas/GDForth/actions) +* [Projects + 0](/yumaikas/GDForth/projects) +* [Security + 0](/yumaikas/GDForth/security) +* [Insights](/yumaikas/GDForth/pulse) + +Additional navigation options + + +* [Code](/yumaikas/GDForth) +* [Issues](/yumaikas/GDForth/issues) +* [Pull requests](/yumaikas/GDForth/pulls) +* [Actions](/yumaikas/GDForth/actions) +* [Projects](/yumaikas/GDForth/projects) +* [Security](/yumaikas/GDForth/security) +* [Insights](/yumaikas/GDForth/pulse) + +# yumaikas/GDForth + +main + +[Branches](/yumaikas/GDForth/branches)[Tags](/yumaikas/GDForth/tags) + +Go to file + +Code + +Open more actions menu + +## Folders and files + +| Name | | Name | Last commit message | Last commit date | +| --- | --- | --- | --- | --- | +| Latest commit History[44 Commits](/yumaikas/GDForth/commits/main/) 44 Commits | | | +| [addons/GDForth](/yumaikas/GDForth/tree/main/addons/GDForth "This path skips through empty directories") | | [addons/GDForth](/yumaikas/GDForth/tree/main/addons/GDForth "This path skips through empty directories") | | | +| [.gitignore](/yumaikas/GDForth/blob/main/.gitignore ".gitignore") | | [.gitignore](/yumaikas/GDForth/blob/main/.gitignore ".gitignore") | | | +| [README.md](/yumaikas/GDForth/blob/main/README.md "README.md") | | [README.md](/yumaikas/GDForth/blob/main/README.md "README.md") | | | +| View all files | | | + +## Repository files navigation + +* [README](#) + +Refer to <./addons/GDForth/README.md> for project details + +## About + +A Forth-alike for better async GDScript + +### Resources + +[Readme](#readme-ov-file) + +### Uh oh! + +There was an error while loading. Please reload this page. + +[Activity](/yumaikas/GDForth/activity) + +### Stars + +[**2** +stars](/yumaikas/GDForth/stargazers) + +### Watchers + +[**1** +watching](/yumaikas/GDForth/watchers) + +### Forks + +[**0** +forks](/yumaikas/GDForth/forks) + +[Report repository](/contact/report-content?content_url=https%3A%2F%2Fgithub.com%2Fyumaikas%2FGDForth&report=yumaikas+%28user%29) + +## [Releases](/yumaikas/GDForth/releases) + +No releases published + +## [Packages 0](/users/yumaikas/packages?repo_name=GDForth) + +No packages published + +## Languages + +* [GDScript + 99.8%](/yumaikas/GDForth/search?l=gdscript) +* [Shell + 0.2%](/yumaikas/GDForth/search?l=shell) + +## Footer + +© 2026 GitHub, Inc. + +### Footer navigation + +* [Terms](https://docs.github.com/site-policy/github-terms/github-terms-of-service) +* [Privacy](https://docs.github.com/site-policy/privacy-policies/github-privacy-statement) +* [Security](https://github.com/security) +* [Status](https://www.githubstatus.com/) +* [Community](https://github.community/) +* [Docs](https://docs.github.com/) +* [Contact](https://support.github.com?tags=dotcom-footer) +* Manage cookies +* Do not share my personal information + + + +You can’t perform that action at this time. \ No newline at end of file diff --git a/references/ForthNotes/HN_post_on_concatenative_language_interpreter.md b/references/ForthNotes/HN_post_on_concatenative_language_interpreter.md new file mode 100644 index 0000000..655283e --- /dev/null +++ b/references/ForthNotes/HN_post_on_concatenative_language_interpreter.md @@ -0,0 +1,12 @@ +# HN post on concatenative language interpreter + +**Source:** https://news.ycombinator.com/item?id=13082825 + +A fun and fairly simple project, with a surprisingly high ratio of usefullness t... | Hacker News + +| | | | | +| --- | --- | --- | --- | +| | | | | | --- | --- | --- | | | **[Hacker News](news)**[new](newest) | [past](front) | [comments](newcomments) | | | | | [login](login?goto=item%3Fid%3D13082825) | | +| +| | | | | | --- | --- | --- | | | | [tzs](user?id=tzs) [on Dec 1, 2016](item?id=13082825) | [parent](item?id=13079611) | [context](item?id=13079611#13082825) | [favorite](fave?id=13082825&auth=7afeba41d4ab4fd61bea26339a10b4f53b8b40b5) | on: [Why I wrote a book about interpreters](item?id=13079611 "Why I wrote a book about interpreters") A fun and fairly simple project, with a surprisingly high ratio of usefullness to effort, is to write an interpreter for a concatenative language. Concatenative languages, like FORTH, can do a lot with very limited resources, making them good candidates for embedded systems. If you want to play around with making your own concatenative language, it is actually surprisingly simple. Here is an overview of a step-by-step approach that can take you from a simple calculator to a full language with some optimization that would actually be quite reasonable to use in an embedded system. So let's start with the calculator. We are going to have a data stack, and all operations will operate on the stack. We make a "dictionary" whose entries are "words" (basically names of functions). For each word in the dictionary, the dictionary contains a pointer to the function implementing that word. We'll need six functions for the calculator: add, sub, mul, div, clr, and print. The words for these will be "+", "-", "x", "/", "clr", and "print". So our dictionary looks like this in C: ``` struct DictEntry { char * word; int (*func)(void); } dict[6] = { {"+", add}, {"-", sub}, {"x", mul}, {"/", div}, {"clr", clr}, {"print", print} }; ``` We need a main loop, which will be something like this (pseudocode): ``` while true token = NextToken() if token is in dictionary call function from that dict entry else if token is a number push that number onto the data stack ``` Write NextToken, making it read from your terminal and parse into whitespace separated strings, implement add, sub, mul, div, clr, and print, with print printing the top item on the data stack on your terminal, and you've got yourself an RPN calculator. Type "2 3 + 4 5 + x print" and you'll get 45. OK, that's fine, but we want something we can program. To get to that, we first extend the dictionary a bit. We add a flag to each entry allowing us to mark the entry as either a C code entry or an interpreted entry, and we add a pointer to an array of integers, and we add a count telling the length of that array of integers. When an entry is marked as C code, it means that the function implementing it is written in C, and the "func" field in the dictionary points to the implementing function. When an entry is marked as interpreted, it means that the pointer to an array of integers points to a list of dictionary offsets, and the function is implemented by invoking the functions of the referenced dictionary entries, in order. A dictionary entry now looks something like this: ``` struct DictEntry { char * word; bool c_flag; void (*func)(void); int * def; int deflen; } ``` (continued in reply) | | | | | | | | | | | --- | --- | --- | --- | | | | | | | --- | --- | --- | | | | [tzs](user?id=tzs) [on Dec 1, 2016](item?id=13082830) [[–]](javascript:void(0)) Now the main loop has to look something like this: ``` while true token = NextToken() if token is in dictionary if dict entry is marked as C code call function from that dict entry else InterpWords(def, deflen) else if token is a number push that number onto the data stack ``` and InterpWords looks something like this ``` void InterpWords(int * def, int deflen) while (deflen-- > 0) InterpOneWord(&dict[*def++]) void InterpOneWord(dict * dp) if (dp->c_flag) (*dp->func)() else InterpWords(dp->def, dp->deflen) ``` With this, we can add new built-in functions defined in terms of already defined functions. Before we do any of that, though, we should add some more stack manipulation functions. Add at least "dup", "drop", and "swap", which, respectively, push a copy of the current top of stack onto the stack, pop an entry from the stack, and exchange the top two items on the stack. For reference, after adding those, the dictionary offsets of the 9 words we've defined are: ``` 0 + 1 - 2 x 3 / 4 clr 5 print 6 dup 7 drop 8 swap ``` and they are all marked as C code. Now let us add a built-in function "sq", which squares the top item on the stack. To do that, add a new dictionary entry initialized like this: ``` {"sq", false, 0, sq_def, 2} ``` where sq\_def looks like this: ``` int sq_def[] = {6, 2} ``` That's marked as being interpreted rather the C code, so when the main loop finds it it will call InterpWords, passing it sqdef and 2, and InterpWords will end up invoking dup and x, with the result being the top of the stack is squared. OK, that's all fine and dandy, but we want to be able to define functions in our language from our language. So far, we can define functions in our language, like sq, but we have to do it by editing a C data structure and recompiling. (continued in reply) | | | | | | | | --- | --- | --- | | | | [tzs](user?id=tzs) [on Dec 1, 2016](item?id=13082833) | [parent](#13082830) [[–]](javascript:void(0)) To do this, we'll need some changes to both InterpWords and/or InterpWord, and to the main loop. The basic idea is that we add a "compiling" mode. When we are in compiling mode the main loop does not execute the tokens it gets. Instead it just makes a list of the dictionary offsets of the words it would have executed. So in compiling mode, if you type "dup x", the main loop doesn't actually call dup and x, it just makes the list {6, 2}. That is used to make the function we are compiling. We'll have to find some way to tell the interpreter what we want to call the new function. The interpreter can than make a new dictionary entry for it, referencing that list of dictionary offsets. The above only covers words in compiling mode...what do we do when the main loop sees a number in compiling mode? That's where we need to extend InterpWords. We need to change the list of dictionary offsets it receives to be able to also specify numbers. Maybe something like this (taking advantage of the fact that dictionary offsets are always non-negative): ``` void InterpWords(int * def, int deflen) while (deflen-- > 0) if (*def >= 0) InterpOneWord(&dict[*def++]) else if (*def == -1) push def[1] onto data stack def += 2; deflen--; else error ``` A -1 in the word offset stream now means that the next item in the stream is a number to push onto the stack rather than a word offset. So now we can support functions like "dup x 10 +" that squares the top of the stack and adds 10, which would compile to {6, 2, -1, 10, 0} We still aren't there, though, because we don't yet have a way to enter or leave compiling mode. That's easy. We'll add a new built-in function, ":". We'll write this in C. What ":" does is read the next token, see if it is a legal word name and not already in use. If it is (legal) and isn't (in use), it creates a new dictionary entry for it, allocates space for the definition, and flips on the global compiling flag. Great! Now we can start defining new words from in our language. Just one problem...how do we terminate compilation? The main loop is compiling everything, so how do we get it to execute the command to stop compiling and finish making the dictionary entry? For that, we need yet another flag in the dictionary: the immediate flag. ``` struct DictEntry { char * word; bool c_flag; void (*func)(void); int * def; int deflen; bool immediate; } ``` Change the main loop so that when it sees a word with the immediate flag set, it executes it even if it is in compiling mode. With that, we can add a word ";", with the immediate flag set, that turns off compiling mode and finalizes the compilation of the word that was being compiled. When we get these changes in, then we would be able to define "sq" from within the language instead of making it a built-in like we did earlier: ": sq dup x ;" Of course, we probably want our language to support some kind of if/else construct and some kind of looping construct. I bet you can see how this will be done. Most of the work is done in InterpWords. Much like we used -1 to indicate that the next entry is a number for the stack, we'll use -2 to indicate a goto. The entry after -2 will be the offset to go to. (Should it be an absolute offset or relative? Your choice). We'll use -3 to indicate a conditional goto. It works like -2, except that it only goes if the top of the stack is non-zero, and it pops the top of the stack. If the top of the stack is zero, it pops it, and then skips over the offset. Here's how we could use this to implement a do...while kind of loop. First think of how we want it to look in our programs. It might be something like this "do while". So we want the compiled code to look like this: ``` -3 offset of body of loop above ``` To make "do" and "while" work, we need to flag their dictionary entries as immediate words. So when we are compiling and hit "do" the code for "do" is executed. For now, let's make this C code. What the "do" code does is simply save the offset of where the next word will be compiled to. What the "while" code does is put the -3 in the compiled code, and then put the offset that was saved by the "do" into the compiled code. You can do similar things for if/else constructs, for loops, and any other control flow you want: make the low level operations you need in InterpWords, and then make immediate words for use during compilation that gather and use the necessary information to write that control flow. Now let's talk a bit about optimization. One thing you can do is some inlining. Consider this function ": cube dup sq x ;". When compiling this, we could notice that "sq" is not C code, and put its definition inline, so we end up compiling cube as if it were written like this: ": cube dup dup x x ;". (BTW, remember earlier when I said it was up to you whether you use absolute or relative offsets in the low level control flow? Relative will make inlining easier if the inlined function has any branches). Now if you are going to implement entirely in C or similar, that's about the end of the simple optimizations (at least as far as my feeble mind can handle). However, if you are willing to work in assembly language some, you can get much fancier. You can make the lowest level built-ins, such as add, mul, dup, and similar assembly language. (In the following I'm going to continue to say C function, for consistency with the earlier stuff, but what it now means is a function that is not defined in our language). We can change the way non-C functions are defined from being a list of dictionary offsets to a pointer to actual code. So for ": sq dup x ;" instead of compiling that as a pointer to the list {6, 2}, we compile it as a pointer to a list of call instructions, followed by a return. For sq, that would look like this: ``` call dup call mul ret ``` Cube would look like this (without optimization) ``` call dup call sq call mul ret ``` and with sq inlined at the high level, it would become ``` call dup call dup call mul call mul ret ``` For built-ins that are position independent assembly code, we can do another level of inlining and replace calls to them with their body. Depending on the addressing modes your processor supports, this could end up with cube being as simple as four instructions (not counting the return), with all the calls eliminated! You can go farther and do things like cache the top few stack items in registers, and add peephole optimizers that go over the compiled code to eliminate redundant operations. The really cool thing is how easy bootstrapping this kind of thing is. You only need a small number of built-in assembly functions to give you enough to write the rest of the language in itself, and these systems tend to be small and perform reasonably well. These kind of languages can be great in embedded systems, and indeed that is where the granddaddy of this kind of language, FORTH, got its start. | | | | | | | | --- | --- | --- | | | | [jim\_lawless](user?id=jim_lawless) [on Dec 2, 2016](item?id=13085684) | [root](#13082830) | [parent](#13082833) | [next](#13087007) [[–]](javascript:void(0)) I agree with your approach! I built a non-Turing-complete Forth-like interpreter in Go a few years ago with words similar to the set you've defined above: [https://lawlessguy.wordpress.com/2013/07/20/an-rpn-interpret...](https://lawlessguy.wordpress.com/2013/07/20/an-rpn-interpreter-in-go-golang/) | | | | | | | | --- | --- | --- | | | | [stevekemp](user?id=stevekemp) [on Dec 2, 2016](item?id=13087007) | [root](#13082830) | [parent](#13082833) | [prev](#13085684) [[–]](javascript:void(0)) As a fan of FORTH that was a great series of comments! I'd suggest a little more work could turn it into a blog post which could be submitted here for more comment and audience. (I recently wrote a FORTH interpreter in Perl, and had lots of fun with it.) | | | +| | | | --- | | | [Guidelines](newsguidelines.html) | [FAQ](newsfaq.html) | [Lists](lists) | [API](https://github.com/HackerNews/API) | [Security](security.html) | [Legal](https://www.ycombinator.com/legal/) | [Apply to YC](https://www.ycombinator.com/apply/) | [Contact](mailto:hn@ycombinator.com) Search: | \ No newline at end of file diff --git a/references/ForthNotes/Homepage.md b/references/ForthNotes/Homepage.md new file mode 100644 index 0000000..b010a67 --- /dev/null +++ b/references/ForthNotes/Homepage.md @@ -0,0 +1,10 @@ +# Homepage + +**Source:** https://colorforth.github.io/index.html + +Chuck Moore's colorForth, OKAD and S40 Forth Multicomputer chip + + + + +### *Updated* 2013 November 6IntroductionThis site is getting some 500-600 visitors a day. Thank you for your interest. *There's a quotation attributed to Burke: "All that is required for evil to triumph is for good men to do nothing."**[Blog](blog.htm)*Comments about life, colorForth and GreenArrays You're welcome to email me your comments. I like to hear from people, and appreciate your suggestions. But there are several problems: * Such email usually arrives in my junk mail folder. I try to retrieve them, but a distinguishing subject line would help.* I won't respond to these emails, except on future postings. 'Cause I don't know who you are, and the the web is full of predators. *[Eval Blog](haypress.htm)*My experience programming GreenArrays' Evaluation Board. [colorForth](cf.htm)A dialect of Forth that uses color to replace punctuation. Native Pentium and Windows versions. Produces extremely compact programs. Instant compile from pre-parsed source. Latest changes are compressed source: colorForth, OKAD and GA4 in 290K (25%). Also blue words that are executed at edit time, for formatting text.[OKAD](vlsi.html)A suite of VLSI design tools for layout and simulation. Compact description of gates, cells and chip. Resulting GDS II file ready for fabrication. [S40 Multicomputer Chip](S40.htm) Spectacular chip! 40 microcomputers, each with 128 words of 18-bit memory. Each capable of 700 Mips. [GreenArrays, Inc](http://greenarraychips.com/)I'm pleased to announce the formation of this company. We plan to develop and exploit the concept of multi-computer chips. That gives me another point of contact: [chuck@greenarraychips.com](mailto:chuck@greenarraychips.com). *[Chuck Moore](bio.html)*[chipchuck@colorforth.com](mailto:chipchuck@colorforth.com) Lives in Nevada at Lake Tahoe. Loves to [hike](hiking.htm) the Tahoe Rim Trail as well as the Pacific Crest Trail. *[Min Moore](min.htm) 1932 - 2005*[Eric Moore](eric.htm)Some pictures of my son[Recipes](recipes.htm)[Programming a Problem-Oriented Language](POL.htm)This is a book I wrote about 1970. It describes the software that became Forth.[Thoughts about Pi](pi.htm)[colorForth Primer](primer.htm)[Books](books.htm)Books I likePoemsSometimes the pros say it best. To be perfectly clear, I've emphasized some lines. [Henry V, Shakespeare [Stout-Hearted Men, Hammerstein](stout.htm) [Invictus, Henley](Invictus.htm) [The Weariest River, Swinburne](WeariestRiver.htm) [Coloring, Sarah Hall Maney](coloring.html) [Road Not Taken, Robert Frost](road.htm) [Mending Wall, Robert Frost](mending.htm) [Stopping by Woods on a Snowy Evening, Robert Frost](stopping.htm) [Ulysses, Alfred Lord Tennyson](tennyson.htm) [The Explorer, Rudyard Kipling](kipling.htm) [My Lost Youth, Henry Wadsworth Longfellow](longfellow.htm) [High Flight, John Gillespie Magee](magee.htm)](Crispin.htm) \ No newline at end of file diff --git a/references/ForthNotes/JV_Noble_A_Beginners_Guide_to_Forth.md b/references/ForthNotes/JV_Noble_A_Beginners_Guide_to_Forth.md new file mode 100644 index 0000000..4d281af --- /dev/null +++ b/references/ForthNotes/JV_Noble_A_Beginners_Guide_to_Forth.md @@ -0,0 +1,2230 @@ +# J.V. Noble: A Beginners Guide to Forth + +**Source:** https://galileo.phys.virginia.edu/classes/551.jvn.fall01/primer.htm + +## A Beginner's Guide to Forth + + +by +J.V. Noble + + +### Contents + +1. [Preliminaries](#intro) + + - [Getting started](#start) + + - [The structure of Forth](#struct) + + - [Extending the dictionary](#dict) + + - [Stacks and reverse Polish notation (RPN)](#stacks) + 1. [Manipulating the parameter stack](#param)- [Remarks on factoring](#factoring)- [The return stack and its uses](#return)- [Local variables and VALUEs](#locals) + - [Using memory](#memory) + + - [Comparing and branching](#branch) + + - [Documenting and commenting Forth code](#comment) + 1. [Parenthesized remarks](#parens)- [Stack comments](#stk_com)- [Drop line (\)](#backslash)- [Comment blocks](#comblok)- [Self-documenting code](#selfdoc) + - [Integer arithmetic operations](#arith) + + - [Looping and structured programming](#loops) + 1. [Indefinite loops](#indef) - [Definite loops](#definite)- [Structured programming](#struc_prog)- [“Top-down” design](#topdown) + - [CREATE ... DOES> (the pearl of Forth)](#create) + 1. [Defining “defining” words](#def_wds) - [Run-time *vs.* compile-time actions](#runtime)- [Dimensioned data (intrinsic units)](#dimdata) - [Advanced uses of the compiler](#advanced) + - [Floating point arithmetic](#fp) + + - [Non-trivial programming example](#bin_root) + + - [Some remarks about strings](#strings) + 1. [Alphanumeric strings](#alph_num_str)- [Pictured Numeric Output](#num_out) + - [Assmbly language programming](#code) + + - [Some useful references](#refs) + +``` + 1. Preliminaries + + Forth is an unusual computer language that has probably been applied + to more varied projects than any other. It is the obvious choice when + the project is exceptionally demanding in terms of completion sched- + ule, speed of execution, compactness of code, or any combination of + the above. + + It has also been called “...one of the best-kept secrets in the com- + puting world.” This is no exaggeration: large corporations have pur- + chased professional Forth development systems from vendors such as + Laboratory Microsystems, Inc., Forth, Inc. or MicroProcessor Engineer- + ing, Ltd. and sworn them to secrecy. + + Some speculate (unkindly) that corporate giants prefer to hide their + shame at using Forth; but I believe they are actually concealing a + secret weapon from their rivals. Whenever Forth has competed directly + with a more conventional language like C it has won hands down, pro- + ducing smaller, faster, more reliable code in far less time. I have + searched for examples with the opposite outcome but have been unable + to find a single instance. + +Table of Contents  ![](up.gif) + +Home  ![](left.gif) +Next  ![](right.gif) + +2. Getting started + + We will use Win32Forth for these illustrations. Download the file + + w32for42.exe + + and double-click on it to install on any Windows 95, -98, -NT, -ME + or -XP –equipped machine. + + + The compressed files will then decompress themselves. They should also + install a program group on your desktop. + + Now start Win32Forth by opening the program group and clicking on the + appropriate icon, probably something like this: ![](win32for.gif) or ![](Win32For6.gif) + + + It should respond by opening a window and writing something like + + 32bit Forth for Windows 95, and NT + Compiled: July 23rd, 1997, 5:11pm + Version: 3.5 Build: 0008 Release Build + Platform: Windows 95 Version: 4.0 Build: 16384 + 491k bytes free + 2,719 Words in Application dictionary + 1,466 Words in System dictionary + 4,185 Words total in dictionaries + 8,293 Windows Constants available + + Loading Win32For.CFG + + *** DON'T PANIC, Press: F1 NOW! *** + + + You can use UPPER or lower-case to type commands and data. Win32Forth + is case-insensitive. + + You can also start the WinView editor by clicking on its icon in the program + group. The features of the editor are fairly standard and self-explanatory. Make + sure to set the preferences (Ctl-Shift-P or use the Edit drop-down menu) to + your own liking. Among other things, WinView is written in Forth (the complete + source is included) and is integrated with Win32Forth so that compiling errors + pop up in the editor. + +Table of Contents  ![](up.gif) + +Home  ![](left.gif) +Next  ![](right.gif) + +3. The structure of Forth + + In the Win32Forth window, now type + + BYE + + The Win32Forth window immediately closes. + + + What just happened? Forth is an interactive programming language con- + sisting entirely of subroutines, called words in Forth jargon. + + Interactive means you type things in at the keyboard and the machine + responds. We will see some details of how it does this below. + + A word is executed (interactively) by naming it. We have just seen + this happen: BYE is a Forth subroutine meaning “exit to the operating + system”. So when we typed BYE BYE was executed, and the system re- + turned control to Windows. + + + Click on the Win32Forth icon again to re-start Forth. + Now we will try something a little more complicated. Enter + + 2 17 + . 19 ok + + What happened? Forth is interpretive. A small program called the “outer + interpreter” continually loops, waiting for input from the keyboard or from + a mass storage device. The input is a sequence of text strings (words or numbers) + separated from each other by the standard Forth delimiter: one or more ASCII blank + (32decimal = 20hex) characters. + + The text strings can be interpreted in only three ways: words (subroutine names), + numbers, or “not defined”. + + + The outer interpreter tries first to look for an incoming word in the dictionary + (a list of already-defined subroutine names). If it finds that word, the inter- + preter executes the corresponding code. + + If no dictionary entry exists, the interpreter tries to read the input as a number. + If the string satisfies the rules defining a number, it is converted to a number + in the machine's internal representation, and stored in a special memory location, + called “the top of the stack” (TOS). + + + In the above example, Forth interpreted 2 and 17 as numbers, and + pushed them both onto the stack. + + "+" is a pre-defined word as is ".", so they were looked up and exe- + cuted. + + "+" added 2 to 17 and left 19 on the stack. + + The word "." (called "dot") removed 19 from the stack and displayed + it on the standard output device (in this case, CRT). + + + The diagram below is a flow chart representing the actions performed + by the Forth outer interpreter during interpretation. + +![](frth_int.gif) + + + + We might also have said + + HEX 0A 14 * . C8 ok + + (Do you understand this? Hint: DECIMAL means “switch to decimal arith- + metic”, whereas HEX stands for “switch to hexadecimal arithmetic”.) + + + If the incoming text can neither be located in the dictionary nor in- + terpreted as a number, Forth issues an error message. Try it: type X + and see + + X + Error: X is undefined + + or type THING and see + + THING + Error: THING is undefined + + + Finally, here is the obligatory "Hello, World!" program. Forth lets you + output text using the word ." as follows (we will explain in §4 below + what : and ; mean): + + : hi ." Hello, World!" ; ok + + Now type in hi and see what happens: + + hi Hello, World! ok + + This can be elaborated with words that tab, emit carriage returns, + display in colors, etc. but that would take us too far afield. + + (The word ." means “Display the string, following the obligatory blank space + and terminated by the close-quote " on the standard output device.”) + + + Forth belongs to the class of Threaded Interpretive Languages. This + means it can interpret commands (subroutines or programs) typed in + at the console, as well as create (compile) new subroutines and pro- + grams. The compiler in a traditional language has the structure shown + below: +![](compiler.gif) + To compile and test a program in a traditional language such + as Fortran, C or Pascal, one prepares an input (source) file, submits it + to a black box that someone else created (the compiler) and then + runs the resulting executable file (which is generally in machine + language). This process can be so tedious that most program + development in traditional languages must be supported by + an elaborate set of programs called the “environment”, + consisting of integrated editors, debuggers, version control + catalogues and the like. + + The outer interpreter/compiler of a Forth system looks like this: +![](frth_int.gif) + + Forth has little in common with the traditional compilation method. + Although the Forth interpreter/compiler diagrammed above looks + complicated, it is simplicity itself compared with the contents of + the ![](blob.gif) representing a traditional black-box compiler. + + + A continuous loop waits for input—from the keyboard, a disk file or + whatever— and acts on it according to its nature. Input consists + of a sequence of words and numbers. If a name is recognized it is + executed; if it is not in the dictionary (where else would you keep + a list of words?) Forth tries to convert it to a number and push it + on the stack. If this is impossible, Forth aborts execution, issues an + error message and waits for more input. + + As we shall see below, what makes Forth a compiler as well as an + interpreter is the set of words (Forth subroutines) that, when they are + typed in and executed, create new Forth subroutines. + +Table of Contents  ![](up.gif) + +Home  ![](left.gif) +Next  ![](right.gif) + +4. Extending the dictionary + + The compiler is one of Forth's most endearing features. Unlike + most other high-level languages, the Forth compiler is part of the + language. (LISP and its dialects also make components of the com- + pilation mechanism available to the programmer.) That is, its com- + ponents are Forth words available to the programmer, that can be + used to solve his problems. + + In this section we discuss how the compiler extends the + dictionary. As noted above, normally a Forth system awaits + input, and interprets (and executes it). We say the system is + normally in interpret mode. + + Forth uses special words to create new dictionary entries, i.e., + new words. The most important are ":" (“start a new definition”) + and ";" (“terminate the definition”). + + Let's try this out: enter + + : *+ * + ; ok + + What happened? The word ":" was executed because it was already + in the dictionary. The action of ":" is + + > Create a new dictionary entry named *+ and switch from + interpret to compile mode. + + > In compile mode, the interpreter looks up words and + —rather than executing them— installs pointers to + their code. (If the text is a number, instead of + pushing it on the stack, Forth builds the number + into the dictionary space allotted for the new word, + following special code that puts the stored number + on the stack whenever that word is executed.) + + > The action of "*+" is thus to execute sequentially + the previously-defined words "*" and "+". + + > The word ";" is special: when it was defined a bit + was turned on in its dictionary entry to mark it as + IMMEDIATE. Thus, rather than writing down the address + of ";", the compiler executes ";" immediately. + (That is, an IMMEDIATE word is always executed, even + if the system is in compile mode.) + + What ";" does is twofold: first, it installs the code + that returns control to the next outer level of the + interpreter; and second, it switches back from compile + mode to interpret mode. + + Now try out *+ : + + DECIMAL 5 6 7 *+ . 47 ok + + This example illustrated two principles of Forth: adding a new word to + the dictionary, and trying it out as soon as it was defined. + + + The diagram below is a flow chart representing the actions performed + by the Forth inner interpreter during compilation. +![](inner.gif) + + + Any word you have added to the dictionary can be decompiled using + the Forth word SEE. Say + + SEE *+ + + and get + + SEE *+ + : *+ * + ; ok + + This can be useful when trying to understand how something works. + +Table of Contents  ![](up.gif) + +Home  ![](left.gif) +Next  ![](right.gif) + +5. Stacks and reverse Polish notation (RPN) + + We now discuss the stack and the “reverse Polish” or “postfix” arith- + metic based on it. (Anyone who has used a Hewlett-Packard calculator + should be familiar with the concept.) + + Virtually all modern CPU's are designed around stacks. Forth effi- + ciently uses its CPU by reflecting this underlying stack architecture + in its syntax. + + + But what is a stack? As the name implies, a stack is the machine ana- + log of a pile of cards with numbers written on them. Numbers are + always added to the top of the pile, and removed from the top of the + pile. The Forth input line + + 2 5 73 -16 ok + + leaves the stack in the state + + cell # contents + + + 0 -16 (TOS) + 1 73 (NOS) + 2 5 + 3 2 + + + where TOS stands for “top-of-stack”, NOS for “next-on-stack”, etc. + + + We usually employ zero-based relative numbering in Forth data struct- + ures (such as stacks, arrays, tables, etc.) so TOS is given relative + #0, NOS #1, etc. + + Suppose we followed the above input line with the line + + + - * . xxx ok + + what would xxx be? The operations would produce the successive stacks + + cell# initial + - * . + stack + + 0 -16 57 -52 -104 + 1 73 5 2 + 2 5 2 + 3 2 empty ( 104 -> CRT ) + stack + + The operation "." (TOS->display) displays -104 to the screen, leaving the + stack empty. That is, xxx is -104. + + + a. Manipulating the parameter stack + + Forth systems incorporate (at least) two stacks: the parameter stack + and the return stack. + + A stack-based system must provide ways to put numbers on the stack, to + remove them, and to rearrange their order. Forth includes standard + words for this purpose. + + Putting numbers on the stack is easy: simply type the number (or in- + corporate it in the definition of a Forth word). + + The word DROP removes the number from TOS and moves up all the other + numbers. (Since the stack usually grows downward in memory, DROP mere- + ly increments the pointer to TOS by 1 cell.) + + SWAP exchanges the top 2 numbers. + + DUP duplicates the TOS into NOS. + + ROT rotates the top 3 numbers. + + + These actions are shown below (we show what each word does to the ini- + tial stack) + + cell | initial | DROP SWAP ROT DUP + + 0 | -16 | 73 73 5 -16 + 1 | 73 | 5 -16 -16 -16 + 2 | 5 | 2 5 73 73 + 3 | 2 | 2 2 5 + 4 | | 2 + + + Forth includes the words OVER, TUCK, PICK and ROLL that act as shown + below (note PICK and ROLL must be preceded by an integer that says + where on the stack an element gets PICK'ed or ROLL'ed): + + cell | initial | OVER TUCK 3 PICK 3 ROLL + + 0 | -16 | 73 -16 2 2 + 1 | 73 | -16 73 -16 -16 + 2 | 5 | 73 -16 73 73 + 3 | 2 | 5 5 5 5 + 4 | | 2 2 2 + + Clearly, 0 PICK is the same as DUP, 1 PICK is a synonym for OVER, 1 ROLL + means SWAP and 2 ROLL means ROT. + + The words PICK and ROLL are mainly useful for dealing with deep stacks. But + the current trend in Forth programming is to avoid making the stack deeper + than 3 or 4 elements. A deeper stack than that is generally considered a sign + that the program has been insufficiently thought out and needs to be factored. + + + + b. Remarks on factoring + Factoring is the process of breaking out repeated pieces of code from sub- + routines and giving them a name. This not only shortens the overall program + but can make the code simpler. Here is a frequently offereded illustration: + + : SUM-OF-SQUARES ( a b -- a*a+b*b ) DUP * SWAP DUP * + ; + + has the repeated phrase DUP * and can be replaced profitably by + + : SQUARED ( a -- a*a ) DUP * ; + + : SUM-OF-SQUARES ( a b -- a*a+b*b ) + SQUARED ( -- a b*b) + SWAP ( -- b*b a) + SQUARED ( -- b*b a*a) + + ( -- b*b + a*a) + ; + + The new version of SUM-OF-SQUARES is 2 words shorter and thus easier to read. + + Before leaving this subject I would like to offer some deeper examples of factoring, + plus a badly factored definition. To begin with the badly factored word, look at + the file float.f in the Win32Forth main directory, and in particular at the word >float. + This word is almost 3 pages long, which makes it virtually impossible to read or + to maintain. + + Here is an example of where factoring leads to great simplification. My linear equations + solver uses Gaussian elimination with row-pivoting. By appropriate transformations the + equations are put in the form of equations with an upper-triangular matrix. Once this is + done the equations can be solved for xk beginning with the n'th (which only requires a + single division to determine the unknown xn); the n-1'st can then be solved by equally + simple algebra in terms of xn, etc. This procedure is called “back-solving” because it + proceeds in reverse order. The word that does the all the work expects addresses of matrix + and inhomogeneous term on the data stack: + + : }}solve ( A{{ V{ --) + initialize triangularize back-solve report ; + + + You will note that the words initialize, triangularize, back-solve and report were + given names that tell you precisely what they do. They represent the major steps of + the algorithm as described above. Of course they have to be defined before they + can be invoked. This is why we describe the typical Forth programming style as + “bottom-up” rather than “top-down” as with other languages. + + My final example of factoring is a routine for adaptive numerical quadrature (integrating + a function of one variable) based on Simpson's Rule. To use it one says + + use( fn.name xa xb err )integral + + The algorithm computes the integral on an interval, then breaks it into two + equal sub-intervals. The sub-integrals are compared with the original—if + they agree within the tolerance the result is accumulated and the integral is + evaluated on the remainder of the interval. If they don't agree the routine + works on the upper sub-interval until convergence is achieved. + + : )integral ( f: xa xb err -- I[xa,xb]) ( xt --) + initialize + BEGIN \ begin indefinite loop + subdivide \ break last subinterval in two + converged? + IF interpolate \ apply Richardson interpolation + shrink-interval + THEN + none-left UNTIL \ loop until done + TotIntegral F@ ( f: -- Integral) \ leave result + ; + + This version has been reduced to seven basic operations, not counting the + system words BEGIN, UNTIL that set up the loop; IF...THEN that sets + up the branch, and F@ that puts the answer on the stack. + + + c. The return stack and its uses + We have remarked above that compilation establishes links from the + calling word to the previously-defined word being invoked. The linkage + mechanism --during execution-- uses the return stack (rstack): the + address of the next word to be invoked is placed on the rstack, so + that when the current word is done executing, the system knows to jump + to the next word. (This is so in most, but not all, modern Forth imple- + mentations. But all have a return stack, whether or not they use them + for linking subroutines.) + + In addition to serving as a reservoir of return addresses (since words + can be nested, the return addresses need a stack to be put on) the + rstack is where the limits of a DO...LOOP construct are placed. + + The user can also store/retrieve to/from the rstack. This is an ex- + ample of using a component for a purpose other than the one it was + designed for. Such use is discouraged for novices since it adds the + spice of danger to programming. See “Note of caution” below. + + To store to the rstack we say >R , and to retrieve we say R> . The + word R@ copies the top of the rstack to the TOS. + + + Why use the rstack when we have a perfectly good parameter stack to + play with? Sometimes it becomes hard to read code that performs com- + plex gymnastics on the stack. The rstack can reduce the complexity. + + Alternatively, VARIABLEs —named locations— provide a place to store + numbers —such as intermediate results in a calculation— off the + stack, again reducing the gymnastics. Try this: + + \ YOU DO THIS \ EXPLANATION + + VARIABLE X ok \ create a named storage location X; + \ X executes by leaving its address + + 3 X ! ok \ ! ("store") expects a number and + \ an address, and stores the number to + \ that address + + X @ . 3 ok \ @ ("fetch") expects an address, and + \ places its contents in TOS. + + However, Forth encourages using as few named variables as possible. + The reason: since VARIABLEs are typically global —any subroutine can + access them— they can cause unwanted interactions among parts of a + large program. + + Although Forth can make variables local to the subroutines that use + them (see “headerless words” in FTR), the rstack can often replace + local variables: + + > The rstack already exists, so it need not be defined anew. + + > When the numbers placed on it are removed, the rstack shrinks, + reclaiming some memory. + + + A note of caution: since the rstack is critical to execution we mess + with it at our peril. If we use the rstack for temporary storage we + must restore it to its initial state. A word that places a number on + the rstack must remove it —using R> or RDROP (if it has been defined) + — before exiting that word. Since DO...LOOP also uses the rstack, + for each >R folowing DO there must be a corresponding R> or RDROP + preceding LOOP. Neglecting these precautions will probably crash + the system. + + RDROP is not an ANS Forth word that can be assumed predefined on any system. + Since it is not Standard, some systems call it R>DROP (which also is not + Standard). Here is its definition if needed: + + : RDROP ( or R>DROP) ( r: n -- ) R> DROP ; + + + d. Local variables and VALUEs + I mentioned VARIABLEs above—a VARIABLE is a subroutine whose action is to + return the address of a named, cell-sized memory location, as in + + VARIABLE x + x . 247496 ok ( it doesn't have to be this address!) + -49 x ! + x @ . -49 ok + + A VALUE is a widely used hybrid of VARIABLE and CONSTANT (see below). We + define and initialize a VALUE as we would a CONSTANT: + + 13 VALUE thirteen ok + + We invoke the new VALUE just as we would a CONSTANT: + + thirteen . 13 ok + + However, we can change a VALUE as though it were a VARIABLE: + + 47 TO thirteen ok + thirteen . 47 ok + + Needless to say, the word TO also works within word definitions, replacing + the VALUE that follows it with whatever is currently in TOS. (Note that + it would be dangerous to follow TO with anything but a VALUE !!) VALUEs + are part of the ANS Forth CORE EXTENSION wordset (that is, the corresponding + code is not guaranteed to be loaded on minimal ANS-compliant systems). + + This is a good time to mention that Forth does no type-checking (unless you add + it yourself). YOU must check that TO is followed by a VALUE and not something + else. + + ANS Forth also includes a LOCALS EXTENSION wordset that implements named memory + locations local to a word definition. Locals are generally dynamic in nature (that + is, their memory is reclaimed upon exiting the word), although the Standard does + not insist on this. A commonly used syntax is LOCALS| a b c ... |, as in this + definition (from a line-drawing algorithm): + + : v+ ( a b c d -- a+c b+d) + LOCALS| d c b a | + a c + b d + ; + + 2 3 4 5 v+ .S [2] 6 8 ok.. ( .S displays the stack without destroying it) + + The important things to remember are + + > the names a, b, c ... can be any Forth-acceptable strings; + + > the local names have meaning only within a word definition; + + > the locals are initialized from the stack as shown in v+ above, + and as in the next example: + + : test-locals ( a b c -- ) + LOCALS| c b a | + CR ." Normal order: " a . b . c . + CR ." Stack order: " c . b . a . + 13 TO a 14 TO b 15 TO c \ how TO works + CR ." Changed: " a . b . c + ; ok + + 3 4 5 test-locals + Normal order: 3 4 5 + Stack order: 5 4 3 + Changed: 13 14 15 ok + + > the locals act like VALUEs, not like VARIABLEs, as the above + example makes clear; + + > the LOCALS EXTENSION wordset requires LOCALS| ... | to accomodate + (at least) 8 local names. + + > LOCALS| ... | is never necessary, nor does it necessarily shorten code, as + the example below makes clear (7 words as opposed to 6 + preamble): + + : v+ ( a b c d -- a+c b+d) 2>R R> + SWAP R> + SWAP ; + + What it does accomplish is to reduce stack juggling and clarify the code + in some cases. + +Table of Contents  ![](up.gif) + +Home  ![](left.gif) +Next  ![](right.gif) + +6. Using memory + + As we just saw, ordinary numbers are fetched from memory to + the stack by @ ("fetch"), and stored by ! (store). + + @ expects an address on the stack and replaces that address by + its contents using, e.g., the phrase X @ + + ! expects a number (NOS) and an address (TOS) to store it in, and + places the number in the memory location referred to by the address, + consuming both arguments in the process, as in the phrase 3 X ! + + Double length numbers can similarly be fetched and stored, by + D@ and D!, if the system has these words. + + Positive numbers that represent characters can be placed in character + -sized cells of memory using C@ and C!. This is convenient for operations + with strings of text, for example screen and keyboard I/O. + + Of course, one cannot put numbers in memory or retrieve them, + for that matter, without a means of allocating memory and of + assigning labels to the memory so allocated. + + The Forth subroutines CREATE and ALLOT are the basic tools for + setting aside memory and attaching a convenient label to it. As + we shall see below, CREATE makes a new dictionary entry, as in + + CREATE X + + Here the new entry has the name X, but it could have been "Joe" + or anything else. The new name is a Forth subroutine that will + return the address of the next available space in memory. Thus + + CREATE X ok + X . 247316 ok + HERE . 247316 ok + + HERE is a subroutine that returns the address of the next available + space—we note that it is the same as the address of X because no + space has been ALLOTted. We can rectify this by saying + + 10 CELLS ALLOT ok + + and checking with + + HERE . 247356 ok + + We see that the next available space is now marked as 40 bytes + further up in memory. (Each CELL is therefore 4 bytes or 32 bits + on this system.) In other words, the subroutine ALLOT increases + the pointer HERE by the number of address units you have told + it to allot. You could have said + + 40 ALLOT + + instead of + + 10 CELLS ALLOT + + but the latter is more portable because it frees you from having + to revise your code if you were to run it on a system with 64-bit + or 16-bit cells (both of which are in common use). + + + By executing the sequence + + CREATE X 10 CELLS ALLOT + + we have set aside enough room to hold 10 32-bit numbers--for example + a table or array--that can be referenced by naming it. If we want to + get at the 6th element of the array (the first element has index 0, + so the 6th has index 5) we would say + + X 5 CELLS + + + to compute its address. To see how this works, let us say + + 137 X 5 CELLS + ! ok + + to store an integer into the 6th array location; then + + X 5 CELLS + @ . 137 ok + + retrieves and displays it. + + + Using the tools provided by CREATE and ALLOT we can devise + any sort of data structure we like. This is why Forth does + not provide a panoply of data structures, such as are to be + found in languages like C, Pascal or Fortran. It is too easy + in Forth to custom tailor any sort of data structure one + wishes. In the section on CREATE...DOES> below you will see + that Forth makes it easy to write subroutines ("constructors") + that create custom data structures--that can even include + code fragments that do useful things. For example, a CONSTANT + is a number you would not want to change during a program's + execution. So you do not want access to its memory location. + How then do you get the number when you need it? You package + the code for @ with the storage location, so that by naming + the CONSTANT you retrieve its contents. Its usage is + + 17 CONSTANT seventeen ok + seventeen . 17 ok + +Table of Contents  ![](up.gif) + +Home  ![](left.gif) +Next  ![](right.gif) + +7. Comparing and branching + + Forth lets you compare two numbers on the stack, using relational + operators ">", "<", "=" . Thus, e.g., the phrase + + 2 3 > ok + + leaves 0 ("false") on the stack, because 2 (NOS) is not greater than 3 + (TOS). Conversely, the phrase + + 2 3 < ok + + leaves -1 ("true") because 2 is less than 3. + + Notes: In some Forths “true” is +1 rather than -1. + + Relational operators consume both arguments and leave a “flag” + to show what happened. + + (Many Forths offer unary relational operators "0=", "0>" and "0<". + These, as might be guessed, determine whether the TOS contains an + integer that is 0, positive or negative.) + + The relational words are used for branching and control. For example, + + : TEST 0 = INVERT IF CR ." Not zero!" THEN ; + + 0 TEST ok ( no action) + -14 TEST + Not zero! ok + + The TOS is compared with zero, and the INVERT operator (bitwise logical + NOT—this flips "true" and "false") is applied to the resulting flag. The + word CR issues a carriage return (newline). Finally, if TOS is non-zero, + IF swallows the flag and executes all the words between itself and the + terminating THEN. If TOS is zero, execution jumps to the word following + THEN. + + The word ELSE is used in the IF...ELSE...THEN statement: a nonzero + value in TOS causes any words between IF and ELSE to be executed, and + words between ELSE and THEN to be skipped. A zero value produces the + opposite behavior. Thus, e.g. + + + : TRUTH CR 0 = IF ." false" ELSE ." true" THEN ; + + 1 TRUTH + true ok + + 0 TRUTH + false ok + + Since THEN is used to terminate an IF statement rather than in its + usual sense, some Forth writers prefer the name ENDIF. + +Table of Contents  ![](up.gif) + +Home  ![](left.gif) +Next  ![](right.gif) + +8. Documenting and commenting Forth code + + Forth is sometimes accused of being a "write-only" language, i.e. some + complain that Forth is cryptic. This is really a complaint against + poor documentation and untelegraphic word names. Unreadability is + equally a flaw of poorly written FORTRAN, PASCAL, C, etc. + + Forth offers programmers who take the trouble tools for producing ex- + ceptionally clear code. + + + a. Parenthesized remarks + + The word (![](red_box.gif) — a left parenthesis followed by a space — says "disre- + gard all following text until the next right parenthesis in the + input stream". Thus we can intersperse explanatory remarks within + colon definitions. + + + b. Stack comments + + A particular form of parenthesized remark describes the effect of a + word on the stack. In the example of a recursive loop (GCD below), + stack comments are really all the documentation necessary. + + Glossaries generally explain the action of a word with a + stack-effect comment. For example, + + ( adr -- n) + + describes the word @ ("fetch"): it says @ expects to find an address + (adr) on the stack, and to leave its contents (n) upon completion. + The corresponding comment for ! would be + + ( n adr -- ) . + + + + c. Drop line (\) + + The word "\" (back-slash followed by space) has recently gained favor + as a method for including longer comments. It simply means "drop ev- + erything in the input stream until the next carriage return". Instruc- + tions to the user, clarifications or usage examples are most naturally + expressed in a block of text with each line set off by "\" . + + + + d. Comment blocks + ANS Forth contains interpreted IF...THEN, in the form of [IF] ... [THEN]. + Although they are generally used for conditional compilation, these words + can be used to create comment blocks. Thus we can say + + FALSE [IF] anything you want to say + [THEN] + + and the included remarks, code, examples or whatever will be ignored + by the compiling mechanism. + + + + e. Self-documenting code + + By eliminating ungrammatical phrases like CALL or GOSUB, Forth pre- + sents the opportunity —via telegraphic names for words— to make code + almost as self-documenting and transparent as a readable English or + German sentence. Thus, for example, a robot control program could con- + tain a phrase like + + 2 TIMES LEFT EYE WINK + + which is clear (although it sounds like a stage direction for Brun- + hilde to vamp Siegfried). It would even be possible without much dif- + ficulty to define the words in the program so that the sequence could + be made English-like: WINK LEFT EYE 2 TIMES . + + One key to doing this is to eliminate “noise” words like + @, !, >R, etc. by factoring them out into expressively + named —and reuseable— subroutines. + + Another is to organize the listing of a subroutine so + that it physically resembles what it is supposed to do. + Two examples are the jump table defined below, as well as + a method for programming finite state automata. + +Table of Contents  ![](up.gif) + +Home  ![](left.gif) +Next  ![](right.gif) + +9. Integer arithmetic operations + + The 1979 or 1983 standards require that a conforming Forth system con- + tain a certain minimum set of pre-defined words. These consist of + arithmetic operators + - * / MOD /MOD */ for (usually) 16-bit signed- + integer (-32767 to +32767) arithmetic, and equivalents for unsigned (0 + to 65535), double-length and mixed-mode (16- mixed with 32-bit) arith- + metic. The list will be found in the glossary accompanying your + system, as well as in SF and FTR. + + Try this example of a non-trivial program that uses arithmetic and + branching to compute the greatest common divisor of two integers using + Euclid's algorithm: + + : TUCK ( a b -- b a b) SWAP OVER ; + : GCD ( a b -- gcd) ?DUP IF TUCK MOD GCD THEN ; + + The word ?DUP duplicates TOS if it is not zero, and leaves it alone + otherwise. If the TOS is 0, therefore, GCD consumes it and does + nothing else. However, if TOS is unequal to 0, then GCD TUCKs TOS + under NOS (to save it); then divides NOS by TOS, keeping the remainder + (MOD). There are now two numbers left on the stack, so we again take + the GCD of them. That is, GCD calls itself. + + If you try the above code it will fail. A dictionary entry + cannot be looked up and found until the terminating ";" + has completed it. So in fact we must use the word RECURSE + to achieve self-reference, as in + + + : TUCK ( a b -- b a b) SWAP OVER ; + : GCD ( a b -- gcd) ?DUP IF TUCK MOD RECURSE THEN ; + + Now try + + 784 48 GCD . 16 ok + + + The ANSI/ISO Forth Standard (adopted in 1994) mandates the minimal set + of arithmetic operators + - * / MOD */ /MOD */MOD and M* . The + standard memory-word size is the cell, which must be at least 16 bits, + but in many modern systems is 32- or even 64 bits wide. Single-length + integers in Win32Forth are 32 bits. The stack on ANS-compliant Forths + is always 1 cell wide. + +Table of Contents  ![](up.gif) + +Home  ![](left.gif) +Next  ![](right.gif) + +10. Looping and structured programming + + Forth has several ways to loop, including the implicit method of re- + cursion, illustrated above. Recursion has a bad name as a looping + method because in most languages that permit recursion, it imposes + unacceptable running time overhead on the program. Worse, recursion + can —for reasons beyond the scope of this Introduction to Forth— be + an extremely inefficient method of expressing the problem. In Forth, + there is virtually no excess overhead in recursive calls because Forth + uses the stack directly. So there is no reason not to recurse if that + is the best way to program the algorithm. But for those times when + recursion simply isn't enough, here are some more standard methods. + + a. Indefinite loops + + The construct + + BEGIN xxx ( -- flag) UNTIL + + executes the words represented by xxx, leaving TOS (flag) set to TRUE + —at which point UNTIL terminates the loop— or to FALSE —at which + point UNTIL jumps back to BEGIN. Try: + + : COUNTDOWN ( n --) + BEGIN CR DUP . 1 - DUP 0 = UNTIL DROP ; + + 5 COUNTDOWN + 5 + 4 + 3 + 2 + 1 ok + + A variant of BEGIN...UNTIL is + + BEGIN xxx ( -- flag) WHILE yyy REPEAT + + Here xxx is executed, WHILE tests the flag and if it is FALSE + leaves the loop; if the flag is TRUE, yyy is executed; REPEAT then + branches back to BEGIN. + + These forms can be used to set up loops that repeat until some + external event (pressing a key at the keyboard, e.g.) sets the + flag to exit the loop. They can also used to make endless loops + (like the outer interpreter of Forth) by forcing the flag + to be FALSE in a definition like + + + : ENDLESS BEGIN xxx FALSE UNTIL ; + + + b. Definite loops + + Most Forths allow indexed loops using DO...LOOP (or step +LOOP). + These are permitted only within definitions + + : BY-ONES ( n --) 0 TUCK DO CR DUP . 1 + LOOP DROP ; + + The words CR DUP . 1 + will be executed n times as the lower + limit, 0, increases in unit steps to n-1. + + To step by 2's, we use the phrase 2 +LOOP to replace LOOP, as with + + : BY-TWOS ( n --) 0 TUCK + DO CR DUP . 2 + 2 +LOOP DROP ; + + These words can be simplified by accessing the loop index with the word I: + + : BY-TWOS ( n --) 0 DO CR I . 2 +LOOP ; + + We can even count backwards, as in launching a rocket, as in + + : countdown 0 SWAP DO CR I . -1 +LOOP ; ok + + 10 countdown + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + 0 ok + + + One may also nest loops and access the index of the outer loop from the inner loop + using the word J, as in + + : NESTED ( n m --) CR + 0 DO DUP ( n n --) + 0 DO CR J . I . + LOOP + LOOP + DROP ; + + 2 3 NESTED + + 0 0 + 0 1 + 1 0 + 1 1 + 2 0 + 2 1 ok + + Here is something to beware of: suppose the initial indices for the DO loop are equal: + that is, something like + + 17 17 DO stuff LOOP + + then the loop will be executed 232-1 times! As the ANS Standard document says, + “This is intolerable.” Therefore ANS Forth defines a special word, ?DO, that will skip + the loop if the indices are equal, and execute it if they are not. It is up to the + programmer to make sure that if the initial index exceeds the final one, as in 0 17 DO , + the program counts down, assuming that is what was intended: + + 0 17 DO stuff -1 +LOOP + + + + c. Structured programming + + N. Wirth invented the Pascal language in reaction to program flow + charts resembling a plate of spaghetti. Such flow diagrams were + often seen in early languages like FORTRAN and assembler. Wirth + intended to eliminate line labels and direct jumps (GOTOs), thereby + forcing control flow to be clear and direct. + + The ideal was subroutines or functions that performed a single + task, with unique entries and exits. Unfortunately, programmers + insisted on GOTOs, so many Pascals and other modern languages now have + them. Worse, the ideal of short subroutines that do one thing only is + unreachable in such languages because the method for calling them and + passing arguments imposes a large overhead. Thus execution speed re- + quires minimizing calls, which in turn means longer, more complex sub- + routines that perform several related tasks. Today structured program- + ming seems to mean little more than writing code with nested IFs in- + dented by a pretty-printer. + + Paradoxically, Forth is the only truly structured language in common + use, although it was not designed with that as its goal. In Forth word + definitions are lists of subroutines. The language contains no GOTO's so + it is impossible to write “spaghetti” code. Forth also encourages + structure through short definitions. The additional running time + incurred in breaking a long procedure into many small ones (this is + called “factoring”) is typically rather small in Forth. Each Forth sub- + routine (word) has one entry and one exit point, and can be written + to perform a single job. + + + + d. “Top-down” design + + “Top-down” programming is a doctrine that one should design the entire + program from the general to the particular: + + > Make an outline, flow chart or whatever, taking a broad overview + of the whole problem. + + > Break the problem into small pieces (decompose it). + + > Then code the individual components. + + The natural programming mode in Forth is “bottom-up” rather than “top- + down” —the most general word appears last, whereas the definitions + must progress from the primitive to the complex. This leads to a some- + what different approach from more familiar languages: + + > In Forth, components are specified roughly, and then as they are + coded they are immediately tested, debugged, redesigned and + improved. + + > The evolution of the components guides the evolution of the outer + levels of the program. + +Table of Contents  ![](up.gif) + +Home  ![](left.gif) +Next  ![](right.gif) + +11. CREATE ... DOES> (the pearl of FORTH) + + Michael Ham has called the word pair CREATE...DOES>, the “pearl of + Forth”. CREATE is a component of the compiler, whose function is to + make a new dictionary entry with a given name (the next name in the + input stream) and nothing else. DOES> assigns a specific run-time ac- + tion to a newly CREATEd word. + + + a. Defining “defining” words + + CREATE finds its most important use in extending the powerful class of + Forth words called “defining” words. The colon compiler ":" is such + a word, as are VARIABLE and CONSTANT. + + The definition of VARIABLE in high-level Forth is simple + + : VARIABLE CREATE 1 CELLS ALLOT ; + + We have already seen how VARIABLE is used in a program. (An altern- + ative definition found in some Forths is + + : VARIABLE CREATE 0 , ; + + —these variables are initialized to 0.) + + Forth lets us define words initialized to contain specific values: for + example, we might want to define the number 17 to be a word. CREATE + and "," ("comma") can do this: + + 17 CREATE SEVENTEEN , ok + + Now test it via + + SEVENTEEN @ . 17 ok . + + + Remarks: + + > The word , ("comma") puts TOS into the next cell of the dic- + tionary and increments the dictionary pointer by that number of + bytes. + + > A word "C," ("see-comma") exists also — it puts a character into + the next character-length slot of the dictionary and increments + the pointer by 1 such slot. (In the ASCII character representation + the slots are 1 byte long; Unicode characters require 2 bytes.) + + + b. Run-time vs. compile-time actions + + In the preceding example, we were able to initialize the variable + SEVENTEEN to 17 when we CREATEd it, but we still have to fetch it to + the stack via SEVENTEEN @ whenever we want it. This is not quite what + we had in mind. We would like to find 17 in TOS when SEVENTEEN is + named. The word DOES> gives us the tool to do this. + + The function of DOES> is to specify a run-time action for the “child” + words of a defining word. Consider the defining word CONSTANT , de- + fined in high-level (of course CONSTANT is usually defined in machine + code for speed) Forth by + + : CONSTANT CREATE , DOES> @ ; + + and used as + + 53 CONSTANT PRIME ok + + Now test it: + + PRIME . 53 ok . + + + What is happening here? + + > CREATE (hidden in CONSTANT) makes an entry named PRIME (the + first word in the input stream following CONSTANT). Then "," + places the TOS (the number 53) in the next cell of the dic- + tionary. + + > Then DOES> (inside CONSTANT) appends the actions of all words be- + tween it and ";" (the end of the definition) —in this case, "@"— + to the child word(s) defined by CONSTANT. + + + c. Dimensioned data (intrinsic units) + + Here is an example of the power of defining words and of the distinc- + tion between compile-time and run-time behaviors. + + Physical problems generally involve quantities that have dimensions, + usually expressed as mass (M), length (L) and time (T) or products of + powers of these. Sometimes there is more than one system of units in + common use to describe the same phenomena. + + For example, U.S. or English police reporting accidents might use + inches, feet and yards; while Continental police would use centimeters + and meters. Rather than write different versions of an accident ana- + lysis program it is simpler to write one program and make unit conver- + sions part of the grammar. This is easy in Forth. + + The simplest method is to keep all internal lengths in millimeters, + say, and convert as follows: + + : INCHES 254 10 */ ; + : FEET [ 254 12 * ] LITERAL 10 */ ; + : YARDS [ 254 36 * ] LITERAL 10 */ ; + : CENTIMETERS 10 * ; + : METERS 1000 * ; + + Note: This example is based on integer arithmetic. The word */ + means “multiply the third number on the stack by NOS, keeping + double precision, and divide by TOS”. That is, the stack com- + ment for */ is ( a b c -- a*b/c). + + + The usage would be + + 10 FEET . 3048 ok + + + The word "[" switches from compile mode to interpret mode while com- + piling. (If the system is interpreting it changes nothing.) The word + "]" switches from interpret to compile mode. + + Barring some error-checking, the “definition” of the colon compiler + ":" is just + + : : CREATE ] DOES> doLIST ; + + and that of ";" is just + + : ; next [ ; IMMEDIATE + + Another use for these switches is to perform arithmetic at compile- + time rather than at run-time, both for program clarity and for easy + modification, as we did in the first try at dimensioned data (that is, + phrases such as + + [ 254 12 * ] LITERAL + + and + + [ 254 36 * ] LITERAL + + which allowed us to incorporate in a clear manner the number of + tenths of millimeters in a foot or a yard. + + + The preceding method of dealing with units required unnecessarily many + definitions and generated unnecessary code. A more compact approach + uses a defining word, UNITS : + + : D, ( hi lo --) SWAP , , ; + : D@ ( adr -- hi lo) DUP @ SWAP CELL+ @ ; + : UNITS CREATE D, DOES> D@ */ ; + + Then we could make the table + + 254 10 UNITS INCHES + 254 12 * 10 UNITS FEET + 254 36 * 10 UNITS YARDS + 10 1 UNITS CENTIMETERS + 1000 1 UNITS METERS + + \ Usage: + 10 FEET . 3048 ok + 3 METERS . 3000 ok + \ ....................... + \ etc. + + This is an improvement, but Forth permits a simple extension that + allows conversion back to the input units, for use in output: + + VARIABLE 0 ! + : AS TRUE ! ; + : ~AS FALSE ! ; + : UNITS CREATE D, DOES> D@ @ + IF SWAP THEN + */ ~AS ; + + \ UNIT DEFINITIONS REMAIN THE SAME. + \ Usage: + 10 FEET . 3048 ok + 3048 AS FEET . 10 ok + + + + d. Advanced uses of the compiler + + Suppose we have a series of push-buttons numbered 0-3, and a word WHAT + to read them. That is, WHAT waits for input from a keypad: when button + #3 is pushed, for example, WHAT leaves 3 on the stack. + + We would like to define a word BUTTON to perform the action of pushing + the n'th button, so we could just say: + + WHAT BUTTON + + In a conventional language BUTTON would look something like + + : BUTTON DUP 0 = IF RING DROP EXIT THEN + DUP 1 = IF OPEN DROP EXIT THEN + DUP 2 = IF LAUGH DROP EXIT THEN + DUP 3 = IF CRY DROP EXIT THEN + ABORT" WRONG BUTTON!" ; + + That is, we would have to go through two decisions on the average. + + Forth makes possible a much neater algorithm, involving a “jump + table”. The mechanism by which Forth executes a subroutine is to + feed its “execution token” (often an address, but not necessarily) + to the word EXECUTE. If we have a table of execution tokens we need + only look up the one corresponding to an index (offset into the table) + fetch it to the stack and say EXECUTE. + + One way to code this is + + CREATE BUTTONS ' RING , ' OPEN , ' LAUGH , ' CRY , + : BUTTON ( nth --) 0 MAX 3 MIN + CELLS BUTTONS + @ EXECUTE ; + + Note how the phrase 0 MAX 3 MIN protects against an out-of-range + index. Although the Forth philosophy is not to slow the code with un- + necessary error checking (because words are checked as they are de- + fined), when programming a user interface some form of error handling + is vital. It is usually easier to prevent errors as we just did, than + to provide for recovery after they are made. + + How does the action-table method work? + + > CREATE BUTTONS makes a dictionary entry BUTTONS. + + > The word ' (“tick”) finds the execution token (xt) of the + following word, and the word , (“comma”) stores it in the + data field of the new word BUTTONS. This is repeated until + all the subroutines we want to select among have their xt's + stored in the table. + + > The table BUTTONS now contains xt's of the various actions of + BUTTON. + + > CELLS then multiplies the index by the appropriate number of + bytes per cell, to get the offset into the table BUTTONS + of the desired xt. + + > BUTTONS + then adds the base address of BUTTONS to get the abso- + lute address where the xt is stored. + + > @ fetches the xt for EXECUTE to execute. + + > EXECUTE then executes the word corresponding to the button pushed. + Simple! + + If a program needs but one action table the preceding method suffices. + However, more complex programs may require many such. In that case + it may pay to set up a system for defining action tables, including + both error-preventing code and the code that executes the proper + choice. One way to code this is + + : ;CASE ; \ do-nothing word + + : CASE: + CREATE HERE -1 >R 0 , \ place for length + BEGIN BL WORD FIND \ get next subroutine + 0= IF CR COUNT TYPE ." not found" ABORT THEN + R> 1+ >R + DUP , ['] ;CASE = + UNTIL R> 1- SWAP ! \ store length + DOES> DUP @ ROT ( -- base_adr len n) + MIN 0 MAX \ truncate index + CELLS + CELL+ @ EXECUTE ; + + Note the two forms of error checking. At compile-time, CASE: + aborts compilation of the new word if we ask it to point to an + undefined subroutine: + + case: test1 DUP SWAP X ;case + X not found + + and we count how many subroutines are in the table (including + the do-nothing one, ;case) so that we can force the index to + lie in the range [0,n]. + + CASE: TEST * / + - ;CASE ok + 15 3 0 TEST . 45 ok + 15 3 1 TEST . 5 ok + 15 3 2 TEST . 18 ok + 15 3 3 TEST . 12 ok + 15 3 4 TEST . . 3 15 ok + + Just for a change of pace, here is another way to do it: + + : jtab: ( Nmax --) \ starts compilation + CREATE \ make a new dictionary entry + 1- , \ store Nmax-1 in its body + ; \ for bounds clipping + + : get_xt ( n base_adr -- xt_addr) + DUP @ ( -- n base_adr Nmax-1) + ROT ( -- base_adr Nmax-1 n) + MIN 0 MAX \ bounds-clip for safety + 1+ CELLS+ ( -- xt_addr = base + 1_cell + offset) + ; + + : | ' , ; \ get an xt and store it in next cell + + : ;jtab DOES> ( n base_adr --) \ ends compilation + get_xt @ EXECUTE \ get token and execute it + ; \ appends table lookup & execute code + + \ Example: + : Snickers ." It's a Snickers Bar!" ; \ stub for test + + \ more stubs + + 5 jtab: CandyMachine + | Snickers + | Payday + | M&Ms + | Hershey + | AlmondJoy + ;jtab + + 3 CandyMachine It's a Hershey Bar! ok + 1 CandyMachine It's a Payday! ok + 7 CandyMachine It's an Almond Joy! ok + 0 CandyMachine It's a Snickers Bar! ok + -1 CandyMachine It's a Snickers Bar! ok + +Table of Contents  ![](up.gif) + +Home  ![](left.gif) +Next  ![](right.gif) + +12. Floating point arithmetic + + Although Forth at one time eschewed floating point arithmetic + (because in the era before math co-processors integer arithmetic + was 3x faster), in recent years a standard set of word names has + been agreed upon. This permits the exchange of programs that will + operate correctly on any computer, as well as the development of + a Scientific Subroutine Library in Forth (FSL). + + Although the ANS Standard does not require a separate stack for + floating point numbers, most programmers who use Forth for numer- + ical analysis employ a separate floating point stack; and most of + the routines in the FSL assume such. We shall do so here as well. + + The floating point operators have the following names and perform + the actions indicated in the accompanying stack comments: + + F@ ( adr --) ( f: -- x) + F! ( adr --) ( f: x --) + F+ ( f: x y -- x+y) + F- ( f: x y -- x-y) + F* ( f: x y -- x*y) + F/ ( f: x y -- x/y) + FEXP ( f: x -- e^x) + FLN ( f: x -- ln[x]) + FSQRT ( f: x -- x^0.5) + + Additional operators, functions, trigonometric functions, etc. can + be found in the FLOATING and FLOATING EXT wordsets. (See dpANS6— + available in HTML, PostScript and MS Word formats. The HTML version + can be accessed from this homepage.) + + To aid in using floating point arithmetic I have created a simple + FORTRAN-like interface for incorporating formulas into Forth words. + + The file ftest.f (included below) illustrates how ftran201.f + should be used. + +\ Test for ANS FORmula TRANslator + +marker -test +fvariable a +fvariable b +fvariable c +fvariable d +fvariable x +fvariable w + +: test0 f" b+c" cr fe. + f" b-c" cr fe. + f" (b-c)/(b+c)" cr fe. ; + +3.e0 b f! +4.e0 c f! +see test0 +test0 + +: test1 f" a=b*c-3.17e-5/tanh(w)+abs(x)" a f@ cr fe. ; +1.e-3 w f! +-2.5e0 x f! +cr cr +see test1 +test1 + +cr cr +: test2 f" c^3.75" cr fe. + f" b^4" cr fe. ; +see test2 +test2 + +\ Baden's test case + +: quadroot c f! b f! a f! + f" d = sqrt(b^2-4*a*c) " + f" (-b+d)/(2*a) " f" (-b-d)/(2*a) " +; +cr cr +see quadroot + +: goldenratio f" max(quad root(1,-1,-1)) " ; +cr cr +see goldenratio +cr cr +goldenratio f. + + + +0 [IF] +Output should look like: + +: test0 + c f@ b f@ f+ cr fe. c f@ fnegate b f@ f+ cr fe. c f@ fnegate b f@ + f+ c f@ b f@ f+ f/ cr fe. ; +7.00000000000000E0 +-1.00000000000000E0 +-142.857142857143E-3 + + +: test1 + x f@ fabs 3.17000000000000E-5 w f@ ftanh f/ fnegate b f@ c f@ f* f+ + f+ a f! a f@ cr fe. ; +14.4682999894333E0 ok + +: test2 + c f@ noop 3.75000000000000E0 f** cr fe. b f@ f^4 cr fe. ; +181.019335983756E0 +81.0000000000000E0 ok + +: QUADROOT C F! B F! A F! B F@ F^2 flit 4.00000 A F@ + C F@ F* F* F- FSQRT D F! B F@ FNEGATE D + F@ F+ flit 2.00000 A F@ F* F/ B F@ FNEGATE + D F@ F- flit 2.00000 A F@ F* F/ ; + + +: GOLDENRATIO flit 1.00000 flit -1.00000 flit -1.00000 + QUADROOT FMAX ; + +1.61803 ok + +with more or fewer places. + +[THEN] + +Table of Contents  ![](up.gif) + +Home  ![](left.gif) +Next  ![](right.gif) + +13. Non-trivial programming example + + To illustrate how to construct a non-trivial program, let + us develop a binary search root-finder. We will use the + FORmula TRANslator ftran201.f to simplify the appearance + of the code (that is, it hides the data fetches and + stores that would otherwise be required). + + First we need to understand the algorithm thoroughly: + + If we know that the roots are bracketed between xa and + xb, and that f(xa)*f(xb) < 0 (at least 1 root lies in + the interval) we take the next guess to be xp = (xa+xb)/2 . + + We then evaluate the function at xp: fp = f(xp). + If fa*fp > 0 we set xa = xp, else we set xb = xp. + We repeat until the ends of the interval containing + the root are sufficiently close together. + + + To begin programming, we note that we will have to keep + track of three points: xa, xb and xp. We also have to + keep track of three function values evaluated at those + points, Ra, Rb and Rp. We also need to specify a pre- + cision, epsilon, within which we expect to determine + the root. + + Next we need to define the user interface. That is, once + we have a subroutine that finds roots, how will we invoke + it? Since we would like to be able to specify the name of + the function to find the root of at the same time we + specify the interval we think the root is in, we need + some way to pass the name to the root finder as an + argument. + + I have previously developed an interface that suits me: I + say + + use( fn.name xa xb precision )bin_root + + as in + + use( f1 0e0 2e0 1e-5 )bin_root + + and the root will be left on the floating point stack. + + + The code for passing names of functions as arguments is + included when you load ftran201.f — the words used in + this program are use( , v: and defines . v: creates a + dummy dictionary entry (named dummy in the program) + which can be made to execute the actual function whose + name is passed to the word )bin_root . + + Here are the data structures and their identifications: + + MARKER -binroots \ say -binroots to unload + + \ Data structures + + FVARIABLE Ra \ f(xa) + FVARIABLE Rb \ f(xb) + FVARIABLE Rp \ f(xp) + FVARIABLE xa \ lower end + FVARIABLE xb \ upper end + FVARIABLE xp \ new guess + FVARIABLE epsilon \ precision + + v: dummy \ create dummy dictionary entry + + The actual root-finding subroutine, )bin_root , will be + quite simple and easy to follow: + + : )bin_root ( xt --) ( f: Low High Precision -- root) + initialize + BEGIN NotConverged? WHILE NewPoint REPEAT + f" (xa+xb)/2" ( f: -- root) + ; + + Note that the subroutines comprising it are telegraph- + ically named so they need no explanation; whereas + )bin_root itself is explained by its stack comments. The + comments on the first line indicate that )bin_root expects + an “execution token” on the data stack, and three floating + point numbers on the floating point stack. These are its + arguments. (See 11d for a discussion of EXECUTE, etc.) + The execution token is what is used to change the + behavior of the dummy dictionary entry dummy : we say + + defines dummy + + in the word initialize to make dummy behave like the + function whose root we are seeking. + + The final comment ( f: -- root) indicates that )bin_root leaves + the answer on the floating point stack. + + + In a sense we are programming from the top down, since we + have begun with the last definition of the program and + are working our way forward. In Forth we often go both + ways —top-down and bottom-up— at the same time. + + + The key words we must now define are initialize , + NotConverged? and NewPoint . We might as well begin with + initialize since it is conceptually simple: + + : initialize ( xt --) ( f: lower upper precision --) + defines dummy \ xt -> DUMMY + f" epsilon=" f" xb=" f" xa=" \ store parameters + f" Ra=dummy(xa)" + f" Rb=dummy(xb)" + f" MoreThan( Ra*Rb, 0)" \ same sign? + ABORT" Even # of roots in interval!" + ; + + The word ABORT" prints the message that follows it and + aborts execution, if it encounters a TRUE flag on the + data stack. It is widely used as a simple error handler. + ABORT (without the " ) simply aborts execution when + it is encountered. So it usually is found inside some + decision structure like an IF...THEN clause. (See 11d for + two examples of usage.) + + ABORT" was preceded by a test. In order to use a test as + a function in a Fortran-like expression (this test con- + sumes two arguments from the floating point stack and + leaves a flag on the data stack), we must define a synonym + for it. The reason is that ftran201.f does not recognize + relational operators like > or < . The definition is* + + : MoreThan ( f: a b) ( -- true if a>b) + POSTPONE F> ; IMMEDIATE + + The code produced by f" MoreThan( Ra*Rb, 0)" is then just + + RA F@ RB F@ F* flit 0.00000E-1 F> + + which is what we want. We have already explained the + phrase defines dummy. The phrases f" xa=" and so on are + shorthand for storing something from the floating point + stack to a floating point variable. Thus f" xa=" + generates the code XA F! . The rest of initialize is to + calculate the function at the endpoints of the supposed + bounding interval (a,b). + + + NotConverged? is a test for (non)convergence. WHILE + expects a flag on the data stack, as described in 10a. So + we define + + : NotConverged? ( -- f) + f" MoreThan( ABS( xa - xb ), epsilon )" ; + + which generates the code + + XB F@ XA F@ F- FABS EPSILON F@ F> + + + What about NewPoint ? Clearly, + + : NewPoint + f" xp = (xa+xb)/2" \ new point + f" Rp = dummy(xp)" + f" MoreThan( Ra*Rp, 0)" \ xp on same side of root as xa? + + IF f" xa=xp" f" Ra=Rp" + ELSE f" xb=xp" f" Rb=Rp" THEN + ; + + That is, we generate a new guess by bisection, evaluate the + function there and decide how to choose the new bounding + interval. + + All that remains is to put the definitions in the proper order + and test the result by loading the program bin_rts.f and + trying out the test case. + + + FALSE [IF] + Usage example: + + : f1 fdup fexp f* 1e0 f- ; ok + use( f1 0e0 2e0 1e-5 )bin_root f. .567142 ok + + [THEN] + + Finally, if we want to be very careful indeed, and/or are + planning to re-use the program, we add an appropriate + boilerplate header, such as that included in the file + bin_rts.f . + + + +--- + + + *Note: the word POSTPONE in this context means that the word following it + —in this case F> — will be compiled into the word that uses MoreThan rather + than in MoreThan itelf. (Note that MoreThan is IMMEDIATE.) This way of doing + things saves some overhead during execution. Some Forths (notably Win32Forth) + define a word SYNONYM to accomplish the same thing. + + +--- + + + +Table of Contents  ![](up.gif) + +Home  ![](left.gif) +Next  ![](right.gif) + +14. Some remarks about strings + As in other languages, alphanumeric strings in Forth are represented as + contiguous arrays in memory, each memory unit being a “character”. + Traditionally a character encoded by the ASCII or EBCDIC systems occupied + one (1) byte of storage, allowing for 256 characters. With the need to encode + alphabets other than the Latin one (e.g. Chinese, Arabic, Hebrew, Cyrillic) a + two-byte encoding called Unicode has been adopted, which allows for 65535 + distinct characters. + + A traditional Forth string consisted of a count byte and up to 255 bytes containing + alphanumeric characters (usually in ASCII). In ANS Forth this scheme has been + abandoned: how strings are stored will depend on the implementation. However + ANS Forth contains words that enable us to manipulate strings without reference + to how they are implemented. + + Most ANS Forths (and Win32Forth is one of them) define S" to have defined + interpretive as well as compiling behavior. This means that if we say + + S" This is a string!" CR TYPE + + we get + + This is a string! ok + + What happened? S" This is a string!" created a string with text beginning at a + “c-address” and with a “count” that says how many characters (including blanks) + the string includes. The address and count are left on the stack. That is, the + proper stack picture would be + + S" This is a string!" ( -- c-addr u) + + (the count is an unsigned integer u because strings of negative length are + meaningless). + + The word CR means “insert a carriage return”, and TYPE means “from the + c-addr output u characters to the screen”. + + Exercise: + Use what you have just learned to write a “Hello world!” program. + + + It is perfectly feasible to define one's own word set for working with strings, depending + on what sort of application one is writing. For example, I have written a program to + translate mathematical formulas in Fortran-like form into Forth code, outputting the + result either to the screen (for test purposes) or embedding it into a Forth definition. + There is even a variant that evaluates the formula, provided all the variables have + been previously defined and given numerical values. To accomplish this required + strings longer than 255 characters, so I defined my own. + + + + I now want to turn to “pictured numerical output”. Many computer programs + need to output numbers in some particular format, no matter how they are stored intern- + ally. For example an accounting program might output monetary amounts in the usual + dollars-and-cents format. The Forth words that accomplish this are + + # , <# , #S , #> , SIGN and HOLD + + They do not have any defined interpretive behavior (although there is no telling what + any particular Forth may do) and are intended to be used within word definitions. Here + is an example: suppose we are writing an accounting program. Since most users will + not be dealing with amounts that exceed $100,000,000 we can use signed 32-bit integers + to represent the dollars and cents. (Such numbers can represent amounts up to + ±(231—1) = ±2147483647 cents.) Signed double-length integers are at least 32 bits long + on all ANS-compatible systems (although they will be 64 bits on 32-bit computers). + Hence we shall use doubles so the program will run on any ANS-compatible + Forth. + + A double-length integer is entered from the keyboard by including a decimal point in + it, as + + -4756.325 ok + + Let us define a word to output a double-length integer. The first part will be to + translate it to an alphanumeric string referred to by c-addr u. + + : (d.$) ( d -- c-adr u) TUCK DABS <# # # [CHAR] . HOLD #S ROT SIGN #> ; + + As the stack comment ( d -- c-adr u) shows, (d.$) consumes a (signed) double-length + integer from the stack and leaves the string data in a form that can be printed to the + screen by the word TYPE. Let us test this: + + 4376.58 (d.$) CR TYPE + 4376.58 ok + + -4376.99 (d.$) CR TYPE + -4376.99 ok + + It is worth exploring what each part does. A double length integer is stored as two + cells on the stack, with the most-significant part on TOS. Thus the word TUCK + places the most-significant part (containing the algebraic sign) above d and then DABS + converts d to |d|. Next, <# begins the process of constructing an alphanumeric + string. The two instances of # peel off the two least-significant digits and put + them in the string. The phrase [CHAR] . HOLD adds a decimal point to the string. + + [CHAR] builds in the representation of the character . as a numeric literal (in + ASCII it is 46). HOLD then adds it to the string under construction. (HOLD has no + meaning except between <# and #>.) Then the word #S takes the rest of the digits + and adds them to the nascent string. + + (Semi)finally, ROT puts the most significant part of d (with its sign) on TOS, and + SIGN adds its algebraic sign to the beginning of the string. (Again, SIGN is only + meaningful between <# and #>.) + + And finally, the word #> cleans everything up and leaves c-addr u + on the stack, ready for display or whatever. + + Exercises: + + a) How would you add a leading dollar sign ($) to the output number? + b) How would you enclose a negative amount in parentheses rather than + displaying a — sign? [That is, ( 4376.99) rather than -4376.99.] + c) Define a word to display a double-length integer in dollar-and-cents format. + +Table of Contents  ![](up.gif) + +Home  ![](left.gif) + +15. Assembly language programming + Most Forths include an assembler that makes programming in machine code almost as + easy as programming in high level Forth. Why would one want to do that? There are + reallly only two reasons for dropping into machine language: + + > One must perform a task requiring carnal knowledge of the hardware; + > Part of the program must be optimized for speed. + + In this section we deal only with the second reason. We imagine that after careful + algorithmic analysis there is no way to further speed up a high level program. However + the requirements of the application demand a substantial speed improvement. Since + most Forths are somewhat inefficient relative to optimized C or Fortran, there may be + a substantial speed gain to be realized from hand-coding in assembly language. An + example is the innermost loop in a linear equations solver. For n equations it is + executed n3 times. Moreover it is a very simple loop, containing 2 fetches, a multi- + plication, a subtraction and a store. Thus it is a perfect candidate to be optimized. + By contrast, the middle- and outermost loops are executed respectively n2 and n times, + so there is little point in optimizing them (that is, for small matrices the running + time is too short to care; whereas for large matrices— n > 100 —the middle loop would + have to run 100× faster to be worth rewriting in machine code. + + It is important to realize that assembly language conventions differ from + Forth to Forth. Moreover the instruction set will be particular to a given + target computer. That is, there is no such thing as a generic assembler + in any programming environment, much less for Forth. Hence everything + we do here will be specific to Win32Forth running on a Pentium-class machine. + + We begin with a little warmup exercise. Suppose I found that my program + used the sequence * + many times. Obviously good factoring practice + would dictate that this sequence be given its own name and defined as + a new subroutine (word). So we might define + + : *+ * + ; + + and substitute it for the sequence * + throughout the program. But + suppose we discover that this short sequence is the bottleneck in our + program's running time, so that speeding it up will greatly increase + speed of execution. (I realize it isn't likely for this example---bear + with me!) So we would like to translate it into machine code. To do + this we first look at the machine code for * and + separately. These + are primitive words and almost certainly will be CODE definitions in + any reasonable Forth. + + Thus we need to disassemble these words. In some Forths this might mean + inspecting the contents of the word byte by byte, and looking up the code + sequences in the operating manual for that cpu. Fortunately for us, + Win32Forth has a built-in disassembler. If we SEE a CODEd definition it + will return the actual byte-codes as well as the names of the instructions + in the Win32Forth assembler. Let us try this out: we get + + see + + + IS CODE + 4017AC 58 pop eax + 4017AD 03D8 add ebx, eax + + ok + + see * + * IS CODE + 401B9C 8BCA mov ecx, edx + 401B9E 58 pop eax + 401B9F F7E3 mul ebx + 401BA1 8BD8 mov ebx, eax + 401BA3 8BD1 mov edx, ecx + + ok + + + To understand these sequences we must bear in mind that Win32Forth keeps + TOS in a 32-bit register, in fact the ebx register. We must also know that + Win32Forth uses the edx register for something or other—probably to do + with the mechanism for executing a word and returning control to the next + word in the program (that is, the threading mechanism). So if a program + is going to modify the edx register, its previous contents have to be + saved somewhere. Since addition of eax to ebx does not affect edx, the + CODE for + doesn't need to protect edx; however, when two 32-bit numbers + are multiplied, the result can contain as many as 64 bits. Thus the product + occupies the two registers eax (bits 0 through 31) and edx (bits 32-63). + + This is the reason for saving edx into the unused ecx register, and then + restoring it afterward. + + It is worth noting, before we go too far, that the Win32Forth assembler + preserves the Intel conventions. That is, + + add ebx, eax + + adds the contents of register eax to ebx, leaving the result in ebx (which + is where we want it because that is TOS). Similarly, the sequences + + mov ecx, edx + + and + + mov ebx, eax + + have the structure + + mov destination, source + + We should also ask why the integer multiplication instruction + + mul ebx + + has only one operand. The answer is that the register eax is the so-called + “accumulator”, so it contains one of the multiplicands initially and then it + and edx contain the product, as noted above. It is then only necessary to + specify where the other multiplicand is coming from (it could be a cell in + memory). + + Therefore to define the word *+ in assembler we would type in + + CODE *+ ( a b c -- b*c+a) \ stack: before -- after + mov ecx, edx \ protect edx because mul alters it + pop eax \ get item b; item c (TOS) is already in ebx + mul ebx \ integer multiply-- c*b -> eax (accumulator) + pop ebx \ get item a + add ebx, eax \ add c*b to a -- result in ebx (TOS) --done + mov edx, ecx \ restore edx + next, \ terminating code for Forth interpreter + END-CODE ok + + Note that the Forth assembler recognizes Forth comments—Intel-style + comments would be preceded by semicolons, but we obviously can't use these + because semicolon is a Forth word. + + The word END-CODE has an obvious meaning, but what about next, (the comma + is part of the name and is significant!). Advanced users of the assembler + sometimes need to define code sequences that do not include the instructions + to transfer control to the next word. So Win32Forth has factored this function + out of the CODE terminating sequence. For this example we require these + instructions to be assembled, so we include next, . + + + Before going further, you should try out this example and convince yourself + it works. + + + For our nontrivial example we are going to hand-code the innermost loop of + my linear equations solver. I programmed this in high-level Forth in the + form + + : }}r1-r2*x ( M{{ r1 r2 -- ) ( f: x -- x) \ initialize assumed + 0 0 + LOCALS| I1 I2 r2 r1 mat{{ | \ local names + frame| aa | \ local fvariable + Iperm{ r1 } @ TO I1 + Iperm{ r2 } @ TO I2 + Nmax r2 ?DO \ begin loop + f" mat{{ I1 I }} = mat{{ I1 I }} + - mat{{ I2 I }} * aa" + LOOP \ end loop + f" aa" |frame ( f: -- x) + ; + + Here Iperm{ is the name of an array of integers that holds the permuted + row-labels; note that the rows we work on do not change within the actual + loop. Neither does the floating point number represented by the local + variable aa. What does change are the row-elements. + + + To translate }}r1-r2*x to assembler we will need to factor it a bit more + finely. Evidently we are subtracting the I'th element of row I2, multi- + plied by aa, from the I'th element of row I1. Moreover, since the matrix + has been partially triangularized already, we do not start with element 0 + but with element r2. Finally, as we have noted previously, ?DO includes + a bounds check so that if r2 equals or is greater than Nmax the loop is + not executed. So we shall revise }}r1-r2*x to include this test explicitly + and CODE only the loop itself. That is, we shall write + + + : incr_addrs ( addr1 addr2 -- addr1+inc addr2+inc) + [ 1 FLOATS ] LITERAL + TUCK + -ROT + SWAP ; + + : inner_loop ( addr1 addr2 Nmax lower_limit -- ) ( f: x -- x) + DO \ begin loop + ( f: aa) ( addr1 addr2) \ loop invariant + 2DUP SWAP F@ ( f: aa m[I1,I]) + FOVER F@ F* F- OVER F! + \ m[I1,I = m[I1,I] - m[I2,I]*x + ( f: x) ( addr1 addr2) \ loop invariant + incr_addrs \ increment addresses + LOOP \ end loop + 2DROP + ; + + : }}r1-r2*x ( M{{ r1 r2 -- ) ( f: x -- x) \ initialize assumed + 0 0 + LOCALS| I1 I2 r2 r1 mat{{ | \ local names + Iperm{ r1 } @ TO I1 + Iperm{ r2 } @ TO I2 + Nmax r2 > + IF mat{{ I1 r2 }} mat{{ I1 r2 }} \ base adresses + Nmax r2 \ loop limits + ( f: x) ( addr1 addr2 Nmax lower_limit) + inner_loop + ( f: x) ( -- ) + THEN + ; + + So what we are going to CODE here is the word inner_loop, since these are + the only instructions executed n3 times. + + CODE inner_loop ( addr1 addr2 Nmax lower_limit -- ) ( f: x -- x) + fld FSIZE FSTACK_MEMORY \ f: -> fpu: + mov ecx, ebx \ ecx = r2 + pop eax \ eax = Nmax + ( addr1 ebx=addr2) + push edx ( addr1 edx ebx) + mov edx, 4 [esp] \ edx = addr1) + \ begin loop + L$1: fld [ebx] [edi] ( fpu: aa m[addr2] + fmul st, st(1) ( fpu: aa m2*aa) + fld [edx] [edi] ( fpu: aa m2*aa m1) + fxch st(1) ( fpu: aa m1 m2*aa) + fsubp st(1), st ( fpu: aa m1-m2*aa) + fstp [edx] [edi] ( fpu: aa) + add [edx], # 8 \ increment addresses + add [ebx], # 8 + inc ecx \ add 1 to loop variable + cmp eax, ecx \ test for done + jl L$1 \ loop if I < Nmax + \ end loop + pop edx \ restore edx + pop ebx + pop ebx \ clean up data stack + fstp FSIZE FSTACK_MEMORY \ fpu: -> f: + next, + END-CODE + + A final remark: I have written a tool for translating automatically a + sequence of floating point operations to CODE for the Intel fpu. This + tool, ctran.f, is specialized for Win32Forth. + +Table of Contents  ![](up.gif) + +Home  ![](left.gif) + +16. Some useful references + > M. Kelly and N. Spies, Forth: A text and Reference (Prentice-Hall, NJ, 1986) + + > L. Brodie, Starting Forth, 2nd ed. (Prentice-Hall, NJ, 1986) + + > L. Brodie, Thinking FORTH (Prentice-Hall, NJ, 1984 (online edition) + + +Table of Contents  ![](up.gif) + +Home  ![](left.gif) +``` \ No newline at end of file diff --git a/references/ForthNotes/JonesForth-arm.md b/references/ForthNotes/JonesForth-arm.md new file mode 100644 index 0000000..aedbbf5 --- /dev/null +++ b/references/ForthNotes/JonesForth-arm.md @@ -0,0 +1,398 @@ +# JonesForth-arm + +**Source:** https://github.com/M2IHP13-admin/JonesForth-arm + +GitHub - M2IHP13-admin/JonesForth-arm + + + +[Skip to content](#start-of-content) + + + + + + + + + + + + + +## Navigation Menu + +Toggle navigation + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2FM2IHP13-admin%2FJonesForth-arm) + +Appearance settings + +* Platform + + + AI CODE CREATION + - [GitHub CopilotWrite better code with AI](https://github.com/features/copilot) + - [GitHub SparkBuild and deploy intelligent apps](https://github.com/features/spark) + - [GitHub ModelsManage and compare prompts](https://github.com/features/models) + - [MCP RegistryNewIntegrate external tools](https://github.com/mcp) + + DEVELOPER WORKFLOWS + - [ActionsAutomate any workflow](https://github.com/features/actions) + - [CodespacesInstant dev environments](https://github.com/features/codespaces) + - [IssuesPlan and track work](https://github.com/features/issues) + - [Code ReviewManage code changes](https://github.com/features/code-review) + + APPLICATION SECURITY + - [GitHub Advanced SecurityFind and fix vulnerabilities](https://github.com/security/advanced-security) + - [Code securitySecure your code as you build](https://github.com/security/advanced-security/code-security) + - [Secret protectionStop leaks before they start](https://github.com/security/advanced-security/secret-protection) + + EXPLORE + - [Why GitHub](https://github.com/why-github) + - [Documentation](https://docs.github.com) + - [Blog](https://github.blog) + - [Changelog](https://github.blog/changelog) + - [Marketplace](https://github.com/marketplace) + + [View all features](https://github.com/features) +* Solutions + + + BY COMPANY SIZE + - [Enterprises](https://github.com/enterprise) + - [Small and medium teams](https://github.com/team) + - [Startups](https://github.com/enterprise/startups) + - [Nonprofits](https://github.com/solutions/industry/nonprofits) + + BY USE CASE + - [App Modernization](https://github.com/solutions/use-case/app-modernization) + - [DevSecOps](https://github.com/solutions/use-case/devsecops) + - [DevOps](https://github.com/solutions/use-case/devops) + - [CI/CD](https://github.com/solutions/use-case/ci-cd) + - [View all use cases](https://github.com/solutions/use-case) + + BY INDUSTRY + - [Healthcare](https://github.com/solutions/industry/healthcare) + - [Financial services](https://github.com/solutions/industry/financial-services) + - [Manufacturing](https://github.com/solutions/industry/manufacturing) + - [Government](https://github.com/solutions/industry/government) + - [View all industries](https://github.com/solutions/industry) + + [View all solutions](https://github.com/solutions) +* Resources + + + EXPLORE BY TOPIC + - [AI](https://github.com/resources/articles?topic=ai) + - [Software Development](https://github.com/resources/articles?topic=software-development) + - [DevOps](https://github.com/resources/articles?topic=devops) + - [Security](https://github.com/resources/articles?topic=security) + - [View all topics](https://github.com/resources/articles) + + EXPLORE BY TYPE + - [Customer stories](https://github.com/customer-stories) + - [Events & webinars](https://github.com/resources/events) + - [Ebooks & reports](https://github.com/resources/whitepapers) + - [Business insights](https://github.com/solutions/executive-insights) + - [GitHub Skills](https://skills.github.com) + + SUPPORT & SERVICES + - [Documentation](https://docs.github.com) + - [Customer support](https://support.github.com) + - [Community forum](https://github.com/orgs/community/discussions) + - [Trust center](https://github.com/trust-center) + - [Partners](https://github.com/partners) +* Open Source + + + COMMUNITY + - [GitHub SponsorsFund open source developers](https://github.com/sponsors) + + PROGRAMS + - [Security Lab](https://securitylab.github.com) + - [Maintainer Community](https://maintainers.github.com) + - [Accelerator](https://github.com/accelerator) + - [Archive Program](https://archiveprogram.github.com) + + REPOSITORIES + - [Topics](https://github.com/topics) + - [Trending](https://github.com/trending) + - [Collections](https://github.com/collections) +* Enterprise + + + ENTERPRISE SOLUTIONS + - [Enterprise platformAI-powered developer platform](https://github.com/enterprise) + + AVAILABLE ADD-ONS + - [GitHub Advanced SecurityEnterprise-grade security features](https://github.com/security/advanced-security) + - [Copilot for BusinessEnterprise-grade AI features](https://github.com/features/copilot/copilot-business) + - [Premium SupportEnterprise-grade 24/7 support](https://github.com/premium-support) +* [Pricing](https://github.com/pricing) + +Search or jump to... + + +# Search code, repositories, users, issues, pull requests... + +Search + +Clear + +[Search syntax tips](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax) + +# Provide feedback + +We read every piece of feedback, and take your input very seriously. + + +Include my email address so I can be contacted + +Cancel + Submit feedback + + + + + +# Saved searches + +## Use saved searches to filter your results more quickly + +Name + +Query + +To see all available qualifiers, see our [documentation](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax). + +Cancel + Create saved search + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2FM2IHP13-admin%2FJonesForth-arm) + +[Sign up](/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E&source=header-repo&source_repo=M2IHP13-admin%2FJonesForth-arm) + +Appearance settings + +Resetting focus + +You signed in with another tab or window. Reload to refresh your session. +You signed out in another tab or window. Reload to refresh your session. +You switched accounts on another tab or window. Reload to refresh your session. + + + +Dismiss alert + +{{ message }} + +[M2IHP13-admin](/M2IHP13-admin) +/ +**[JonesForth-arm](/M2IHP13-admin/JonesForth-arm)** +Public + +* [Notifications](/login?return_to=%2FM2IHP13-admin%2FJonesForth-arm) You must be signed in to change notification settings +* [Fork + 52](/login?return_to=%2FM2IHP13-admin%2FJonesForth-arm) +* [Star + 89](/login?return_to=%2FM2IHP13-admin%2FJonesForth-arm) + +### License + +[LGPL-3.0 license](/M2IHP13-admin/JonesForth-arm/blob/master/LICENSE) + +[89 +stars](/M2IHP13-admin/JonesForth-arm/stargazers) [52 +forks](/M2IHP13-admin/JonesForth-arm/forks) [Branches](/M2IHP13-admin/JonesForth-arm/branches) [Tags](/M2IHP13-admin/JonesForth-arm/tags) [Activity](/M2IHP13-admin/JonesForth-arm/activity) + +[Star](/login?return_to=%2FM2IHP13-admin%2FJonesForth-arm) + +[Notifications](/login?return_to=%2FM2IHP13-admin%2FJonesForth-arm) You must be signed in to change notification settings + +* [Code](/M2IHP13-admin/JonesForth-arm) +* [Issues + 0](/M2IHP13-admin/JonesForth-arm/issues) +* [Pull requests + 0](/M2IHP13-admin/JonesForth-arm/pulls) +* [Actions](/M2IHP13-admin/JonesForth-arm/actions) +* [Projects + 0](/M2IHP13-admin/JonesForth-arm/projects) +* [Wiki](/M2IHP13-admin/JonesForth-arm/wiki) +* [Security + 0](/M2IHP13-admin/JonesForth-arm/security) +* [Insights](/M2IHP13-admin/JonesForth-arm/pulse) + +Additional navigation options + + +* [Code](/M2IHP13-admin/JonesForth-arm) +* [Issues](/M2IHP13-admin/JonesForth-arm/issues) +* [Pull requests](/M2IHP13-admin/JonesForth-arm/pulls) +* [Actions](/M2IHP13-admin/JonesForth-arm/actions) +* [Projects](/M2IHP13-admin/JonesForth-arm/projects) +* [Wiki](/M2IHP13-admin/JonesForth-arm/wiki) +* [Security](/M2IHP13-admin/JonesForth-arm/security) +* [Insights](/M2IHP13-admin/JonesForth-arm/pulse) + +# M2IHP13-admin/JonesForth-arm + +master + +[Branches](/M2IHP13-admin/JonesForth-arm/branches)[Tags](/M2IHP13-admin/JonesForth-arm/tags) + +Go to file + +Code + +Open more actions menu + +## Folders and files + +| Name | | Name | Last commit message | Last commit date | +| --- | --- | --- | --- | --- | +| Latest commit History[58 Commits](/M2IHP13-admin/JonesForth-arm/commits/master/) 58 Commits | | | +| [.gitattributes](/M2IHP13-admin/JonesForth-arm/blob/master/.gitattributes ".gitattributes") | | [.gitattributes](/M2IHP13-admin/JonesForth-arm/blob/master/.gitattributes ".gitattributes") | | | +| [AUTHORS](/M2IHP13-admin/JonesForth-arm/blob/master/AUTHORS "AUTHORS") | | [AUTHORS](/M2IHP13-admin/JonesForth-arm/blob/master/AUTHORS "AUTHORS") | | | +| [LICENSE](/M2IHP13-admin/JonesForth-arm/blob/master/LICENSE "LICENSE") | | [LICENSE](/M2IHP13-admin/JonesForth-arm/blob/master/LICENSE "LICENSE") | | | +| [Makefile](/M2IHP13-admin/JonesForth-arm/blob/master/Makefile "Makefile") | | [Makefile](/M2IHP13-admin/JonesForth-arm/blob/master/Makefile "Makefile") | | | +| [README.md](/M2IHP13-admin/JonesForth-arm/blob/master/README.md "README.md") | | [README.md](/M2IHP13-admin/JonesForth-arm/blob/master/README.md "README.md") | | | +| [jonesforth.S](/M2IHP13-admin/JonesForth-arm/blob/master/jonesforth.S "jonesforth.S") | | [jonesforth.S](/M2IHP13-admin/JonesForth-arm/blob/master/jonesforth.S "jonesforth.S") | | | +| [jonesforth.f](/M2IHP13-admin/JonesForth-arm/blob/master/jonesforth.f "jonesforth.f") | | [jonesforth.f](/M2IHP13-admin/JonesForth-arm/blob/master/jonesforth.f "jonesforth.f") | | | +| [perf\_dupdrop.c](/M2IHP13-admin/JonesForth-arm/blob/master/perf_dupdrop.c "perf_dupdrop.c") | | [perf\_dupdrop.c](/M2IHP13-admin/JonesForth-arm/blob/master/perf_dupdrop.c "perf_dupdrop.c") | | | +| [perf\_dupdrop.f](/M2IHP13-admin/JonesForth-arm/blob/master/perf_dupdrop.f "perf_dupdrop.f") | | [perf\_dupdrop.f](/M2IHP13-admin/JonesForth-arm/blob/master/perf_dupdrop.f "perf_dupdrop.f") | | | +| [test\_comparison.f](/M2IHP13-admin/JonesForth-arm/blob/master/test_comparison.f "test_comparison.f") | | [test\_comparison.f](/M2IHP13-admin/JonesForth-arm/blob/master/test_comparison.f "test_comparison.f") | | | +| [test\_comparison.f.out](/M2IHP13-admin/JonesForth-arm/blob/master/test_comparison.f.out "test_comparison.f.out") | | [test\_comparison.f.out](/M2IHP13-admin/JonesForth-arm/blob/master/test_comparison.f.out "test_comparison.f.out") | | | +| [test\_exception.f](/M2IHP13-admin/JonesForth-arm/blob/master/test_exception.f "test_exception.f") | | [test\_exception.f](/M2IHP13-admin/JonesForth-arm/blob/master/test_exception.f "test_exception.f") | | | +| [test\_exception.f.out](/M2IHP13-admin/JonesForth-arm/blob/master/test_exception.f.out "test_exception.f.out") | | [test\_exception.f.out](/M2IHP13-admin/JonesForth-arm/blob/master/test_exception.f.out "test_exception.f.out") | | | +| [test\_nqueens.f](/M2IHP13-admin/JonesForth-arm/blob/master/test_nqueens.f "test_nqueens.f") | | [test\_nqueens.f](/M2IHP13-admin/JonesForth-arm/blob/master/test_nqueens.f "test_nqueens.f") | | | +| [test\_nqueens.f.out](/M2IHP13-admin/JonesForth-arm/blob/master/test_nqueens.f.out "test_nqueens.f.out") | | [test\_nqueens.f.out](/M2IHP13-admin/JonesForth-arm/blob/master/test_nqueens.f.out "test_nqueens.f.out") | | | +| [test\_number.f](/M2IHP13-admin/JonesForth-arm/blob/master/test_number.f "test_number.f") | | [test\_number.f](/M2IHP13-admin/JonesForth-arm/blob/master/test_number.f "test_number.f") | | | +| [test\_number.f.out](/M2IHP13-admin/JonesForth-arm/blob/master/test_number.f.out "test_number.f.out") | | [test\_number.f.out](/M2IHP13-admin/JonesForth-arm/blob/master/test_number.f.out "test_number.f.out") | | | +| [test\_read\_file.f](/M2IHP13-admin/JonesForth-arm/blob/master/test_read_file.f "test_read_file.f") | | [test\_read\_file.f](/M2IHP13-admin/JonesForth-arm/blob/master/test_read_file.f "test_read_file.f") | | | +| [test\_read\_file.f.out](/M2IHP13-admin/JonesForth-arm/blob/master/test_read_file.f.out "test_read_file.f.out") | | [test\_read\_file.f.out](/M2IHP13-admin/JonesForth-arm/blob/master/test_read_file.f.out "test_read_file.f.out") | | | +| [test\_stack.f](/M2IHP13-admin/JonesForth-arm/blob/master/test_stack.f "test_stack.f") | | [test\_stack.f](/M2IHP13-admin/JonesForth-arm/blob/master/test_stack.f "test_stack.f") | | | +| [test\_stack.f.out](/M2IHP13-admin/JonesForth-arm/blob/master/test_stack.f.out "test_stack.f.out") | | [test\_stack.f.out](/M2IHP13-admin/JonesForth-arm/blob/master/test_stack.f.out "test_stack.f.out") | | | +| [test\_stack\_trace.f](/M2IHP13-admin/JonesForth-arm/blob/master/test_stack_trace.f "test_stack_trace.f") | | [test\_stack\_trace.f](/M2IHP13-admin/JonesForth-arm/blob/master/test_stack_trace.f "test_stack_trace.f") | | | +| [test\_stack\_trace.f.out](/M2IHP13-admin/JonesForth-arm/blob/master/test_stack_trace.f.out "test_stack_trace.f.out") | | [test\_stack\_trace.f.out](/M2IHP13-admin/JonesForth-arm/blob/master/test_stack_trace.f.out "test_stack_trace.f.out") | | | +| View all files | | | + +## Repository files navigation + +* [README](#) +* [LGPL-3.0 license](#) + +# Jonesforth-ARM + +An ARM port of X86 JonesForth by Richard W.M. Jones [rich@annexia.org](mailto:rich@annexia.org) +at . + +## What is this ? + +Jonesforth-ARM is a Forth interpreter developed for ARM. + +The algorithm for our unsigned DIVMOD instruction is extracted from 'ARM +Software Development Toolkit User Guide v2.50' published by ARM in 1997-1998 + +Compared to the original interpreter: + +* We did not keep the jonesforth.f section allowing to compile assembly from + the Forth interpreter because it was X86 specific. +* We pass all the original JonesForth's tests on ARM (except one which + depends on the above X86 assembly compilation). +* We added a native signed DIVMOD instruction (S/MOD) + +Another project porting Jonesforth on ARM is ongoing at + + +## Build and run instructions + +If you are building on the ARM target, just type, + +``` +$ make +``` + +to build the forth interpreter. + +After building, we recommend that you run the test-suite by executing, + +``` +$ make test +``` + +To launch the forth interpreter, type + +``` +$ cat jonesforth.f - | ./jonesforth +``` + +## Contributors: + +ABECASSIS Felix, BISPO VIEIRA Ricardo, BLANC Benjamin, BORDESSOULES Arthur, +BOUDJEMAI Yassine, BRICAGE Marie, ETSCHMANN Marc, GAYE Ndeye Aram, +GONCALVES Thomas, GOUGEAUD Sebastien, HAINE Christopher, OLIVEIRA Pablo, +PLAZA ONATE Florian, POPOV Mihail + +## About + +No description, website, or topics provided. + +### Resources + +[Readme](#readme-ov-file) + +### License + +[LGPL-3.0 license](#LGPL-3.0-1-ov-file) + +### Uh oh! + +There was an error while loading. Please reload this page. + +[Activity](/M2IHP13-admin/JonesForth-arm/activity) + +### Stars + +[**89** +stars](/M2IHP13-admin/JonesForth-arm/stargazers) + +### Watchers + +[**14** +watching](/M2IHP13-admin/JonesForth-arm/watchers) + +### Forks + +[**52** +forks](/M2IHP13-admin/JonesForth-arm/forks) + +[Report repository](/contact/report-content?content_url=https%3A%2F%2Fgithub.com%2FM2IHP13-admin%2FJonesForth-arm&report=M2IHP13-admin+%28user%29) + +## [Releases](/M2IHP13-admin/JonesForth-arm/releases) + +No releases published + +## [Packages 0](/users/M2IHP13-admin/packages?repo_name=JonesForth-arm) + +No packages published + +## [Contributors 4](/M2IHP13-admin/JonesForth-arm/graphs/contributors) + +### Uh oh! + +There was an error while loading. Please reload this page. + +## Languages + +* [Forth + 62.4%](/M2IHP13-admin/JonesForth-arm/search?l=forth) +* [Assembly + 35.9%](/M2IHP13-admin/JonesForth-arm/search?l=assembly) +* Other + 1.7% + +## Footer + +© 2026 GitHub, Inc. + +### Footer navigation + +* [Terms](https://docs.github.com/site-policy/github-terms/github-terms-of-service) +* [Privacy](https://docs.github.com/site-policy/privacy-policies/github-privacy-statement) +* [Security](https://github.com/security) +* [Status](https://www.githubstatus.com/) +* [Community](https://github.community/) +* [Docs](https://docs.github.com/) +* [Contact](https://support.github.com?tags=dotcom-footer) +* Manage cookies +* Do not share my personal information + + + +You can’t perform that action at this time. \ No newline at end of file diff --git a/references/ForthNotes/Jonesforthgit.md b/references/ForthNotes/Jonesforthgit.md new file mode 100644 index 0000000..7de0c63 --- /dev/null +++ b/references/ForthNotes/Jonesforthgit.md @@ -0,0 +1,68 @@ +# Jonesforth.git + +**Source:** http://git.annexia.org/?p=jonesforth.git;a=summary + +xml version="1.0" encoding="utf-8"? + + + + + + + + +annexia.org >> repositories - jonesforth.git/summary + + + +[![git](static/git-logo.png)](http://git-scm.com/ "git homepage")[git.annexia.org](http://git.annexia.org/) / [jonesforth.git](/?p=jonesforth.git;a=summary) / summary + +commit +grep +author +committer +pickaxe +[?](/?p=jonesforth.git;a=search_help) search: +re + +summary | [shortlog](/?p=jonesforth.git;a=shortlog) | [log](/?p=jonesforth.git;a=log) | [commit](/?p=jonesforth.git;a=commit;h=66c56998125f3ac265a3a1df9821fd52cfeee8cc) | [commitdiff](/?p=jonesforth.git;a=commitdiff;h=66c56998125f3ac265a3a1df9821fd52cfeee8cc) | [tree](/?p=jonesforth.git;a=tree) + +| | | +| --- | --- | +| description | JONESFORTH - A sometimes minimal FORTH compiler and tutorial | +| owner | | +| last change | Fri, 11 Sep 2009 08:33:13 +0000 (08:33 +0000) | +| URL | git://git.annexia.org/jonesforth.git | + +[shortlog](/?p=jonesforth.git;a=shortlog) + +| | | | | +| --- | --- | --- | --- | +| *2009-09-11* | [rich](/?p=jonesforth.git;a=search;s=rich;st=author "Search for commits authored by rich") | [Version 47](/?p=jonesforth.git;a=commit;h=66c56998125f3ac265a3a1df9821fd52cfeee8cc) [master](/?p=jonesforth.git;a=shortlog;h=refs/heads/master) | [commit](/?p=jonesforth.git;a=commit;h=66c56998125f3ac265a3a1df9821fd52cfeee8cc) | [commitdiff](/?p=jonesforth.git;a=commitdiff;h=66c56998125f3ac265a3a1df9821fd52cfeee8cc) | [tree](/?p=jonesforth.git;a=tree;h=66c56998125f3ac265a3a1df9821fd52cfeee8cc;hb=66c56998125f3ac265a3a1df9821fd52cfeee8cc) | [snapshot](/?p=jonesforth.git;a=snapshot;h=66c56998125f3ac265a3a1df9821fd52cfeee8cc;sf=tgz "in format: tar.gz") | +| *2009-09-11* | [rich](/?p=jonesforth.git;a=search;s=rich;st=author "Search for commits authored by rich") | [Fix ROT/-ROT (Ian Osgood).](/?p=jonesforth.git;a=commit;h=dccbff0e169d5467a78be5c6d935fa505f6a029f) | [commit](/?p=jonesforth.git;a=commit;h=dccbff0e169d5467a78be5c6d935fa505f6a029f) | [commitdiff](/?p=jonesforth.git;a=commitdiff;h=dccbff0e169d5467a78be5c6d935fa505f6a029f) | [tree](/?p=jonesforth.git;a=tree;h=dccbff0e169d5467a78be5c6d935fa505f6a029f;hb=dccbff0e169d5467a78be5c6d935fa505f6a029f) | [snapshot](/?p=jonesforth.git;a=snapshot;h=dccbff0e169d5467a78be5c6d935fa505f6a029f;sf=tgz "in format: tar.gz") | +| *2007-10-22* | [rich](/?p=jonesforth.git;a=search;s=rich;st=author "Search for commits authored by rich") | [Fix test\_read\_file so it reads its own output (which...](/?p=jonesforth.git;a=commit;h=092aa5189f24fbfb1714c1d2d31c26a666102c3c "Fix test_read_file so it reads its own output (which should obviously") | [commit](/?p=jonesforth.git;a=commit;h=092aa5189f24fbfb1714c1d2d31c26a666102c3c) | [commitdiff](/?p=jonesforth.git;a=commitdiff;h=092aa5189f24fbfb1714c1d2d31c26a666102c3c) | [tree](/?p=jonesforth.git;a=tree;h=092aa5189f24fbfb1714c1d2d31c26a666102c3c;hb=092aa5189f24fbfb1714c1d2d31c26a666102c3c) | [snapshot](/?p=jonesforth.git;a=snapshot;h=092aa5189f24fbfb1714c1d2d31c26a666102c3c;sf=tgz "in format: tar.gz") | +| *2007-10-12* | [rich](/?p=jonesforth.git;a=search;s=rich;st=author "Search for commits authored by rich") | [Documentation.](/?p=jonesforth.git;a=commit;h=c089529de15a934abb14f8e9b0aa5ef08e6edd00) | [commit](/?p=jonesforth.git;a=commit;h=c089529de15a934abb14f8e9b0aa5ef08e6edd00) | [commitdiff](/?p=jonesforth.git;a=commitdiff;h=c089529de15a934abb14f8e9b0aa5ef08e6edd00) | [tree](/?p=jonesforth.git;a=tree;h=c089529de15a934abb14f8e9b0aa5ef08e6edd00;hb=c089529de15a934abb14f8e9b0aa5ef08e6edd00) | [snapshot](/?p=jonesforth.git;a=snapshot;h=c089529de15a934abb14f8e9b0aa5ef08e6edd00;sf=tgz "in format: tar.gz") | +| *2007-10-12* | [rich](/?p=jonesforth.git;a=search;s=rich;st=author "Search for commits authored by rich") | [Fix perf\_dupdrop forth test.](/?p=jonesforth.git;a=commit;h=cea392870a443a3d773d18d1627fa94712387cf5) | [commit](/?p=jonesforth.git;a=commit;h=cea392870a443a3d773d18d1627fa94712387cf5) | [commitdiff](/?p=jonesforth.git;a=commitdiff;h=cea392870a443a3d773d18d1627fa94712387cf5) | [tree](/?p=jonesforth.git;a=tree;h=cea392870a443a3d773d18d1627fa94712387cf5;hb=cea392870a443a3d773d18d1627fa94712387cf5) | [snapshot](/?p=jonesforth.git;a=snapshot;h=cea392870a443a3d773d18d1627fa94712387cf5;sf=tgz "in format: tar.gz") | +| *2007-10-12* | [rich](/?p=jonesforth.git;a=search;s=rich;st=author "Search for commits authored by rich") | [Tip on dumping out the latest word.](/?p=jonesforth.git;a=commit;h=a9bb8b18891404c2fd315f2fc5cbeaf6c25e9b43) | [commit](/?p=jonesforth.git;a=commit;h=a9bb8b18891404c2fd315f2fc5cbeaf6c25e9b43) | [commitdiff](/?p=jonesforth.git;a=commitdiff;h=a9bb8b18891404c2fd315f2fc5cbeaf6c25e9b43) | [tree](/?p=jonesforth.git;a=tree;h=a9bb8b18891404c2fd315f2fc5cbeaf6c25e9b43;hb=a9bb8b18891404c2fd315f2fc5cbeaf6c25e9b43) | [snapshot](/?p=jonesforth.git;a=snapshot;h=a9bb8b18891404c2fd315f2fc5cbeaf6c25e9b43;sf=tgz "in format: tar.gz") | +| *2007-10-11* | [rich](/?p=jonesforth.git;a=search;s=rich;st=author "Search for commits authored by rich") | [Wrote code to do performance comparisons.](/?p=jonesforth.git;a=commit;h=aa173d5f30ea45f0c06799c858c4a91681cf0cf7) | [commit](/?p=jonesforth.git;a=commit;h=aa173d5f30ea45f0c06799c858c4a91681cf0cf7) | [commitdiff](/?p=jonesforth.git;a=commitdiff;h=aa173d5f30ea45f0c06799c858c4a91681cf0cf7) | [tree](/?p=jonesforth.git;a=tree;h=aa173d5f30ea45f0c06799c858c4a91681cf0cf7;hb=aa173d5f30ea45f0c06799c858c4a91681cf0cf7) | [snapshot](/?p=jonesforth.git;a=snapshot;h=aa173d5f30ea45f0c06799c858c4a91681cf0cf7;sf=tgz "in format: tar.gz") | +| *2007-10-11* | [rich](/?p=jonesforth.git;a=search;s=rich;st=author "Search for commits authored by rich") | [Test assembler & INLINE](/?p=jonesforth.git;a=commit;h=f8688e0ca6ee2928ae1441ba2b7f5d2c8f43dea5) | [commit](/?p=jonesforth.git;a=commit;h=f8688e0ca6ee2928ae1441ba2b7f5d2c8f43dea5) | [commitdiff](/?p=jonesforth.git;a=commitdiff;h=f8688e0ca6ee2928ae1441ba2b7f5d2c8f43dea5) | [tree](/?p=jonesforth.git;a=tree;h=f8688e0ca6ee2928ae1441ba2b7f5d2c8f43dea5;hb=f8688e0ca6ee2928ae1441ba2b7f5d2c8f43dea5) | [snapshot](/?p=jonesforth.git;a=snapshot;h=f8688e0ca6ee2928ae1441ba2b7f5d2c8f43dea5;sf=tgz "in format: tar.gz") | +| *2007-10-11* | [rich](/?p=jonesforth.git;a=search;s=rich;st=author "Search for commits authored by rich") | [Basic stack tests](/?p=jonesforth.git;a=commit;h=a28fd94bb9711f62659bc89a275af9eb7134bece) | [commit](/?p=jonesforth.git;a=commit;h=a28fd94bb9711f62659bc89a275af9eb7134bece) | [commitdiff](/?p=jonesforth.git;a=commitdiff;h=a28fd94bb9711f62659bc89a275af9eb7134bece) | [tree](/?p=jonesforth.git;a=tree;h=a28fd94bb9711f62659bc89a275af9eb7134bece;hb=a28fd94bb9711f62659bc89a275af9eb7134bece) | [snapshot](/?p=jonesforth.git;a=snapshot;h=a28fd94bb9711f62659bc89a275af9eb7134bece;sf=tgz "in format: tar.gz") | +| *2007-10-11* | [rich](/?p=jonesforth.git;a=search;s=rich;st=author "Search for commits authored by rich") | [INLINE assembly](/?p=jonesforth.git;a=commit;h=ac014bc0a927ca7ab4177636056fd267384a8f47) | [commit](/?p=jonesforth.git;a=commit;h=ac014bc0a927ca7ab4177636056fd267384a8f47) | [commitdiff](/?p=jonesforth.git;a=commitdiff;h=ac014bc0a927ca7ab4177636056fd267384a8f47) | [tree](/?p=jonesforth.git;a=tree;h=ac014bc0a927ca7ab4177636056fd267384a8f47;hb=ac014bc0a927ca7ab4177636056fd267384a8f47) | [snapshot](/?p=jonesforth.git;a=snapshot;h=ac014bc0a927ca7ab4177636056fd267384a8f47;sf=tgz "in format: tar.gz") | +| *2007-10-11* | [rich](/?p=jonesforth.git;a=search;s=rich;st=author "Search for commits authored by rich") | [Implement 2DROP, 2DUP, 2SWAP as asm primitives.](/?p=jonesforth.git;a=commit;h=ae7508776fa28d069e0d890e6878f09a8e3f05ee) | [commit](/?p=jonesforth.git;a=commit;h=ae7508776fa28d069e0d890e6878f09a8e3f05ee) | [commitdiff](/?p=jonesforth.git;a=commitdiff;h=ae7508776fa28d069e0d890e6878f09a8e3f05ee) | [tree](/?p=jonesforth.git;a=tree;h=ae7508776fa28d069e0d890e6878f09a8e3f05ee;hb=ae7508776fa28d069e0d890e6878f09a8e3f05ee) | [snapshot](/?p=jonesforth.git;a=snapshot;h=ae7508776fa28d069e0d890e6878f09a8e3f05ee;sf=tgz "in format: tar.gz") | +| *2007-10-10* | [rich](/?p=jonesforth.git;a=search;s=rich;st=author "Search for commits authored by rich") | [Assembly code.](/?p=jonesforth.git;a=commit;h=465979550d58288f6bee28c49064d9c841a6f45f) | [commit](/?p=jonesforth.git;a=commit;h=465979550d58288f6bee28c49064d9c841a6f45f) | [commitdiff](/?p=jonesforth.git;a=commitdiff;h=465979550d58288f6bee28c49064d9c841a6f45f) | [tree](/?p=jonesforth.git;a=tree;h=465979550d58288f6bee28c49064d9c841a6f45f;hb=465979550d58288f6bee28c49064d9c841a6f45f) | [snapshot](/?p=jonesforth.git;a=snapshot;h=465979550d58288f6bee28c49064d9c841a6f45f;sf=tgz "in format: tar.gz") | +| *2007-10-07* | [rich](/?p=jonesforth.git;a=search;s=rich;st=author "Search for commits authored by rich") | [Restructure Makefile to add automated tests.](/?p=jonesforth.git;a=commit;h=83c6612bf07228f70d25136c850f660721379632) | [commit](/?p=jonesforth.git;a=commit;h=83c6612bf07228f70d25136c850f660721379632) | [commitdiff](/?p=jonesforth.git;a=commitdiff;h=83c6612bf07228f70d25136c850f660721379632) | [tree](/?p=jonesforth.git;a=tree;h=83c6612bf07228f70d25136c850f660721379632;hb=83c6612bf07228f70d25136c850f660721379632) | [snapshot](/?p=jonesforth.git;a=snapshot;h=83c6612bf07228f70d25136c850f660721379632;sf=tgz "in format: tar.gz") | +| *2007-09-30* | [rich](/?p=jonesforth.git;a=search;s=rich;st=author "Search for commits authored by rich") | [Fix CLOSE](/?p=jonesforth.git;a=commit;h=bedb4b2f3f229eb41f7eb6af84aff5d1d660c805) | [commit](/?p=jonesforth.git;a=commit;h=bedb4b2f3f229eb41f7eb6af84aff5d1d660c805) | [commitdiff](/?p=jonesforth.git;a=commitdiff;h=bedb4b2f3f229eb41f7eb6af84aff5d1d660c805) | [tree](/?p=jonesforth.git;a=tree;h=bedb4b2f3f229eb41f7eb6af84aff5d1d660c805;hb=bedb4b2f3f229eb41f7eb6af84aff5d1d660c805) | [snapshot](/?p=jonesforth.git;a=snapshot;h=bedb4b2f3f229eb41f7eb6af84aff5d1d660c805;sf=tgz "in format: tar.gz") | +| *2007-09-29* | [rich](/?p=jonesforth.git;a=search;s=rich;st=author "Search for commits authored by rich") | ['SPACE' -> BL (standard FORTH word)](/?p=jonesforth.git;a=commit;h=912d572e049973aac0dd5ae44c81944a76236883) | [commit](/?p=jonesforth.git;a=commit;h=912d572e049973aac0dd5ae44c81944a76236883) | [commitdiff](/?p=jonesforth.git;a=commitdiff;h=912d572e049973aac0dd5ae44c81944a76236883) | [tree](/?p=jonesforth.git;a=tree;h=912d572e049973aac0dd5ae44c81944a76236883;hb=912d572e049973aac0dd5ae44c81944a76236883) | [snapshot](/?p=jonesforth.git;a=snapshot;h=912d572e049973aac0dd5ae44c81944a76236883;sf=tgz "in format: tar.gz") | +| *2007-09-29* | [rich](/?p=jonesforth.git;a=search;s=rich;st=author "Search for commits authored by rich") | [Added O\_\* constants for open(2) syscall](/?p=jonesforth.git;a=commit;h=abcbc5d578daa147d957f9e3c5874690ae779328) | [commit](/?p=jonesforth.git;a=commit;h=abcbc5d578daa147d957f9e3c5874690ae779328) | [commitdiff](/?p=jonesforth.git;a=commitdiff;h=abcbc5d578daa147d957f9e3c5874690ae779328) | [tree](/?p=jonesforth.git;a=tree;h=abcbc5d578daa147d957f9e3c5874690ae779328;hb=abcbc5d578daa147d957f9e3c5874690ae779328) | [snapshot](/?p=jonesforth.git;a=snapshot;h=abcbc5d578daa147d957f9e3c5874690ae779328;sf=tgz "in format: tar.gz") | +| [...](/?p=jonesforth.git;a=shortlog) | | | | + +[heads](/?p=jonesforth.git;a=heads) + +| | | | +| --- | --- | --- | +| *16 years ago* | [master](/?p=jonesforth.git;a=shortlog;h=refs/heads/master) | [shortlog](/?p=jonesforth.git;a=shortlog;h=refs/heads/master) | [log](/?p=jonesforth.git;a=log;h=refs/heads/master) | [tree](/?p=jonesforth.git;a=tree;h=refs/heads/master;hb=refs/heads/master) | + +JONESFORTH - A sometimes minimal FORTH compiler and tutorial + +[RSS](/?p=jonesforth.git;a=rss "log RSS feed") +[Atom](/?p=jonesforth.git;a=atom "log Atom feed") \ No newline at end of file diff --git a/references/ForthNotes/Literals_ifs_and_loops.md b/references/ForthNotes/Literals_ifs_and_loops.md new file mode 100644 index 0000000..66208da --- /dev/null +++ b/references/ForthNotes/Literals_ifs_and_loops.md @@ -0,0 +1,195 @@ +# Literals, ifs, and loops + +**Source:** https://muforth.dev/threaded-code-literals-ifs-and-loops/ + +Threaded code: Literals, ifs, and loops – muforth + + +# Threaded code: Literals, ifs, and loops + +--- + +While writing my [introduction to threaded code](/threaded-code/) I suggested that non-leaf routines – colon words, in Forth lingo – can be represented as a list of addresses that get executed in sequence. This suggested that all code executes in a straight line and then returns to its caller. We all know this isn’t true, but threaded code that runs in a straight line is already tricky and tedious to explain; explaining literals and control structures at the same time seemed like too much. + +But we are here now, and we understand how threading-in-a-straight-line works, so let’s see how loops, branches, and literals work in a threaded world. + +--- + +In the real world, code doesn’t always execute in a straight line and then return – and yet, at the moment, which the machinery that we’ve defined so far, that’s all we can do. We also have no way to represent literal data – addresses or numbers that we might want to compute with. We can write a code word called `+` that pops two values off the data stack, adds them, and pushes the result, but if we want to add 8 to something, how do we do that? + +With just three runtime code words we can add if/then/else, while loops, and literals to our system. + +The names are arbitrary, but in many Forth systems the convention is to give them parenthesized names. These are not words that mere mortals normally execute; they exist as part of the hidden “runtime fabric” of the system. The parentheses suggest their “underlying” or “runtime” nature. + +Here they are: + +``` + (lit) Fetch into W the address pointed to by IP + Increment IP by address size (skip literal) + Push W onto the data stack + Execute NEXT +``` + +``` + (branch) Fetch into W the address pointed to by IP + Set IP to W + Execute NEXT +``` + +``` + (0branch) Pop a value off the data stack + If the value is zero, execute (branch) + Otherwise, increment IP by address size (skip branch address) +``` + +The `(branch)` above does an *absolute* branch. If you prefer relative branches, modify it thus: + +``` + (branch) Fetch into W the address pointed to by IP + Set IP to IP + W + Execute NEXT +``` + +Let’s assume we have a code word `+` that adds two values. To create a word that adds 8 to whatever is on the top of the stack, we would create a colon word with the following (textual) definition: + +``` + : add8 8 + ; +``` + +which, assuming an ITC system, would get compiled to: + +``` + add8 + ~~~~ + address of NEST ( all colon words start with this) + address of (lit) + 8 + address of + + address of UNNEST +``` + +The `;` adds the address of UNNEST at the end and ends the compilation. + +(This is getting outside the scope of our discussion, which is about the *execution machinery*, but in Forth systems `;` has *two* tasks: to compile the address of UNNEST, and to exit “compilation mode” – a special mode of *textual* interpretation that is the essence of the Forth compiler – and return to normal “interpretation” mode.) + +For if/then/else and looping we use *flag* values – truth values – that we compute and leave on the stack for `(0branch)` to test and consume. + +To make this even more concrete, let’s add five more code words to our system: + +``` + < Pop two values off the data stack + If the first is less than the second, push -1 + Otherwise, push 0 + Execute NEXT +``` + +``` + 0= Pop a value off the data stack + If the value is zero, push -1 + Otherwise, push 0 + Execute NEXT +``` + +``` + dup Pop a value off the data stack + Push it back onto data stack + Push it a second time + Execute NEXT +``` + +``` + 2dup Pop two values off the data stack + Push them back onto data stack, in the same order + Push them a second time, also in the same order + Execute NEXT +``` + +``` + swap Pop two values off the data stack + Push them back onto data stack, in the reverse order + Execute NEXT +``` + +In many Forth systems -1 is the preferred “true” value because it is represented (on almost all machines!!) by an all-ones bit pattern, which can be logically ANDed with other values... but we digress. ;-) + +From our definition of `(0branch)` above it should be clear that *any* non-zero value is true, and only zero is false. + +Let’s write a simple loop. (There is a better, more efficient, and more idiomatic way to do this, but it is outside the scope of this example. ;-) + +``` + -8 begin 1 + dup 0= until +``` + +This will get compiled to the following “address list”: + +``` + 00 address of (lit) + 04 -8 + 08 address of (lit) + 0c 1 + 10 address of + + 14 address of dup + 18 address of 0= + 1c address of (0branch) + 20 08 + 24 ... +``` + +We have to `dup` the value before we test it with `0=` because `0=` *consumes* the value before pushing its true or false flag. + +The word `begin` compiles no code; it “marks” the location that `(0branch)` later branches back to. + +I’ve added memory addresses in hex (which assume a byte-addressed machine with 32-bit addresses) to make the branch destination easier to describe. + +We write if/then like this: + +``` + 2dup < if swap then +``` + +This compiles to the following: + +``` + 00 address of 2dup + 04 address of < + 08 address of (0branch) + 0c 1c + 10 address of swap + 1c ... +``` + +As before, we `2dup` the values because `<` consumes them. + +Like `begin`, `then` compiles no code; it resolves the forward branch that `if` compiled. Words like if, then, begin, and until are called *compiling* words because they execute at compile time and do something special, like resolve a forward or backward branch address. + +Adding an `else` clause looks like this: + +``` + 0= if 4 else 8 then + +``` + +This code compiles to: + +``` + 00 address of 0= + 04 address of (0branch) + 08 1c + 0c address of (lit) + 10 4 + 14 address of (branch) + 18 24 + 1c address of (lit) + 20 8 + 24 address of + + 28 ... +``` + +`if` compiles the `(0branch)`, `else` compiles the `(branch)` and resolves the forward `(0branch)`, and `then` resolves the forward `(branch)`. + +Remember: `(0branch)` means branch if *false*. + +--- + +[Send feedback](/cdn-cgi/l/email-protection#ba9f8d8d9f8c8f9f8c889f8c829f8c8b9f8cde9f8d899f8d8e9f8c8f9f8d889f8e8a9f8cdf9f8c839f8cde9f8c889f8cd99f8c8f9f8cde9f8c8b9f8c899f8c829f8c839f8cdf9f8c8f9f8d899f88df9f8c899f8cdc9f8cde85c9cfd8d0dfd9ce879f8fd8d7cfdcd5c8ced29f8fde9f888aeed2c8dfdbdedfde9f888ad9d5dedf9f89db9f888af6d3cedfc8dbd6c99f88d99f888ad3dcc99f88d99f888adbd4de9f888ad6d5d5cac9) on this page (last edited 2017 May 01) +Browse [all pages](/all-pages/) +Return [home](/) \ No newline at end of file diff --git a/references/ForthNotes/MiniForth.md b/references/ForthNotes/MiniForth.md new file mode 100644 index 0000000..ab5ab71 --- /dev/null +++ b/references/ForthNotes/MiniForth.md @@ -0,0 +1,621 @@ +# MiniForth + +**Source:** https://github.com/ttsiodras/MiniForth + +GitHub - ttsiodras/MiniForth: A tiny Forth I built in a week. Blog post: https://www.thanassis.space/miniforth.html + + + +[Skip to content](#start-of-content) + + + + + + + + + + + + + +## Navigation Menu + +Toggle navigation + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2Fttsiodras%2FMiniForth) + +Appearance settings + +* Platform + + + AI CODE CREATION + - [GitHub CopilotWrite better code with AI](https://github.com/features/copilot) + - [GitHub SparkBuild and deploy intelligent apps](https://github.com/features/spark) + - [GitHub ModelsManage and compare prompts](https://github.com/features/models) + - [MCP RegistryNewIntegrate external tools](https://github.com/mcp) + + DEVELOPER WORKFLOWS + - [ActionsAutomate any workflow](https://github.com/features/actions) + - [CodespacesInstant dev environments](https://github.com/features/codespaces) + - [IssuesPlan and track work](https://github.com/features/issues) + - [Code ReviewManage code changes](https://github.com/features/code-review) + + APPLICATION SECURITY + - [GitHub Advanced SecurityFind and fix vulnerabilities](https://github.com/security/advanced-security) + - [Code securitySecure your code as you build](https://github.com/security/advanced-security/code-security) + - [Secret protectionStop leaks before they start](https://github.com/security/advanced-security/secret-protection) + + EXPLORE + - [Why GitHub](https://github.com/why-github) + - [Documentation](https://docs.github.com) + - [Blog](https://github.blog) + - [Changelog](https://github.blog/changelog) + - [Marketplace](https://github.com/marketplace) + + [View all features](https://github.com/features) +* Solutions + + + BY COMPANY SIZE + - [Enterprises](https://github.com/enterprise) + - [Small and medium teams](https://github.com/team) + - [Startups](https://github.com/enterprise/startups) + - [Nonprofits](https://github.com/solutions/industry/nonprofits) + + BY USE CASE + - [App Modernization](https://github.com/solutions/use-case/app-modernization) + - [DevSecOps](https://github.com/solutions/use-case/devsecops) + - [DevOps](https://github.com/solutions/use-case/devops) + - [CI/CD](https://github.com/solutions/use-case/ci-cd) + - [View all use cases](https://github.com/solutions/use-case) + + BY INDUSTRY + - [Healthcare](https://github.com/solutions/industry/healthcare) + - [Financial services](https://github.com/solutions/industry/financial-services) + - [Manufacturing](https://github.com/solutions/industry/manufacturing) + - [Government](https://github.com/solutions/industry/government) + - [View all industries](https://github.com/solutions/industry) + + [View all solutions](https://github.com/solutions) +* Resources + + + EXPLORE BY TOPIC + - [AI](https://github.com/resources/articles?topic=ai) + - [Software Development](https://github.com/resources/articles?topic=software-development) + - [DevOps](https://github.com/resources/articles?topic=devops) + - [Security](https://github.com/resources/articles?topic=security) + - [View all topics](https://github.com/resources/articles) + + EXPLORE BY TYPE + - [Customer stories](https://github.com/customer-stories) + - [Events & webinars](https://github.com/resources/events) + - [Ebooks & reports](https://github.com/resources/whitepapers) + - [Business insights](https://github.com/solutions/executive-insights) + - [GitHub Skills](https://skills.github.com) + + SUPPORT & SERVICES + - [Documentation](https://docs.github.com) + - [Customer support](https://support.github.com) + - [Community forum](https://github.com/orgs/community/discussions) + - [Trust center](https://github.com/trust-center) + - [Partners](https://github.com/partners) +* Open Source + + + COMMUNITY + - [GitHub SponsorsFund open source developers](https://github.com/sponsors) + + PROGRAMS + - [Security Lab](https://securitylab.github.com) + - [Maintainer Community](https://maintainers.github.com) + - [Accelerator](https://github.com/accelerator) + - [Archive Program](https://archiveprogram.github.com) + + REPOSITORIES + - [Topics](https://github.com/topics) + - [Trending](https://github.com/trending) + - [Collections](https://github.com/collections) +* Enterprise + + + ENTERPRISE SOLUTIONS + - [Enterprise platformAI-powered developer platform](https://github.com/enterprise) + + AVAILABLE ADD-ONS + - [GitHub Advanced SecurityEnterprise-grade security features](https://github.com/security/advanced-security) + - [Copilot for BusinessEnterprise-grade AI features](https://github.com/features/copilot/copilot-business) + - [Premium SupportEnterprise-grade 24/7 support](https://github.com/premium-support) +* [Pricing](https://github.com/pricing) + +Search or jump to... + + +# Search code, repositories, users, issues, pull requests... + +Search + +Clear + +[Search syntax tips](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax) + +# Provide feedback + +We read every piece of feedback, and take your input very seriously. + + +Include my email address so I can be contacted + +Cancel + Submit feedback + + + + + +# Saved searches + +## Use saved searches to filter your results more quickly + +Name + +Query + +To see all available qualifiers, see our [documentation](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax). + +Cancel + Create saved search + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2Fttsiodras%2FMiniForth) + +[Sign up](/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E&source=header-repo&source_repo=ttsiodras%2FMiniForth) + +Appearance settings + +Resetting focus + +You signed in with another tab or window. Reload to refresh your session. +You signed out in another tab or window. Reload to refresh your session. +You switched accounts on another tab or window. Reload to refresh your session. + + + +Dismiss alert + +{{ message }} + +[ttsiodras](/ttsiodras) +/ +**[MiniForth](/ttsiodras/MiniForth)** +Public + +* [Notifications](/login?return_to=%2Fttsiodras%2FMiniForth) You must be signed in to change notification settings +* [Fork + 7](/login?return_to=%2Fttsiodras%2FMiniForth) +* [Star + 95](/login?return_to=%2Fttsiodras%2FMiniForth) + +A tiny Forth I built in a week. Blog post: + +### License + +[MIT license](/ttsiodras/MiniForth/blob/master/LICENSE) + +[95 +stars](/ttsiodras/MiniForth/stargazers) [7 +forks](/ttsiodras/MiniForth/forks) [Branches](/ttsiodras/MiniForth/branches) [Tags](/ttsiodras/MiniForth/tags) [Activity](/ttsiodras/MiniForth/activity) + +[Star](/login?return_to=%2Fttsiodras%2FMiniForth) + +[Notifications](/login?return_to=%2Fttsiodras%2FMiniForth) You must be signed in to change notification settings + +* [Code](/ttsiodras/MiniForth) +* [Issues + 0](/ttsiodras/MiniForth/issues) +* [Pull requests + 0](/ttsiodras/MiniForth/pulls) +* [Actions](/ttsiodras/MiniForth/actions) +* [Projects + 0](/ttsiodras/MiniForth/projects) +* [Security + 0](/ttsiodras/MiniForth/security) +* [Insights](/ttsiodras/MiniForth/pulse) + +Additional navigation options + + +* [Code](/ttsiodras/MiniForth) +* [Issues](/ttsiodras/MiniForth/issues) +* [Pull requests](/ttsiodras/MiniForth/pulls) +* [Actions](/ttsiodras/MiniForth/actions) +* [Projects](/ttsiodras/MiniForth/projects) +* [Security](/ttsiodras/MiniForth/security) +* [Insights](/ttsiodras/MiniForth/pulse) + +# ttsiodras/MiniForth + +master + +[Branches](/ttsiodras/MiniForth/branches)[Tags](/ttsiodras/MiniForth/tags) + +Go to file + +Code + +Open more actions menu + +## Folders and files + +| Name | | Name | Last commit message | Last commit date | +| --- | --- | --- | --- | --- | +| Latest commit History[41 Commits](/ttsiodras/MiniForth/commits/master/) 41 Commits | | | +| [contrib](/ttsiodras/MiniForth/tree/master/contrib "contrib") | | [contrib](/ttsiodras/MiniForth/tree/master/contrib "contrib") | | | +| [simavr @ a56b550](/buserror/simavr/tree/a56b550872906a971ac128002772d90c9e30377d "simavr") | | [simavr @ a56b550](/buserror/simavr/tree/a56b550872906a971ac128002772d90c9e30377d "simavr") | | | +| [src](/ttsiodras/MiniForth/tree/master/src "src") | | [src](/ttsiodras/MiniForth/tree/master/src "src") | | | +| [src\_x86](/ttsiodras/MiniForth/tree/master/src_x86 "src_x86") | | [src\_x86](/ttsiodras/MiniForth/tree/master/src_x86 "src_x86") | | | +| [testing](/ttsiodras/MiniForth/tree/master/testing "testing") | | [testing](/ttsiodras/MiniForth/tree/master/testing "testing") | | | +| [.gitignore](/ttsiodras/MiniForth/blob/master/.gitignore ".gitignore") | | [.gitignore](/ttsiodras/MiniForth/blob/master/.gitignore ".gitignore") | | | +| [.gitmodules](/ttsiodras/MiniForth/blob/master/.gitmodules ".gitmodules") | | [.gitmodules](/ttsiodras/MiniForth/blob/master/.gitmodules ".gitmodules") | | | +| [LICENSE](/ttsiodras/MiniForth/blob/master/LICENSE "LICENSE") | | [LICENSE](/ttsiodras/MiniForth/blob/master/LICENSE "LICENSE") | | | +| [Makefile](/ttsiodras/MiniForth/blob/master/Makefile "Makefile") | | [Makefile](/ttsiodras/MiniForth/blob/master/Makefile "Makefile") | | | +| [README.md](/ttsiodras/MiniForth/blob/master/README.md "README.md") | | [README.md](/ttsiodras/MiniForth/blob/master/README.md "README.md") | | | +| [config.mk](/ttsiodras/MiniForth/blob/master/config.mk "config.mk") | | [config.mk](/ttsiodras/MiniForth/blob/master/config.mk "config.mk") | | | +| View all files | | | + +## Repository files navigation + +* [README](#) +* [MIT license](#) + +*( Wrote [a blog post about this here](https://www.thanassis.space/miniforth.html) )* + +It was raining hard, a week ago. + +And what could you possibly do on a rainy Saturday afternoon? + +Well... + +You can make a Forth interpreter/compiler from scratch... +...then put it inside a 1.5$ Blue Pill microcontroller... +...and finally, inside an Arduino UNO... +... within its tiny 2K RAM! + +Click on the image to watch it blinking the LED of my Arduino: + +[![Here's a video of it action, blinking my Arduino :-)](https://camo.githubusercontent.com/10dcc45a92a8eb1fbc79bbcf7127dea99324e316bf5b5ce1bd0515f9c86e5da5/68747470733a2f2f696d672e796f75747562652e636f6d2f76692f7865506f6c6c62437a6f772f302e6a7067)](https://www.youtube.com/watch?v=xePollbCzow) + +I haven't done anything even *remotely* close to this in decades... +I *loved* building it. + +The rainy afternoon turned into a week-long hackfest *(was looking +forward every day to the post-work FORTH-tinkering in the afternoon...)* + +The result: a tiny, mini, micro Forth. In portable C++ :-) +It has... + +* basic arithmetic +* star-slash (double-word accurate muldiv) +* literals +* constants +* variables +* direct memory access +* string printing +* reseting +* comments +* nested DO/LOOP +* comparisons +* nested IF/ELSE/THEN +* ...and of course, functions (Forth words) + +Here's an ascii-cast recording of it in action: + +[![Recording of building and uploading on an Arduino UNO](https://camo.githubusercontent.com/429594b830bb91d714d4beb75bd9684a0108521b63c4a5669fa2ce955d2b396d/68747470733a2f2f61736369696e656d612e6f72672f612f3432333634392e737667)](https://asciinema.org/a/423649?autoplay=1) + +Read the test scenario below to see my supported Forth constructs. + +# Portability, ArduinoSTL and Valgrind/AddressSanitizer checks + +I meant it when I said "portable". Part of my reasoning was, that +in addition to targeting multiple platforms (e.g. BluePill and +Arduino) I wanted to be able to use Valgrind and AddressSanitizer +to detect - in the host! - any issues I have with my memory handling. + +Since I had embedded targets in mind, I tried ArduinoSTL - but it was too +wasteful memory-wise. It also made the build process significantly slower. +I therefore built my own [memory pool, as well as list, tuple and string-like +C++ templates](https://github.com/ttsiodras/MiniForth/tree/master/src/mini_stl.h). It was a nice challenge, re-inventing a tiny C++ STL... + +And I understand STL a lot better now, after building small pieces of it myself :-) + +# Simulation / Debugging + +I setup simulation via [simavr](https://github.com/buserror/simavr.git). +This tremendously improved my developing speed, since a simulator +spawns and runs much faster than the real board. Due to the code +being portable, debugging took place mostly in the host GDB; +and after Valgrind and AddressSanitizer gave their blessing, I usually +found out that the simulator (and the real board) worked fine as well. + +# BluePill vs Arduino UNO + +Thanks to ArduinoSTL, I quickly reached the point of running inside the +BluePill. The 1.5$ mini-monster has 10 times more SRAM than an Arduino UNO; +so in a couple of days, I had a [working branch](https://github.com/ttsiodras/MiniForth/tree/BluePill-STM32F103C). + +[![The 1.5$ 'Beast'](/ttsiodras/MiniForth/raw/master/contrib/BluePill.jpg "The 1.5$ 'Beast'")](/ttsiodras/MiniForth/blob/master/contrib/BluePill.jpg) + +But as said above, that wasn't nearly enough to make it work in my +Arduino UNO. That required far more work *(see below)*. + +As for the BluePill, I should note that, as in all my other embedded targets, +I prefer a development workflow that is based on normal bootloaders +*(not on programmers)*. I therefore burned the +[stm32duino](https://github.com/rogerclarkmelbourne/STM32duino-bootloader) +bootloader on the BluePill, which allowed me to easily program it +in subsequent iterations via the USB connection (and a simple `make upload`). + +The same USB connection would then function as a serial port immediately +afterwards - allowing me to interact with the newly uploaded Forth in the +BluePill. + +The screenshot below is from a `tmux`: on the left, the output from `make upload`; +and on the right, I used `picocom` to interact with my mini-Forth +over the serial port: + +[![Compiling, uploading and testing](/ttsiodras/MiniForth/raw/master/contrib/itworks.jpg "Compiling, uploading and testing")](/ttsiodras/MiniForth/blob/master/contrib/itworks.jpg) + +# Memory - the final frontier + +That covered the first two days. + +But when I tried compiling for the Arduino UNO, I realised that the ArduinoSTL +was not enough. I run out of memory... + +So I built my own [mini-STL](https://github.com/ttsiodras/MiniForth/tree/master/src/mini_stl.h), +and tightly controlled *all* memory utilisation. + +I also used macro-magic to move all strings to Flash at compile-time +(see `dprintf` in the code)... And saved memory everywhere I could, +re-using error messages across various operations - and storing the +entire array of native operations in Flash. + +Nothing flexes your coding muscles as much as optimising; whether it is +for speed or for space. See the implementation of ".S" for example, +where the (obvious) stack reversal code is also the most wasteful... +Changing it to a slower but memory-preserving algorithm allowed me +to use ".S" even when almost all my memory is full. + +# C++ vs C + +I know that many developers hate C++. I even wrote a +[blog post](https://www.thanassis.space/cpp.html) about it. + +And I understand why - they see code like this... + +``` +#include "mini_stl.h" + +template +typename forward_list::box *forward_list::_freeList = NULL; +``` + +...and they start screaming - "what the hell is that", "incomprehensible +madness", etc. + +But there are very important benefits in using C++ - and templates +in particular. You write less code, with no additional run-time or +memory overhead compared to C, and with a lot more compile-time checks +that watch your back (for things that would otherwise blow up in your face). + +See my Optional for example, that emulates (badly) the optional +type of Rust/OCaml/F#/Scala/Kotlin etc. It **forces** you to check +your returned error codes: + +``` +Optional Forth::needs_a_number(const __FlashStringHelper *msg) +{ + if (_stack.empty()) + return error(emptyMsgFlash, msg); + auto topVal = *_stack.begin(); + if (topVal._kind == StackNode::LIT) + return topVal._u.intVal; + else + return FAILURE; +} +``` + +You can't "forget" to check the potential for a failure coded inside +your returned value - because your code has to "unwrap" it. I could have +done this better, but I chose to implement it via simple tuples +(this was a one-weeks-afternoons hack, after all :-) + +As for the template "magic" incantation above - it *is* true magic: My +`forward_list` template is using free-lists to store the `pop_front`-ed +elements and reuse them in subsequent allocations. I wanted these free-lists to +be global (i.e. static members) because lists of the same type must re-use a +single, commonly-shared free-list. The magic spell tells the compiler I want to +instantiate these globals *once*, for each type T that I use in any +lists in my code. + +# My Forth test scenario - including a FizzBuzz! + +Yep, FizzBuzz - we are fully Turing complete. And would surely pass +Joel's interview :-) + +``` +." Reset... " RESET +." Check comments... " \ Yes, we support the new-style comments :-) +." Computing simple addition of 3 + 4... " 3 4 + . +." Is 1 = 2 ?... " 1 2 = . +." Is 1 > 2 ?... " 1 2 > . +." Is 1 < 2 ?... " 1 2 < . +." Define pi at double-word precision... " : pi 355 113 */ ; +." Use definition to compute 10K times PI... " 10000 pi . +." Check: 23 mod 7... " 23 7 MOD . +." Defining 1st level function1... " : x2 2 * ; +." Defining 1st level function2... " : p4 4 + ; +." 2nd level word using both - must print 24... " 10 x2 p4 . +." Defining a variable with value 123... " 123 variable ot3 +." Printing variable's value... " ot3 @ . +." Defining The Constant (TM)... " 42 constant lifeUniverse +." Printing The Constant (TM)... " lifeUniverse . +." Setting the variable to The Constant (TM)... " lifeUniverse ot3 ! +." Printing variable's value... " ot3 @ . +." Setting the variable to hex 0x11... " $11 ot3 ! +." Printing variable's value... " ot3 @ . +." Setting the variable to binary 10100101... " %10100101 ot3 ! +." Printing variable's value... " ot3 @ . +." Defining helper... " : p5 5 U.R . ; +." Defining 3 times loop... " : x3lp 3 0 DO I p5 LOOP ; +." Calling loop... " x3lp +." Defining loop calling loop 2 times... " : x6lp 2 0 DO x3lp LOOP ; +." Nested-looping 2x3 times... " x6lp +." Inline: " : m 3 1 DO 3 1 DO CR J p5 I p5 ." = " J I * p5 LOOP LOOP ; +." Use inline loops with two indexes... " m +." Make multiples of 7 via DUP... " : m7s 10 0 DO DUP I * . LOOP DROP ; +." Print them and DROP the 7... " 7 m7s +." Reset... " RESET +\ Time for Turing completeness... +." Let's do Fizz-Buzz! " \ Turing Completeness check... +\ fizz ( n -- 0_or_1 n ) +." Define fizz... " : fizz DUP 3 MOD 0 = IF ." fizz " 1 ELSE 0 THEN SWAP ; +\ buzz ( n -- 0_or_1 n ) +." Define buzz... " : buzz DUP 5 MOD 0 = IF ." buzz " 1 ELSE 0 THEN SWAP ; +\ emitNum ( 0_or_1 0_or_1 n -- ) +." Define emitNum... " : emitNum ROT ROT + 0 = if . ELSE DROP THEN ; +\ mainloop ( n -- ) +." Define mainloop... " : mainloop ." ( " fizz buzz emitNum ." ) " ; +\ fb ( -- ) +." Define fizzbuzz... " : fb 37 1 DO I mainloop LOOP ; +." Run it! " fb +." Report memory usage... " .S +." All done! " +``` + +# Automation + +I am a strong believer in automation. The final form of my `Makefile` +therefore has many rules - e.g. `make arduino-sim` - that automate +various parts of the workflow. + +Here's what they do: + +* **arduino**: Compiles the code for Arduino UNO - builds `src/tmp/myforth.ino.{elf,hex}` +* **arduino-sim**: After building, launches the compiled mini-Forth in `simduino`. +* **upload**: After building, uploads to an Arduino attached to the port + configured inside `config.mk`. +* **terminal**: After uploading, launches a `picocom` terminal with + all appropriate settings to interact with my Forth. +* **x86**: Builds for x86. Actually, should easily build for any native target (ARM, etc). +* **test-address-sanitizer**: Uses the x86 binary to test the code, executing + all steps of the scenario shown above. The binary is built with the + address sanitizer enabled (to detect memory issues). +* **test-valgrind**: Same, but with Valgrind. +* **test-simulator**: Spawns `simavr` and sends the entire test scenario shown + above to it - while showing the responses received from it. +* **test-arduino**: Sends the entire test scenario shown above to an + Arduino Uno connected to the port specified in `config.mk` + and shows the responses received over that serial port. +* **blink-arduino**: Sends the "hello word" of the HW world: a tiny + [Forth program](/ttsiodras/MiniForth/blob/master/testing/blinky.fs) blinking the Arduino's LED. + +Another example of automation - the complete test scenario shown in the +previous section, is not just an example in the documentation; it is +extracted automatically from this README and fed into the Valgrind and +AddressSanitizer tests... and also into the Python testing script that +sends the data to the board in real-time. + +[DRY](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself), folks. + +# Conclusion + +I thoroughly enjoyed building this. I know full well that Forths are not +supposed to be built in C++; they are supposed to be built in assembly, +and also, utilise the Flash to store the user-compiled code at run-time. + +But that wasn't the point of this - the point was to have fun and learn Forth. +And what better way to learn a language than to actually implement it! :-) + +And... as a child of the 80s... I now know first-hand what +[Jupiter Ace](https://en.wikipedia.org/wiki/Jupiter_Ace) was about :-) + +Fork the code, and enjoy tinkering with it! +Thanassis. + +## About + +A tiny Forth I built in a week. Blog post: + +### Topics + +[arduino](/topics/arduino "Topic: arduino") +[cpp](/topics/cpp "Topic: cpp") +[forth](/topics/forth "Topic: forth") + +### Resources + +[Readme](#readme-ov-file) + +### License + +[MIT license](#MIT-1-ov-file) + +### Uh oh! + +There was an error while loading. Please reload this page. + +[Activity](/ttsiodras/MiniForth/activity) + +### Stars + +[**95** +stars](/ttsiodras/MiniForth/stargazers) + +### Watchers + +[**6** +watching](/ttsiodras/MiniForth/watchers) + +### Forks + +[**7** +forks](/ttsiodras/MiniForth/forks) + +[Report repository](/contact/report-content?content_url=https%3A%2F%2Fgithub.com%2Fttsiodras%2FMiniForth&report=ttsiodras+%28user%29) + +## [Releases 2](/ttsiodras/MiniForth/releases) + +[Final release - optimal memory/flash use everywhere. + +Latest + +Jul 9, 2021](/ttsiodras/MiniForth/releases/tag/v1.1) + +[+ 1 release](/ttsiodras/MiniForth/releases) + +## [Packages 0](/users/ttsiodras/packages?repo_name=MiniForth) + +No packages published + +## Languages + +* [C++ + 80.5%](/ttsiodras/MiniForth/search?l=c%2B%2B) +* [C + 10.9%](/ttsiodras/MiniForth/search?l=c) +* [Makefile + 4.9%](/ttsiodras/MiniForth/search?l=makefile) +* [Python + 1.5%](/ttsiodras/MiniForth/search?l=python) +* [Shell + 1.3%](/ttsiodras/MiniForth/search?l=shell) +* [Forth + 0.9%](/ttsiodras/MiniForth/search?l=forth) + +## Footer + +© 2026 GitHub, Inc. + +### Footer navigation + +* [Terms](https://docs.github.com/site-policy/github-terms/github-terms-of-service) +* [Privacy](https://docs.github.com/site-policy/privacy-policies/github-privacy-statement) +* [Security](https://github.com/security) +* [Status](https://www.githubstatus.com/) +* [Community](https://github.community/) +* [Docs](https://docs.github.com/) +* [Contact](https://support.github.com?tags=dotcom-footer) +* Manage cookies +* Do not share my personal information + + + +You can’t perform that action at this time. \ No newline at end of file diff --git a/references/ForthNotes/Repo.md b/references/ForthNotes/Repo.md new file mode 100644 index 0000000..d2b0c43 --- /dev/null +++ b/references/ForthNotes/Repo.md @@ -0,0 +1,466 @@ +# Repo + +**Source:** https://github.com/nimblemachines/muforth#under-active-development + +GitHub - nimblemachines/muforth: A simple, indirect-threaded Forth, written in C; for target compiling; runs on Linux, BSD, OSX, and Cygwin + + + +[Skip to content](#start-of-content) + + + + + + + + + + + + + +## Navigation Menu + +Toggle navigation + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2Fnimblemachines%2Fmuforth) + +Appearance settings + +* Platform + + + AI CODE CREATION + - [GitHub CopilotWrite better code with AI](https://github.com/features/copilot) + - [GitHub SparkBuild and deploy intelligent apps](https://github.com/features/spark) + - [GitHub ModelsManage and compare prompts](https://github.com/features/models) + - [MCP RegistryNewIntegrate external tools](https://github.com/mcp) + + DEVELOPER WORKFLOWS + - [ActionsAutomate any workflow](https://github.com/features/actions) + - [CodespacesInstant dev environments](https://github.com/features/codespaces) + - [IssuesPlan and track work](https://github.com/features/issues) + - [Code ReviewManage code changes](https://github.com/features/code-review) + + APPLICATION SECURITY + - [GitHub Advanced SecurityFind and fix vulnerabilities](https://github.com/security/advanced-security) + - [Code securitySecure your code as you build](https://github.com/security/advanced-security/code-security) + - [Secret protectionStop leaks before they start](https://github.com/security/advanced-security/secret-protection) + + EXPLORE + - [Why GitHub](https://github.com/why-github) + - [Documentation](https://docs.github.com) + - [Blog](https://github.blog) + - [Changelog](https://github.blog/changelog) + - [Marketplace](https://github.com/marketplace) + + [View all features](https://github.com/features) +* Solutions + + + BY COMPANY SIZE + - [Enterprises](https://github.com/enterprise) + - [Small and medium teams](https://github.com/team) + - [Startups](https://github.com/enterprise/startups) + - [Nonprofits](https://github.com/solutions/industry/nonprofits) + + BY USE CASE + - [App Modernization](https://github.com/solutions/use-case/app-modernization) + - [DevSecOps](https://github.com/solutions/use-case/devsecops) + - [DevOps](https://github.com/solutions/use-case/devops) + - [CI/CD](https://github.com/solutions/use-case/ci-cd) + - [View all use cases](https://github.com/solutions/use-case) + + BY INDUSTRY + - [Healthcare](https://github.com/solutions/industry/healthcare) + - [Financial services](https://github.com/solutions/industry/financial-services) + - [Manufacturing](https://github.com/solutions/industry/manufacturing) + - [Government](https://github.com/solutions/industry/government) + - [View all industries](https://github.com/solutions/industry) + + [View all solutions](https://github.com/solutions) +* Resources + + + EXPLORE BY TOPIC + - [AI](https://github.com/resources/articles?topic=ai) + - [Software Development](https://github.com/resources/articles?topic=software-development) + - [DevOps](https://github.com/resources/articles?topic=devops) + - [Security](https://github.com/resources/articles?topic=security) + - [View all topics](https://github.com/resources/articles) + + EXPLORE BY TYPE + - [Customer stories](https://github.com/customer-stories) + - [Events & webinars](https://github.com/resources/events) + - [Ebooks & reports](https://github.com/resources/whitepapers) + - [Business insights](https://github.com/solutions/executive-insights) + - [GitHub Skills](https://skills.github.com) + + SUPPORT & SERVICES + - [Documentation](https://docs.github.com) + - [Customer support](https://support.github.com) + - [Community forum](https://github.com/orgs/community/discussions) + - [Trust center](https://github.com/trust-center) + - [Partners](https://github.com/partners) +* Open Source + + + COMMUNITY + - [GitHub SponsorsFund open source developers](https://github.com/sponsors) + + PROGRAMS + - [Security Lab](https://securitylab.github.com) + - [Maintainer Community](https://maintainers.github.com) + - [Accelerator](https://github.com/accelerator) + - [Archive Program](https://archiveprogram.github.com) + + REPOSITORIES + - [Topics](https://github.com/topics) + - [Trending](https://github.com/trending) + - [Collections](https://github.com/collections) +* Enterprise + + + ENTERPRISE SOLUTIONS + - [Enterprise platformAI-powered developer platform](https://github.com/enterprise) + + AVAILABLE ADD-ONS + - [GitHub Advanced SecurityEnterprise-grade security features](https://github.com/security/advanced-security) + - [Copilot for BusinessEnterprise-grade AI features](https://github.com/features/copilot/copilot-business) + - [Premium SupportEnterprise-grade 24/7 support](https://github.com/premium-support) +* [Pricing](https://github.com/pricing) + +Search or jump to... + + +# Search code, repositories, users, issues, pull requests... + +Search + +Clear + +[Search syntax tips](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax) + +# Provide feedback + +We read every piece of feedback, and take your input very seriously. + + +Include my email address so I can be contacted + +Cancel + Submit feedback + + + + + +# Saved searches + +## Use saved searches to filter your results more quickly + +Name + +Query + +To see all available qualifiers, see our [documentation](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax). + +Cancel + Create saved search + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2Fnimblemachines%2Fmuforth) + +[Sign up](/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E&source=header-repo&source_repo=nimblemachines%2Fmuforth) + +Appearance settings + +Resetting focus + +You signed in with another tab or window. Reload to refresh your session. +You signed out in another tab or window. Reload to refresh your session. +You switched accounts on another tab or window. Reload to refresh your session. + + + +Dismiss alert + +{{ message }} + +[nimblemachines](/nimblemachines) +/ +**[muforth](/nimblemachines/muforth)** +Public + +* [Notifications](/login?return_to=%2Fnimblemachines%2Fmuforth) You must be signed in to change notification settings +* [Fork + 34](/login?return_to=%2Fnimblemachines%2Fmuforth) +* [Star + 153](/login?return_to=%2Fnimblemachines%2Fmuforth) + +A simple, indirect-threaded Forth, written in C; for target compiling; runs on Linux, BSD, OSX, and Cygwin + +[muforth.dev/](https://muforth.dev/ "https://muforth.dev/") + +### License + +[View license](/nimblemachines/muforth/blob/master/LICENSE) + +[153 +stars](/nimblemachines/muforth/stargazers) [34 +forks](/nimblemachines/muforth/forks) [Branches](/nimblemachines/muforth/branches) [Tags](/nimblemachines/muforth/tags) [Activity](/nimblemachines/muforth/activity) + +[Star](/login?return_to=%2Fnimblemachines%2Fmuforth) + +[Notifications](/login?return_to=%2Fnimblemachines%2Fmuforth) You must be signed in to change notification settings + +* [Code](/nimblemachines/muforth) +* [Issues + 17](/nimblemachines/muforth/issues) +* [Pull requests + 1](/nimblemachines/muforth/pulls) +* [Actions](/nimblemachines/muforth/actions) +* [Projects + 0](/nimblemachines/muforth/projects) +* [Security + 0](/nimblemachines/muforth/security) +* [Insights](/nimblemachines/muforth/pulse) + +Additional navigation options + + +* [Code](/nimblemachines/muforth) +* [Issues](/nimblemachines/muforth/issues) +* [Pull requests](/nimblemachines/muforth/pulls) +* [Actions](/nimblemachines/muforth/actions) +* [Projects](/nimblemachines/muforth/projects) +* [Security](/nimblemachines/muforth/security) +* [Insights](/nimblemachines/muforth/pulse) + +# nimblemachines/muforth + +master + +[Branches](/nimblemachines/muforth/branches)[Tags](/nimblemachines/muforth/tags) + +Go to file + +Code + +Open more actions menu + +## Folders and files + +| Name | | Name | Last commit message | Last commit date | +| --- | --- | --- | --- | --- | +| Latest commit History[3,159 Commits](/nimblemachines/muforth/commits/master/) 3,159 Commits | | | +| [.vim](/nimblemachines/muforth/tree/master/.vim ".vim") | | [.vim](/nimblemachines/muforth/tree/master/.vim ".vim") | | | +| [doc](/nimblemachines/muforth/tree/master/doc "doc") | | [doc](/nimblemachines/muforth/tree/master/doc "doc") | | | +| [mu](/nimblemachines/muforth/tree/master/mu "mu") | | [mu](/nimblemachines/muforth/tree/master/mu "mu") | | | +| [scripts](/nimblemachines/muforth/tree/master/scripts "scripts") | | [scripts](/nimblemachines/muforth/tree/master/scripts "scripts") | | | +| [src](/nimblemachines/muforth/tree/master/src "src") | | [src](/nimblemachines/muforth/tree/master/src "src") | | | +| [talks](/nimblemachines/muforth/tree/master/talks "talks") | | [talks](/nimblemachines/muforth/tree/master/talks "talks") | | | +| [.gitattributes](/nimblemachines/muforth/blob/master/.gitattributes ".gitattributes") | | [.gitattributes](/nimblemachines/muforth/blob/master/.gitattributes ".gitattributes") | | | +| [BUILDING](/nimblemachines/muforth/blob/master/BUILDING "BUILDING") | | [BUILDING](/nimblemachines/muforth/blob/master/BUILDING "BUILDING") | | | +| [LICENSE](/nimblemachines/muforth/blob/master/LICENSE "LICENSE") | | [LICENSE](/nimblemachines/muforth/blob/master/LICENSE "LICENSE") | | | +| [README.md](/nimblemachines/muforth/blob/master/README.md "README.md") | | [README.md](/nimblemachines/muforth/blob/master/README.md "README.md") | | | +| View all files | | | + +## Repository files navigation + +* [README](#) +* [License](#) + +# What is muforth? + +muforth is a small, simple, fast, indirect-threaded code (ITC) Forth intended +for use as a cross-compiler for microcontrollers and other embedded devices. +It is written in C and its core is very portable. Because of its Forth nature, +it is naturally extensible, scriptable, and customizable. + +muforth is very well-suited to interactive coding, debugging, and exploration, +and is a great tool for bringing up new hardware. + +It has support – in varying degrees of completeness – for a number of +different architectures and chip families. + +* [8051](/nimblemachines/muforth/blob/master/mu/target/8051) +* [ARMv6-m](/nimblemachines/muforth/blob/master/mu/target/ARM/v6-m) (aka Cortex-M0/M0+) +* [ARMv7-m](/nimblemachines/muforth/blob/master/mu/target/ARM/v7-m) (aka Cortex-M3/M4/M7) +* [AVR](/nimblemachines/muforth/blob/master/mu/target/AVR) (Atmel/Microchip) +* [HC08 and HCS08](/nimblemachines/muforth/blob/master/mu/target/S08) (Motorola/Freescale/NXP) +* [MSP430](/nimblemachines/muforth/blob/master/mu/target/MSP430) (TI) +* [PIC18](/nimblemachines/muforth/blob/master/mu/target/PIC18) (Microchip) +* [RISC-V](/nimblemachines/muforth/blob/master/mu/target/RISC-V) (initially, the SiFive FE310 and GigaDevice + GD32VF103) + +# Tethered vs self-hosted + +Unlike a "self-hosted" Forth, where the target contains the dictionary, the +text interpreter, and all the tools necessary for assembling and compiling +code, muforth supports a *tethered* development model. muforth runs on the +*host* machine, compiling code and data that are later copied to the *target* +machine and executed there. + +Because the dictionary and all the compilation tools reside on the *host*, +only the *compiled* code and data reside on the target. This makes it possible +to target *very* small devices that only have a few kilobytes of flash and a +few hundred bytes of RAM. In contrast, a self-hosted Forth often needs 16 KiB +(or more) of flash to be useful, and consumes RAM for the text interpreter and +compiler. + +The host machine is also orders of magnitude faster than the target, so doing +the compilation on the host is essentially instantaneous. + +# Why yet another Forth? + +I initially wrote muforth because I wanted to try out some implementation +ideas. The core language primitives are written in C, but initially muforth +compiled Forth words via a simple native code compiler for the x86. I quickly +realized that simplicity and portability were more important than speed. The +current implementation is a straightforward indirect-threaded Forth - and it +is *quite* fast! + +Its implementation is no longer the point. Its sole reason for existing is to +be a cross-compiler for *other* Forths, and their implementations are in no +way tied to muforth’s. In fact, muforth can be used to compile *any* sort of +code onto the target. I've used it very successfully as a smart assembler for +writing AVR and S08 code. + +By keeping it small and simple, it is much more likely to be a useful tool +that people can customize. + +It’s [BSD licensed](/nimblemachines/muforth/blob/master/LICENSE), so do what you want with it! I’d love to hear +about innovative or unusual uses of muforth. + +# Starting points + +[BUILDING](/nimblemachines/muforth/blob/master/BUILDING) will tell you how to build muforth. It’s very simple. + +Look in [mu/target/](/nimblemachines/muforth/blob/master/mu/target) to find a target that interests you. There is +generally a `mu/target//build.mu4` that loads the cross-build +environment. Use it as an “index” to find the assembler, disassembler, +meta-compiler, kernel, and other key pieces of code. + +# Documentation + +Sadly, there isn’t a lot of documentation right now. A good place to start is +to read the source. + +The code – both the C code that implements the Forth virtual machine and the +muforth code that does everything else – is carefully and in some cases +extensively (even obsessively!) commented. Right now your best source of +documentation is the code! Luckily for you, there isn’t that much of it, so +reading it is actually possible. That’s part of the point of muforth; I want +it to be a [convivial tool](https://www.nimblemachines.com/convivial-tool/). + +The heart of the system is the Forth code that muforth reads when it first +starts: [mu/startup.mu4](/nimblemachines/muforth/blob/master/mu/startup.mu4). You’ll learn a lot by reading this! + +[muforth.dev](https://muforth.dev/) will +eventually host the muforth documentation. At the moment, it is a collection +of [journals, essays, and “getting started” pages](https://muforth.dev/all-pages/). + +# News + +Follow [@muforth.dev](https://bsky.app/profile/muforth.dev) for updates about +the project and related things (eg, interesting development boards) that I'm +thinking about. + +# Talks + +In March 2008 I gave a [talk](https://vimeo.com/859408) about bootstrapping, +muforth, and [convivial tools](https://www.nimblemachines.com/convivial-tool/). + +Warning: I wave my arms around a lot, and the audio and video quality isn’t +that great, but you might find it interesting, or at least amusing. + +It’s also hard to see my slides. If you want to “follow along”, +[download my slides](https://raw.githubusercontent.com/nimblemachines/muforth/master/talks/2008-mar-30-PNCA), +and use `less` to view them – ideally in a text window that is at least 30 +lines high – like so: + +``` +less -30 ~/muforth/talks/2008-mar-30-PNCA +``` + +[![March 2008 talk on Vimeo](https://user-images.githubusercontent.com/3320/214488827-47171f1b-5221-44d0-b9d9-7febcff83628.png)](https://vimeo.com/859408) + +# Above all, enjoy! + +## About + +A simple, indirect-threaded Forth, written in C; for target compiling; runs on Linux, BSD, OSX, and Cygwin + +[muforth.dev/](https://muforth.dev/ "https://muforth.dev/") + +### Resources + +[Readme](#readme-ov-file) + +### License + +[View license](#License-1-ov-file) + +### Uh oh! + +There was an error while loading. Please reload this page. + +[Activity](/nimblemachines/muforth/activity) + +### Stars + +[**153** +stars](/nimblemachines/muforth/stargazers) + +### Watchers + +[**20** +watching](/nimblemachines/muforth/watchers) + +### Forks + +[**34** +forks](/nimblemachines/muforth/forks) + +[Report repository](/contact/report-content?content_url=https%3A%2F%2Fgithub.com%2Fnimblemachines%2Fmuforth&report=nimblemachines+%28user%29) + +## [Releases](/nimblemachines/muforth/releases) + +No releases published + +## [Packages 0](/users/nimblemachines/packages?repo_name=muforth) + +No packages published + +### Uh oh! + +There was an error while loading. Please reload this page. + +## [Contributors 4](/nimblemachines/muforth/graphs/contributors) + +### Uh oh! + +There was an error while loading. Please reload this page. + +## Languages + +* [Forth + 90.9%](/nimblemachines/muforth/search?l=forth) +* [Assembly + 3.3%](/nimblemachines/muforth/search?l=assembly) +* [Lua + 2.9%](/nimblemachines/muforth/search?l=lua) +* [C + 2.1%](/nimblemachines/muforth/search?l=c) +* [Roff + 0.3%](/nimblemachines/muforth/search?l=roff) +* [Shell + 0.2%](/nimblemachines/muforth/search?l=shell) +* Other + 0.3% + +## Footer + +© 2026 GitHub, Inc. + +### Footer navigation + +* [Terms](https://docs.github.com/site-policy/github-terms/github-terms-of-service) +* [Privacy](https://docs.github.com/site-policy/privacy-policies/github-privacy-statement) +* [Security](https://github.com/security) +* [Status](https://www.githubstatus.com/) +* [Community](https://github.community/) +* [Docs](https://docs.github.com/) +* [Contact](https://support.github.com?tags=dotcom-footer) +* Manage cookies +* Do not share my personal information + + + +You can’t perform that action at this time. \ No newline at end of file diff --git a/references/ForthNotes/SmithForth_RISC-V.md b/references/ForthNotes/SmithForth_RISC-V.md new file mode 100644 index 0000000..6c4f923 --- /dev/null +++ b/references/ForthNotes/SmithForth_RISC-V.md @@ -0,0 +1,357 @@ +# SmithForth_RISC-V + +**Source:** https://github.com/AndreiDuma/SmithForth_RISC-V + +GitHub - AndreiDuma/SmithForth\_RISC-V: An accessible Forth written in machine code for the RISC-V architecture. + + + +[Skip to content](#start-of-content) + + + + + + + + + + + + + +## Navigation Menu + +Toggle navigation + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2FAndreiDuma%2FSmithForth_RISC-V) + +Appearance settings + +* Platform + + + AI CODE CREATION + - [GitHub CopilotWrite better code with AI](https://github.com/features/copilot) + - [GitHub SparkBuild and deploy intelligent apps](https://github.com/features/spark) + - [GitHub ModelsManage and compare prompts](https://github.com/features/models) + - [MCP RegistryNewIntegrate external tools](https://github.com/mcp) + + DEVELOPER WORKFLOWS + - [ActionsAutomate any workflow](https://github.com/features/actions) + - [CodespacesInstant dev environments](https://github.com/features/codespaces) + - [IssuesPlan and track work](https://github.com/features/issues) + - [Code ReviewManage code changes](https://github.com/features/code-review) + + APPLICATION SECURITY + - [GitHub Advanced SecurityFind and fix vulnerabilities](https://github.com/security/advanced-security) + - [Code securitySecure your code as you build](https://github.com/security/advanced-security/code-security) + - [Secret protectionStop leaks before they start](https://github.com/security/advanced-security/secret-protection) + + EXPLORE + - [Why GitHub](https://github.com/why-github) + - [Documentation](https://docs.github.com) + - [Blog](https://github.blog) + - [Changelog](https://github.blog/changelog) + - [Marketplace](https://github.com/marketplace) + + [View all features](https://github.com/features) +* Solutions + + + BY COMPANY SIZE + - [Enterprises](https://github.com/enterprise) + - [Small and medium teams](https://github.com/team) + - [Startups](https://github.com/enterprise/startups) + - [Nonprofits](https://github.com/solutions/industry/nonprofits) + + BY USE CASE + - [App Modernization](https://github.com/solutions/use-case/app-modernization) + - [DevSecOps](https://github.com/solutions/use-case/devsecops) + - [DevOps](https://github.com/solutions/use-case/devops) + - [CI/CD](https://github.com/solutions/use-case/ci-cd) + - [View all use cases](https://github.com/solutions/use-case) + + BY INDUSTRY + - [Healthcare](https://github.com/solutions/industry/healthcare) + - [Financial services](https://github.com/solutions/industry/financial-services) + - [Manufacturing](https://github.com/solutions/industry/manufacturing) + - [Government](https://github.com/solutions/industry/government) + - [View all industries](https://github.com/solutions/industry) + + [View all solutions](https://github.com/solutions) +* Resources + + + EXPLORE BY TOPIC + - [AI](https://github.com/resources/articles?topic=ai) + - [Software Development](https://github.com/resources/articles?topic=software-development) + - [DevOps](https://github.com/resources/articles?topic=devops) + - [Security](https://github.com/resources/articles?topic=security) + - [View all topics](https://github.com/resources/articles) + + EXPLORE BY TYPE + - [Customer stories](https://github.com/customer-stories) + - [Events & webinars](https://github.com/resources/events) + - [Ebooks & reports](https://github.com/resources/whitepapers) + - [Business insights](https://github.com/solutions/executive-insights) + - [GitHub Skills](https://skills.github.com) + + SUPPORT & SERVICES + - [Documentation](https://docs.github.com) + - [Customer support](https://support.github.com) + - [Community forum](https://github.com/orgs/community/discussions) + - [Trust center](https://github.com/trust-center) + - [Partners](https://github.com/partners) +* Open Source + + + COMMUNITY + - [GitHub SponsorsFund open source developers](https://github.com/sponsors) + + PROGRAMS + - [Security Lab](https://securitylab.github.com) + - [Maintainer Community](https://maintainers.github.com) + - [Accelerator](https://github.com/accelerator) + - [Archive Program](https://archiveprogram.github.com) + + REPOSITORIES + - [Topics](https://github.com/topics) + - [Trending](https://github.com/trending) + - [Collections](https://github.com/collections) +* Enterprise + + + ENTERPRISE SOLUTIONS + - [Enterprise platformAI-powered developer platform](https://github.com/enterprise) + + AVAILABLE ADD-ONS + - [GitHub Advanced SecurityEnterprise-grade security features](https://github.com/security/advanced-security) + - [Copilot for BusinessEnterprise-grade AI features](https://github.com/features/copilot/copilot-business) + - [Premium SupportEnterprise-grade 24/7 support](https://github.com/premium-support) +* [Pricing](https://github.com/pricing) + +Search or jump to... + + +# Search code, repositories, users, issues, pull requests... + +Search + +Clear + +[Search syntax tips](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax) + +# Provide feedback + +We read every piece of feedback, and take your input very seriously. + + +Include my email address so I can be contacted + +Cancel + Submit feedback + + + + + +# Saved searches + +## Use saved searches to filter your results more quickly + +Name + +Query + +To see all available qualifiers, see our [documentation](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax). + +Cancel + Create saved search + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2FAndreiDuma%2FSmithForth_RISC-V) + +[Sign up](/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E&source=header-repo&source_repo=AndreiDuma%2FSmithForth_RISC-V) + +Appearance settings + +Resetting focus + +You signed in with another tab or window. Reload to refresh your session. +You signed out in another tab or window. Reload to refresh your session. +You switched accounts on another tab or window. Reload to refresh your session. + + + +Dismiss alert + +{{ message }} + +[AndreiDuma](/AndreiDuma) +/ +**[SmithForth\_RISC-V](/AndreiDuma/SmithForth_RISC-V)** +Public + +* [Notifications](/login?return_to=%2FAndreiDuma%2FSmithForth_RISC-V) You must be signed in to change notification settings +* [Fork + 2](/login?return_to=%2FAndreiDuma%2FSmithForth_RISC-V) +* [Star + 23](/login?return_to=%2FAndreiDuma%2FSmithForth_RISC-V) + +An accessible Forth written in machine code for the RISC-V architecture. + +### License + +[EUPL-1.2 license](/AndreiDuma/SmithForth_RISC-V/blob/main/LICENSE) + +[23 +stars](/AndreiDuma/SmithForth_RISC-V/stargazers) [2 +forks](/AndreiDuma/SmithForth_RISC-V/forks) [Branches](/AndreiDuma/SmithForth_RISC-V/branches) [Tags](/AndreiDuma/SmithForth_RISC-V/tags) [Activity](/AndreiDuma/SmithForth_RISC-V/activity) + +[Star](/login?return_to=%2FAndreiDuma%2FSmithForth_RISC-V) + +[Notifications](/login?return_to=%2FAndreiDuma%2FSmithForth_RISC-V) You must be signed in to change notification settings + +* [Code](/AndreiDuma/SmithForth_RISC-V) +* [Issues + 2](/AndreiDuma/SmithForth_RISC-V/issues) +* [Pull requests + 0](/AndreiDuma/SmithForth_RISC-V/pulls) +* [Security + 0](/AndreiDuma/SmithForth_RISC-V/security) +* [Insights](/AndreiDuma/SmithForth_RISC-V/pulse) + +Additional navigation options + + +* [Code](/AndreiDuma/SmithForth_RISC-V) +* [Issues](/AndreiDuma/SmithForth_RISC-V/issues) +* [Pull requests](/AndreiDuma/SmithForth_RISC-V/pulls) +* [Security](/AndreiDuma/SmithForth_RISC-V/security) +* [Insights](/AndreiDuma/SmithForth_RISC-V/pulse) + +# AndreiDuma/SmithForth\_RISC-V + +main + +[Branches](/AndreiDuma/SmithForth_RISC-V/branches)[Tags](/AndreiDuma/SmithForth_RISC-V/tags) + +Go to file + +Code + +Open more actions menu + +## Folders and files + +| Name | | Name | Last commit message | Last commit date | +| --- | --- | --- | --- | --- | +| Latest commit History[4 Commits](/AndreiDuma/SmithForth_RISC-V/commits/main/) 4 Commits | | | +| [.gitignore](/AndreiDuma/SmithForth_RISC-V/blob/main/.gitignore ".gitignore") | | [.gitignore](/AndreiDuma/SmithForth_RISC-V/blob/main/.gitignore ".gitignore") | | | +| [LICENSE](/AndreiDuma/SmithForth_RISC-V/blob/main/LICENSE "LICENSE") | | [LICENSE](/AndreiDuma/SmithForth_RISC-V/blob/main/LICENSE "LICENSE") | | | +| [Makefile](/AndreiDuma/SmithForth_RISC-V/blob/main/Makefile "Makefile") | | [Makefile](/AndreiDuma/SmithForth_RISC-V/blob/main/Makefile "Makefile") | | | +| [README.md](/AndreiDuma/SmithForth_RISC-V/blob/main/README.md "README.md") | | [README.md](/AndreiDuma/SmithForth_RISC-V/blob/main/README.md "README.md") | | | +| [SForth.dmp](/AndreiDuma/SmithForth_RISC-V/blob/main/SForth.dmp "SForth.dmp") | | [SForth.dmp](/AndreiDuma/SmithForth_RISC-V/blob/main/SForth.dmp "SForth.dmp") | | | +| [build.sh](/AndreiDuma/SmithForth_RISC-V/blob/main/build.sh "build.sh") | | [build.sh](/AndreiDuma/SmithForth_RISC-V/blob/main/build.sh "build.sh") | | | +| [input.fs](/AndreiDuma/SmithForth_RISC-V/blob/main/input.fs "input.fs") | | [input.fs](/AndreiDuma/SmithForth_RISC-V/blob/main/input.fs "input.fs") | | | +| [system.fs](/AndreiDuma/SmithForth_RISC-V/blob/main/system.fs "system.fs") | | [system.fs](/AndreiDuma/SmithForth_RISC-V/blob/main/system.fs "system.fs") | | | +| View all files | | | + +## Repository files navigation + +* [README](#) +* [EUPL-1.2 license](#) + +This is an accessible Forth implementation written directly in machine +code for the RISC-V architecture. It is an adaptation of David +Smith's excellent x86-64 [SmithForth](https://dacvs.neocities.org/SF/). + +Run with `make run`. You will need to run Linux either on RISC-V +hardware or in a QEMU environment. + +This project was developed as part of my Master's [thesis](https://github.com/AndreiDuma/SmithForth_RISC-V/releases/download/v1.0/From_x86-64_Forth_to_RISC-V_Andrei_Dorian_Duma_2024.pdf), in +which I thoroughly annotate SmithForth's machine code before porting +it to RISC-V. The abstract of my thesis is given below: + +> In this thesis we present the implementation of a usable Forth +> system, built using only RISC-V machine code and the Linux operating +> system as foundations. We begin by justifying the need for +> accessible programming language implementations, discussing +> desirable features in educational compilers. Having selected Forth +> as our language of choice for an educational language +> implementation, we review existing Forth systems and we motivate why +> creating a RISC-V port is a worthwhile task. Next we thoroughly +> examine SmithForth, a high-quality Forth system for the x86-64 +> architecture. After understanding its principles, we port it to +> RISC-V, adapting it to our purposes. Finally, we extend this Forth +> system in Forth itself: we write a RISC- V assembler, we provide +> useful arithmetic and logic operators plus conditional and looping +> constructs. We complete our demonstration with a Forth +> implementation of FizzBuzz, showing the usability of the system. + +Those interested can [download](https://github.com/AndreiDuma/SmithForth_RISC-V/releases/download/v1.0/From_x86-64_Forth_to_RISC-V_Andrei_Dorian_Duma_2024.pdf) the thesis document in PDF format. + +## About + +An accessible Forth written in machine code for the RISC-V architecture. + +### Topics + +[compiler](/topics/compiler "Topic: compiler") +[master-thesis](/topics/master-thesis "Topic: master-thesis") +[forth](/topics/forth "Topic: forth") +[machine-code](/topics/machine-code "Topic: machine-code") +[risc-v](/topics/risc-v "Topic: risc-v") + +### Resources + +[Readme](#readme-ov-file) + +### License + +[EUPL-1.2 license](#EUPL-1.2-1-ov-file) + +### Uh oh! + +There was an error while loading. Please reload this page. + +[Activity](/AndreiDuma/SmithForth_RISC-V/activity) + +### Stars + +[**23** +stars](/AndreiDuma/SmithForth_RISC-V/stargazers) + +### Watchers + +[**4** +watching](/AndreiDuma/SmithForth_RISC-V/watchers) + +### Forks + +[**2** +forks](/AndreiDuma/SmithForth_RISC-V/forks) + +[Report repository](/contact/report-content?content_url=https%3A%2F%2Fgithub.com%2FAndreiDuma%2FSmithForth_RISC-V&report=AndreiDuma+%28user%29) + +## [Releases 1](/AndreiDuma/SmithForth_RISC-V/releases) + +[Thesis v1.0 + +Latest + +Sep 12, 2024](/AndreiDuma/SmithForth_RISC-V/releases/tag/v1.0) + +## Languages + +* [Forth + 95.2%](/AndreiDuma/SmithForth_RISC-V/search?l=forth) +* [Shell + 3.3%](/AndreiDuma/SmithForth_RISC-V/search?l=shell) +* [Makefile + 1.5%](/AndreiDuma/SmithForth_RISC-V/search?l=makefile) + +## Footer + +© 2026 GitHub, Inc. + +### Footer navigation + +* [Terms](https://docs.github.com/site-policy/github-terms/github-terms-of-service) +* [Privacy](https://docs.github.com/site-policy/privacy-policies/github-privacy-statement) +* [Security](https://github.com/security) +* [Status](https://www.githubstatus.com/) +* [Community](https://github.community/) +* [Docs](https://docs.github.com/) +* [Contact](https://support.github.com?tags=dotcom-footer) +* Manage cookies +* Do not share my personal information + + + +You can’t perform that action at this time. \ No newline at end of file diff --git a/references/ForthNotes/StoneKnifeForth.md b/references/ForthNotes/StoneKnifeForth.md new file mode 100644 index 0000000..2cd14b9 --- /dev/null +++ b/references/ForthNotes/StoneKnifeForth.md @@ -0,0 +1,878 @@ +# StoneKnifeForth + +**Source:** https://github.com/kragen/stoneknifeforth + +GitHub - kragen/stoneknifeforth: a tiny self-hosted Forth implementation + + + +[Skip to content](#start-of-content) + + + + + + + + + + + + + +## Navigation Menu + +Toggle navigation + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2Fkragen%2Fstoneknifeforth) + +Appearance settings + +* Platform + + + AI CODE CREATION + - [GitHub CopilotWrite better code with AI](https://github.com/features/copilot) + - [GitHub SparkBuild and deploy intelligent apps](https://github.com/features/spark) + - [GitHub ModelsManage and compare prompts](https://github.com/features/models) + - [MCP RegistryNewIntegrate external tools](https://github.com/mcp) + + DEVELOPER WORKFLOWS + - [ActionsAutomate any workflow](https://github.com/features/actions) + - [CodespacesInstant dev environments](https://github.com/features/codespaces) + - [IssuesPlan and track work](https://github.com/features/issues) + - [Code ReviewManage code changes](https://github.com/features/code-review) + + APPLICATION SECURITY + - [GitHub Advanced SecurityFind and fix vulnerabilities](https://github.com/security/advanced-security) + - [Code securitySecure your code as you build](https://github.com/security/advanced-security/code-security) + - [Secret protectionStop leaks before they start](https://github.com/security/advanced-security/secret-protection) + + EXPLORE + - [Why GitHub](https://github.com/why-github) + - [Documentation](https://docs.github.com) + - [Blog](https://github.blog) + - [Changelog](https://github.blog/changelog) + - [Marketplace](https://github.com/marketplace) + + [View all features](https://github.com/features) +* Solutions + + + BY COMPANY SIZE + - [Enterprises](https://github.com/enterprise) + - [Small and medium teams](https://github.com/team) + - [Startups](https://github.com/enterprise/startups) + - [Nonprofits](https://github.com/solutions/industry/nonprofits) + + BY USE CASE + - [App Modernization](https://github.com/solutions/use-case/app-modernization) + - [DevSecOps](https://github.com/solutions/use-case/devsecops) + - [DevOps](https://github.com/solutions/use-case/devops) + - [CI/CD](https://github.com/solutions/use-case/ci-cd) + - [View all use cases](https://github.com/solutions/use-case) + + BY INDUSTRY + - [Healthcare](https://github.com/solutions/industry/healthcare) + - [Financial services](https://github.com/solutions/industry/financial-services) + - [Manufacturing](https://github.com/solutions/industry/manufacturing) + - [Government](https://github.com/solutions/industry/government) + - [View all industries](https://github.com/solutions/industry) + + [View all solutions](https://github.com/solutions) +* Resources + + + EXPLORE BY TOPIC + - [AI](https://github.com/resources/articles?topic=ai) + - [Software Development](https://github.com/resources/articles?topic=software-development) + - [DevOps](https://github.com/resources/articles?topic=devops) + - [Security](https://github.com/resources/articles?topic=security) + - [View all topics](https://github.com/resources/articles) + + EXPLORE BY TYPE + - [Customer stories](https://github.com/customer-stories) + - [Events & webinars](https://github.com/resources/events) + - [Ebooks & reports](https://github.com/resources/whitepapers) + - [Business insights](https://github.com/solutions/executive-insights) + - [GitHub Skills](https://skills.github.com) + + SUPPORT & SERVICES + - [Documentation](https://docs.github.com) + - [Customer support](https://support.github.com) + - [Community forum](https://github.com/orgs/community/discussions) + - [Trust center](https://github.com/trust-center) + - [Partners](https://github.com/partners) +* Open Source + + + COMMUNITY + - [GitHub SponsorsFund open source developers](https://github.com/sponsors) + + PROGRAMS + - [Security Lab](https://securitylab.github.com) + - [Maintainer Community](https://maintainers.github.com) + - [Accelerator](https://github.com/accelerator) + - [Archive Program](https://archiveprogram.github.com) + + REPOSITORIES + - [Topics](https://github.com/topics) + - [Trending](https://github.com/trending) + - [Collections](https://github.com/collections) +* Enterprise + + + ENTERPRISE SOLUTIONS + - [Enterprise platformAI-powered developer platform](https://github.com/enterprise) + + AVAILABLE ADD-ONS + - [GitHub Advanced SecurityEnterprise-grade security features](https://github.com/security/advanced-security) + - [Copilot for BusinessEnterprise-grade AI features](https://github.com/features/copilot/copilot-business) + - [Premium SupportEnterprise-grade 24/7 support](https://github.com/premium-support) +* [Pricing](https://github.com/pricing) + +Search or jump to... + + +# Search code, repositories, users, issues, pull requests... + +Search + +Clear + +[Search syntax tips](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax) + +# Provide feedback + +We read every piece of feedback, and take your input very seriously. + + +Include my email address so I can be contacted + +Cancel + Submit feedback + + + + + +# Saved searches + +## Use saved searches to filter your results more quickly + +Name + +Query + +To see all available qualifiers, see our [documentation](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax). + +Cancel + Create saved search + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2Fkragen%2Fstoneknifeforth) + +[Sign up](/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E&source=header-repo&source_repo=kragen%2Fstoneknifeforth) + +Appearance settings + +Resetting focus + +You signed in with another tab or window. Reload to refresh your session. +You signed out in another tab or window. Reload to refresh your session. +You switched accounts on another tab or window. Reload to refresh your session. + + + +Dismiss alert + +{{ message }} + +[kragen](/kragen) +/ +**[stoneknifeforth](/kragen/stoneknifeforth)** +Public + +* [Notifications](/login?return_to=%2Fkragen%2Fstoneknifeforth) You must be signed in to change notification settings +* [Fork + 24](/login?return_to=%2Fkragen%2Fstoneknifeforth) +* [Star + 436](/login?return_to=%2Fkragen%2Fstoneknifeforth) + +a tiny self-hosted Forth implementation + +### License + +[CC0-1.0 license](/kragen/stoneknifeforth/blob/master/LICENSE.md) + +[436 +stars](/kragen/stoneknifeforth/stargazers) [24 +forks](/kragen/stoneknifeforth/forks) [Branches](/kragen/stoneknifeforth/branches) [Tags](/kragen/stoneknifeforth/tags) [Activity](/kragen/stoneknifeforth/activity) + +[Star](/login?return_to=%2Fkragen%2Fstoneknifeforth) + +[Notifications](/login?return_to=%2Fkragen%2Fstoneknifeforth) You must be signed in to change notification settings + +* [Code](/kragen/stoneknifeforth) +* [Issues + 2](/kragen/stoneknifeforth/issues) +* [Pull requests + 2](/kragen/stoneknifeforth/pulls) +* [Actions](/kragen/stoneknifeforth/actions) +* [Projects + 0](/kragen/stoneknifeforth/projects) +* [Wiki](/kragen/stoneknifeforth/wiki) +* [Security + 0](/kragen/stoneknifeforth/security) +* [Insights](/kragen/stoneknifeforth/pulse) + +Additional navigation options + + +* [Code](/kragen/stoneknifeforth) +* [Issues](/kragen/stoneknifeforth/issues) +* [Pull requests](/kragen/stoneknifeforth/pulls) +* [Actions](/kragen/stoneknifeforth/actions) +* [Projects](/kragen/stoneknifeforth/projects) +* [Wiki](/kragen/stoneknifeforth/wiki) +* [Security](/kragen/stoneknifeforth/security) +* [Insights](/kragen/stoneknifeforth/pulse) + +# kragen/stoneknifeforth + +master + +[Branches](/kragen/stoneknifeforth/branches)[Tags](/kragen/stoneknifeforth/tags) + +Go to file + +Code + +Open more actions menu + +## Folders and files + +| Name | | Name | Last commit message | Last commit date | +| --- | --- | --- | --- | --- | +| Latest commit History[113 Commits](/kragen/stoneknifeforth/commits/master/) 113 Commits | | | +| [.gitattributes](/kragen/stoneknifeforth/blob/master/.gitattributes ".gitattributes") | | [.gitattributes](/kragen/stoneknifeforth/blob/master/.gitattributes ".gitattributes") | | | +| [.gitignore](/kragen/stoneknifeforth/blob/master/.gitignore ".gitignore") | | [.gitignore](/kragen/stoneknifeforth/blob/master/.gitignore ".gitignore") | | | +| [386.c](/kragen/stoneknifeforth/blob/master/386.c "386.c") | | [386.c](/kragen/stoneknifeforth/blob/master/386.c "386.c") | | | +| [LICENSE.md](/kragen/stoneknifeforth/blob/master/LICENSE.md "LICENSE.md") | | [LICENSE.md](/kragen/stoneknifeforth/blob/master/LICENSE.md "LICENSE.md") | | | +| [Makefile](/kragen/stoneknifeforth/blob/master/Makefile "Makefile") | | [Makefile](/kragen/stoneknifeforth/blob/master/Makefile "Makefile") | | | +| [Q.tbf1](/kragen/stoneknifeforth/blob/master/Q.tbf1 "Q.tbf1") | | [Q.tbf1](/kragen/stoneknifeforth/blob/master/Q.tbf1 "Q.tbf1") | | | +| [README.md](/kragen/stoneknifeforth/blob/master/README.md "README.md") | | [README.md](/kragen/stoneknifeforth/blob/master/README.md "README.md") | | | +| [TODO](/kragen/stoneknifeforth/blob/master/TODO "TODO") | | [TODO](/kragen/stoneknifeforth/blob/master/TODO "TODO") | | | +| [build](/kragen/stoneknifeforth/blob/master/build "build") | | [build](/kragen/stoneknifeforth/blob/master/build "build") | | | +| [cat.tbf1](/kragen/stoneknifeforth/blob/master/cat.tbf1 "cat.tbf1") | | [cat.tbf1](/kragen/stoneknifeforth/blob/master/cat.tbf1 "cat.tbf1") | | | +| [cat1.tbf1](/kragen/stoneknifeforth/blob/master/cat1.tbf1 "cat1.tbf1") | | [cat1.tbf1](/kragen/stoneknifeforth/blob/master/cat1.tbf1 "cat1.tbf1") | | | +| [disassemble](/kragen/stoneknifeforth/blob/master/disassemble "disassemble") | | [disassemble](/kragen/stoneknifeforth/blob/master/disassemble "disassemble") | | | +| [hello42.tbf1](/kragen/stoneknifeforth/blob/master/hello42.tbf1 "hello42.tbf1") | | [hello42.tbf1](/kragen/stoneknifeforth/blob/master/hello42.tbf1 "hello42.tbf1") | | | +| [hi.tbf1](/kragen/stoneknifeforth/blob/master/hi.tbf1 "hi.tbf1") | | [hi.tbf1](/kragen/stoneknifeforth/blob/master/hi.tbf1 "hi.tbf1") | | | +| [onescreen.tbf1](/kragen/stoneknifeforth/blob/master/onescreen.tbf1 "onescreen.tbf1") | | [onescreen.tbf1](/kragen/stoneknifeforth/blob/master/onescreen.tbf1 "onescreen.tbf1") | | | +| [star.tbf1](/kragen/stoneknifeforth/blob/master/star.tbf1 "star.tbf1") | | [star.tbf1](/kragen/stoneknifeforth/blob/master/star.tbf1 "star.tbf1") | | | +| [tiny.asm](/kragen/stoneknifeforth/blob/master/tiny.asm "tiny.asm") | | [tiny.asm](/kragen/stoneknifeforth/blob/master/tiny.asm "tiny.asm") | | | +| [tinyboot.py](/kragen/stoneknifeforth/blob/master/tinyboot.py "tinyboot.py") | | [tinyboot.py](/kragen/stoneknifeforth/blob/master/tinyboot.py "tinyboot.py") | | | +| [tinyboot.s](/kragen/stoneknifeforth/blob/master/tinyboot.s "tinyboot.s") | | [tinyboot.s](/kragen/stoneknifeforth/blob/master/tinyboot.s "tinyboot.s") | | | +| [tinyboot1.tbf1](/kragen/stoneknifeforth/blob/master/tinyboot1.tbf1 "tinyboot1.tbf1") | | [tinyboot1.tbf1](/kragen/stoneknifeforth/blob/master/tinyboot1.tbf1 "tinyboot1.tbf1") | | | +| [trace.py](/kragen/stoneknifeforth/blob/master/trace.py "trace.py") | | [trace.py](/kragen/stoneknifeforth/blob/master/trace.py "trace.py") | | | +| [trim.py](/kragen/stoneknifeforth/blob/master/trim.py "trim.py") | | [trim.py](/kragen/stoneknifeforth/blob/master/trim.py "trim.py") | | | +| View all files | | | + +## Repository files navigation + +* [README](#) +* [CC0-1.0 license](#) + +# StoneKnifeForth + +This is StoneKnifeForth, a very simple language inspired by Forth. It +is not expected to be useful; instead, its purpose is to show how +simple a compiler can be. The compiler is a bit under two pages of +code when the comments are removed. + +This package includes a “metacircular compiler” which is written in +StoneKnifeForth and compiles StoneKnifeForth to an x86 Linux ELF +executable. + +There is also a StoneKnifeForth interpreter written in Python (tested +with Python 2.4). It seems to be about 100× slower than code emitted +by the compiler. + +(All of the measurements below may be a bit out of date.) + +On my 700MHz laptop, measuring wall-clock time: + +* compiling the compiler, using the compiler running in the interpreter, + takes about 10 seconds; +* compiling the compiler, using the compiler compiled with the compiler, + takes about 0.1 seconds; +* compiling a version of the compiler from which comments and extra + whitespace have been “trimmed”, using the compiler compiled with the + compiler, takes about 0.02 seconds. + +So this is a programming language implementation that can recompile +itself from source twice per 24fps movie frame. The entire “trimmed” +source code is 1902 bytes, which is less than half the size of the +nearest comparable project that I’m aware of, `otccelf`, which is 4748 +bytes. + +As demonstrated by the interpreter written in Python, the programming +language itself is essentially machine-independent, with very few +x86 quirks: + +* items on the stack are 32 bits in size; +* arithmetic is 32-bit; +* stack items stored in memory not only take up 4 bytes, but they are + little-endian. + +(It would be fairly easy to make a tiny “compiler” if the source +language were, say, x86 machine code.) + +The output executable is 4063 bytes, containing about 1400 +instructions. `valgrind` reports that it takes 1,813,395 instructions +to compile itself. (So you would think that it could compile itself +in 2.6 ms. The long runtimes are a result of reading its input one +byte at at time.) + +## Why? To Know What I’m Doing + +A year and a half ago, I wrote a [metacircular Bicicleta-language +interpreter](http://lists.canonical.org/pipermail/kragen-hacks/2007-February/000450.html), and I said: + +> Alan Kay frequently expresses enthusiasm over the metacircular Lisp +> interpreter in the Lisp 1.5 Programmer’s Manual. For example, in +> +> he writes: +> +> > ``` +> > Yes, that was the big revelation to me when I was in graduate +> > school — when I finally understood that the half page of code on +> > the bottom of page 13 of the Lisp 1.5 manual was Lisp in +> > itself. These were “Maxwell’s Equations of Software!” This is the +> > whole world of programming in a few lines that I can put my hand +> > over. +> > +> > I realized that anytime I want to know what I’m doing, I can just +> > write down the kernel of this thing in a half page and it’s not +> > going to lose any power. In fact, it’s going to gain power by +> > being able to reenter itself much more readily than most systems +> > done the other way can possibly do. +> > ``` + +But if you try to implement a Lisp interpreter in a low-level language +by translating that metacircular interpreter into it (as [I did later +that year](http://lists.canonical.org/pipermail/kragen-hacks/2007-September/000464.html)) you run into a problem. The metacircular interpreter +glosses over a large number of things that turn out to be nontrivial +to implement — indeed, about half of the code is devoted to things +outside of the scope of the metacircular interpreter. Here’s a list +of issues that the Lisp 1.5 metacircular interpreter neglects, some +semantic and some merely implementational: + +* memory management +* argument evaluation order +* laziness vs. strictness +* other aspects of control flow +* representation and comparison of atoms +* representation of pairs +* parsing +* type checking and type testing (atom) +* recursive function call and return +* tail-calls +* lexical vs. dynamic scoping + +In John C. Reynolds’s paper, “[Definitional Interpreters +Revisited](http://www.brics.dk/~hosc/local/HOSC-11-4-pp355-361.pdf)”, Higher-Order and Symbolic Computation, 11, 355–361 +(1998), he says: + +> In the fourth and third paragraphs before the end of Section 5, I +> should have emphasized the fact that a metacircular interpreter is +> not really a definition, since it is trivial when the defining +> language is understood, and otherwise it is ambiguous. In +> particular, Interpreters I and II say nothing about order of +> application, while Interpreters I and III say little about +> higher-order functions. Jim Morris put the matter more strongly: +> +> > The activity of defining features in terms of themselves is highly +> > suspect, especially when they are as subtle as functional +> > objects. It is a fad that should be debunked, in my opinion. A +> > real significance of [a self-defined] interpreter . . . is that it +> > displays a simple universal function for the language in +> > question. +> +> On the other hand, I clearly remember that John McCarthy’s +> definition of LISP [1DI], which is a definitional interpreter in the +> style of II, was a great help when I first learned that language. But +> it was not the sole support of my understanding. + +(For what it’s worth, it may not even the case that self-defined +interpreters are necessarily Turing-complete; it might be possible to +write a non-Turing-complete metacircular interpreter for a +non-Turing-complete language, such as David Turner’s Total Functional +Programming systems.) + +A metacircular compiler forces you to confront this extra complexity. +Moreover, metacircular compilers are self-sustaining in a way that +interpreters aren’t; once you have the compiler running, you are free +to add features to the language it supports, then take advantage of +those features in the compiler. + +So this is a “stone knife” programming tool: bootstrapped out of +almost nothing as quickly as possible. + +## Why? To Develop a Compiler Incrementally + +When I wrote Ur-Scheme, my thought was to see if I could figure out +how to develop a compiler incrementally, starting by building a small +working metacircular compiler in less than a day, and adding features +from there. I pretty much failed; it took me two and a half weeks to +get it to compile itself successfully. + +Part of the problem is that a minimal subset of R5RS Scheme powerful +enough to write a compiler in — without making the compiler even +larger due to writing it in a low-level language — is still a +relatively large language. Ur-Scheme doesn’t have much arithmetic, +but it does have integers, dynamic typing, closures, characters, +strings, lists, recursion, booleans, variadic functions, `let` to +introduce local variables, character and string literals, a sort of +crude macro system, five different conditional forms (if, cond, case, +and, or), quotation, tail-call optimization, function argument count +verification, bounds checking, symbols, buffered input to keep it from +taking multiple seconds to compile itself, and a library of functions +for processing lists, strings, and characters. And each of those +things was added because it was necessary to get the compiler to be +able to compile itself. The end result was that the compiler is 90 +kilobytes of source code, about 1600 lines if you leave out the +comments. + +Now, maybe you can write 1600 lines of working Scheme in a day, but I +sure as hell can’t. It’s still not a very large compiler, as +compilers go, but it’s a lot bigger than `otccelf`. So I hypothesized +that maybe a simpler language, without a requirement for compatibility +with something else, would enable me to get a compiler bootstrapped +more easily. + +So StoneKnifeForth was born. It’s inspired by Forth, so it inherits +most of Forth’s traditional simplifications: + +* no expressions; +* no statements; +* no types, dynamic or static; +* no floating-point (although Ur-Scheme doesn’t have floating-point either); +* no scoping, lexical or dynamic; +* no dynamic memory allocation; + +And it added a few of its own: + +* no names of more than one byte; +* no user-defined IMMEDIATE words (the Forth equivalent of Lisp macros); +* no interpretation state, so no compile-time evaluation at all; +* no interactive REPL; +* no `do` loops; +* no `else` on `if` statements; +* no recursion; +* no access to the return stack; +* no access to the filesystem, just stdin and stdout; +* no multithreading. + +Surprisingly, the language that results is still almost bearable to +write a compiler in, although it definitely has the flavor of an +assembler. + +Unfortunately, I still totally failed to get it done in a day. It was +15 days from when I first started scribbling about it in my notebook +until it was able to compile itself successfully, although `git` only +shows active development happening on six of those days (including +some help from my friend Aristotle). So that’s an improvement, but +not as much of an improvement as I would like. At that point, it was +13k of source, 114 non-comment lines of code, which is definitely a +lot smaller than Ur-Scheme’s 90k and 1600 lines. (Although there are +another 181 lines of Python for the bootstrap interpreter.) + +It’s possible to imagine writing and debugging 114 lines of code in a +day, or even 300 lines. It’s still maybe a bit optimistic to think I could +do that in a day, so maybe I need to find a way to increase +incrementality further. + +My theory was that once I had a working compiler, I could add features +to the language incrementally and test them as I went. So far I +haven’t gotten to that part. + +## Why? Wirth envy + +[Michael Franz writes](http://www.ics.uci.edu/~franz/Site/pubs-pdf/BC03.pdf "Oberon — the overlooked jewel"): + +> In order to find the optimal cost/benefit ratio, Wirth used a highly +> intuitive metric, the origin of which is unknown to me but that may +> very well be Wirth’s own invention. He used the compiler’s +> self-compilation speed as a measure of the compiler’s +> quality. Considering that Wirth’s compilers were written in the +> languages they compiled, and that compilers are substantial and +> non-trivial pieces of software in their own right, this introduced a +> highly practical benchmark that directly contested a compiler’s +> complexity against its performance. Under the self-compilation speed +> benchmark, only those optimizations were allowed to be incorporated +> into a compiler that accelerated it by so much that the intrinsic +> cost of the new code addition was fully compensated. + +Wirth is clearly one of the great apostles of simplicity in +programming, together with with Edsger Dijkstra and Chuck Moore. But +I doubt very much that the Oberon compiler could ever compile itself +in 2 million instructions, given the complexity of the Oberon +language. + +R. Kent Dybvig used the same criterion; speaking of the 1985–1987 +development of Chez Scheme, [he writes](http://www.cs.indiana.edu/~dyb/pubs/hocs.pdf "The Development of Chez Scheme"): + +> At some point we actually instituted the following rule to keep a +> lid on compilation overhead: if an optimization doesn’t make the +> compiler itself enough faster to make up for the cost of doing the +> optimization, the optimization is discarded. This ruled out several +> optimizations we tried, including an early attempt at a source +> optimizer. + +## Far-Fetched Ways This Code Could Actually be Useful + +The obvious way that it could be useful is that you could read it and +learn things from it, then put them to use in actually useful +software. This section is about the far-fetched ways instead. + +If you want to counter Ken Thompson’s “Trusting Trust” attack, you +would want to start with a minimal compiler on a minimal chip; +StoneKnifeForth might be a good approach. + +## Blind Alleys + +Here are some things I thought about but didn’t do. + +### Making More Things Into Primitives + +There are straightforward changes to reduce the executable size +further, but they would make the compiler more complicated, not +simpler. Some of the most-referenced routines should be open-coded, +which should also speed it up, as well as making them available to +other programs compiled with the same compiler. Here are the routines +that were called in more than 10 places some time ago: + +``` + 11 0x169 xchg + 13 0xc20 Lit + 22 0x190 - (now replaced by +, which is only used in 25 places) + 25 0x15b pop + 26 0x1bc = + 35 0x13d dup + 60 0x286 . +``` + +Of these, `xchg`, `pop`, `-`, `=`, and `dup` could all be open-coded +at zero or negative cost at the call sites, and then their definitions +and temporary variables could be removed. + +I tried out open-coding `xchg`, `pop`, `dup`, and `+`. The executable +shrank by 346 bytes (from 4223 bytes to 3877 bytes, an 18% reduction; +it also executed 42% fewer instructions to compile itself, from +1,492,993 down to 870,863 on the “trimmed” version of itself), and the +source code stayed almost exactly the same size, at 119 non-comment +lines; the machine-code definitions were one line each. They look +like this: + +``` +dup 'd = [ pop 80 . ; ] ( dup is `push %eax` ) +dup 'p = [ pop 88 . ; ] ( pop is `pop %eax` ) +dup 'x = [ pop 135 . 4 . 36 . ; ] ( xchg is xchg %eax, (%esp) +dup '+ = [ pop 3 . 4 . 36 . 89 . ; ] ( `add [%esp], %eax; pop %ecx` ) +``` + +However, I decided not to do this. The current compiler already +contains 58 bytes of machine code, and this would add another 9 bytes +to that. The high-level Forth definitions (`: dup X ! ;` and the +like) are, I think, easier to understand and verify the correctness +of; and they don’t depend on lower-level details like what +architecture we’re compiling for, or how we represent the stacks. +Additionally, it adds another step to the bootstrap process. + +### Putting the Operand Stack on `%edi` + +Forth uses two stacks: one for procedure nesting (the “return stack”) +and one for parameter passing (the “data stack” or “operand stack”). +This arrangement is shared by other Forth-like languages such as +PostScript and HP calculator programs. Normally, in Forth, unlike in +these other languages, the “return stack” is directly accessible to +the user. + +Right now, StoneKnifeForth stores these two stacks mostly in memory, +although it keeps the top item of the operand stack in `%eax`. The +registers `%esp` and `%ebp` point to the locations of the stacks in +memory; the one that’s currently being used is in `%esp`, and the +other one is in `%ebp`. So the compiler has to emit an `xchg %esp, %ebp` instruction whenever it switches between the two stacks. As a +result, when compiling itself, something like 30% of the instructions +it emits are `xchg %esp, %ebp`. + +Inspired, I think, by colorForth, I considered just keeping the +operand stack pointer in `%edi` and using it directly from there, +rather than swapping it into `%esp`. The x86 has a `stosd` +instruction (GCC calls it `stosl`) which will write a 32-bit value in +`%eax` into memory at `%edi` and increment (or decrement) `%edi` by 4, +which is ideal for pushing values from `%eax` (as in `Lit`, to make +room for the new value). Popping values off the stack, though, +becomes somewhat hairier. The `lodsd` or `lodsl` instruction that +corresponds to `stosl` uses `%esi` instead of `%edi`, you have to set +“DF”, the direction flag, to get it to decrement instead of +incrementing, and like `stosl`, it accesses memory *before* updating +the index register, not after. + +So, although we would eliminate a lot of redundant and ugly `xchg` +instructions in the output, as well as the `Restack`, `u`, `U`, and +`%flush` functions, a bunch of the relatively simple instruction +sequences currently emitted by the compiler would become hairier. +I think the changes are more or less as follows: + +* `!` is currently `pop (%eax); pop %eax`, which is three bytes; this + occurs 17 times in the output. The new code would be: + sub $8, %edi + mov 4(%edi), %ecx + mov %ecx, (%eax) + mov (%edi), %eax + This is ten bytes. `store`, the byte version of `!`, is similar. +* `-` is currently `sub %eax, (%esp); pop %eax`, which is four bytes; + this occurs 23 times in the output. The new code would be seven + bytes: + sub $4, %edi + sub %eax, (%edi) + mov (%edi), %eax + There's something analogous in `<`, although it only occurs three + times. +* in `JZ`, `jnz`, and `Getchar`, there are occurrences of `pop %eax`, + which is one byte (88). The new code would be five bytes: + sub $4, %edi + mov (%edi), %eax + `JZ` occurs 38 times in the output, `jnz` occurs 5 times, and + Getchar occurs once. +* `Msyscall` would change a bit. + +There are 193 occurrences of `push %eax` in the output code at the +moment, each of which is followed by a move-immediate into %eax. +These would just change to `stosd`, which is also one byte. + +So this change would increase the amount of machine code in the +compiler source by 10 - 3 + 7 - 4 + 5 - 1 + 5 - 1 + 5 - 1 = 22 bytes, +which is a lot given that there’s only 58 bytes there now; I think +that would make the compiler harder to follow, although `Restack` does +too. It would also increase the size of the compiler output by (10 - +3) \* 17 + (7 - 4) \* 23 + (5 - 1) \* (38 + 5 + 1) = 364 bytes, although +it would eliminate 430 `xchg %esp, %ebp` instructions, two bytes each, +for a total of 2 \* 430 - 364 = 496 bytes less; and the resulting +program would gain (4 - 2) \* 17 + (3 - 2) \* 23 + (2 - 1) \* (38 + 5 + + +1. = 101 instructions, then lose the 430 `xchg` instructions. + +My initial thought was that it would be silly to space-optimize +popping at the expense of pushing; although they happen the same +number of times during the execution of the program, generally more +data is passed to callees than is returned to callers, so the number +of push sites is greater than the number of pop sites. (In this +program, it’s about a factor of 2, according to the above numbers.) +Also, consumers of values from the stack often want to do something +interesting with the top two values on the stack, not just discard the +top-of-stack: `-` subtracts, `<` compares, `!` and `store` send it to +memory. Only `JZ` and `jnz` (and `pop`) just want to discard +top-of-stack — but to my surprise, they make up half of the pops. + +However, I wasn’t thinking about the number of places in the compiler +where machine code would be added. What if I used `%esi` instead of +`%edi`, to get a single-byte single-instruction pop (in the form of +`lodsl`) instead of a single-byte push? This would make `Lit` (the +only thing that increases the depth of the operand stack) uglier, and +each of the 193 occurrencies of `push %eax` that result from the 193 +calls to `Lit` in the compilation process would get four bytes bigger +(totaling 772 extra bytes) but the seven or so primitives that +*decrease* the depth of the operand stack would gain less extra +complexity. And we’d still lose the `xchg %esp, %ebp` crap, including +the code to avoid emitting them. + +## What’s Next + +Maybe putting the operand stack on `%esi`. + +Maybe factor some commonality out of the implementation of `-` and +`<`. + +If we move the creation of the ELF header and `Msyscall` and `/buf` to +run-time instead of compile-time, we could eliminate the `#` and +`byte` compile-time directives, both from the compiler and the +interpreter; the output would be simpler; `Msyscall` and `/buf` +wouldn't need two separate names and tricky code to poke them into the +output; the tricky code wouldn’t need a nine-line comment explaining +it; the characters ‘E’, ‘L’, and ‘F’ wouldn’t need to be magic +numbers. + +Maybe factor out "0 1 -"! + +Maybe pull the interpreter and compiler code into a literate document +that explains them. + +Maybe building a compiler for a slightly bigger and better language on +top of this one. Maybe something like Lua, Scheme, or Smalltalk. A +first step toward that would be something that makes parsing a little +more convenient. Another step might be to establish some kind of +intermediate representation in the compiler, and perhaps some kind of +pattern-matching facility to make it easier to specify rewrites on the +intermediate representation (either for optimizations or for code +generation). + +Certainly the system as it exists is not that convenient to program +in, the code is pretty hard to read, and when it fails, it is hard to +debug — especially in the compiler, which doesn’t have any way to emit +error messages. Garbage collection, arrays with bounds-checking, +finite maps (associative arrays), strong typing (any typing, really), +dynamic dispatch, some thing that saves you from incorrect stack +effects, metaprogramming, and so on, these would all help; an +interactive REPL would be a useful non-linguistic feature. + +## Copyright status + +I (Kragen Javier Sitaker) wrote StoneKnifeForth in 2008 and published +it immediately in Argentina. I didn't add an explicit copyright +license at the time, but here is one now: + +> [To the extent possible under law, Kragen Javier Sitaker has waived +> all copyright and related or neighboring rights to +> StoneKnifeForth](https://creativecommons.org/publicdomain/zero/1.0/). This +> work is published from: Argentina. + +For more details, I've included the CC0 "legal code" in +[LICENSE.md](/kragen/stoneknifeforth/blob/master/LICENSE.md). + +## Related work + +Andre Adrian’s 2008 BASICO: + +> * is a small imperative programming language that is just powerful +> enough to compile itself (compiler bootstrapping). +> * has no GOTO, but has while-break-wend and multiple return +> * has C-like string handling. +> * is implemented in less then 1000 source code lines for the compiler. +> * produces real binary programs for x86 processors, not P-code or +> Byte-Code. +> * uses the C compiler toolchain (assembler, linker) +> * uses C library functions like printf(), getchar(), strcpy(), +> isdigit(), rand() for run-time support. + +Actually it produces assembly, not executables. + +Version 0.9 was released 15 Jul 2006. The 1000 source lines include a +recursive-descent parser and a hand-coded lexer. + +Sample code: + +``` +// return 1 if ch is in s, 0 else +func in(ch: char, s: array char): int +var i: int +begin + i = 0 + while s[i] # 0 do + if ch = s[i] then + return 1 + endif + i = i + 1 + wend + return 0 +end +``` + +FIRST and THIRD, from [the IOCCC entry](http://www.ioccc.org/1992/buzzard.2.design). + +[Ian Piumarta’s COLA](http://piumarta.com/software/cola/) system. + +Oberon. + +Fabrice Bellard’s [OTCC](https://bellard.org/otcc/). + +[F-83](https://github.com/ForthHub/F83). + +eForth, especially the ITC [eForth](http://www.exemark.com/FORTH/eForthOverviewv5.pdf). + +Jack Crenshaw’s [Let’s Build a Compiler](http://compilers.iecc.com/crenshaw/). This is a how-to book +that walks you through an incrementally-constructed compiler for a toy +language, written in Pascal, in about 340 pages of text. The text is +really easy to read, but it will still take at least three to ten +hours to read. It uses recursive-descent parsing, no intermediate +representation, and it emits 68000 assembly code. + +Ikarus. + +[Ur-Scheme](http://canonical.org/~kragen/sw/urscheme/). + +PyPy. + +Bootstrapping a simple compiler from nothing: +Edmund GRIMLEY EVANS +2001 + + +## About + +a tiny self-hosted Forth implementation + +### Resources + +[Readme](#readme-ov-file) + +### License + +[CC0-1.0 license](#CC0-1.0-1-ov-file) + +### Uh oh! + +There was an error while loading. Please reload this page. + +[Activity](/kragen/stoneknifeforth/activity) + +### Stars + +[**436** +stars](/kragen/stoneknifeforth/stargazers) + +### Watchers + +[**21** +watching](/kragen/stoneknifeforth/watchers) + +### Forks + +[**24** +forks](/kragen/stoneknifeforth/forks) + +[Report repository](/contact/report-content?content_url=https%3A%2F%2Fgithub.com%2Fkragen%2Fstoneknifeforth&report=kragen+%28user%29) + +## [Releases](/kragen/stoneknifeforth/releases) + +No releases published + +## [Packages 0](/users/kragen/packages?repo_name=stoneknifeforth) + +No packages published + +## [Contributors 4](/kragen/stoneknifeforth/graphs/contributors) + +### Uh oh! + +There was an error while loading. Please reload this page. + +## Languages + +* [Forth + 50.1%](/kragen/stoneknifeforth/search?l=forth) +* [C + 23.4%](/kragen/stoneknifeforth/search?l=c) +* [Python + 16.6%](/kragen/stoneknifeforth/search?l=python) +* [Assembly + 7.6%](/kragen/stoneknifeforth/search?l=assembly) +* [Shell + 2.3%](/kragen/stoneknifeforth/search?l=shell) + +## Footer + +© 2026 GitHub, Inc. + +### Footer navigation + +* [Terms](https://docs.github.com/site-policy/github-terms/github-terms-of-service) +* [Privacy](https://docs.github.com/site-policy/privacy-policies/github-privacy-statement) +* [Security](https://github.com/security) +* [Status](https://www.githubstatus.com/) +* [Community](https://github.community/) +* [Docs](https://docs.github.com/) +* [Contact](https://support.github.com?tags=dotcom-footer) +* Manage cookies +* Do not share my personal information + + + +You can’t perform that action at this time. \ No newline at end of file diff --git a/references/ForthNotes/Substack_Article.md b/references/ForthNotes/Substack_Article.md new file mode 100644 index 0000000..82c4b4b --- /dev/null +++ b/references/ForthNotes/Substack_Article.md @@ -0,0 +1,316 @@ +# Substack Article + +**Source:** https://edsabode.substack.com/p/onats-kyra-compiled-forths-a-new + +Onat's KYRA, Compiled FORTHs, a new rabbit hole.. + + + +[![Eds Abode](https://substackcdn.com/image/fetch/$s_!CWqS!,w_40,h_40,c_fill,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F269dc3fe-008b-4f8a-bc69-13c53c840346_376x378.png)](/) + +# [Eds Abode](/) + +SubscribeSign in + +# Onat's KYRA, Compiled FORTHs, a new rabbit hole.. + +[![Ed's avatar](https://substackcdn.com/image/fetch/$s_!_PzK!,w_36,h_36,c_fill,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8fed2663-82a9-4c29-9a20-fab2605e47f3_376x378.png)](https://substack.com/@edsabode) + +[Ed](https://substack.com/@edsabode) + +May 30, 2025 + +2 + +Share + +While on twitter doing the usual engagements, someone linked me a vod of a non-text based editor done entirely in a custom toolchain: + +I can’t write yet on everything that’s going on in this talk. But what I do know is that I will be making time to learn. Below will be notes that I’ve accumulated so far in this pursuit. + +Onat has a website an [article](https://onatto.github.io/lang.html) on KYRA. We immediately learn that its a “concatenative language” derived from offshoots of FORTH. Particularly Moore’s own [colorFORTH](https://colorforth.github.io/cf.htm) along with taking heavy inspiration from Timothy Lottes’s custom compiled Forth-like he worked on throughout the late 2000s up to 2016 at least (his blog is dead and the only archive of it is a github [repo](https://github.com/gomson/TimothyLottes.github.io)). + +[![](https://substackcdn.com/image/fetch/$s_!Dx2Y!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1cb08da-0b75-4db5-b33a-0040de289d41_1920x1080.png)](https://substackcdn.com/image/fetch/$s_!Dx2Y!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1cb08da-0b75-4db5-b33a-0040de289d41_1920x1080.png) + +[![](https://substackcdn.com/image/fetch/$s_!7nj0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e2a374d-a99f-4a64-bd07-b36ef76e625d_1920x1080.png)](https://substackcdn.com/image/fetch/$s_!7nj0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e2a374d-a99f-4a64-bd07-b36ef76e625d_1920x1080.png) + +Edit - Older Vod from 2020: + +--- + +## TimothyLottes.github.io + +I will catalogue below all the relevant pages from Timothy Lottes’s archived blog. They can previewed without download a zip archive with the preview button on the top right-corner of github’s text viewer: + +[![](https://substackcdn.com/image/fetch/$s_!sFJ6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c5bb33e-94db-4eeb-a5d2-b6a3e99519b1_1258x269.png)](https://substackcdn.com/image/fetch/$s_!sFJ6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c5bb33e-94db-4eeb-a5d2-b6a3e99519b1_1258x269.png) + +* [20070910 - 2 4th | !2 4th](https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20070910.html) +* [20070912 - The Making of a Font](https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20070912.html) +* [20070915 - Building the Chicken Without an Egg](https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20070915.html) +* [20070919 - Editor Working](https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20070919.html) +* [20070921 - Assembler in Atom4th](https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20070921.html) + + [![](https://substackcdn.com/image/fetch/$s_!APbi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81401d69-cd06-4ec5-ad3c-c1357ff9577e_640x480.jpeg)](https://substackcdn.com/image/fetch/$s_!APbi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81401d69-cd06-4ec5-ad3c-c1357ff9577e_640x480.jpeg) +* [20140816 - Vintage Programming](https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20140816.html) + +[![](https://substackcdn.com/image/fetch/$s_!_ApA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde18f837-12fd-4edc-b265-7ecd2371bb8a_640x640.png)](https://substackcdn.com/image/fetch/$s_!_ApA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde18f837-12fd-4edc-b265-7ecd2371bb8a_640x640.png) + +* [20141231 - Continued Notes on Custom Language](https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20141231.html) +* [20150414 - From Scratch Bug](https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20150414.html) +* [20150420 - From Scratch Bug 2 : Source-Less Programming](https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20150420.html) + + + [20150422 - Source-Less Programming : 2](https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20150422.html) + + [20150423 - Source-Less Programming : 3](https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20150423.html) + + [20150424 - Source-Less Programming : 4](https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20150424.html) + + [20150426 - Source-Less Programming : 5](https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20150426.html) +* [20150710 - Inspiration Reboot](https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20150710.html) +* [20150714 - 1536-1 : The Programmer Addiction = Feedback](https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20150714.html) + + + [20150715 - 1536-2 : Assembling From the Nothing](https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20150715.html) + + [20150722 - 1536-3 : Simplify, Repeat](https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20150722.html) + + [20150809 - 1536-4 : Coloring](https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20150809.html) + + [![](https://substackcdn.com/image/fetch/$s_!Sc2T!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0799032f-f2d8-43ec-a7ee-bf3b8fcdc16f_640x400.png)](https://substackcdn.com/image/fetch/$s_!Sc2T!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0799032f-f2d8-43ec-a7ee-bf3b8fcdc16f_640x400.png) + + [20150810 - 1536-5 : Keys](https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20150810.html) + + [![](https://substackcdn.com/image/fetch/$s_!wv3-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faff0bdf1-272a-4d85-929e-3a9d7917c628_640x400.png)](https://substackcdn.com/image/fetch/$s_!wv3-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faff0bdf1-272a-4d85-929e-3a9d7917c628_640x400.png) +* [20151113 - Rethinking the Symbolic Dictionary](https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20151113.html) +* [20151222 - Random Holiday 2015](https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20151222.html) +* [20161113 - Vintage Programming 2](https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20161113.html) +* github.com/TimothyLottes/A (DEAD) + +--- + +The above is great and all, but very difficult to enter the world of if you don’t have any assembly background. In my case; I’ve only recently began to focus on curating my C, C++ and more recently: Odin code more closely; as of being introduced to the “Handmade” communities around 2019. With the furthest I’ve gone being reducing runtime symbol pollution, making sure my code paths and data structures are simple and sane. I can read disassembly to a useful extent… So what’s the best place to start? + +As with most things I find it’s easiest to learn something by constructive a narrative to world build off of. So gaining a historical perspective of FORTH’s development and attempting to chain that in with some “Trial By Fire” guide to forth and a “compiled” FORTH. Most forths have this interpreter layer and operation with how they behave that seems to act as a mock repl or editor. From what I can tell Onat’s and Lottes’s goals are something else, where the editor provided that mechanism not the “language” processing layer. + +* The classic *start* page for FORTH: [Forth Language](https://wiki.c2.com/?ForthLanguage) + + + History and more laid out there + + *StartingForth* book.. +* [jonesforth.S](https://github.com/nornagon/jonesforth/blob/master/jonesforth.S) seems to be the best introduction to the original language. + +After I finish my initial knowledge base curation I think I’ll start with getting jonesforth ported to a windows x64 process sandbox. I’ll need to learn dealing with assembly directly. I’ll probably will go with GAS, FASM, or MASM, whichever provides an easier debugging experience. The original source is targeting x86-32 linux. I could try to get that ported to work on a steam deck instead after as well… Much to digest. + +2 + +Share + +#### Discussion about this post + +CommentsRestacks + +![User's avatar](https://substackcdn.com/image/fetch/$s_!TnFC!,w_32,h_32,c_fill,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack.com%2Fimg%2Favatars%2Fdefault-light.png) + +TopLatest + +No posts + +### Ready for more? + +Subscribe + +© 2026 Ed · [Privacy](https://substack.com/privacy) ∙ [Terms](https://substack.com/tos) ∙ [Collection notice](https://substack.com/ccpa#personal-data-collected) + +[Start your Substack](https://substack.com/signup?utm_source=substack&utm_medium=web&utm_content=footer)[Get the app](https://substack.com/app/app-store-redirect?utm_campaign=app-marketing&utm_content=web-footer-button) + +[Substack](https://substack.com) is the home for great culture + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +This site requires JavaScript to run correctly. Please [turn on JavaScript](https://enable-javascript.com/) or unblock scripts \ No newline at end of file diff --git a/references/ForthNotes/Threaded_code.md b/references/ForthNotes/Threaded_code.md new file mode 100644 index 0000000..40446ba --- /dev/null +++ b/references/ForthNotes/Threaded_code.md @@ -0,0 +1,315 @@ +# Threaded code + +**Source:** https://muforth.dev/threaded-code/ + +Threaded code – muforth + + +# Threaded code + +--- + +My aim here is to tackle threaded code: What it is, why it is, how it works, and why it’s great (and not so great). + +Rather than starting with a definition and then attempting an explanation of the definition, I want to start with a thought experiment. + +Take a program. Then refactor it in such a way that it consists entirely of only two kinds of routines: + +* leaf routines, which compute and do I/O, but which make no calls to other code +* twig routines, which do *no* computation or I/O; instead, they *only* call other code (which can be twig or leaf routines) + +(I was tempted to use the usual tree-structure names of “leaf” and “branch”, but branch is overloaded with the idea of a jump, which might be confusing in this context. So: twig.) + +The performance-minded among you are now aghast. “What? No open-coded arithmetic? No inlining of functions?” + +Yes, it’s true. Our restructuring has a performance cost, but it has advantages too. We’ll get to both. + +Since our twig routines now consist entirely of calls (except for the last instruction, a “return”) we can remove the call opcodes. We end up with a list of addresses. The return instruction that ended our original routine is replaced by the address of a special “exit” routine. + +The tail-recursively-minded among you will have already objected “But that last call and return can be replaced by a jump!” Not so with threaded code. There is no way to say we want to “jump” to an address rather than “call” it, so we lose the ability to convert tail calls to jumps. Twig routines always end with the address of the “exit” routine. Another disadvantage to threading. However, we soldier on. + +With the opcodes removed, our twig routines are no longer code. We can’t “call” one and expect anything good to happen. The CPU will happily start interpreting the list of addresses as instructions and head off into the weeds. + +We need a *header* of some kind that tells the CPU that this is not a leaf routine (which we haven’t changed – leaf routines are still machine code) but a twig routine. The header is generally a call to *another* special “runtime” routine. What should this routine do? Because we have been *called*, we must have been called by another twig routine. Just as with machine code that calls other machine code, we need to push a call stack of some kind. But what do we push onto the stack? + +Let’s back up. We haven’t talked about *how we are interpreting the list of addresses* that make up the body of a twig routine. + +We need a tiny piece of code somewhere that fetches the next address and “executes” the routine that it points to. (I am being purposely vague here.) We are fetching and executing “instructions”, which means we need our own “program counter” or “address pointer” or whatever you want to call it, which will always point to the next “instruction” (really an address) to execute. In the Forth world this pointer is usually called **IP** – the “instruction” (or perhaps “interpretation”) pointer. Our tiny piece of code will fetch the “instruction” (address) that IP points to, increment IP by the size (in bytes) of an address, and then somehow “execute” the code at that address. + +I’m not sure about other language communities, but in the Forth community this tiny piece of code is called **NEXT**. Its only job: to execute the next address in the list. + +Now that we have an idea of what it means to execute a list of addresses, what happens when a twig routine calls another twig routine? In order to interpret the list of addresses in the *called* twig routine we have to set IP to point to the *first* of the list of addresses and then run NEXT. But at that moment IP points to the place in the caller’s list of addresses that we should return to, and we don’t want to clobber it, otherwise we would “lose our place” in the execution of the calling twig routine. + +Thus, before setting IP to point to the first address in the called word, we have to push the caller’s IP onto our call stack. + +And this is *precisely* the code that the header of our twig routine calls. I call it **NEST**. It is often called **DOCOLON** (for reasons that should become clear later). + +The dual of this – the special “exit” routine alluded to above, the address of which ends every list of addresses in a twig routine – I call **UNNEST**. It pops the previous IP off the call stack, and then runs NEXT, thus resuming interpretation in the calling twig routine. (Many Forths call this **EXIT**, for obvious reasons.) + +We have all the pieces now, but a few questions remain. Where is NEXT? And *what* is NEXT? + +We can do another thought experiment. Let’s say we are executing NEST. We push the caller’s IP, set IP to point to the first address in our called twig routine... And then what? Do we return? If so, to what? There isn’t a “main” machine code routine to return to. Weirdly, there isn’t a loop somewhere that repeatedly executes NEXT. Instead, NEXT is *everywhere*. + +Every leaf routine ends, not with a return instruction, but with NEXT. NEST ends with NEXT. UNNEST ends with NEXT. + +To “fire up” this interpreter, all we have to do is set IP to point somewhere, and then execute NEXT. Any NEXT. Anywhere. At this point, our threaded code interpreter is off and running. + +To recap: We need three small routines to make all this work: NEXT, NEST, and UNNEST. + +``` + NEXT: Fetch the address pointed to by IP + Increment IP by address size + Jump to fetched address +``` + +``` + NEST: Push IP onto call stack + Set IP to point to the first address of the called twig routine + Execute NEXT +``` + +``` + UNNEST: Pop IP from call stack + Execute NEXT +``` + +Because NEXT is short – often one to three instructions – it is usually copied inline into the body of NEST, UNNEST, and any other leaf routines. + +### [Direct-threaded code (DTC)](#direct-threaded-code-dtc) + +What I have just described is usually referred to as *direct-threaded code* (DTC). It is *direct* because NEXT jumps directly to the address fetched from the list of addresses that make up the body of a twig routine. + +Because Forth has two stacks – a data (or parameter) stack, and a return (or call) stack, we should be clear that NEST and UNNEST push and pop the *return* stack (often called the R stack). In fact, I don’t see how this threading model can work with a single stack. + +(Side note: Forth’s call stack and the machine’s call stack do not have to be the same! And often they are not. If the machine has push and pop operations it is usually more efficient to use the machine’s call stack as the Forth data stack, and to put the Forth call stack (the return, or “R” stack) somewhere else.) + +It’s not clear from my description above how NEST computes the new IP (the address of the first address in the list). There are two ways to do it. + +If the “header” of the twig routine is a *call* to NEST, then NEST can pop the (machine’s) call stack. The popped address will be the address of the first address in the list. (This is the semantics of any call instruction: push the following address onto the machine’s call stack, then jump to the destination. We are “misusing” call to push the address of the list of addresses, which immediately follow the call in memory.) + +But there is another way, and it’s often more efficient. We designate another pointer register – often called W (for “word”, as pieces of Forth code are usually referred to as “words”) – for use by NEXT and NEST, and modify them thus: + +``` + NEXT: Fetch into W the address pointed to by IP + Increment IP by address size + Jump to W +``` + +``` + NEST: Push IP onto call stack + Set IP to W + sizeof(Jump) + Execute NEXT +``` + +Now the “call NEST” is replaced by “jump NEST” in the twig routine’s header. Since W points to the header, by offseting it (by the size of the jump instruction), we can calculate the address of the first address in the list, which directly follows the jump to NEST. We set IP to this address. + +Our two kinds of words – leaf and twig – now look like this: + +``` + leaf word twig word + ~~~~~~~~~ ~~~~~~~~~ + machine code jump NEST + machine code address 1 + ... address 2 + machine code ... + NEXT address n + address of UNNEST +``` + +When NEXT executes a leaf word, that “Jump to W” jumps directly to machine code. But when it executes a twig word, it jumps to a jump. We all know how terrible this is! Pipeline refill time! + +What if we replaced this “code indirection” – a jump to a jump – with a *data* indirection? + +Enter... + +### [Indirect-threaded code (ITC)](#indirect-threaded-code-itc) + +By replacing the jump NEST (or call NEST) instruction at the beginning of every twig word with a *pointer* to NEST, and by adding an indirection to NEXT: + +``` + NEXT: Fetch into W the address pointed to by IP + Increment IP by address size + Fetch into X the address pointed to by W + Jump to X +``` + +and by making a small change to NEST: + +``` + NEST: Push IP onto call stack + Set IP to W + address size + Execute NEXT +``` + +we arrive at indirect-threaded code, also known as ITC. + +Remember: DTC is *direct* because NEXT jumps directly to the address fetched from the list of addresses that make up the body of a twig routine. + +Thus: ITC is *indirect* because NEXT jumps indirectly *through* the address fetched from the list of addresses that make up the body of a twig routine. + +I’ve written the above version of ITC NEXT the way you would write it for a RISC machine. A CISC machine with auto-increment addressing can collapse the first two instructions into one; one with indirect addressing can collapse the last two into one. + +ITC NEXT is two instructions on the MSP430, and four – basically the four steps outlined above – on RISC-V. + +There is another change we need to make for indirect threading to work. With DTC the bodies of both leaf and twig words started with *machine code*; with ITC, the bodies of both have to start with a *pointer to machine code*. + +Which means we have to change our leaf words for ITC. We add a machine code pointer that simply points to the code that follows it. + +``` + leaf word twig word + +----------+ +----------+ + | addr |---+ | addr |-------> NEST + +----------+ | +----------+ + machine code <-+ address 1 + machine code address 2 + ... ... + machine code address n + NEXT address of UNNEST +``` + +### [Useful nomenclature](#useful-nomenclature) + +Since it’s tricky to explain all this, it’s useful to have a common vocabulary when talking about threading and the structure of words in a threaded system. Again, since it’s what I’m familiar with, I’m going to use the Forth terminology. + +The machine code pointer at the start of every word in an ITC system is called a **code pointer**. + +That first slot of a word – in both ITC and DTC systems – is called the **code field**, and the body that follows – machine code in the case of a leaf word, and addresses in a twig word – is called the **parameter field**. + +Leaf words are called **code** words, and twig words are called **colon** words. These names come from the Forth words that construct them: `code` and `:`. + +Since we would like to be able to think and talk clearly about indirection, we give names to two important addresses: + +* The address of a code field is called, unsurprisingly, a **code field address** – usually abbreviated **cfa**. +* The address of a parameter field is called, also unsurprisingly, a **parameter field address** – usually abbreviated **pfa**. + +In a DTC system, a cfa points to a code field, which *contains* machine code. + +In an ITC system, a cfa points to a code field, which *points to* machine code. + +In both cases, the addresses in the body (parameter field) of a colon word (twig word) are all cfa’s. (Note: It’s possible to use pfa’s instead, and [there are good reasons to do this](/threaded-code-variations/). + +### [Everything is executable!](#everything-is-executable) + +We are not yet at the end of our story! + +It turns out that code and colon (leaf and twig) words are *not* the only kinds of words in a threaded code system. What about data? + +I’ll use the examples of two common Forth data types: variables and constants + +While there are probably other approaches, on threaded Forth systems everything in the system – including data types! – has executable behavior. You can – and indeed *must* – execute *everything*. (Curiously, in this way a threaded Forth is somewhat like Lisp: code and data are isomorphic.) + +What might it mean to *execute* a variable or a constant? Let’s start with constants, since they are simpler (though both are straightforward). + +A constant pushes its value onto the data stack. That’s it! + +Can we turn this *idea* of a constant into a structure in memory that will work with our threaded interpreter? After defining a constant called `hex-fives` with the value 5555\_5555, we would have the following representation in memory: + +``` + DTC ITC + hex-fives hex-fives + ~~~~~~~~~ ~~~~~~~~~ + jump to CONSTANT address of CONSTANT (code field) + 5555_5555 5555_5555 (parameter field) +``` + +In both cases – DTC and ITC – the representation consists of a code field and a parameter field – just like code and colon words. Whereas colon words have a code field that refers to NEST, constants have a code field that refers to CONSTANT, which looks like this: + +``` + CONSTANT: Add to W the size of the code field (calculate pfa) + Fetch value pointed to by W into W (fetch contents) + Push W onto the data stack + Execute NEXT +``` + +Remember that after executing NEXT, W contains a cfa: it points to the code field, *not* the parameter field. (Actually, this isn’t [written in stone](/threaded-code-variations/).) + +If we use `hex-fives` in a colon word, it gets compiled like any other word. To add `hex-fives` to the value on the top of the data stack, we would compile the following address list: + +``` + address of hex-fives + address of + +``` + +Variables are only slightly more complicated. Variables in Forth are treated like ML references: you have to explicitly dereference them. There are two words to do this: `@` (“fetch”) and `!` (“store”). `@` consumes an address from the data stack, fetches its value from memory, and pushes that value onto to the data stack; `!` consumes a value and an address from the data stack, and stores the value at that address in memory. + +What does a variable *do*? It pushes the *address* of its value onto the data stack. + +Variables look like this: + +``` + DTC ITC + radix radix + ~~~~~~~~~ ~~~~~~~~~ + jump to VARIABLE address of VARIABLE (code field) + 2 2 (parameter field) +``` + +Here we have a variable called “radix” with the current value 2 (we are in binary). + +The code that all variables execute is remarkably similar to CONSTANT. Where CONSTANT pushed *value* stored in the parameter field, VARIABLE pushes the *address* of the parameter field – the **pfa**. + +``` + VARIABLE: Add to W the size of the code field (calculate pfa) + Push W onto the data stack (push pfa) + Execute NEXT +``` + +Simple examples: + +``` + radix @ +``` + +fetches the current value; + +``` + 10 radix ! +``` + +changes the radix to 10 (now we are in decimal). + +It is out of the scope of this discussion, but every Forth system has mechanisms for creating new kinds of data with their own, specific execution behaviors. + +### [Threaded code advantages](#threaded-code-advantages) + +Elegance, simplicity, uniformity, code density. + +It’s quite easy to bring up a threaded-code implementation on a new architecture, and, once running, high-level tools written for a completely different architecture are likely to work unmodified, or with very small modifications. + +The structural uniformity makes it very easy to extend and modify *without changing the underlying implementation*. I can add new data structures and new control structures at will without modifying the core compiler. + +Because we cannot inline code, everything becomes a separate word. This has an interesting side effect: it aggressively removes *redundancy* from programs, which tend to become much smaller. + +On occasion, threading is actually *faster* than native code. In native code a subroutine call requires the equivalent of two jumps: the call, and the return. On pipelined machines these can take several cycles. + +When executing code words in a threaded system, only *one* jump is required! Only *one* execution of NEXT is required to execute a word. As a result, on some systems, DTC can be faster than call/return, and ITC is often no worse than call/return (but much more powerful). + +### [Threaded code disadvantages](#threaded-code-disadvantages) + +Speed, and, sometimes, size. + +Since we lose the ablitily to do any kind of code inlining, even simple things like “add these two numbers” have to be written as separate routines and “called” via NEXT. This is obviously slower than inlining. + +In terms of size, on processors where an instruction is smaller than an address – eg, on 32-bit machines with 16-bit instructions – native code can sometimes be denser, but generally the “deduplication” that threading encourages will offset this. + +### [Conclusions](#conclusions) + +Threaded code is an extraordinarily simple and elegant way to implement language interpreters. Compared to bytecoded interpreters it is quite fast, and compilers for it are essentially trivial. + +Because it creates a system entirely composed of uniform pieces, extensibility of the system by users is almost unlimited, and building generic tools is dramatically simplified! + +All this for a modest execution time penalty... ;-) + +### [To explore further](#to-explore-further) + +Read about [threaded code variations](/threaded-code-variations/). I talk about why sometimes it makes sense to put pfa’s rather than cfa’s into address lists (colon word bodies). + +Read about [literals, ifs, and loops](/threaded-code-literals-ifs-and-loops/) in threaded code systems. I’ve suggested here that all colon words consist of a list of addresses that are executed in sequence. Real code branches and loops. And uses literal numbers. + +Read about the [difference between a “call” instruction and a “branch-and-link” instruction](/call-versus-branch-and-link/), and how both relate to threaded code. + +--- + +[Send feedback](/cdn-cgi/l/email-protection#3b1e0c0c1e0d0e1e0d091e0d031e0d0a1e0d5f1e0c081e0c0f1e0d0e1e0c091e0f0b1e0d5e1e0d021e0d5f1e0d091e0d581e0d0e1e0d5f1e0d0a1e0d081e0d031e0d021e0d5e1e0d0e1e0c081e095e1e0d081e0d5d1e0d5f04484e59515e584f061e0e59564e5d54494f531e0e5f1e090b6f53495e5a5f5e5f1e090b58545f5e) on this page (last edited 2021 June 07) +Browse [all pages](/all-pages/) +Return [home](/) \ No newline at end of file diff --git a/references/ForthNotes/Variations.md b/references/ForthNotes/Variations.md new file mode 100644 index 0000000..821a4c2 --- /dev/null +++ b/references/ForthNotes/Variations.md @@ -0,0 +1,117 @@ +# Variations + +**Source:** https://muforth.dev/threaded-code-variations/ + +Threaded code: Variations – muforth + + +# Threaded code: Variations + +--- + +### [Address lists: cfa’s or pfa’s?](#address-lists:-cfas-or-pfas) + +In my introduction to [threaded code](/threaded-code/) I mentioned that colon word bodies consist of a list of cfa’s (code field addresses), but that sometimes it makes sense to use pfa’s instead. We are going to explore that idea here. + +First, let’s recap the definitions: + +The address of a code field is called, unsurprisingly, a **code field address** – usually abbreviated **cfa**. + +The address of a parameter field is called, also unsurprisingly, a **parameter field address** – usually abbreviated **pfa**. + +In a DTC system, a cfa points to a code field, which *contains* machine code. + +In an ITC system, a cfa points to a code field, which *points to* machine code. + +The main reason for using cfa’s in address lists is that it’s the *obvious* thing to do. The cfa points to the code field, which we either jump *to* (DTC) or jump *through* (ITC). Why would we want to use anything else? + +The answer is suggested not by the code of NEXT, but by NEST, VARIABLE, and CONSTANT – the “runtime” routines for colon words, variables, and constants, respectively. Let’s look at them again: + +``` + DTC_NEST: Push IP onto call stack + Set IP to W + sizeof(Jump) + Execute NEXT +``` + +``` + ITC_NEST: Push IP onto call stack + Set IP to W + address size + Execute NEXT +``` + +``` + VARIABLE: Add to W the size of the code field (ie, calculate pfa) + Push W onto the data stack (push pfa) + Execute NEXT +``` + +``` + CONSTANT: Add to W the size of the code field (calculate pfa) + Fetch value pointed to by W into W (fetch contents of parameter field) + Push W onto the data stack + Execute NEXT +``` + +Whether calculating the new IP in NEST, or calculating the address of the value in VARIABLE and CONSTANT, we are always adding an offset to W. Because of how NEXT works, W contains the cfa. We want the pfa. + +Whenever a programmer creates a new data type that has an assembler runtime (using `;code`) they have to do this same arithmetic on W. Why not do it one place? + +The natural “one place” is in NEXT. So what would we change? Our aim is to exit NEXT with W containing a pfa instead of a cfa. + +Let’s look at DTC first. Here is DTC NEXT: + +``` + NEXT: Fetch into W the address pointed to by IP + Increment IP by address size + Jump to W +``` + +We have conflicting requirements here. For DTC we have to jump *to* the code field. We have no choice there. But somehow we want W to point to the parameter field – one memory cell higher. How to do both? + +If the address list contains cfa’s, then the first step of NEXT will put a cfa into W. Can we jump to W and increment it in one instruction? Not likely. + +What about using pfa’s in the address list. Does this help? W will have the right value when we exit from NEXT, but can we jump to W minus an offset? It depends on the machine. And it might make NEXT longer – possibly significantly longer. + +On some machines the best way to do DTC NEXT doesn’t involve W at all. For example, on the MSP430 the shortest DTC NEXT is one instruction: + +``` + mov pc, (ip)+ +``` + +This does the auto-increment of IP and the jump to the fetched cfa, but leaves to the runtimes the computation of the pfa. This approach requires that code fields contain *calls* rather than *jumps* in order to “capture” the pfa somewhere (it gets pushed onto the machine’s call stack). + +DTC doesn’t offer a lot of wiggle room. Maybe ITC is better. Let’s take a look. + +Here is ITC NEXT: + +``` + NEXT: Fetch into W the address pointed to by IP + Increment IP by address size + Fetch into X the address pointed to by W + Jump to X +``` + +As we did with DTC, let’s start with the case where address lists contain cfa’s. Just as with DTC NEXT, the first step of ITC NEXT loads a cfa into W. On a machine with auto-increment addressing we can have the “Fetch into X” step increment W so that when we get to NEST (or one of the other “runtimes”) W will contain the pfa. + +It might take an extra cycle (it does on the MSP430) but because in every case except executing a code word we will have to take at least a cycle to do arithmetic on W, it might make sense to auto-increment instead. It’s also less error-prone to do it, correctly, in one place. (This is what I have done in the MSP430 ITC kernel.) + +If we *don’t* have auto-increment (eg, most true RISC machines – ARM (excepting v6-M) doesn’t count ;-) but can use a *negative offset* in our memory access instructions, then it makes sense to use pfa’s in our address lists instead of cfa’s. If we do this, the first step of NEXT loads W with a pfa, which is what we want. But the “Fetch into X” step needs to load from the cfa instead, so we offset *backwards* by the size of an address. This sounds convoluted, but it’s actually the most efficient approach. + +Here is that version of ITC NEXT: + +``` + NEXT: Fetch into W the address pointed to by IP (this is a pfa, not a cfa!) + Increment IP by address size + Fetch into X the address pointed to by (W - address size) + Jump to X +``` + +This is what I have done for the RISC-V ITC NEXT. + +You have to work *with* the strengths and *against* the weaknesses of your architecture – not the other way around! There is no fixed answer. Using cfa’s is not always the “perfect and beautiful” approach. Nor is using pfa’s. It pays to tinker and draw pictures and pay attention to instruction cycle-times and sizes. + +--- + +[Send feedback](/cdn-cgi/l/email-protection#0c293b3b293a39293a3e293a34293a3d293a68293b3f293b38293a39293b3e29383c293a69293a35293a68293a3e293a6f293a39293a68293a3d293a3f293a34293a35293a69293a39293b3f293e69293a3f293a6a293a68337f796e66696f783129396e61796a637e7864293968293e3c58647e696d686968293e3c6f636869293f6d293e3c5a6d7e656d786563627f) on this page (last edited 2017 April 24) +Browse [all pages](/all-pages/) +Return [home](/) \ No newline at end of file diff --git a/references/ForthNotes/Website.md b/references/ForthNotes/Website.md new file mode 100644 index 0000000..583d49c --- /dev/null +++ b/references/ForthNotes/Website.md @@ -0,0 +1,17 @@ +# Website + +**Source:** https://wiki.c2.com + +**notice** + +javascript required to view this site + +**why** + +measured improvement in server performance + +awesome incremental search + +![](spin.gif) + +This site uses features not available in older browsers. \ No newline at end of file diff --git a/references/ForthNotes/Website_-_Bit_Test_Complement.md b/references/ForthNotes/Website_-_Bit_Test_Complement.md new file mode 100644 index 0000000..9539a0e --- /dev/null +++ b/references/ForthNotes/Website_-_Bit_Test_Complement.md @@ -0,0 +1,158 @@ +# Website - Bit Test Complement + +**Source:** https://onatto.github.io/lang.html + +Bit Test Complement + + + +Bit Test Complement + +[Home](index.html) +[Language](lang.html) +[Journey](journey.html) +[Art](videos.html) +[Blog](blog.html) + +## The Kyra Language + +``` +Kyra is an avant-garde concatenative language, built with entirely different principles from status quo and other forth-like languages. +The language is incredibly efficient for those who know how to wield it, I really can't go back to coding in C-like for personal stuff anymore. +It's a foundational meta-language built from first-principles, doesn't make any assumptions about runtime or the problems it solves. +It molds into whatever language needs to exist to solve given problems freely and usually much more efficiently than in other languages. +It builds on a simple design I got inspired from Timothy Lottes, an enigmatic legendary coder who understood Forth philosophy more than any. + +The core idea is to invent new 'languages' to generate whatever we need to solve the problem at hand. +Concatenative nature lets compose words naturally, can invent a comfortable language whatever the problem is. + +Programming is still stuck with cruft of the old, while having long forgotten important wisdom of the old, namely the Forth philosophy. +This philosophy piqued my curiousity around 2017, I didn't understand it fully until I built and coded a lot in Kyra. +I don't think most people who've coded in Forth understand it either. +They're either thinking too complex from implementation or philosophy perspective, mostly stuck in dogma from the past. + +Coming from the C paradigm, coding freeform like this without any rules is already hard, it's especially hard without a proper IDE. +It's also quite unsafe, no types, no safety-belts, which are unnecessary anyway, although the world disagrees with this. + +The compiler is implemented in 1800 bytes of x64 assembly, rest of the IDE is written in C, soon to be bootstrapped. +The editor uses compute-only Vulkan with GPA profiling for AMD, utilizing GPU pointers and bindless. + +![](stuff/html.png) + +Even this sites HTML/CSS is defined/generated in Kyra + + +![](stuff/markdown.png) + +Custom Markdown-like lite language for content, freeform, parsed in Kyra generating HTML +``` + +## Conciseness/Expressivity + +``` +The language lets writing code as concise as possible from scratch, usually much more so than other languages. +Here's some figures for a codebase totalling 4K lines of code, no cheating via external/stdlib code: + +- Complete x64 assembler, fastest in the world, in only 192 lines + - All base instructions, all SSE instructions without VEX-prefix, all addressing modes including RIP-relative + - Tiny in size, generated 194 instructions/756 bytes of x64 code + 3KB for instruction descriptor tables + - Hyper-optimized, millions of instructions generated per second per core + - Ryzen5900HX @3.6Ghz: 180M instr/second/core + - Ryzen1700X @3.4Ghz: 105M instr/second/core + - Ryzen2500U @2.0Ghz: 80M instr/second/core +- Compute-only SPIRV assembler with type checking and swizzles in 768 lines, rust-gpu is 23k lines in comparison + - Compiling shaders in <5ms (cached, mostly driver validation overhead) by generating SPIR-V fed to the driver directly + This bypasses glslang > file.out > hotload > fread > driver overhead entirely, which is ~100x faster. +- Line-based SDF font renderer 128 lines, custom font definition in 192 lines. +- HTML/CSS language which this site is generated in, totaling 448 lines along with a simple markdown-like format + - Building this whole site takes <10ms, most of it spent on file I/O +- Self-Gravitational Spin Systems in 256 lines defining 4 shaders +``` + +## Instant Iteration + +``` +Ideally everything should be instant: compiling, editing, testing, visualization, debugging, intellisense... + +Currently my code compiles around 1-2 ms unless I'm dealing with external code such as the Vulkan driver or Capstone. +Less than 10ms iteration times(less than a frame) makes even 1 second feel like an eternity. +Instead of taking large steps, I take small steps which leads to a lot less bugs with instant testing. + +I once had compiles go up to 5ms, profiled to understand why(thousand paper cuts), then optimized it back to 1ms in assembly. +This might seem extreme but performance regressions are cumulative, they're best profiled, understood and solved when they surface. +So when I see other languages compiling in seconds up to a minute I feel sad that no one thinks this is a big problem. +As usual with the attitude of programmers towards performance, compile-time performance too gets swept under the rug to be solved later. +Which is the worst time to solve this problem because you're left speculating where the papercuts may be after big offenders are gone. + +Actually even 1ms is relatively long, in the next iteration of the language I plan to bring this down to sub-millisecond range. +``` + +## Performance/Optimizability + +``` +Optimal performance means squeezing every bit of given hardware instead of relying on compilers to generate good code. + +Optimal performance everywhere doesn't matter when most code will be cold, so we can afford to generate less than optimal code. +When code is hot, we need to be consistently reason about the generated code instead of having to check if compiler is being stupid. + +I eventually figured out optimal performance from a high-level representation is essentially impossible, it's literally an AI problem. +No compiler can hope to write generate as good as handwritten assembly by a coder who knows what they're doing in total control. +What matters is that code remains optimizable instead of magic optimizations applied everywhere, I want less magic, more control/optimizability. + +Optimal register allocation across functions is unnecesarily complex and unreliable, a human mind can do this way better and reliable than a compiler. +Trying to be optimal regarding spills(3ns each) here and there won't help performance unless that code is hot. +Although thousand paper cuts kills performance real quick, it's bad to be equally slow everywhere, like having a stack machine or garbage collection. +``` + +## Profiling + +``` +Crucial to performance, we need to be able to profile a section or entirety of our codebase, continously and instantly within the IDE. +Continous profiling is especially crucial to track down performance regressions instead of trying to fix them later. +I use inline RDTSC for extreme fine-grained CPU profiling, sokol_time is quite nice/minimal for coarse-grained. +I've got integrated GPU profiling via AMD GPA. +Also examining generated GPU assembly is illuminating both for performance, debugging or getting angry at compilers shipped in drivers. +``` + +## Crash Resilience + +``` +Integrating the IDE and the app into a single program for instant-iteration is great until you hard-crash, which breaks the flow. +With crash-resilence the IDE not only survives the (soft)crash but also gives a full callstack. +This is especially necessary for environments like in VR where a crash is catastrophic, restart takes longer than desktop. +``` + +## Debuggability + +``` +Instant iteration makes debugging mostly trivial when workflow is making small changes followed by testing immediately. +There can be only few things going wrong with this kind of workflow, it works out quite well so I don't need much debugging. +Although sometimes things will go wrong and even with crash-resilience the IDE crashes. +This isn't too bad as it takes <1s to restart, still somewhat annoying once I've gotten used to not hard-crashing at all. +The debugger is still in research, I'll probably eventually write an external debugger, didn't have to so far. +Need disassembly+register dump for the crash site, that mostly gives enough of an idea how things have gone wrong. +``` + +## Visulization + +``` +Visualization is fundamental, before any output happens we've no idea whether the code we've written actually works. +A lot of the time in programming is spent on writing printfs just so we can understand what is going on. +With instant-iteration, having a few words which help with visualisation is good enough but this kind of UX can be vastly improved. +I still haven't implemented the ultimate immediate no-code visualization yet, I have a few approaches for the next iteration. +``` + +## Navigability + +``` +Also called 'intellisense', I can jump instantly to the definition and occurances of a word/variable, solved elegantly requiring minimal energy. +I can even visualize with a single word in which order given words are executed, quite handy and lacking in other languages. +However, I don't have code completion because it's not needed when most words are quite short. +``` + +## Version Control + +``` +The current IDE features custom builtin version control with up to 512 undo/redos for each version, no merge, single branch, quite good for a single developer. +I've got a few ideas for a version control system that works with multiple developers, no time or need to implement it yet. +``` \ No newline at end of file diff --git a/references/ForthNotes/Wikipedia.md b/references/ForthNotes/Wikipedia.md new file mode 100644 index 0000000..ba61a72 --- /dev/null +++ b/references/ForthNotes/Wikipedia.md @@ -0,0 +1,275 @@ +# Wikipedia + +**Source:** https://en.wikipedia.org/wiki/Concatenative_programming_language + +Concatenative programming language - Wikipedia + +[Jump to content](#bodyContent) + +Main menu + +Main menu + +move to sidebar +hide + +Navigation + +* [Main page](/wiki/Main_Page "Visit the main page [z]") +* [Contents](/wiki/Wikipedia:Contents "Guides to browsing Wikipedia") +* [Current events](/wiki/Portal:Current_events "Articles related to current events") +* [Random article](/wiki/Special:Random "Visit a randomly selected article [x]") +* [About Wikipedia](/wiki/Wikipedia:About "Learn about Wikipedia and how it works") +* [Contact us](//en.wikipedia.org/wiki/Wikipedia:Contact_us "How to contact Wikipedia") + +Contribute + +* [Help](/wiki/Help:Contents "Guidance on how to use and edit Wikipedia") +* [Learn to edit](/wiki/Help:Introduction "Learn how to edit Wikipedia") +* [Community portal](/wiki/Wikipedia:Community_portal "The hub for editors") +* [Recent changes](/wiki/Special:RecentChanges "A list of recent changes to Wikipedia [r]") +* [Upload file](/wiki/Wikipedia:File_upload_wizard "Add images or other media for use on Wikipedia") +* [Special pages](/wiki/Special:SpecialPages "A list of all special pages [q]") + +[![](/static/images/icons/enwiki-25.svg) + +![Wikipedia](/static/images/mobile/copyright/wikipedia-wordmark-en-25.svg) +![The Free Encyclopedia](/static/images/mobile/copyright/wikipedia-tagline-en-25.svg)](/wiki/Main_Page) + +[Search](/wiki/Special:Search "Search Wikipedia [f]") + +Search + +Appearance + +* [Donate](https://donate.wikimedia.org/?wmf_source=donate&wmf_medium=sidebar&wmf_campaign=en.wikipedia.org&uselang=en) +* [Create account](/w/index.php?title=Special:CreateAccount&returnto=Concatenative+programming+language "You are encouraged to create an account and log in; however, it is not mandatory") +* [Log in](/w/index.php?title=Special:UserLogin&returnto=Concatenative+programming+language "You're encouraged to log in; however, it's not mandatory. [o]") + +Personal tools + +* [Donate](https://donate.wikimedia.org/?wmf_source=donate&wmf_medium=sidebar&wmf_campaign=en.wikipedia.org&uselang=en) +* [Create account](/w/index.php?title=Special:CreateAccount&returnto=Concatenative+programming+language "You are encouraged to create an account and log in; however, it is not mandatory") +* [Log in](/w/index.php?title=Special:UserLogin&returnto=Concatenative+programming+language "You're encouraged to log in; however, it's not mandatory. [o]") + +## Contents + +move to sidebar +hide + +* [(Top)](#) +* [1 + Example](#Example) +* [2 + Properties](#Properties) +* [3 + Implementations](#Implementations) +* [4 + See also](#See_also) +* [5 + References](#References) +* [6 + External links](#External_links) + +Toggle the table of contents + +# Concatenative programming language + +5 languages + +* [Português](https://pt.wikipedia.org/wiki/Linguagem_de_programa%C3%A7%C3%A3o_concatenativa "Linguagem de programação concatenativa – Portuguese") +* [Русский](https://ru.wikipedia.org/wiki/%D0%9A%D0%BE%D0%BD%D0%BA%D0%B0%D1%82%D0%B5%D0%BD%D0%B0%D1%82%D0%B8%D0%B2%D0%BD%D1%8B%D0%B9_%D1%8F%D0%B7%D1%8B%D0%BA_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F "Конкатенативный язык программирования – Russian") +* [Српски / srpski](https://sr.wikipedia.org/wiki/%D0%9A%D0%BE%D0%BD%D0%BA%D0%B0%D1%82%D0%B5%D0%BD%D0%B0%D1%82%D0%B8%D0%B2%D0%BD%D0%B8_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D1%81%D0%BA%D0%B8_%D1%98%D0%B5%D0%B7%D0%B8%D0%BA "Конкатенативни програмски језик – Serbian") +* [Українська](https://uk.wikipedia.org/wiki/%D0%9A%D0%BE%D0%BD%D0%BA%D0%B0%D1%82%D0%B5%D0%BD%D0%B0%D1%82%D0%B8%D0%B2%D0%BD%D0%B0_%D0%BC%D0%BE%D0%B2%D0%B0_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D1%83%D0%B2%D0%B0%D0%BD%D0%BD%D1%8F "Конкатенативна мова програмування – Ukrainian") +* [中文](https://zh.wikipedia.org/wiki/%E4%B8%B2%E6%8E%A5%E5%BC%8F%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80 "串接式编程语言 – Chinese") + +[Edit links](https://www.wikidata.org/wiki/Special:EntityPage/Q4230857#sitelinks-wikipedia "Edit interlanguage links") + +* [Article](/wiki/Concatenative_programming_language "View the content page [c]") +* [Talk](/wiki/Talk:Concatenative_programming_language "Discuss improvements to the content page [t]") + +English + +* [Read](/wiki/Concatenative_programming_language) +* [Edit](/w/index.php?title=Concatenative_programming_language&action=edit "Edit this page [e]") +* [View history](/w/index.php?title=Concatenative_programming_language&action=history "Past revisions of this page [h]") + + + +Tools + +Tools + +move to sidebar +hide + +Actions + +* [Read](/wiki/Concatenative_programming_language) +* [Edit](/w/index.php?title=Concatenative_programming_language&action=edit "Edit this page [e]") +* [View history](/w/index.php?title=Concatenative_programming_language&action=history) + +General + +* [What links here](/wiki/Special:WhatLinksHere/Concatenative_programming_language "List of all English Wikipedia pages containing links to this page [j]") +* [Related changes](/wiki/Special:RecentChangesLinked/Concatenative_programming_language "Recent changes in pages linked from this page [k]") +* [Upload file](//en.wikipedia.org/wiki/Wikipedia:File_Upload_Wizard "Upload files [u]") +* [Permanent link](/w/index.php?title=Concatenative_programming_language&oldid=1337586589 "Permanent link to this revision of this page") +* [Page information](/w/index.php?title=Concatenative_programming_language&action=info "More information about this page") +* [Cite this page](/w/index.php?title=Special:CiteThisPage&page=Concatenative_programming_language&id=1337586589&wpFormIdentifier=titleform "Information on how to cite this page") +* [Get shortened URL](/w/index.php?title=Special:UrlShortener&url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FConcatenative_programming_language) +* [Download QR code](/w/index.php?title=Special:QrCode&url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FConcatenative_programming_language) + +Print/export + +* [Download as PDF](/w/index.php?title=Special:DownloadAsPdf&page=Concatenative_programming_language&action=show-download-screen "Download this page as a PDF file") +* [Printable version](/w/index.php?title=Concatenative_programming_language&printable=yes "Printable version of this page [p]") + +In other projects + +* [Wikidata item](https://www.wikidata.org/wiki/Special:EntityPage/Q4230857 "Structured data on this page hosted by Wikidata [g]") + +Appearance + +move to sidebar +hide + +From Wikipedia, the free encyclopedia + +Type of programming language + +A **concatenative programming language** is a [point-free](/wiki/Point-free_programming "Point-free programming") computer [programming language](/wiki/Programming_language "Programming language") in which all expressions denote [functions](/wiki/Function_(mathematics) "Function (mathematics)"), and the [juxtaposition](/wiki/Juxtaposition "Juxtaposition") of [expressions](/wiki/Expression_(computer_science) "Expression (computer science)") denotes [function composition](/wiki/Function_composition "Function composition").[[1]](#cite_note-dobbscodetalk-1) Concatenative programming replaces [function application](/wiki/Function_application "Function application"), which is common in other [programming paradigms](/wiki/Programming_paradigm "Programming paradigm"), with [function composition](/wiki/Function_composition_(computer_science) "Function composition (computer science)") as the default way to build [subroutines](/wiki/Function_(computer_programming) "Function (computer programming)"). + +## Example + +[[edit](/w/index.php?title=Concatenative_programming_language&action=edit§ion=1 "Edit section: Example")] + +For example, a nesting of operations in an applicative language like the following: + +``` +baz(bar(foo(x))) +``` + +...is written in a concatenative language as a sequence of functions:[[2]](#cite_note-2) + +``` +x foo bar baz +``` + +Functions and procedures written in concatenative style are not [value level](/wiki/Value-level_programming "Value-level programming"), i.e., they typically do not represent the data structures they operate on with explicit names or [identifiers](/wiki/Identifier#In_computer_science "Identifier"). Instead they are [function level](/wiki/Function-level_programming "Function-level programming") – a function is defined as a [pipeline](/wiki/Pipeline_(software) "Pipeline (software)"), or a sequence of operations that take parameters from an implicit [data structure](/wiki/Data_structure "Data structure") on which all functions operate, and return the function results to that shared structure so that it will be used by the next operator.[[3]](#cite_note-3) + +The combination of compositional [semantics](/wiki/Semantics_(computer_science) "Semantics (computer science)") with a [syntax](/wiki/Syntax_(programming_languages) "Syntax (programming languages)") that mirrors such a semantic makes concatenative languages highly amenable to algebraic manipulation of programs;[[4]](#cite_note-4) although it may be difficult to write mathematical expressions directly in them.[[5]](#cite_note-whymatters-5) Concatenative languages can be implemented efficiently with a [stack machine](/wiki/Stack_machine "Stack machine"), and are commonly present implicitly in [virtual machines](/wiki/Virtual_machine "Virtual machine") in the form of their [instruction sets](/wiki/Instruction_set "Instruction set").[[5]](#cite_note-whymatters-5) + +## Properties + +[[edit](/w/index.php?title=Concatenative_programming_language&action=edit§ion=2 "Edit section: Properties")] + +The properties of concatenative languages are the result of their compositional syntax and semantics: + +* The reduction of any expression is the simplification of one function to another function; it is never necessary to deal with the application of functions to objects.[[6]](#cite_note-6) +* Any subexpression can be replaced with a name that represents the same subexpression. In concatenative programming practice, this is called [factoring](/wiki/Code_refactoring "Code refactoring"), and is used extensively to simplify programs into smaller parts. +* The syntax and semantics of concatenative languages form the algebraic structure of a [monoid](/wiki/Monoid "Monoid").[[7]](#cite_note-7) +* Concatenative languages can be made well-suited to an implementation inspired by [linear logic](/wiki/Linear_logic "Linear logic") where no [garbage](/wiki/Garbage_(computer_science) "Garbage (computer science)") is ever generated.[[8]](#cite_note-8) + +## Implementations + +[[edit](/w/index.php?title=Concatenative_programming_language&action=edit§ion=3 "Edit section: Implementations")] + +The first concatenative programming language was [Forth](/wiki/Forth_(programming_language) "Forth (programming language)"), although [Joy](/wiki/Joy_(programming_language) "Joy (programming language)") was the first language which was termed concatenative. Other concatenative languages are [dc](/wiki/Dc_(computer_program) "Dc (computer program)"), [Factor](/wiki/Factor_(programming_language) "Factor (programming language)"), Onyx, [PostScript](/wiki/PostScript "PostScript"), [RPL](/wiki/RPL_(programming_language) "RPL (programming language)"), Staapl,[[9]](#cite_note-Staapl-9) and experimental and discontinued ones including: Enchilada,[[10]](#cite_note-Enchilada-10) Om,[[11]](#cite_note-Om-11) XY.[[12]](#cite_note-XY-12) + +Most existing concatenative languages are [stack-based](/wiki/Stack-oriented_programming "Stack-oriented programming"). This is not required, and other models have been proposed.[[12]](#cite_note-XY-12)[[10]](#cite_note-Enchilada-10)[[11]](#cite_note-Om-11) Concatenative languages are currently used for [embedded](/wiki/Embedded_system "Embedded system"),[[9]](#cite_note-Staapl-9) [desktop](/wiki/Application_software "Application software"), and [web programming](/wiki/Web_development "Web development"), as [target languages](/wiki/Translator_(computing) "Translator (computing)"), and for research purposes. + +Most concatenative languages are [dynamically typed](/wiki/Dynamically_typed "Dynamically typed"). Exceptions include the [statically typed](/wiki/Statically_typed "Statically typed") Cat language[[13]](#cite_note-13) and its successor, Kitten.[[14]](#cite_note-14) + +## See also + +[[edit](/w/index.php?title=Concatenative_programming_language&action=edit§ion=4 "Edit section: See also")] + +* [Function-level programming](/wiki/Function-level_programming "Function-level programming") +* [Homoiconicity](/wiki/Homoiconicity "Homoiconicity") +* [Stack-oriented programming language](/wiki/Stack-oriented_programming_language "Stack-oriented programming language") +* [Tacit programming](/wiki/Tacit_programming "Tacit programming") + +## References + +[[edit](/w/index.php?title=Concatenative_programming_language&action=edit§ion=5 "Edit section: References")] + +1. **[^](#cite_ref-dobbscodetalk_1-0)** Diggins, Christopher (2008-12-31). ["What is a concatenative language"](http://drdobbs.com/blogs/architecture-and-design/228701299). *[Dr. Dobb's Journal](/wiki/Dr._Dobb%27s_Journal "Dr. Dobb's Journal")*. Retrieved 2013-07-01. +2. **[^](#cite_ref-2)** ["Name code not values"](http://concatenative.org/wiki/view/Concatenative%20language/Name%20code%20not%20values). Concatenative.org. Retrieved 13 September 2013. +3. **[^](#cite_ref-3)** ["Concatenative language"](http://concatenative.org/wiki/view/Concatenative%20language). Concatenative.org. Retrieved 13 September 2013. +4. **[^](#cite_ref-4)** ["Rationale for Joy, a functional language"](https://web.archive.org/web/20110115151536/http://www.latrobe.edu.au/philosophy/phimvt/joy/j00rat.html). Archived from [the original](http://www.latrobe.edu.au/philosophy/phimvt/joy/j00rat.html) on 2011-01-15. +5. ^ [***a***](#cite_ref-whymatters_5-0) [***b***](#cite_ref-whymatters_5-1) Purdy, Jon (12 February 2012). ["Why Concatenative Programming Matters"](http://evincarofautumn.blogspot.com/2012/02/why-concatenative-programming-matters.html). *The Big Mud Puddle*. Retrieved 12 August 2025. +6. **[^](#cite_ref-6)** von Thun, Manfred (2011). ["Joy compared with other functional languages"](https://web.archive.org/web/20111006225512/http://www.latrobe.edu.au/phimvt/joy/j08cnt.html). Archived from [the original](http://www.latrobe.edu.au/phimvt/joy/j08cnt.html) on 2011-10-06. +7. **[^](#cite_ref-7)** von Thun, Manfred (2009). ["Mathematical foundations of Joy"](https://web.archive.org/web/20100731060810/http://www.latrobe.edu.au/philosophy/phimvt/joy/j02maf.html). Archived from [the original](http://www.latrobe.edu.au/philosophy/phimvt/joy/j02maf.html) on 2010-07-31. +8. **[^](#cite_ref-8)** Baker, Henry (1993). [Linear Logic and Permutation Stacks: The Forth Shall Be First](https://web.archive.org/web/20140724091729/http://home.pipeline.com/~hbaker1/ForthStack.html) (Report). Nimble Computer Corporation. Archived from [the original](http://home.pipeline.com/~hbaker1/ForthStack.html) on 2014-07-24. Retrieved 2013-07-01 – via Home.pipeline.com. +9. ^ [***a***](#cite_ref-Staapl_9-0) [***b***](#cite_ref-Staapl_9-1) Schouten, Tom (zwizwa). ["Staapl: Forth on Scheme for Embedded Controllers"](http://zwizwa.be/staapl/). *Zwizwa LLC*. Retrieved 12 August 2025. +10. ^ [***a***](#cite_ref-Enchilada_10-0) [***b***](#cite_ref-Enchilada_10-1) rapido; NewDave; jacintheford; goren (2 January 2024). ["Enchilada"](https://concatenative.org/wiki/view/Enchilada). *Concatenative.org*. Retrieved 12 August 2025. +11. ^ [***a***](#cite_ref-Om_11-0) [***b***](#cite_ref-Om_11-1) sparist. ["The Om Programming Language"](https://www.om-language.com/). *Om-language.com*. Retrieved 12 August 2025. +12. ^ [***a***](#cite_ref-XY_12-0) [***b***](#cite_ref-XY_12-1) Apter, Stevan (2004). ["The Concatenative Language XY"](http://www.nsl.com/k/xy/xy.htm). *no stinking loops*. Retrieved 12 August 2025. +13. **[^](#cite_ref-13)** ["Cat Specification"](https://web.archive.org/web/20150205081218/http://cat-language.com/manual.html). Cat-language.com. Archived from [the original](http://www.cat-language.com/manual.html) on 2015-02-05. Retrieved 2013-07-01. +14. **[^](#cite_ref-14)** Purdy, Jon. ["Kitten Programming Language"](https://kittenlang.org/). *kittenlang.org*. Retrieved 2025-03-31.[*[dead link](/wiki/Wikipedia:Link_rot "Wikipedia:Link rot")*] + +## External links + +[[edit](/w/index.php?title=Concatenative_programming_language&action=edit§ion=6 "Edit section: External links")] + +* [Concatenative.org: Wiki](http://www.concatenative.org/), about concatenative programming + +| * [v](/wiki/Template:Programming_paradigms_navbox "Template:Programming paradigms navbox") * [t](/wiki/Template_talk:Programming_paradigms_navbox "Template talk:Programming paradigms navbox") * [e](/wiki/Special:EditPage/Template:Programming_paradigms_navbox "Special:EditPage/Template:Programming paradigms navbox") [Programming paradigms](/wiki/Programming_paradigm "Programming paradigm") | | +| --- | --- | +| [Imperative](/wiki/Imperative_programming "Imperative programming") | | | | | --- | --- | | [Structured](/wiki/Structured_programming "Structured programming") | * [Jackson structures](/wiki/Jackson_structured_programming "Jackson structured programming") * [Block-structured](/wiki/Block_(programming) "Block (programming)") * [Modular](/wiki/Modular_programming "Modular programming") * [Non-structured](/wiki/Non-structured_programming "Non-structured programming") * [Procedural](/wiki/Procedural_programming "Procedural programming") * [Programming in the large and in the small](/wiki/Programming_in_the_large_and_programming_in_the_small "Programming in the large and programming in the small") * [Design by contract](/wiki/Design_by_contract "Design by contract") * [Invariant-based](/wiki/Invariant-based_programming "Invariant-based programming") * [Nested function](/wiki/Nested_function "Nested function") | | [Object-oriented](/wiki/Object-oriented_programming "Object-oriented programming") | * [Class-based](/wiki/Class-based_programming "Class-based programming"), [Prototype-based](/wiki/Prototype-based_programming "Prototype-based programming"), [Object-based](/wiki/Object-based_language "Object-based language") * [Agent](/wiki/Agent-oriented_programming "Agent-oriented programming") * [Immutable object](/wiki/Immutable_object "Immutable object") * [Persistent](/wiki/Persistent_programming_language "Persistent programming language") * [Uniform function call syntax](/wiki/Uniform_function_call_syntax "Uniform function call syntax") | | +| [Declarative](/wiki/Declarative_programming "Declarative programming") | | | | | --- | --- | | [Functional](/wiki/Functional_programming "Functional programming") | * [Recursive](/wiki/Recursion_(computer_science) "Recursion (computer science)") * [Anonymous function](/wiki/Anonymous_function "Anonymous function") ([Partial application](/wiki/Partial_application "Partial application")) * [Higher-order](/wiki/Higher-order_programming "Higher-order programming") * [Purely functional](/wiki/Purely_functional_programming "Purely functional programming") * [Total](/wiki/Total_functional_programming "Total functional programming") * [Strict](/wiki/Strict_programming_language "Strict programming language") * [GADTs](/wiki/Generalized_algebraic_data_type "Generalized algebraic data type") * [Dependent types](/wiki/Dependent_type "Dependent type") * [Functional logic](/wiki/Functional_logic_programming "Functional logic programming") * [Point-free style](/wiki/Tacit_programming "Tacit programming") * [Expression-oriented](/wiki/Expression-oriented_programming_language "Expression-oriented programming language") * [Applicative](/wiki/Applicative_programming_language "Applicative programming language"), Concatenative * [Function-level](/wiki/Function-level_programming "Function-level programming"), [Value-level](/wiki/Value-level_programming "Value-level programming") * [Monad](/wiki/Monad_(functional_programming) "Monad (functional programming)") | | [Dataflow](/wiki/Dataflow_programming "Dataflow programming") | * [Flow-based](/wiki/Flow-based_programming "Flow-based programming") * [Reactive](/wiki/Reactive_programming "Reactive programming") ([Functional reactive](/wiki/Functional_reactive_programming "Functional reactive programming")) * [Signals](/wiki/SIGNAL_(programming_language) "SIGNAL (programming language)") * [Streams](/wiki/Stream_processing "Stream processing") * [Synchronous](/wiki/Synchronous_programming_language "Synchronous programming language") | | [Logic](/wiki/Logic_programming "Logic programming") | * [Abductive logic](/wiki/Abductive_logic_programming "Abductive logic programming") * [Answer set](/wiki/Answer_set_programming "Answer set programming") * [Constraint](/wiki/Constraint_programming "Constraint programming") ([Constraint logic](/wiki/Constraint_logic_programming "Constraint logic programming")) * [Inductive logic](/wiki/Inductive_logic_programming "Inductive logic programming") * [Nondeterministic](/wiki/Nondeterministic_programming "Nondeterministic programming") * [Ontology](/wiki/Ontology_language "Ontology language") * [Probabilistic logic](/wiki/Probabilistic_logic_programming "Probabilistic logic programming") * [Query](/wiki/Query_language "Query language") | | [Domain- specific language](/wiki/Domain-specific_language "Domain-specific language") (DSL) | * [Algebraic modeling](/wiki/Algebraic_modeling_language "Algebraic modeling language") * [Array](/wiki/Array_programming "Array programming") * [Automata-based](/wiki/Automata-based_programming "Automata-based programming") ([Action](/wiki/Action_language "Action language")) * [Command](/wiki/Command_language "Command language") ([Spacecraft](/wiki/Spacecraft_command_language "Spacecraft command language")) * [Differentiable](/wiki/Differentiable_programming "Differentiable programming") * [End-user](/wiki/End-user_development "End-user development") * [Grammar-oriented](/wiki/Grammar-oriented_programming "Grammar-oriented programming") * [Interface description](/wiki/Interface_description_language "Interface description language") * [Language-oriented](/wiki/Language-oriented_programming "Language-oriented programming") * [List comprehension](/wiki/List_comprehension "List comprehension") * [Low-code](/wiki/Low-code_development_platform "Low-code development platform") * [Modeling](/wiki/Modeling_language "Modeling language") * [Natural language](/wiki/Natural_language_programming "Natural language programming") * [Non-English-based](/wiki/Non-English-based_programming_languages "Non-English-based programming languages") * [Page description](/wiki/Page_description_language "Page description language") * [Pipes](/wiki/Pipeline_(software) "Pipeline (software)") and [filters](/wiki/Filter_(software) "Filter (software)") * [Probabilistic](/wiki/Probabilistic_programming "Probabilistic programming") * [Quantum](/wiki/Quantum_programming "Quantum programming") * [Scientific](/wiki/Scientific_programming_language "Scientific programming language") * [Scripting](/wiki/Scripting_language "Scripting language") * [Set-theoretic](/wiki/Set_theoretic_programming "Set theoretic programming") * [Simulation](/wiki/Simulation_language "Simulation language") * [Stack-based](/wiki/Stack-oriented_programming "Stack-oriented programming") * [System](/wiki/System_programming_language "System programming language") * [Tactile](/wiki/Tactile_programming_language "Tactile programming language") * [Templating](/wiki/Template_processor "Template processor") * [Transformation](/wiki/Transformation_language "Transformation language") ([Graph rewriting](/wiki/Graph_rewriting "Graph rewriting"), [Production](/wiki/Production_system_(computer_science) "Production system (computer science)"), [Pattern](/wiki/Pattern_matching "Pattern matching")) * [Visual](/wiki/Visual_programming_language "Visual programming language") | | +| [Concurrent](/wiki/Concurrent_computing "Concurrent computing"), [parallel](/wiki/Parallel_computing "Parallel computing") | * [Actor-based](/wiki/Actor_model "Actor model") * [Automatic mutual exclusion](/wiki/Automatic_mutual_exclusion "Automatic mutual exclusion") * [Choreographic programming](/wiki/Choreographic_programming "Choreographic programming") * [Concurrent logic](/wiki/Concurrent_logic_programming "Concurrent logic programming") ([Concurrent constraint logic](/wiki/Concurrent_constraint_logic_programming "Concurrent constraint logic programming")) * [Concurrent OO](/wiki/Concurrent_object-oriented_programming "Concurrent object-oriented programming") * [Macroprogramming](/wiki/Macroprogramming "Macroprogramming") * [Multitier programming](/wiki/Multitier_programming "Multitier programming") * [Organic computing](/wiki/Organic_computing "Organic computing") * [Parallel programming models](/wiki/Parallel_programming_model "Parallel programming model") * [Partitioned global address space](/wiki/Partitioned_global_address_space "Partitioned global address space") * [Process-oriented](/wiki/Process-oriented_programming "Process-oriented programming") * [Relativistic programming](/wiki/Relativistic_programming "Relativistic programming") * [Service-oriented](/wiki/Service-oriented_programming "Service-oriented programming") * [Structured concurrency](/wiki/Structured_concurrency "Structured concurrency") | +| [Metaprogramming](/wiki/Metaprogramming "Metaprogramming") | * [Attribute-oriented](/wiki/Attribute-oriented_programming "Attribute-oriented programming") * [Automatic](/wiki/Automatic_programming "Automatic programming") ([Inductive](/wiki/Inductive_programming "Inductive programming")) * [Dynamic](/wiki/Dynamic_programming_language "Dynamic programming language") * [Extensible](/wiki/Extensible_programming "Extensible programming") * [Generic](/wiki/Generic_programming "Generic programming") * [Homoiconicity](/wiki/Homoiconicity "Homoiconicity") * [Interactive](/wiki/Interactive_programming "Interactive programming") * [Macro](/wiki/Macro_(computer_science) "Macro (computer science)") ([Hygienic](/wiki/Hygienic_macro "Hygienic macro")) * [Metalinguistic abstraction](/wiki/Metalinguistic_abstraction "Metalinguistic abstraction") * [Multi-stage](/wiki/Multi-stage_programming "Multi-stage programming") * [Program synthesis](/wiki/Program_synthesis "Program synthesis") ([Bayesian](/wiki/Bayesian_program_synthesis "Bayesian program synthesis"), [by demonstration](/wiki/Programming_by_demonstration "Programming by demonstration"), [by example](/wiki/Programming_by_example "Programming by example"), [vibe coding](/wiki/Vibe_coding "Vibe coding")) * [Reflective](/wiki/Reflective_programming "Reflective programming") * [Self-modifying code](/wiki/Self-modifying_code "Self-modifying code") * [Symbolic](/wiki/Symbolic_programming "Symbolic programming") * [Template](/wiki/Template_metaprogramming "Template metaprogramming") | +| [Separation of concerns](/wiki/Separation_of_concerns "Separation of concerns") | * [Aspects](/wiki/Aspect-oriented_programming "Aspect-oriented programming") * [Components](/wiki/Component-based_software_engineering "Component-based software engineering") * [Data-driven](/wiki/Data-driven_programming "Data-driven programming") * [Data-oriented](/wiki/Data-oriented_design "Data-oriented design") * [Event-driven](/wiki/Event-driven_programming "Event-driven programming") * [Features](/wiki/Feature-oriented_programming "Feature-oriented programming") * [Literate](/wiki/Literate_programming "Literate programming") * [Roles](/wiki/Role-oriented_programming "Role-oriented programming") * [Subjects](/wiki/Subject-oriented_programming "Subject-oriented programming") | +| Comparisons/Lists | [Comparison](/wiki/Comparison_of_programming_languages "Comparison of programming languages") ([multi-paradigm](/wiki/Comparison_of_multi-paradigm_programming_languages "Comparison of multi-paradigm programming languages"), [object-oriented](/wiki/Comparison_of_programming_languages_(object-oriented_programming) "Comparison of programming languages (object-oriented programming)"), [functional](/wiki/Comparison_of_functional_programming_languages "Comparison of functional programming languages")), [List](/wiki/List_of_programming_languages "List of programming languages") ([OO](/wiki/List_of_object-oriented_programming_languages "List of object-oriented programming languages"), [by type](/wiki/List_of_programming_languages_by_type "List of programming languages by type")) | + +| * [v](/wiki/Template:Types_of_programming_languages "Template:Types of programming languages") * [t](/wiki/Template_talk:Types_of_programming_languages "Template talk:Types of programming languages") * [e](/wiki/Special:EditPage/Template:Types_of_programming_languages "Special:EditPage/Template:Types of programming languages") [Types of programming languages](/wiki/Programming_paradigm "Programming paradigm") | | +| --- | --- | +| Level | * [Machine](/wiki/Machine_code "Machine code") * [Assembly](/wiki/Assembly_language "Assembly language") * [Compiled](/wiki/Compiled_language "Compiled language") * [Interpreted](/wiki/Interpreted_language "Interpreted language") * [Low-level](/wiki/Low-level_programming_language "Low-level programming language") * [High-level](/wiki/High-level_programming_language "High-level programming language") * [Very high-level](/wiki/Very_high-level_programming_language "Very high-level programming language") * [Esoteric](/wiki/Esoteric_programming_language "Esoteric programming language") | +| [Generation](/wiki/Programming_language_generations "Programming language generations") | * [First](/wiki/First-generation_programming_language "First-generation programming language") * [Second](/wiki/Second-generation_programming_language "Second-generation programming language") * [Third](/wiki/Third-generation_programming_language "Third-generation programming language") * [Fourth](/wiki/Fourth-generation_programming_language "Fourth-generation programming language") * [Fifth](/wiki/Fifth-generation_programming_language "Fifth-generation programming language") | + +![](https://en.wikipedia.org/wiki/Special:CentralAutoLogin/start?useformat=desktop&type=1x1&usesul3=1) + +Retrieved from "" + +[Category](/wiki/Help:Category "Help:Category"): + +* [Concatenative programming languages](/wiki/Category:Concatenative_programming_languages "Category:Concatenative programming languages") + +Hidden categories: + +* [All articles with dead external links](/wiki/Category:All_articles_with_dead_external_links "Category:All articles with dead external links") +* [Articles with dead external links from February 2026](/wiki/Category:Articles_with_dead_external_links_from_February_2026 "Category:Articles with dead external links from February 2026") +* [Articles with short description](/wiki/Category:Articles_with_short_description "Category:Articles with short description") +* [Short description matches Wikidata](/wiki/Category:Short_description_matches_Wikidata "Category:Short description matches Wikidata") +* [Articles with example JavaScript code](/wiki/Category:Articles_with_example_JavaScript_code "Category:Articles with example JavaScript code") + +* This page was last edited on 10 February 2026, at 09:59 (UTC). +* Text is available under the [Creative Commons Attribution-ShareAlike 4.0 License](/wiki/Wikipedia:Text_of_the_Creative_Commons_Attribution-ShareAlike_4.0_International_License "Wikipedia:Text of the Creative Commons Attribution-ShareAlike 4.0 International License"); + additional terms may apply. By using this site, you agree to the [Terms of Use](https://foundation.wikimedia.org/wiki/Special:MyLanguage/Policy:Terms_of_Use "foundation:Special:MyLanguage/Policy:Terms of Use") and [Privacy Policy](https://foundation.wikimedia.org/wiki/Special:MyLanguage/Policy:Privacy_policy "foundation:Special:MyLanguage/Policy:Privacy policy"). Wikipedia® is a registered trademark of the [Wikimedia Foundation, Inc.](https://wikimediafoundation.org/), a non-profit organization. + +* [Privacy policy](https://foundation.wikimedia.org/wiki/Special:MyLanguage/Policy:Privacy_policy) +* [About Wikipedia](/wiki/Wikipedia:About) +* [Disclaimers](/wiki/Wikipedia:General_disclaimer) +* [Contact Wikipedia](//en.wikipedia.org/wiki/Wikipedia:Contact_us) +* [Legal & safety contacts](https://foundation.wikimedia.org/wiki/Special:MyLanguage/Legal:Wikimedia_Foundation_Legal_and_Safety_Contact_Information) +* [Code of Conduct](https://foundation.wikimedia.org/wiki/Special:MyLanguage/Policy:Universal_Code_of_Conduct) +* [Developers](https://developer.wikimedia.org) +* [Statistics](https://stats.wikimedia.org/#/en.wikipedia.org) +* [Cookie statement](https://foundation.wikimedia.org/wiki/Special:MyLanguage/Policy:Cookie_statement) +* [Mobile view](//en.wikipedia.org/w/index.php?title=Concatenative_programming_language&mobileaction=toggle_view_mobile) + +* [![Wikimedia Foundation](/static/images/footer/wikimedia.svg)](https://www.wikimedia.org/) +* [![Powered by MediaWiki](/w/resources/assets/mediawiki_compact.svg)](https://www.mediawiki.org/) + +Search + +Search + +Toggle the table of contents + +Concatenative programming language + +5 languages +[Add topic](#) \ No newline at end of file diff --git a/references/ForthNotes/Wikipedia_Page.md b/references/ForthNotes/Wikipedia_Page.md new file mode 100644 index 0000000..c7e63eb --- /dev/null +++ b/references/ForthNotes/Wikipedia_Page.md @@ -0,0 +1,804 @@ +# Wikipedia Page + +**Source:** https://en.wikipedia.org/wiki/Forth_(programming_language) + +Forth (programming language) - Wikipedia + +[Jump to content](#bodyContent) + +Main menu + +Main menu + +move to sidebar +hide + +Navigation + +* [Main page](/wiki/Main_Page "Visit the main page [z]") +* [Contents](/wiki/Wikipedia:Contents "Guides to browsing Wikipedia") +* [Current events](/wiki/Portal:Current_events "Articles related to current events") +* [Random article](/wiki/Special:Random "Visit a randomly selected article [x]") +* [About Wikipedia](/wiki/Wikipedia:About "Learn about Wikipedia and how it works") +* [Contact us](//en.wikipedia.org/wiki/Wikipedia:Contact_us "How to contact Wikipedia") + +Contribute + +* [Help](/wiki/Help:Contents "Guidance on how to use and edit Wikipedia") +* [Learn to edit](/wiki/Help:Introduction "Learn how to edit Wikipedia") +* [Community portal](/wiki/Wikipedia:Community_portal "The hub for editors") +* [Recent changes](/wiki/Special:RecentChanges "A list of recent changes to Wikipedia [r]") +* [Upload file](/wiki/Wikipedia:File_upload_wizard "Add images or other media for use on Wikipedia") +* [Special pages](/wiki/Special:SpecialPages "A list of all special pages [q]") + +[![](/static/images/icons/enwiki-25.svg) + +![Wikipedia](/static/images/mobile/copyright/wikipedia-wordmark-en-25.svg) +![The Free Encyclopedia](/static/images/mobile/copyright/wikipedia-tagline-en-25.svg)](/wiki/Main_Page) + +[Search](/wiki/Special:Search "Search Wikipedia [f]") + +Search + +Appearance + +* [Donate](https://donate.wikimedia.org/?wmf_source=donate&wmf_medium=sidebar&wmf_campaign=en.wikipedia.org&uselang=en) +* [Create account](/w/index.php?title=Special:CreateAccount&returnto=Forth+%28programming+language%29 "You are encouraged to create an account and log in; however, it is not mandatory") +* [Log in](/w/index.php?title=Special:UserLogin&returnto=Forth+%28programming+language%29 "You're encouraged to log in; however, it's not mandatory. [o]") + +Personal tools + +* [Donate](https://donate.wikimedia.org/?wmf_source=donate&wmf_medium=sidebar&wmf_campaign=en.wikipedia.org&uselang=en) +* [Create account](/w/index.php?title=Special:CreateAccount&returnto=Forth+%28programming+language%29 "You are encouraged to create an account and log in; however, it is not mandatory") +* [Log in](/w/index.php?title=Special:UserLogin&returnto=Forth+%28programming+language%29 "You're encouraged to log in; however, it's not mandatory. [o]") + +## Contents + +move to sidebar +hide + +* [(Top)](#) +* [1 + Uses](#Uses) +* [2 + History](#History) +* [3 + Overview](#Overview) +* [4 + Facilities](#Facilities) + + + Toggle Facilities subsection + + [4.1 + Operating system, files, and multitasking](#Operating_system,_files,_and_multitasking) + + [4.2 + Self-compilation and cross compilation](#Self-compilation_and_cross_compilation) +* [5 + Structure of the language](#Structure_of_the_language) + + + Toggle Structure of the language subsection + + [5.1 + Structure of the compiler](#Structure_of_the_compiler) + - [5.1.1 + Compilation state and interpretation state](#Compilation_state_and_interpretation_state) + - [5.1.2 + Immediate words](#Immediate_words) + - [5.1.3 + Unnamed words and execution tokens](#Unnamed_words_and_execution_tokens) + - [5.1.4 + Parsing words and comments](#Parsing_words_and_comments) + + [5.2 + Structure of code](#Structure_of_code) + + [5.3 + Data objects](#Data_objects) +* [6 + Examples](#Examples) + + + Toggle Examples subsection + + [6.1 + “Hello, World!”](#“Hello,_World!”) + + [6.2 + Mixing states of compiling and interpreting](#Mixing_states_of_compiling_and_interpreting) + + [6.3 + RC4 cipher program](#RC4_cipher_program) +* [7 + Forth engines](#Forth_engines) +* [8 + Implementations](#Implementations) +* [9 + See also](#See_also) +* [10 + Notes](#Notes) +* [11 + References](#References) +* [12 + External links](#External_links) + +Toggle the table of contents + +# Forth (programming language) + +34 languages + +* [中文](https://zh.wikipedia.org/wiki/Forth "Forth – Chinese") +* [Кыргызча](https://ky.wikipedia.org/wiki/%D0%A4%D0%BE%D1%80%D1%82_(%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B0%D0%BB%D0%BE%D0%BE_%D1%82%D0%B8%D0%BB%D0%B8) "Форт (программалоо тили) – Kyrgyz") +* [한국어](https://ko.wikipedia.org/wiki/%ED%8F%AC%EC%8A%A4_(%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D_%EC%96%B8%EC%96%B4) "포스 (프로그래밍 언어) – Korean") +* [Français](https://fr.wikipedia.org/wiki/Forth_(langage) "Forth (langage) – French") +* [Español](https://es.wikipedia.org/wiki/Forth "Forth – Spanish") +* [Magyar](https://hu.wikipedia.org/wiki/Forth_(programoz%C3%A1si_nyelv) "Forth (programozási nyelv) – Hungarian") +* [Italiano](https://it.wikipedia.org/wiki/Forth_(linguaggio) "Forth (linguaggio) – Italian") +* [Galego](https://gl.wikipedia.org/wiki/Forth "Forth – Galician") +* [Deutsch](https://de.wikipedia.org/wiki/Forth_(Programmiersprache) "Forth (Programmiersprache) – German") +* [日本語](https://ja.wikipedia.org/wiki/Forth "Forth – Japanese") +* [Ελληνικά](https://el.wikipedia.org/wiki/Forth "Forth – Greek") +* [Simple English](https://simple.wikipedia.org/wiki/Forth "Forth – Simple English") +* [العربية](https://ar.wikipedia.org/wiki/%D9%81%D9%88%D8%B1%D8%AB_(%D9%84%D8%BA%D8%A9_%D8%A8%D8%B1%D9%85%D8%AC%D8%A9) "فورث (لغة برمجة) – Arabic") +* [Nederlands](https://nl.wikipedia.org/wiki/Forth_(programmeertaal) "Forth (programmeertaal) – Dutch") +* [Svenska](https://sv.wikipedia.org/wiki/Forth_(programspr%C3%A5k) "Forth (programspråk) – Swedish") +* [Português](https://pt.wikipedia.org/wiki/Forth "Forth – Portuguese") +* [Esperanto](https://eo.wikipedia.org/wiki/Forth_(programlingvo) "Forth (programlingvo) – Esperanto") +* [Тоҷикӣ](https://tg.wikipedia.org/wiki/Forth "Forth – Tajik") +* [Русский](https://ru.wikipedia.org/wiki/%D0%A4%D0%BE%D1%80%D1%82_(%D1%8F%D0%B7%D1%8B%D0%BA_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F) "Форт (язык программирования) – Russian") +* [Norsk bokmål](https://no.wikipedia.org/wiki/Forth_(programmeringsspr%C3%A5k) "Forth (programmeringsspråk) – Norwegian Bokmål") +* [Català](https://ca.wikipedia.org/wiki/Forth "Forth – Catalan") +* [Suomi](https://fi.wikipedia.org/wiki/Forth_(ohjelmointikieli) "Forth (ohjelmointikieli) – Finnish") +* [Українська](https://uk.wikipedia.org/wiki/Forth "Forth – Ukrainian") +* [Čeština](https://cs.wikipedia.org/wiki/Forth_(programovac%C3%AD_jazyk) "Forth (programovací jazyk) – Czech") +* [Български](https://bg.wikipedia.org/wiki/Forth "Forth – Bulgarian") +* [Interlingua](https://ia.wikipedia.org/wiki/Forth_(linguage_de_programmation) "Forth (linguage de programmation) – Interlingua") +* [Беларуская](https://be.wikipedia.org/wiki/%D0%A4%D0%BE%D1%80%D1%82_(%D0%BC%D0%BE%D0%B2%D0%B0_%D0%BF%D1%80%D0%B0%D0%B3%D1%80%D0%B0%D0%BC%D0%B0%D0%B2%D0%B0%D0%BD%D0%BD%D1%8F) "Форт (мова праграмавання) – Belarusian") +* [Latviešu](https://lv.wikipedia.org/wiki/Forth_(programm%C4%93%C5%A1anas_valoda) "Forth (programmēšanas valoda) – Latvian") +* [Српски / srpski](https://sr.wikipedia.org/wiki/Forth_(%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D1%81%D0%BA%D0%B8_%D1%98%D0%B5%D0%B7%D0%B8%D0%BA) "Forth (програмски језик) – Serbian") +* [فارسی](https://fa.wikipedia.org/wiki/%D8%B2%D8%A8%D8%A7%D9%86_%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87%E2%80%8C%D9%86%D9%88%DB%8C%D8%B3%DB%8C_%D9%81%D9%88%D8%B1%D8%AB "زبان برنامه‌نویسی فورث – Persian") +* [Polski](https://pl.wikipedia.org/wiki/Forth_(j%C4%99zyk_programowania) "Forth (język programowania) – Polish") +* [粵語](https://zh-yue.wikipedia.org/wiki/Forth "Forth – Cantonese") +* [Slovenščina](https://sl.wikipedia.org/wiki/Forth_(programski_jezik) "Forth (programski jezik) – Slovenian") +* [ꠍꠤꠟꠐꠤ](https://syl.wikipedia.org/wiki/%EA%A0%9A%EA%A0%9E%EA%A0%86%EA%A0%95 "ꠚꠞ꠆ꠕ – Sylheti") + +[Edit links](https://www.wikidata.org/wiki/Special:EntityPage/Q275472#sitelinks-wikipedia "Edit interlanguage links") + +* [Article](/wiki/Forth_(programming_language) "View the content page [c]") +* [Talk](/wiki/Talk:Forth_(programming_language) "Discuss improvements to the content page [t]") + +English + +* [Read](/wiki/Forth_(programming_language)) +* [Edit](/w/index.php?title=Forth_(programming_language)&action=edit "Edit this page [e]") +* [View history](/w/index.php?title=Forth_(programming_language)&action=history "Past revisions of this page [h]") + + + +Tools + +Tools + +move to sidebar +hide + +Actions + +* [Read](/wiki/Forth_(programming_language)) +* [Edit](/w/index.php?title=Forth_(programming_language)&action=edit "Edit this page [e]") +* [View history](/w/index.php?title=Forth_(programming_language)&action=history) + +General + +* [What links here](/wiki/Special:WhatLinksHere/Forth_(programming_language) "List of all English Wikipedia pages containing links to this page [j]") +* [Related changes](/wiki/Special:RecentChangesLinked/Forth_(programming_language) "Recent changes in pages linked from this page [k]") +* [Upload file](//en.wikipedia.org/wiki/Wikipedia:File_Upload_Wizard "Upload files [u]") +* [Permanent link](/w/index.php?title=Forth_(programming_language)&oldid=1330667744 "Permanent link to this revision of this page") +* [Page information](/w/index.php?title=Forth_(programming_language)&action=info "More information about this page") +* [Cite this page](/w/index.php?title=Special:CiteThisPage&page=Forth_%28programming_language%29&id=1330667744&wpFormIdentifier=titleform "Information on how to cite this page") +* [Get shortened URL](/w/index.php?title=Special:UrlShortener&url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FForth_%28programming_language%29) +* [Download QR code](/w/index.php?title=Special:QrCode&url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FForth_%28programming_language%29) + +Print/export + +* [Download as PDF](/w/index.php?title=Special:DownloadAsPdf&page=Forth_%28programming_language%29&action=show-download-screen "Download this page as a PDF file") +* [Printable version](/w/index.php?title=Forth_(programming_language)&printable=yes "Printable version of this page [p]") + +In other projects + +* [Wikimedia Commons](https://commons.wikimedia.org/wiki/Category:Forth_(programming_language)) +* [Wikibooks](https://en.wikibooks.org/wiki/Forth) +* [Wikidata item](https://www.wikidata.org/wiki/Special:EntityPage/Q275472 "Structured data on this page hosted by Wikidata [g]") + +Appearance + +move to sidebar +hide + +From Wikipedia, the free encyclopedia + +Stack-based programming language + +"FORTH" redirects here. For other uses, see [Forth (disambiguation)](/wiki/Forth_(disambiguation) "Forth (disambiguation)"). + +| Forth | | +| --- | --- | +| [Paradigm](/wiki/Programming_paradigm "Programming paradigm") | [concatenative](/wiki/Concatenative_programming_language "Concatenative programming language") ([stack-based](/wiki/Stack-oriented_programming "Stack-oriented programming")), [procedural](/wiki/Procedural_programming "Procedural programming"), [reflective](/wiki/Reflective_programming "Reflective programming") | +| [Designed by](/wiki/Software_design "Software design") | [Charles H. Moore](/wiki/Charles_H._Moore "Charles H. Moore") | +| First appeared | 1970; 56 years ago (1970) | +| [Typing discipline](/wiki/Type_system "Type system") | Typeless | +| [Filename extensions](/wiki/Filename_extension "Filename extension") | .fs, .fth, .4th, .f, .forth[*[citation needed](/wiki/Wikipedia:Citation_needed "Wikipedia:Citation needed")*] | +| Website | [forth-standard.org](https://forth-standard.org) | +| Major [implementations](/wiki/Programming_language_implementation "Programming language implementation") | | +| SwiftForth (Forth, Inc.) [Gforth](/wiki/Gforth "Gforth") (GNU Project) VFX Forth (MicroProcessor Engineering) | | +| Influenced | | +| [Bitcoin Script](/wiki/Bitcoin#Transactions "Bitcoin"), [Factor](/wiki/Factor_(programming_language) "Factor (programming language)"), [Joy](/wiki/Joy_(programming_language) "Joy (programming language)"), [RPL](/wiki/RPL_(programming_language) "RPL (programming language)"), [Rebol](/wiki/Rebol "Rebol"), [STOIC](/wiki/STOIC "STOIC"), [8th](/w/index.php?title=8th_(programming_language)&action=edit&redlink=1 "8th (programming language) (page does not exist)") | | + +**Forth** is a [stack-oriented](/wiki/Stack-oriented_programming "Stack-oriented programming") [programming language](/wiki/Programming_language "Programming language") and interactive [integrated development environment](/wiki/Integrated_development_environment "Integrated development environment") designed by [Charles H. "Chuck" Moore](/wiki/Charles_H._Moore "Charles H. Moore") and first used by other programmers in 1970. Although not an [acronym](/wiki/Acronym "Acronym"), the language's name in its early years was often spelled in [all capital letters](/wiki/All_caps "All caps") as *FORTH*. The FORTH-79 and FORTH-83 implementations, which were not written by Moore, became *[de facto](/wiki/De_facto "De facto")* standards, and an official [technical standard](/wiki/Technical_standard "Technical standard") of the language was published in 1994 as ANS Forth. A wide range of Forth derivatives existed before and after ANS Forth. The [free and open-source software](/wiki/Free_and_open-source_software "Free and open-source software") [Gforth](/wiki/Gforth "Gforth") implementation is actively maintained, as are several [commercially](/wiki/Commercial_software "Commercial software") supported systems. + +Forth typically combines a compiler with an integrated command shell, where the user interacts via [subroutines](/wiki/Subroutine "Subroutine") called *words*.[[a]](#cite_note-3) + +Words can be defined, tested, redefined, and debugged without recompiling or restarting the whole program. All syntactic elements, including variables, operators, and control flow, are defined as words. A [stack](/wiki/Stack_(abstract_data_type) "Stack (abstract data type)") is used to pass parameters between words, leading to a [Reverse Polish notation](/wiki/Reverse_Polish_notation "Reverse Polish notation") style. + +For much of Forth's existence, the standard technique was to compile to [threaded code](/wiki/Threaded_code "Threaded code"), which can be interpreted faster than [bytecode](/wiki/Bytecode "Bytecode"). One of the early benefits of Forth was size: an entire development environment—including compiler, editor, and user programs—could fit in memory on an 8-bit or similarly limited system. No longer constrained by space, there are modern implementations that generate [optimized](/wiki/Optimizing_compiler "Optimizing compiler") [machine code](/wiki/Machine_code "Machine code") like other language compilers. + +The relative simplicity of creating a basic Forth system has led to many personal and proprietary variants, such as the custom Forth used to implement the bestselling 1986 video game *[Starflight](/wiki/Starflight "Starflight")* from [Electronic Arts](/wiki/Electronic_Arts "Electronic Arts").[[3]](#cite_note-maher-4) Forth is used in the [Open Firmware](/wiki/Open_Firmware "Open Firmware") [boot loader](/wiki/Boot_loader "Boot loader"), in [spaceflight](/wiki/Spaceflight "Spaceflight") applications[[4]](#cite_note-oSWRm-5) such as the [*Philae* spacecraft](/wiki/Philae_(spacecraft) "Philae (spacecraft)"),[[5]](#cite_note-zYmBe-6)[[6]](#cite_note-sgEMh-7) and in other embedded systems which involve interaction with hardware. + +Beginning in the early 1980s, Moore developed a series of microprocessors for executing compiled Forth-like code directly and experimented with smaller languages based on Forth concepts, including cmForth and [colorForth](/wiki/ColorForth "ColorForth"). Most of these languages were created to support Moore's own projects, such as chip design. + +## Uses + +[[edit](/w/index.php?title=Forth_(programming_language)&action=edit§ion=1 "Edit section: Uses")] + +Forth has a niche in astronomical and space applications[[7]](#cite_note-C4Oss-8) as well as a history in [embedded systems](/wiki/Embedded_system "Embedded system"). The [Open Firmware](/wiki/Open_Firmware "Open Firmware") [boot ROMs](/wiki/Boot_ROM "Boot ROM") used by [Apple](/wiki/Apple_Inc. "Apple Inc."), [IBM](/wiki/IBM "IBM"), [Sun](/wiki/Sun_Microsystems "Sun Microsystems"), and [OLPC XO-1](/wiki/OLPC_XO "OLPC XO") contain a Forth environment. + +Forth has often been used to bring up new hardware. Forth was the first [resident software](/wiki/Resident_monitor "Resident monitor") on the new [Intel 8086](/wiki/Intel_8086 "Intel 8086") chip in 1978, and MacFORTH was the first resident development system for the [Macintosh 128K](/wiki/Macintosh_128K "Macintosh 128K") in 1984.[[8]](#cite_note-evolution-9) + +Circa 1982, [Atari, Inc.](/wiki/Atari,_Inc. "Atari, Inc.") used an elaborate animated demo written in Forth to showcase capabilities of the [Atari 8-bit computers](/wiki/Atari_8-bit_computers "Atari 8-bit computers") in department stores.[[9]](#cite_note-10) [Electronic Arts](/wiki/Electronic_Arts "Electronic Arts") published multiple video games in the 1980s that were written in Forth, including *[Worms?](/wiki/Worms%3F "Worms?")* (1983),[[10]](#cite_note-11) *[Adventure Construction Set](/wiki/Adventure_Construction_Set "Adventure Construction Set")* (1984),[[11]](#cite_note-12) *[Amnesia](/wiki/Amnesia_(1986_video_game) "Amnesia (1986 video game)")* (1986),[[12]](#cite_note-13) *[Starflight](/wiki/Starflight "Starflight")* (1986),[[3]](#cite_note-maher-4) and *[Lords of Conquest](/wiki/Lords_of_Conquest "Lords of Conquest")* (1986). Robot coding game *[ChipWits](/wiki/ChipWits "ChipWits")* (1984) was developed in MacFORTH for the [Macintosh 128K](/wiki/Macintosh_128K "Macintosh 128K"),[[13]](#cite_note-14) while the [Commodore 64](/wiki/Commodore_64 "Commodore 64") port was written with SuperForth 64.[[14]](#cite_note-15) + +[Ashton-Tate's RapidFile](/wiki/Ashton-Tate#RapidFile "Ashton-Tate") (1986), a flat-file database program, and VP-Planner[[15]](#cite_note-16) from [Paperback Software International](/wiki/Paperback_Software_International "Paperback Software International") (1983), a spreadsheet program competing with [Lotus 1-2-3](/wiki/Lotus_1-2-3 "Lotus 1-2-3"), were written in Forth. + +The [Canon Cat](/wiki/Canon_Cat "Canon Cat") (1987) uses Forth for its system programming. + +[Rockwell](/wiki/Rockwell_International "Rockwell International") produced single-chip microcomputers with resident Forth kernels: the R65F11 and R65F12. + +ASYST was a Forth expansion for measuring and controlling on PCs.[[16]](#cite_note-Rwirj-17) + +## History + +[[edit](/w/index.php?title=Forth_(programming_language)&action=edit§ion=2 "Edit section: History")] + +Forth evolved from [Charles H. Moore](/wiki/Charles_H._Moore "Charles H. Moore")'s personal programming system, which had been in continuous development since 1968.[[8]](#cite_note-evolution-9)[[17]](#cite_note-WYK4Z-18) Forth was first exposed to other programmers in the early 1970s, starting with [Elizabeth Rather](/wiki/Elizabeth_Rather "Elizabeth Rather") at the United States [National Radio Astronomy Observatory](/wiki/National_Radio_Astronomy_Observatory "National Radio Astronomy Observatory") (NRAO).[[8]](#cite_note-evolution-9) After their work at NRAO, Charles Moore and Elizabeth Rather formed FORTH, Inc. in 1973, refining and porting Forth systems to dozens of other platforms in the next decade. + +Moore saw Forth as a successor to compile-link-go [third-generation programming languages](/wiki/Third-generation_programming_language "Third-generation programming language"), or software for "fourth generation" hardware. He recalls how the name was coined:[[18]](#cite_note-19) + +> At [Mohasco](/wiki/Mohawk_Industries "Mohawk Industries") ["in the late 1960s"] I also worked directly on an [IBM 1130](/wiki/IBM_1130 "IBM 1130") interfaced with an [IBM 2250](/wiki/IBM_2250 "IBM 2250") graphics display. The 1130 was a very important computer: it had the first cartridge disk, as well as a card reader, a card punch (as backup for the disk), and a console typewriter. The 1130 let the programmer, for the first time, totally control the computer interactively. + +> FORTH first appeared as an entity on that 1130. It was called F-O-R-T-H, a five-letter abbreviation of FOURTH, standing for fourth-generation computer language. That was the day, you may remember, of third-generation computers and I was going to leapfrog. But because FORTH ran on the 1130 (which permitted only five-character identifiers), the name was shortened. + +FORTH, Inc.'s microFORTH was developed for the [Intel 8080](/wiki/Intel_8080 "Intel 8080"), [Motorola 6800](/wiki/Motorola_6800 "Motorola 6800"), [Zilog Z80](/wiki/Zilog_Z80 "Zilog Z80"), and [RCA 1802](/wiki/RCA_1802 "RCA 1802") microprocessors, starting in 1976. MicroFORTH was later used by hobbyists to generate Forth systems for other architectures, such as the [6502](/wiki/MOS_Technology_6502 "MOS Technology 6502") in 1978. The Forth Interest Group was formed in 1978.[[19]](#cite_note-20) It promoted and distributed its own version of the language, FIG-Forth, for most makes of home computer. + +Forth was popular in the early 1980s,[[20]](#cite_note-1AvuY-21) because it was well suited to the limited memory of [microcomputers](/wiki/Microcomputer "Microcomputer"). The ease of implementing the language led to many implementations.[[21]](#cite_note-family-tree-22) The [Jupiter ACE](/wiki/Jupiter_Ace "Jupiter Ace") home computer has Forth in its [ROM](/wiki/Read-only_memory "Read-only memory")-resident operating system. Insoft GraFORTH is a version of Forth with graphics extensions for the Apple II.[[22]](#cite_note-gWyzb-23) + +Common practice was codified in the de facto standards FORTH-79[[23]](#cite_note-qyrcN-24) and FORTH-83[[24]](#cite_note-BQ2oi-25) in the years 1979 and 1983, respectively. These standards were unified by [ANSI](/wiki/American_National_Standards_Institute "American National Standards Institute") in 1994, commonly referred to as ANS Forth.[[25]](#cite_note-IGDIN-26)[[26]](#cite_note-KojQK-27) + +As of 2018, the source for the original 1130 version of FORTH has been recovered, and is now being updated to run on a restored or emulated 1130 system.[[27]](#cite_note-BtuRy-28) + +## Overview + +[[edit](/w/index.php?title=Forth_(programming_language)&action=edit§ion=3 "Edit section: Overview")] + +Further information: [Reverse Polish notation](/wiki/Reverse_Polish_notation "Reverse Polish notation") + +Forth emphasizes the use of small, simple functions called *words*. Words for bigger tasks call upon many smaller words that each accomplish a distinct sub-task. A large Forth program is a hierarchy of words. These words, being distinct modules that communicate implicitly via a stack mechanism, can be prototyped, built and tested independently. The highest level of Forth code may resemble an English-language description of the application. Forth has been called a *meta-application language*: a language that can be used to create [problem-oriented languages](/wiki/Domain-specific_language "Domain-specific language").[[28]](#cite_note-29) + +Forth relies on implicit use of a [data stack](/wiki/Stack_(abstract_data_type) "Stack (abstract data type)") and [reverse Polish notation](/wiki/Reverse_Polish_notation "Reverse Polish notation") which is commonly used in calculators from [Hewlett-Packard](/wiki/Hewlett-Packard "Hewlett-Packard"). In RPN, the operator is placed after its operands, as opposed to the more common [infix notation](/wiki/Infix_notation "Infix notation") where the operator is placed between its operands. Postfix notation makes the language easier to parse and extend; Forth's flexibility makes a static [BNF](/wiki/Backus-Naur_form "Backus-Naur form") grammar inappropriate, and it does not have a monolithic compiler. Extending the compiler only requires writing a new word, instead of modifying a grammar and changing the underlying implementation. + +Using RPN, one can compute the value of the arithmetic expression (25 × 10) + 50 in the following way: + +``` + 25 10 * 50 + CR . + 300 ok +``` + +[![](//upload.wikimedia.org/wikipedia/commons/thumb/6/6e/Stack1.svg/250px-Stack1.svg.png)](/wiki/File:Stack1.svg) + +First the numbers 25 and 10 are put on the stack. + +[![](//upload.wikimedia.org/wikipedia/commons/thumb/f/fd/Forthstack1_5.svg/250px-Forthstack1_5.svg.png)](/wiki/File:Forthstack1_5.svg) + +The word `*` takes the top two numbers from the stack, multiplies them, and puts the product back on the stack. + +[![](//upload.wikimedia.org/wikipedia/commons/thumb/7/7f/Forthstack2.svg/250px-Forthstack2.svg.png)](/wiki/File:Forthstack2.svg) + +Then the number 50 is placed on the stack. + +[![](//upload.wikimedia.org/wikipedia/commons/thumb/6/64/Forthstack3.svg/250px-Forthstack3.svg.png)](/wiki/File:Forthstack3.svg) + +The word `+` takes the top two numbers from the stack, adds them, and puts the sum back on the stack. `CR` ([carriage return](/wiki/Carriage_return "Carriage return")) starts the output on a new line. Finally, `.` prints the result. As everything has completed successfully, the Forth system prints `OK`.[[29]](#cite_note-3yqc9-30) + +Even Forth's structural features are stack-based. For example: + +``` + : FLOOR5 ( n -- n' ) DUP 6 < IF DROP 5 ELSE 1 - THEN ; +``` + +The colon indicates the beginning of a new definition, in this case a new word (again, *word* is the term used for a subroutine) called `FLOOR5`. The text in parentheses is a comment, advising that this word expects a number on the stack and will return a possibly changed number (on the stack). + +The subroutine uses the following commands: `DUP` duplicates the number on the stack; `6` pushes a 6 on top of the stack; `<` compares the top two numbers on the stack (6 and the `DUP`ed input), and replaces them with a true-or-false value; `IF` takes a true-or-false value and chooses to execute commands immediately after it or to skip to the `ELSE`; `DROP` discards the value on the stack; `5` pushes a 5 on top of the stack; and `THEN` ends the conditional. + +The `FLOOR5` word is equivalent to this function written in the [C programming language](/wiki/C_(programming_language) "C (programming language)") using the [conditional operator](/wiki/Ternary_conditional_operator "Ternary conditional operator") '?:' + +``` +int floor5(int v) { + return (v < 6) ? 5 : (v - 1); +} +``` + +This function is written more succinctly as: + +``` + : FLOOR5 ( n -- n' ) 1- 5 MAX ; +``` + +This can be run as follows: + +``` + 1 FLOOR5 CR . + 5 ok + 8 FLOOR5 CR . + 7 ok +``` + +First a number (1 or 8) is pushed onto the stack, `FLOOR5` is called, which pops the number again and pushes the result. `CR` moves the output to a new line (again, this is only here for readability). Finally, a call to `.` pops the result and prints. + +## Facilities + +[[edit](/w/index.php?title=Forth_(programming_language)&action=edit§ion=4 "Edit section: Facilities")] + +Forth's [grammar](/wiki/Formal_grammar "Formal grammar") has no official specification. Instead, it is defined by a simple algorithm. The interpreter reads a line of input from the user input device, which is then parsed for a word using spaces as a [delimiter](/wiki/Delimiter "Delimiter"); some systems recognise additional [whitespace](/wiki/Whitespace_character "Whitespace character") characters. When the interpreter finds a word, it looks the word up in the *dictionary*. If the word is found, the interpreter executes the code associated with the word, and then returns to parse the rest of the input stream. If the word isn't found, the word is assumed to be a number and an attempt is made to convert it into a number and push it on the stack; if successful, the interpreter continues parsing the input stream. Otherwise, if both the lookup and the number conversion fail, the interpreter prints the word followed by an error message indicating that the word is not recognised, flushes the input stream, and waits for new user input.[[30]](#cite_note-6dQ7P-31) + +The definition of a new word is started with the word `:` (colon) and ends with the word `;` (semi-colon). For example, + +``` + : X DUP 1+ . . ; +``` + +will compile the word `X`, and makes the name findable in the dictionary. When executed by typing `10 X` at the console this will print `11 10`.[[31]](#cite_note-compiler-32) + +Most Forth systems include an [assembler](/wiki/Assembly_language#Assembler "Assembly language") to write words using the processor's facilities. Forth assemblers often use a reverse Polish syntax in which the parameters of an instruction precede the instruction. A typical reverse Polish assembler prepares the operands on the stack and the mnemonic copies the whole instruction into memory as the last step. A Forth assembler is by nature a macro assembler, so that it is easy to define an alias for registers according to their role in the Forth system: e.g. "dsp" for the register used as the data stack pointer.[[32]](#cite_note-NAFQu-33) + +### Operating system, files, and multitasking + +[[edit](/w/index.php?title=Forth_(programming_language)&action=edit§ion=5 "Edit section: Operating system, files, and multitasking")] + +Most Forth systems run under a host operating system such as [Microsoft Windows](/wiki/Microsoft_Windows "Microsoft Windows"), [Linux](/wiki/Linux "Linux") or a version of [Unix](/wiki/Unix "Unix") and use the host operating system's file system for source and data files; the ANSI Forth Standard describes the words used for I/O. All modern Forth systems use normal text files for source, even if they are embedded. An embedded system with a resident compiler gets its source via a serial line. + +Classic Forth systems traditionally use neither [operating system](/wiki/Operating_system "Operating system") nor [file system](/wiki/File_system "File system"). Instead of storing code in files, source code is stored in disk blocks written to physical disk addresses. The word `BLOCK` is employed to translate the number of a 1K-sized block of disk space into the address of a buffer containing the data, which is managed automatically by the Forth system. Block use has become rare since the mid-1990s. In a hosted system those blocks too are allocated in a normal file in any case. + +[Multitasking](/wiki/Computer_multitasking "Computer multitasking"), most commonly [cooperative](/wiki/Computer_multitasking#Cooperative_multitasking/time-sharing "Computer multitasking") [round-robin scheduling](/wiki/Round-robin_scheduling "Round-robin scheduling"), is normally available (although multitasking words and support are not covered by the ANSI Forth Standard). The word `PAUSE` is used to save the current task's execution context, to locate the next task, and restore its execution context. Each task has its own stacks, private copies of some control variables and a scratch area. Swapping tasks is simple and efficient; as a result, Forth multitaskers are available even on very simple [microcontrollers](/wiki/Microcontroller "Microcontroller"), such as the [Intel 8051](/wiki/Intel_MCS-51 "Intel MCS-51"), [Atmel AVR](/wiki/Atmel_AVR "Atmel AVR"), and [TI MSP430](/wiki/TI_MSP430 "TI MSP430").[[33]](#cite_note-nxtDb-34) + +Other non-standard facilities include a mechanism for issuing [calls](/wiki/System_call "System call") to the host OS or [windowing systems](/wiki/Windowing_system "Windowing system"), and many provide extensions that employ the scheduling provided by the operating system. Typically they have a larger and different set of words from the stand-alone Forth's `PAUSE` word for task creation, suspension, destruction and modification of priority. + +### Self-compilation and cross compilation + +[[edit](/w/index.php?title=Forth_(programming_language)&action=edit§ion=6 "Edit section: Self-compilation and cross compilation")] + +A full-featured Forth system with all source code will compile itself, a technique commonly called meta-compilation or [self-hosting](/wiki/Self-hosting_(compilers) "Self-hosting (compilers)"), by Forth programmers (although the term doesn't exactly match [meta-compilation](/wiki/Meta-Compilation "Meta-Compilation") as it is normally defined). The usual method is to redefine the handful of words that place compiled bits into memory. The compiler's words use specially named versions of fetch and store that can be redirected to a buffer area in memory. The buffer area simulates or accesses a memory area beginning at a different address than the code buffer. Such compilers define words to access both the target computer's memory, and the host (compiling) computer's memory.[[34]](#cite_note-Swdke-35) + +After the fetch and store operations are redefined for the code space, the compiler, assembler, etc. are recompiled using the new definitions of fetch and store. This effectively reuses all the code of the compiler and interpreter. Then, the Forth system's code is compiled, but this version is stored in the buffer. The buffer in memory is written to disk, and ways are provided to load it temporarily into memory for testing. When the new version appears to work, it is written over the previous version. + +Numerous variations of such compilers exist for different environments. For [embedded systems](/wiki/Embedded_system "Embedded system"), the code may instead be written to another computer, a technique known as [cross compilation](/wiki/Cross-compilation "Cross-compilation"), over a serial port or even a single [TTL](/wiki/Transistor%E2%80%93transistor_logic "Transistor–transistor logic") bit, while keeping the word names and other non-executing parts of the dictionary in the original compiling computer. The minimum definitions for such a Forth compiler are the words that fetch and store a byte, and the word that commands a Forth word to be executed. Often the most time-consuming part of writing a remote port is constructing the initial program to implement fetch, store and execute, but many modern microprocessors have integrated debugging features (such as the [Motorola CPU32](/wiki/Motorola_CPU32 "Motorola CPU32")) that eliminate this task.[[35]](#cite_note-E5iFy-36) + +## Structure of the language + +[[edit](/w/index.php?title=Forth_(programming_language)&action=edit§ion=7 "Edit section: Structure of the language")] + +The basic data structure of Forth is the "dictionary" which maps "words" to executable code or named data structures. The dictionary is laid out in memory as a tree of [linked lists](/wiki/Linked_list "Linked list") with the links proceeding from the latest (most recently) defined word to the oldest, until a [sentinel value](/wiki/Sentinel_value "Sentinel value"), usually a NULL pointer, is found. A context switch causes a list search to start at a different leaf. A linked list search continues as the branch merges into the main trunk leading eventually back to the sentinel, the root. +There can be several dictionaries. In rare cases such as meta-compilation a dictionary might be isolated and stand-alone. +The effect resembles that of nesting namespaces and can overload keywords depending on the context. + +A defined word generally consists of *head* and *body* with the head consisting of the *name field* (NF) and the *link field* (LF), and body consisting of the *code field* (CF) and the *parameter field* (PF). + +Head and body of a dictionary entry are treated separately because they may not be contiguous. For example, when a Forth program is recompiled for a new platform, the head may remain on the compiling computer, while the body goes to the new platform. In some environments (such as [embedded systems](/wiki/Embedded_system "Embedded system")) the heads occupy memory unnecessarily. However, some cross-compilers may put heads in the target if the target itself is expected to support an interactive Forth.[[36]](#cite_note-lx5fY-37) + +The exact format of a dictionary entry is not prescribed, and implementations vary. + +### Structure of the compiler + +[[edit](/w/index.php?title=Forth_(programming_language)&action=edit§ion=8 "Edit section: Structure of the compiler")] + +The compiler itself is not a monolithic program. It consists of Forth words visible to the system, and usable by a programmer. This allows a programmer to change the compiler's words for special purposes. Compilation in traditional Forth systems is straightforward and does not involve building and optimizing an abstract representation of the code. (Some newer Forth compilers use more elaborate compilation methods, as common in other languages.) + +The "compile time" flag in the name field is set for words with "compile time" behavior. Most simple words execute the same code whether they are typed on a command line, or embedded in code. When compiling these, the compiler simply places code or a threaded pointer to the word.[[31]](#cite_note-compiler-32) + +The classic examples of compile-time words are the [control structures](/wiki/Control_structure "Control structure") such as `IF` and `WHILE`. Almost all of Forth's control structures and almost all of its compiler are implemented as compile-time words. Apart from some rarely used [control flow](/wiki/Control_flow "Control flow") words only found in a few implementations, such as the conditional return word `?EXIT` used in Ulrich Hoffmann's preForth, all of Forth's [control flow](/wiki/Control_flow "Control flow") words are executed during compilation to compile various combinations of primitive words along with their branch addresses.[[1]](#cite_note-preForth_slides-1)[[2]](#cite_note-preForth-2) + +For instance, `IF` and `WHILE`, and the words that match with those, set up `BRANCH` (unconditional branch) and `?BRANCH` (pop a value off the stack, and branch if it is false). Counted loop [control flow](/wiki/Control_flow "Control flow") words work similarly but set up combinations of primitive words that work with a counter, and so on. During compilation, the data stack is used to support control structure balancing, nesting, and back-patching of branch addresses. The snippet: + +``` + ... DUP 6 < IF DROP 5 ELSE 1 - THEN ... +``` + +would often be compiled to the following sequence inside a definition: + +``` + ... DUP LIT 6 < ?BRANCH 5 DROP LIT 5 BRANCH 3 LIT 1 - ... +``` + +The numbers after `BRANCH` represent relative jump addresses. `LIT` is the primitive word for pushing a "literal" number onto the data stack. (Faster, shorter code would be compiled using pointers to constants instead of `LIT` and embedded data, if any of the numbers involved have been separately defined as constants. There would be similar changes if yet other words were used instead of constants, and so on.) + +#### Compilation state and interpretation state + +[[edit](/w/index.php?title=Forth_(programming_language)&action=edit§ion=9 "Edit section: Compilation state and interpretation state")] + +The word `:` (colon) parses a name as a parameter, creates a dictionary entry (a *colon definition*) and enters compilation state. The interpreter continues to read space-delimited words from the user input device. If a word is found, the interpreter executes the *compilation semantics* associated with the word, instead of the *interpretation semantics*. The default compilation semantics of a word are to append its interpretation semantics to the current definition.[[31]](#cite_note-compiler-32) + +The word `;` (semi-colon) finishes the current definition and returns to interpretation state. It is an example of a word whose compilation semantics differ from the default. The interpretation semantics of `;` (semi-colon), most control flow words, and several other words are undefined in ANS Forth, meaning that they must only be used inside of definitions and not on the interactive command line.[[31]](#cite_note-compiler-32) + +The interpreter state can be changed manually with the words `[` (left-bracket) and `]` (right-bracket) which enter interpretation state or compilation state, respectively. These words can be used with the word `LITERAL` to calculate a value during a compilation and to insert the calculated value into the current colon definition. `LITERAL` has the compilation semantics to take an object from the data stack and to append semantics to the current colon definition to place that object on the data stack. + +In ANS Forth, the current state of the interpreter can be read from the [flag](/wiki/Flag_(programming) "Flag (programming)") `STATE` which contains the value true when in compilation state and false otherwise. This allows the implementation of so-called *state-smart words* with behavior that changes according to the current state of the interpreter. + +#### Immediate words + +[[edit](/w/index.php?title=Forth_(programming_language)&action=edit§ion=10 "Edit section: Immediate words")] + +The word `IMMEDIATE` marks the most recent colon definition as an *immediate word*, effectively replacing its compilation semantics with its interpretation semantics.[[37]](#cite_note-odMGJ-38) Immediate words are normally executed during compilation, not compiled, but this can be overridden by the programmer in either state. `;` is an example of an immediate word. In ANS Forth, the word `POSTPONE` takes a name as a parameter and appends the compilation semantics of the named word to the current definition even if the word was marked immediate. Forth-83 defined separate words `COMPILE` and `[COMPILE]` to force the compilation of non-immediate and immediate words, respectively. + +Instead of reserving space for an Immediate flag in every definition, some implementations of Forth use an Immediates Dictionary which is checked first when in compile mode. + +#### Unnamed words and execution tokens + +[[edit](/w/index.php?title=Forth_(programming_language)&action=edit§ion=11 "Edit section: Unnamed words and execution tokens")] + +In ANS Forth, unnamed words can be defined with the word `:NONAME` which compiles the following words up to the next `;` (semi-colon) and leaves an *execution token* on the data stack. The execution token provides an opaque handle for the compiled semantics, similar to the [function pointers](/wiki/Function_pointer "Function pointer") of the [C programming language](/wiki/C_(programming_language) "C (programming language)"). + +Execution tokens can be stored in variables. The word `EXECUTE` takes an execution token from the data stack and performs the associated semantics. The word `COMPILE,` (compile-comma) takes an execution token from the data stack and appends the associated semantics to the current definition. + +The word `'` (tick) takes the name of a word as a parameter and returns the execution token associated with that word on the data stack. In interpretation state, `' RANDOM-WORD EXECUTE` is equivalent to `RANDOM-WORD`.[[38]](#cite_note-iUYBX-39) + +#### Parsing words and comments + +[[edit](/w/index.php?title=Forth_(programming_language)&action=edit§ion=12 "Edit section: Parsing words and comments")] + +The words `:` (colon), `POSTPONE`, `'` (tick) are examples of *parsing words* that take their arguments from the user input device instead of the data stack. Another example is the word `(` (paren) which reads and ignores the following words up to and including the next right parenthesis and is used to place comments in a colon definition. Similarly, the word `\` (backslash) is used for comments that continue to the end of the current line. To be parsed correctly, `(` (paren) and `\` (backslash) must be separated by whitespace from the following comment text. + +### Structure of code + +[[edit](/w/index.php?title=Forth_(programming_language)&action=edit§ion=13 "Edit section: Structure of code")] + +In most Forth systems, the body of a code definition consists of either [machine language](/wiki/Machine_language "Machine language"), or some form of [threaded code](/wiki/Threaded_code "Threaded code"). The original Forth which follows the informal FIG standard (Forth Interest Group), is a TIL (Threaded Interpretive Language). This is also called indirect-threaded code, but direct-threaded and subroutine threaded Forths have also become popular in modern times. The fastest modern Forths, such as SwiftForth, VFX Forth, and iForth, compile Forth to native machine code. + +### Data objects + +[[edit](/w/index.php?title=Forth_(programming_language)&action=edit§ion=14 "Edit section: Data objects")] + +When a word is a variable or other data object, the CF points to the runtime code associated with the defining word that created it. A defining word has a characteristic "defining behavior" (creating a dictionary entry plus possibly allocating and initializing data space) and also specifies the behavior of an instance of the class of words constructed by this defining word. Examples include: + +`VARIABLE` +: Names an uninitialized, one-cell memory location. Instance behavior of a `VARIABLE` returns its address on the stack. + +`CONSTANT` +: Names a value (specified as an argument to `CONSTANT`). Instance behavior returns the value. + +`CREATE` +: Names a location; space may be allocated at this location, or it can be set to contain a string or other initialized value. Instance behavior returns the address of the beginning of this space. + +Forth also provides a facility by which a programmer can define new application-specific defining words, specifying both a custom defining behavior and instance behavior. Some examples include circular buffers, named bits on an I/O port, and automatically indexed arrays. + +Data objects defined by these and similar words are global in scope. The function provided by local variables in other languages is provided by the data stack in Forth (although Forth also has real local variables). Forth programming style uses very few named data objects compared with other languages; typically such data objects are used to contain data which is used by a number of words or tasks (in a multitasked implementation).[[39]](#cite_note-ceEJ3-40) + +Forth does not enforce consistency of [data type](/wiki/Data_type "Data type") usage; it is the programmer's responsibility to use appropriate operators to fetch and store values or perform other operations on data. + +## Examples + +[[edit](/w/index.php?title=Forth_(programming_language)&action=edit§ion=15 "Edit section: Examples")] + +### “Hello, World!” + +[[edit](/w/index.php?title=Forth_(programming_language)&action=edit§ion=16 "Edit section: “Hello, World!”")] + +``` + : HELLO ( -- ) CR ." Hello, World!" ; +``` + +``` +HELLO +Hello, World! +``` + +The word `CR` (Carriage Return) causes the output following `CR` +to be displayed on a new line. The parsing word `."` (dot-quote) reads a double-quote delimited string and appends code to the current definition so that the parsed string will be displayed upon execution. The space character separating the word `."` from the string `Hello, World!` is not included as part of the string. It is needed so that the parser recognizes `."` as a Forth word. + +A standard Forth system is also an interpreter, and the same output can be obtained by typing the following code fragment into the Forth console: + +``` + CR .( Hello, World!) +``` + +`.(` (dot-paren) is an immediate word that parses a parenthesis-delimited string and displays it. As with the word `."` the space character separating `.(` from `Hello, World!` is not part of the string. + +The word `CR` comes before the text to print. By convention, the Forth interpreter does not start output on a new line. Also by convention, the interpreter waits for input at the end of the previous line, after an `ok` prompt. There is no implied "flush-buffer" action in Forth's `CR`, as sometimes is in other programming languages. + +### Mixing states of compiling and interpreting + +[[edit](/w/index.php?title=Forth_(programming_language)&action=edit§ion=17 "Edit section: Mixing states of compiling and interpreting")] + +Here is the definition of a word `EMIT-Q` which when executed emits the single character `Q`: + +``` + : EMIT-Q 81 ( the ASCII value for the character 'Q' ) EMIT ; +``` + +This definition was written to use the [ASCII](/wiki/ASCII "ASCII") value of the `Q` character (81) directly. The text between the parentheses is a comment and is ignored by the compiler. The word `EMIT` takes a value from the data stack and displays the corresponding character. + +The following redefinition of `EMIT-Q` uses the words `[` (left-bracket), `]` (right-bracket), `CHAR` and `LITERAL` to temporarily switch to interpreter state, calculate the ASCII value of the `Q` character, return to compilation state and append the calculated value to the current colon definition: + +``` + : EMIT-Q [ CHAR Q ] LITERAL EMIT ; +``` + +The parsing word `CHAR` takes a space-delimited word as parameter and places the value of its first character on the data stack. The word `[CHAR]` is an immediate version of `CHAR`. Using `[CHAR]`, the example definition for `EMIT-Q` could be rewritten like this: + +``` + : EMIT-Q [CHAR] Q EMIT ; \ Emit the single character 'Q' +``` + +This definition used `\` (backslash) for the describing comment. + +Both `CHAR` and `[CHAR]` are predefined in ANS Forth. Using `IMMEDIATE` and `POSTPONE`, `[CHAR]` could have been defined like this: + +``` + : [CHAR] CHAR POSTPONE LITERAL ; IMMEDIATE +``` + +### RC4 cipher program + +[[edit](/w/index.php?title=Forth_(programming_language)&action=edit§ion=18 "Edit section: RC4 cipher program")] + +In 1987, [Ron Rivest](/wiki/Ron_Rivest "Ron Rivest") developed the [RC4](/wiki/RC4 "RC4") cipher-system for RSA Data Security, Inc. Its description follows: + +> We have an array of 256 bytes, all different. Every time the array is used it changes by swapping two bytes. The swaps are controlled by counters *i* and *j*, each initially 0. To get a new *i*, add 1. To get a new *j*, add the array byte at the new *i*. Exchange the array bytes at *i* and *j*. The code is the array byte at the sum of the array bytes at *i* and *j*. This is XORed with a byte of the plaintext to encrypt, or the ciphertext to decrypt. The array is initialized by first setting it to 0 through 255. Then step through it using *i* and *j*, getting the new *j* by adding to it the array byte at *i* and a key byte, and swapping the array bytes at *i* and *j*. Finally, *i* and *j* are set to 0. All additions are modulo 256. + +The following Standard Forth version uses Core and Core Extension words only. + +``` +0 value ii 0 value jj +0 value KeyAddr 0 value KeyLen +create SArray 256 allot \ state array of 256 bytes +: KeyArray KeyLen mod KeyAddr ; + +: get_byte + c@ ; +: set_byte + c! ; +: as_byte 255 and ; +: reset_ij 0 TO ii 0 TO jj ; +: i_update 1 + as_byte TO ii ; +: j_update ii SArray get_byte + as_byte TO jj ; +: swap_s_ij + jj SArray get_byte + ii SArray get_byte jj SArray set_byte + ii SArray set_byte +; + +: rc4_init ( KeyAddr KeyLen -- ) + 256 min TO KeyLen TO KeyAddr + 256 0 DO i i SArray set_byte LOOP + reset_ij + BEGIN + ii KeyArray get_byte jj + j_update + swap_s_ij + ii 255 < WHILE + ii i_update + REPEAT + reset_ij +; +: rc4_byte + ii i_update jj j_update + swap_s_ij + ii SArray get_byte jj SArray get_byte + as_byte SArray get_byte xor +; +``` + +This is one way to test the code: + +``` +hex +create AKey 61 c, 8A c, 63 c, D2 c, FB c, +: test cr 0 DO rc4_byte . LOOP cr ; +AKey 5 rc4_init +2C F9 4C EE DC 5 test \ output should be: F1 38 29 C9 DE +``` + +## Forth engines + +[[edit](/w/index.php?title=Forth_(programming_language)&action=edit§ion=19 "Edit section: Forth engines")] + +A processor designed to support a specific programming language is called a language "engine".[[40]](#cite_note-dumse-41) + +Forth engines are hardware platforms specifically designed to support developing and running programs written in Forth. (Likewise, [Lisp machines](/wiki/Lisp_machine "Lisp machine") were specifically designed to support developing and running programs written in Lisp, the [Pascal MicroEngine](/wiki/Pascal_MicroEngine "Pascal MicroEngine") was specifically designed to support developing and running programs written in Pascal, etc.). + +The first commercially available single-chip Forth engine was the Rockwell R65F11,[[40]](#cite_note-dumse-41) +a chip that includes a Forth kernel in ROM, +an [enhanced 6502](/wiki/MOS_Technology_6502#Variations_and_derivatives "MOS Technology 6502"), SRAM, and various interface circuits that previously required peripheral chips.[[40]](#cite_note-dumse-41)[[41]](#cite_note-42)[[42]](#cite_note-43)[[43]](#cite_note-44)[[44]](#cite_note-45) + +Many other commercial CPUs (Harris RTX-2000, Novix NC4016, F21, MARC4, KimKlone, etc.) and many [homebrew CPUs](/wiki/Homebrew_CPU "Homebrew CPU") (My4TH, J1, H2, Mark 1 FORTH Computer, etc.) are specifically designed to run Forth. Typically they implement common Forth primitives such as the "Forth NEXT" as single instructions. + +## Implementations + +[[edit](/w/index.php?title=Forth_(programming_language)&action=edit§ion=20 "Edit section: Implementations")] + +Because Forth is simple to implement and has no standard reference implementation, there are numerous versions of the language. In addition to supporting the standard varieties of desktop computer systems ([POSIX](/wiki/POSIX "POSIX"), [Microsoft Windows](/wiki/Microsoft_Windows "Microsoft Windows"), [macOS](/wiki/MacOS "MacOS")), many of these Forth systems also target a variety of [embedded systems](/wiki/Embedded_system "Embedded system"). Listed here are some of the systems which conform to the 1994 ANS Forth standard. + +* ASYST, a Forth-like system for data collection and analysis [[45]](#cite_note-46)[[16]](#cite_note-Rwirj-17) +* [Gforth](/wiki/Gforth "Gforth"), a portable ANS Forth implementation from the [GNU Project](/wiki/GNU_Project "GNU Project") +* [noForth](https://home.hccnet.nl/anij/nof/noforth.html), an ANS Forth implementation (as far as possible) for Flash microcontrollers (MSP430, RISC-V & RP2040) +* [Open Firmware](/wiki/Open_Firmware "Open Firmware"), a [bootloader](/wiki/Bootloader "Bootloader") and [firmware](/wiki/Firmware "Firmware") standard based on ANS Forth +* [pForth](/wiki/PForth "PForth"), portable Forth written in C +* SP-Forth, ANS Forth implementation from the Russian Forth Interest Group (RuFIG) +* Swift Forth, machine code generating implementation from Forth, Inc. +* VFX Forth, optimizing native code Forth +* [Firth](https://littlemanstackmachine.org/firth.html), an adaptation of Forth for the Little Man Stack Machine computer. +* [Shi](https://gitlab.com/higaski/Shi), a fast and tiny embeddable Forth implementation written for the Thumb-2 ISA (ARMv7-M and newer). + +## See also + +[[edit](/w/index.php?title=Forth_(programming_language)&action=edit§ion=21 "Edit section: See also")] + +* [Video games written in Forth](/wiki/Category:Video_games_written_in_Forth "Category:Video games written in Forth") +* [RTX2010](/wiki/RTX2010 "RTX2010"), a CPU that runs Forth natively + +## Notes + +[[edit](/w/index.php?title=Forth_(programming_language)&action=edit§ion=22 "Edit section: Notes")] + +1. **[^](#cite_ref-3)** + There are exceptions, such as Ulrich Hoffmann's preForth[[1]](#cite_note-preForth_slides-1)[[2]](#cite_note-preForth-2) and Tom Zimmer's TCOM + +## References + +[[edit](/w/index.php?title=Forth_(programming_language)&action=edit§ion=23 "Edit section: References")] + +1. ^ [***a***](#cite_ref-preForth_slides_1-0) [***b***](#cite_ref-preForth_slides_1-1) + ["Ulrich Hoffmann's preForth slides"](http://www.euroforth.org/ef18/papers/hoffmann-slides.pdf) (PDF). +2. ^ [***a***](#cite_ref-preForth_2-0) [***b***](#cite_ref-preForth_2-1) + ["Ulrich Hoffmann's preForth"](http://www.euroforth.org/ef18/papers/hoffmann.pdf) (PDF). +3. ^ [***a***](#cite_ref-maher_4-0) [***b***](#cite_ref-maher_4-1) Maher, Jimmy (October 28, 2014). ["Starflight"](https://www.filfre.net/2014/10/starflight/). *The Digital Antiquarian*. Retrieved April 29, 2023. +4. **[^](#cite_ref-oSWRm_5-0)** [NASA applications of Forth](https://web.archive.org/web/20101024223709/http://forth.gsfc.nasa.gov/) (original NASA server no longer running, copy from archive.org) +5. **[^](#cite_ref-zYmBe_6-0)** ["Intersil's RTX processors and Forth software controlled the successful Philae landing"](https://web.archive.org/web/20230429195754/https://mpeforth.com/press/MPE_PR_From_Telescope_to_Comet_2014_11_13.pdf) (PDF). *MicroProcessor Engineering Limited*. October 13, 2014. Archived from [the original](https://mpeforth.com/press/MPE_PR_From_Telescope_to_Comet_2014_11_13.pdf) (PDF) on April 29, 2023. Retrieved April 29, 2023. +6. **[^](#cite_ref-sgEMh_7-0)** ["Here comes Philae! Powered by an RTX2010"](https://www.cpushack.com/2014/11/12/here-comes-philae-powered-by-an-rtx2010/). *The CPU Shack Museum*. October 12, 2014. Retrieved April 29, 2023. +7. **[^](#cite_ref-C4Oss_8-0)** ["Space Related Applications of Forth"](https://web.archive.org/web/20101024223709/http://forth.gsfc.nasa.gov/). Archived from [the original](https://forth.gsfc.nasa.gov) on 2010-10-24. Retrieved 2007-09-04. +8. ^ [***a***](#cite_ref-evolution_9-0) [***b***](#cite_ref-evolution_9-1) [***c***](#cite_ref-evolution_9-2) Rather, Elizabeth D.; Colburn, Donald R.; Moore, Charles H. (1996) [1993]. ["The evolution of Forth"](http://www.forth.com/resources/evolution/index.html). In Bergin, Thomas J.; Gibson, Richard G. (eds.). *History of programming languages---II*. Association for Computing Machinery. pp. 625–670. [doi](/wiki/Doi_(identifier) "Doi (identifier)"):[10.1145/234286.1057832](https://doi.org/10.1145%2F234286.1057832). [ISBN](/wiki/ISBN_(identifier) "ISBN (identifier)") [0201895021](/wiki/Special:BookSources/0201895021 "Special:BookSources/0201895021"). +9. **[^](#cite_ref-10)** ["Atari In-Store Demonstration Program"](http://www.atarimania.com/demo-atari-400-800-xl-xe-in-store-demonstration-program_19329.html). *Atari Mania*. +10. **[^](#cite_ref-11)** Maynard, David S. ["David Maynard: Software Artist"](https://www.software-artist.com). +11. **[^](#cite_ref-12)** John Romero (2020-09-23). ["Time Warp: Episode 9 - Stuart Smith"](https://appletimewarp.libsyn.com/episode-9-stuart-smith) (Podcast). Event occurs at 29:02. +12. **[^](#cite_ref-13)** Aycock, John (2023). [*Amnesia Remembered: Reverse Engineering a Digital Artifact*](https://www.berghahnbooks.com/title/AycockAmnesia). Berghahn Books. p. 79. [ISBN](/wiki/ISBN_(identifier) "ISBN (identifier)") [978-1800738676](/wiki/Special:BookSources/978-1800738676 "Special:BookSources/978-1800738676"). +13. **[^](#cite_ref-14)** Sharp, Doug (8 April 2023). ["FORTH Programming Language (Going FORTH)"](https://chipwits.com/2023/04/08/forth-programming-language-going-forth/). +14. **[^](#cite_ref-15)** Rochat, Jan (February 6, 2025). ["Back to 1985: How We Remade ChipWits for the C64"](https://chipwits.com/2025/02/06/back-to-1985-how-we-remade-chipwits-for-the-c64/). +15. **[^](#cite_ref-16)** ["FORTH GETS ITS OWN SPECIAL INTEREST GROUP"](https://techmonitor.ai/technology/forth_gets_its_own_special_interest_group). *Tech Monitor*. 6 February 1989. +16. ^ [***a***](#cite_ref-Rwirj_17-0) [***b***](#cite_ref-Rwirj_17-1) Campbell et al, "Up and Running with Asyst 2.0", MacMillan Software Co., 1987 +17. **[^](#cite_ref-WYK4Z_18-0)** Moore, Charles H. (1991). ["Forth - The Early Years"](https://web.archive.org/web/20060615025259/http://www.colorforth.com/HOPL.html). Archived from [the original](http://www.colorforth.com/HOPL.html) on 2006-06-15. Retrieved 2006-06-03. +18. **[^](#cite_ref-19)** Moore, Charles H. (August 1980). ["The Evolution of FORTH, an Unusual Language"](https://archive.org/details/byte-magazine-1980-08/page/n77/mode/2up). *BYTE Magazine*. **5** (8): 82. +19. **[^](#cite_ref-20)** ["ANS 1994 Specification, Annex C ("Perspective")"](https://www.taygeta.com/forth/dpansc.htm). *taygeta.com*. +20. **[^](#cite_ref-1AvuY_21-0)** ["The Forth Language"](https://archive.org/details/byte-magazine-1980-08/), *BYTE Magazine*, **5** (8), 1980 +21. **[^](#cite_ref-family-tree_22-0)** M. Anton Ertl. ["Forth family tree and timeline"](https://www.complang.tuwien.ac.at/forth/family-tree/). +22. **[^](#cite_ref-gWyzb_23-0)** Lutus, Paul (1982). ["GraFORTH Language Manual"](https://archive.org/details/graforth1). *archive.org*. Insoft. +23. **[^](#cite_ref-qyrcN_24-0)** ["The Forth-79 Standard"](https://www.physics.wisc.edu/~lmaurer/forth/Forth-79.pdf) (PDF). Retrieved 2023-04-29. +24. **[^](#cite_ref-BQ2oi_25-0)** ["The Forth-83 Standard"](https://web.archive.org/web/20230405001333/https://forth.sourceforge.net/standard/fst83/). Archived from [the original](https://forth.sourceforge.net/standard/fst83/) on 2023-04-05. Retrieved 2023-04-29. +25. **[^](#cite_ref-IGDIN_26-0)** ["Programming Languages: Forth"](https://www.taygeta.com/forth/dpans.html). ANSI technical committee X3J14. 24 March 1994. Retrieved 2006-06-03. +26. **[^](#cite_ref-KojQK_27-0)** ["Standard Forth (ANSI INCITS 215-1994) Reference"](http://quartus.net/files/PalmOS/Forth/Docs/stdref.pdf) (PDF). Quartus Handheld Software. 13 September 2005. Retrieved 2023-04-29. +27. **[^](#cite_ref-BtuRy_28-0)** Claunch, Carl (2018-03-02). ["Restoring the original source code for FORTH on the IBM 1130"](https://rescue1130.blogspot.com/2018/03/restoring-original-source-code-for.html). *rescue1130*. Retrieved July 30, 2018. +28. **[^](#cite_ref-29)** + Brodie, Leo (1987). [*Starting Forth*](https://www.forth.com/starting-forth/index.html) (2nd ed.). Prentice-Hall. [ISBN](/wiki/ISBN_(identifier) "ISBN (identifier)") [978-0-13-843079-5](/wiki/Special:BookSources/978-0-13-843079-5 "Special:BookSources/978-0-13-843079-5"). +29. **[^](#cite_ref-3yqc9_30-0)** [Brodie 1987](#CITEREFBrodie1987), p. 20 +30. **[^](#cite_ref-6dQ7P_31-0)** + [Brodie 1987](#CITEREFBrodie1987), p. 14 +31. ^ [***a***](#cite_ref-compiler_32-0) [***b***](#cite_ref-compiler_32-1) [***c***](#cite_ref-compiler_32-2) [***d***](#cite_ref-compiler_32-3) + [Brodie 1987](#CITEREFBrodie1987), p. 16 +32. **[^](#cite_ref-NAFQu_33-0)** Rodriguez, Brad. ["Build Your Own Assembler, Part 2: a 6809 Forth Assembler"](https://www.bradrodriguez.com/papers/6809asm.txt). Retrieved 2023-04-29. +33. **[^](#cite_ref-nxtDb_34-0)** Rodriguez, Brad. ["Multitasking 8051 CamelForth"](https://www.bradrodriguez.com/papers/8051task.pdf) (PDF). Retrieved 2023-04-29. +34. **[^](#cite_ref-Swdke_35-0)** Rodriguez, Brad (July–August 1995). ["MOVING FORTH, Part 8: CamelForth for the 6809"](https://www.bradrodriguez.com/papers/moving8.htm). Retrieved 2023-04-29. +35. **[^](#cite_ref-E5iFy_36-0)** Shoebridge, Peter (1998-12-21). ["Motorola Background Debugging Mode Driver for Windows NT"](https://web.archive.org/web/20070606083244/http://www.zeecube.com/archive/bdm/index.htm). Archived from [the original](http://www.zeecube.com/archive/bdm/index.htm) on 2007-06-06. Retrieved 2006-06-19. +36. **[^](#cite_ref-lx5fY_37-0)** Martin, Harold M. (March 1991). ["Developing a tethered Forth model"](https://doi.org/10.1145%2F122089.122091). *ACM SIGFORTH Newsletter*. **2** (3). ACM Press: 17–19. [doi](/wiki/Doi_(identifier) "Doi (identifier)"):[10.1145/122089.122091](https://doi.org/10.1145%2F122089.122091). [S2CID](/wiki/S2CID_(identifier) "S2CID (identifier)") [26362015](https://api.semanticscholar.org/CorpusID:26362015). +37. **[^](#cite_ref-odMGJ_38-0)** [Brodie 1987](#CITEREFBrodie1987), p. 273 +38. **[^](#cite_ref-iUYBX_39-0)** [Brodie 1987](#CITEREFBrodie1987), p. 199 +39. **[^](#cite_ref-ceEJ3_40-0)** "Under The Hood". *[Brodie 1987](#CITEREFBrodie1987)*. p. 241. "To summarize, there are three kinds of variables: System variables contain values used by the entire Forth system. User variables contain values that are unique for each task, even though the definitions can be used by all tasks in the system. Regular variables can be accessible either system-wide or within a single task only, depending upon whether they are defined within `OPERATOR` or within a private task." +40. ^ [***a***](#cite_ref-dumse_41-0) [***b***](#cite_ref-dumse_41-1) [***c***](#cite_ref-dumse_41-2) Randy M. Dumse. + "The R65F11 and F68K Single-Chip Forth Computers". + [[1]](http://www.forth.org/bournemouth/jfar/vol2/no1/article1.pdf)[*[permanent dead link](/wiki/Wikipedia:Link_rot "Wikipedia:Link rot")*] + [[2]](http://soton.mpeforth.com/flag/jfar/vol2/no1/article1.pdf) [Archived](https://web.archive.org/web/20141202144044/http://soton.mpeforth.com/flag/jfar/vol2/no1/article1.pdf) 2014-12-02 at the [Wayback Machine](/wiki/Wayback_Machine "Wayback Machine") + 1984. +41. **[^](#cite_ref-42)** + Ed Schmauch. + ["A Computerized Corrosion Monitoring System"](http://www.forth.org/bournemouth/jfar/vol4/no2/article48.pdf)[*[permanent dead link](/wiki/Wikipedia:Link_rot "Wikipedia:Link rot")*]. + 1986. +42. **[^](#cite_ref-43)** Lawrence P. Forsley. + ["Embedded systems: 1990 Rochester Forth Conference: June 12 – 16th, 1990 University of Rochester"](https://books.google.com/books?id=Yx8YAQAAMAAJ) [Archived](https://web.archive.org/web/20150325214054/http://books.google.com/books?id=Yx8YAQAAMAAJ) 2015-03-25 at the [Wayback Machine](/wiki/Wayback_Machine "Wayback Machine"). + p. 51. +43. **[^](#cite_ref-44)** Rockwell. + ["RSC-Forth User's Manual"](http://www.smallestplcoftheworld.org/RSC-FORTH_User's_Manual.pdf) [Archived](https://web.archive.org/web/20131207015149/http://smallestplcoftheworld.org/RSC-FORTH_User%27s_Manual.pdf) 2013-12-07 at the [Wayback Machine](/wiki/Wayback_Machine "Wayback Machine"). + 1983. +44. **[^](#cite_ref-45)** ["Rockwell R65F11 R65F12 Forth Based Microcomputers"](http://archive.6502.org/datasheets/rockwell_r65f11_r65f12_forth_microcomputers.pdf) (PDF). June 1987. [Archived](https://web.archive.org/web/20200804035007/http://archive.6502.org/datasheets/rockwell_r65f11_r65f12_forth_microcomputers.pdf) (PDF) from the original on 4 August 2020. Retrieved 28 Apr 2020. +45. **[^](#cite_ref-46)** Hary, David; Oshio, Koichi; Flanagan, Steven D. (1987). "The ASYST Software for Scientific Computing". *Science*. **236** (4805): 1128–32. [Bibcode](/wiki/Bibcode_(identifier) "Bibcode (identifier)"):[1987Sci...236.1128H](https://ui.adsabs.harvard.edu/abs/1987Sci...236.1128H). [doi](/wiki/Doi_(identifier) "Doi (identifier)"):[10.1126/science.236.4805.1128](https://doi.org/10.1126%2Fscience.236.4805.1128). [JSTOR](/wiki/JSTOR_(identifier) "JSTOR (identifier)") [1699106](https://www.jstor.org/stable/1699106). [PMID](/wiki/PMID_(identifier) "PMID (identifier)") [17799670](https://pubmed.ncbi.nlm.nih.gov/17799670). [S2CID](/wiki/S2CID_(identifier) "S2CID (identifier)") [30463062](https://api.semanticscholar.org/CorpusID:30463062). + +## External links + +[[edit](/w/index.php?title=Forth_(programming_language)&action=edit§ion=24 "Edit section: External links")] + +* [Forth 2012 Standard](https://forth-standard.org) official site +* [*Programming a problem-oriented language*](https://forth.org/POL.pdf) unpublished book by Charles H. Moore (1970) +* [Annual European Forth Conference](https://www.euroforth.org/) 1985–present +* [Forth Research](https://www.complang.tuwien.ac.at/projects/forth.html) at Institut für Computersprachen + +[![](//upload.wikimedia.org/wikipedia/en/thumb/4/4a/Commons-logo.svg/40px-Commons-logo.svg.png)](/wiki/File:Commons-logo.svg) + +Wikimedia Commons has media related to [Forth (programming language)](https://commons.wikimedia.org/wiki/Category:Forth_(programming_language) "commons:Category:Forth (programming language)"). + +[![](//upload.wikimedia.org/wikipedia/commons/thumb/d/df/Wikibooks-logo-en-noslogan.svg/40px-Wikibooks-logo-en-noslogan.svg.png)](/wiki/File:Wikibooks-logo-en-noslogan.svg) + +Wikibooks has a book on the topic of: ***[Forth](https://en.wikibooks.org/wiki/Forth "wikibooks:Forth")*** + +| * [v](/wiki/Template:Programming_languages "Template:Programming languages") * [t](/wiki/Template_talk:Programming_languages "Template talk:Programming languages") * [e](/wiki/Special:EditPage/Template:Programming_languages "Special:EditPage/Template:Programming languages") [Programming languages](/wiki/Programming_language "Programming language") | | +| --- | --- | +| * [Comparison](/wiki/Comparison_of_programming_languages "Comparison of programming languages") * [Timeline](/wiki/Timeline_of_programming_languages "Timeline of programming languages") * [History](/wiki/History_of_programming_languages "History of programming languages") | | +| * [Ada](/wiki/Ada_(programming_language) "Ada (programming language)") * [ALGOL](/wiki/ALGOL "ALGOL") + [Simula](/wiki/Simula "Simula") * [APL](/wiki/APL_(programming_language) "APL (programming language)") * [Assembly](/wiki/Assembly_language "Assembly language") * [BASIC](/wiki/BASIC "BASIC") + [Visual Basic](/wiki/Visual_Basic "Visual Basic") - [classic](/wiki/Visual_Basic_(classic) "Visual Basic (classic)") - [.NET](/wiki/Visual_Basic_(.NET) "Visual Basic (.NET)") * [C](/wiki/C_(programming_language) "C (programming language)") * [C++](/wiki/C%2B%2B "C++") * [C#](/wiki/C_Sharp_(programming_language) "C Sharp (programming language)") * [COBOL](/wiki/COBOL "COBOL") * [Erlang](/wiki/Erlang_(programming_language) "Erlang (programming language)") + [Elixir](/wiki/Elixir_(programming_language) "Elixir (programming language)") * Forth * [Fortran](/wiki/Fortran "Fortran") * [Go](/wiki/Go_(programming_language) "Go (programming language)") * [Haskell](/wiki/Haskell "Haskell") * [Java](/wiki/Java_(programming_language) "Java (programming language)") * [JavaScript](/wiki/JavaScript "JavaScript") * [Julia](/wiki/Julia_(programming_language) "Julia (programming language)") * [Kotlin](/wiki/Kotlin "Kotlin") * [Lisp](/wiki/Lisp_(programming_language) "Lisp (programming language)") * [Lua](/wiki/Lua "Lua") * [MATLAB](/wiki/MATLAB "MATLAB") * [ML](/wiki/ML_(programming_language) "ML (programming language)") + [Caml](/wiki/Caml "Caml") - [OCaml](/wiki/OCaml "OCaml") + [Standard ML](/wiki/Standard_ML "Standard ML") * [Pascal](/wiki/Pascal_(programming_language) "Pascal (programming language)") + [Object Pascal](/wiki/Object_Pascal "Object Pascal") * [Perl](/wiki/Perl "Perl") + [Raku](/wiki/Raku_(programming_language) "Raku (programming language)") * [PHP](/wiki/PHP "PHP") * [Prolog](/wiki/Prolog "Prolog") * [Python](/wiki/Python_(programming_language) "Python (programming language)") * [R](/wiki/R_(programming_language) "R (programming language)") * [Ruby](/wiki/Ruby_(programming_language) "Ruby (programming language)") * [Rust](/wiki/Rust_(programming_language) "Rust (programming language)") * [SAS](/wiki/SAS_language "SAS language") * [SQL](/wiki/SQL "SQL") * [Scratch](/wiki/Scratch_(programming_language) "Scratch (programming language)") * [Shell](/wiki/Shell_script "Shell script") * [Smalltalk](/wiki/Smalltalk "Smalltalk") * [Swift](/wiki/Swift_(programming_language) "Swift (programming language)") * *[more...](/wiki/List_of_programming_languages "List of programming languages")* | | +| * **Lists:** [Alphabetical](/wiki/List_of_programming_languages "List of programming languages") * [Categorical](/wiki/List_of_programming_languages_by_type "List of programming languages by type") * [Generational](/wiki/Generational_list_of_programming_languages "Generational list of programming languages") * [Non-English-based](/wiki/Non-English-based_programming_languages "Non-English-based programming languages") * [Category](/wiki/Category:Programming_languages "Category:Programming languages") | | + +| [Authority control databases](/wiki/Help:Authority_control "Help:Authority control") [Edit this at Wikidata](https://www.wikidata.org/wiki/Q275472#identifiers "Edit this at Wikidata") | | +| --- | --- | +| International | * [GND](https://d-nb.info/gnd/4017981-3) | +| National | * [United States](https://id.loc.gov/authorities/sh85050918) * [Israel](https://www.nli.org.il/en/authorities/987007545715805171) | +| Other | * [Yale LUX](https://lux.collections.yale.edu/view/concept/931111ef-f1ef-4ba1-8d0d-0108e93a3b91) | + +![](https://en.wikipedia.org/wiki/Special:CentralAutoLogin/start?useformat=desktop&type=1x1&usesul3=1) + +Retrieved from "" + +[Categories](/wiki/Help:Category "Help:Category"): + +* [Forth programming language family](/wiki/Category:Forth_programming_language_family "Category:Forth programming language family") +* [Concatenative programming languages](/wiki/Category:Concatenative_programming_languages "Category:Concatenative programming languages") +* [Stack-based virtual machines](/wiki/Category:Stack-based_virtual_machines "Category:Stack-based virtual machines") +* [Systems programming languages](/wiki/Category:Systems_programming_languages "Category:Systems programming languages") +* [Programming languages created in 1970](/wiki/Category:Programming_languages_created_in_1970 "Category:Programming languages created in 1970") +* [Extensible syntax programming languages](/wiki/Category:Extensible_syntax_programming_languages "Category:Extensible syntax programming languages") +* [Programming languages with an ISO standard](/wiki/Category:Programming_languages_with_an_ISO_standard "Category:Programming languages with an ISO standard") +* [Programming languages](/wiki/Category:Programming_languages "Category:Programming languages") +* [1970 software](/wiki/Category:1970_software "Category:1970 software") + +Hidden categories: + +* [All articles with dead external links](/wiki/Category:All_articles_with_dead_external_links "Category:All articles with dead external links") +* [Articles with dead external links from May 2017](/wiki/Category:Articles_with_dead_external_links_from_May_2017 "Category:Articles with dead external links from May 2017") +* [Articles with permanently dead external links](/wiki/Category:Articles_with_permanently_dead_external_links "Category:Articles with permanently dead external links") +* [Webarchive template wayback links](/wiki/Category:Webarchive_template_wayback_links "Category:Webarchive template wayback links") +* [Articles with short description](/wiki/Category:Articles_with_short_description "Category:Articles with short description") +* [Short description is different from Wikidata](/wiki/Category:Short_description_is_different_from_Wikidata "Category:Short description is different from Wikidata") +* [All articles with unsourced statements](/wiki/Category:All_articles_with_unsourced_statements "Category:All articles with unsourced statements") +* [Articles with unsourced statements from April 2022](/wiki/Category:Articles_with_unsourced_statements_from_April_2022 "Category:Articles with unsourced statements from April 2022") +* [Commons category link is on Wikidata](/wiki/Category:Commons_category_link_is_on_Wikidata "Category:Commons category link is on Wikidata") +* [Articles with example C code](/wiki/Category:Articles_with_example_C_code "Category:Articles with example C code") + +* This page was last edited on 1 January 2026, at 20:21 (UTC). +* Text is available under the [Creative Commons Attribution-ShareAlike 4.0 License](/wiki/Wikipedia:Text_of_the_Creative_Commons_Attribution-ShareAlike_4.0_International_License "Wikipedia:Text of the Creative Commons Attribution-ShareAlike 4.0 International License"); + additional terms may apply. By using this site, you agree to the [Terms of Use](https://foundation.wikimedia.org/wiki/Special:MyLanguage/Policy:Terms_of_Use "foundation:Special:MyLanguage/Policy:Terms of Use") and [Privacy Policy](https://foundation.wikimedia.org/wiki/Special:MyLanguage/Policy:Privacy_policy "foundation:Special:MyLanguage/Policy:Privacy policy"). Wikipedia® is a registered trademark of the [Wikimedia Foundation, Inc.](https://wikimediafoundation.org/), a non-profit organization. + +* [Privacy policy](https://foundation.wikimedia.org/wiki/Special:MyLanguage/Policy:Privacy_policy) +* [About Wikipedia](/wiki/Wikipedia:About) +* [Disclaimers](/wiki/Wikipedia:General_disclaimer) +* [Contact Wikipedia](//en.wikipedia.org/wiki/Wikipedia:Contact_us) +* [Legal & safety contacts](https://foundation.wikimedia.org/wiki/Special:MyLanguage/Legal:Wikimedia_Foundation_Legal_and_Safety_Contact_Information) +* [Code of Conduct](https://foundation.wikimedia.org/wiki/Special:MyLanguage/Policy:Universal_Code_of_Conduct) +* [Developers](https://developer.wikimedia.org) +* [Statistics](https://stats.wikimedia.org/#/en.wikipedia.org) +* [Cookie statement](https://foundation.wikimedia.org/wiki/Special:MyLanguage/Policy:Cookie_statement) +* [Mobile view](//en.wikipedia.org/w/index.php?title=Forth_(programming_language)&mobileaction=toggle_view_mobile) + +* [![Wikimedia Foundation](/static/images/footer/wikimedia.svg)](https://www.wikimedia.org/) +* [![Powered by MediaWiki](/w/resources/assets/mediawiki_compact.svg)](https://www.mediawiki.org/) + +Search + +Search + +Toggle the table of contents + +Forth (programming language) + +34 languages +[Add topic](#) \ No newline at end of file diff --git a/references/ForthNotes/b4_virtual_machine.md b/references/ForthNotes/b4_virtual_machine.md new file mode 100644 index 0000000..55646f7 --- /dev/null +++ b/references/ForthNotes/b4_virtual_machine.md @@ -0,0 +1,445 @@ +# b4 virtual machine + +**Source:** https://github.com/tangentstorm/b4 + +GitHub - tangentstorm/b4: b4 : a tiny forth-like virtual machine + + + +[Skip to content](#start-of-content) + + + + + + + + + + + + + +## Navigation Menu + +Toggle navigation + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2Ftangentstorm%2Fb4) + +Appearance settings + +* Platform + + + AI CODE CREATION + - [GitHub CopilotWrite better code with AI](https://github.com/features/copilot) + - [GitHub SparkBuild and deploy intelligent apps](https://github.com/features/spark) + - [GitHub ModelsManage and compare prompts](https://github.com/features/models) + - [MCP RegistryNewIntegrate external tools](https://github.com/mcp) + + DEVELOPER WORKFLOWS + - [ActionsAutomate any workflow](https://github.com/features/actions) + - [CodespacesInstant dev environments](https://github.com/features/codespaces) + - [IssuesPlan and track work](https://github.com/features/issues) + - [Code ReviewManage code changes](https://github.com/features/code-review) + + APPLICATION SECURITY + - [GitHub Advanced SecurityFind and fix vulnerabilities](https://github.com/security/advanced-security) + - [Code securitySecure your code as you build](https://github.com/security/advanced-security/code-security) + - [Secret protectionStop leaks before they start](https://github.com/security/advanced-security/secret-protection) + + EXPLORE + - [Why GitHub](https://github.com/why-github) + - [Documentation](https://docs.github.com) + - [Blog](https://github.blog) + - [Changelog](https://github.blog/changelog) + - [Marketplace](https://github.com/marketplace) + + [View all features](https://github.com/features) +* Solutions + + + BY COMPANY SIZE + - [Enterprises](https://github.com/enterprise) + - [Small and medium teams](https://github.com/team) + - [Startups](https://github.com/enterprise/startups) + - [Nonprofits](https://github.com/solutions/industry/nonprofits) + + BY USE CASE + - [App Modernization](https://github.com/solutions/use-case/app-modernization) + - [DevSecOps](https://github.com/solutions/use-case/devsecops) + - [DevOps](https://github.com/solutions/use-case/devops) + - [CI/CD](https://github.com/solutions/use-case/ci-cd) + - [View all use cases](https://github.com/solutions/use-case) + + BY INDUSTRY + - [Healthcare](https://github.com/solutions/industry/healthcare) + - [Financial services](https://github.com/solutions/industry/financial-services) + - [Manufacturing](https://github.com/solutions/industry/manufacturing) + - [Government](https://github.com/solutions/industry/government) + - [View all industries](https://github.com/solutions/industry) + + [View all solutions](https://github.com/solutions) +* Resources + + + EXPLORE BY TOPIC + - [AI](https://github.com/resources/articles?topic=ai) + - [Software Development](https://github.com/resources/articles?topic=software-development) + - [DevOps](https://github.com/resources/articles?topic=devops) + - [Security](https://github.com/resources/articles?topic=security) + - [View all topics](https://github.com/resources/articles) + + EXPLORE BY TYPE + - [Customer stories](https://github.com/customer-stories) + - [Events & webinars](https://github.com/resources/events) + - [Ebooks & reports](https://github.com/resources/whitepapers) + - [Business insights](https://github.com/solutions/executive-insights) + - [GitHub Skills](https://skills.github.com) + + SUPPORT & SERVICES + - [Documentation](https://docs.github.com) + - [Customer support](https://support.github.com) + - [Community forum](https://github.com/orgs/community/discussions) + - [Trust center](https://github.com/trust-center) + - [Partners](https://github.com/partners) +* Open Source + + + COMMUNITY + - [GitHub SponsorsFund open source developers](https://github.com/sponsors) + + PROGRAMS + - [Security Lab](https://securitylab.github.com) + - [Maintainer Community](https://maintainers.github.com) + - [Accelerator](https://github.com/accelerator) + - [Archive Program](https://archiveprogram.github.com) + + REPOSITORIES + - [Topics](https://github.com/topics) + - [Trending](https://github.com/trending) + - [Collections](https://github.com/collections) +* Enterprise + + + ENTERPRISE SOLUTIONS + - [Enterprise platformAI-powered developer platform](https://github.com/enterprise) + + AVAILABLE ADD-ONS + - [GitHub Advanced SecurityEnterprise-grade security features](https://github.com/security/advanced-security) + - [Copilot for BusinessEnterprise-grade AI features](https://github.com/features/copilot/copilot-business) + - [Premium SupportEnterprise-grade 24/7 support](https://github.com/premium-support) +* [Pricing](https://github.com/pricing) + +Search or jump to... + + +# Search code, repositories, users, issues, pull requests... + +Search + +Clear + +[Search syntax tips](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax) + +# Provide feedback + +We read every piece of feedback, and take your input very seriously. + + +Include my email address so I can be contacted + +Cancel + Submit feedback + + + + + +# Saved searches + +## Use saved searches to filter your results more quickly + +Name + +Query + +To see all available qualifiers, see our [documentation](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax). + +Cancel + Create saved search + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2Ftangentstorm%2Fb4) + +[Sign up](/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E&source=header-repo&source_repo=tangentstorm%2Fb4) + +Appearance settings + +Resetting focus + +You signed in with another tab or window. Reload to refresh your session. +You signed out in another tab or window. Reload to refresh your session. +You switched accounts on another tab or window. Reload to refresh your session. + + + +Dismiss alert + +{{ message }} + +[tangentstorm](/tangentstorm) +/ +**[b4](/tangentstorm/b4)** +Public + +* [Notifications](/login?return_to=%2Ftangentstorm%2Fb4) You must be signed in to change notification settings +* [Fork + 4](/login?return_to=%2Ftangentstorm%2Fb4) +* [Star + 39](/login?return_to=%2Ftangentstorm%2Fb4) + +b4 : a tiny forth-like virtual machine + +[www.reddit.com/r/b4lang/](http://www.reddit.com/r/b4lang/ "http://www.reddit.com/r/b4lang/") + +[39 +stars](/tangentstorm/b4/stargazers) [4 +forks](/tangentstorm/b4/forks) [Branches](/tangentstorm/b4/branches) [Tags](/tangentstorm/b4/tags) [Activity](/tangentstorm/b4/activity) + +[Star](/login?return_to=%2Ftangentstorm%2Fb4) + +[Notifications](/login?return_to=%2Ftangentstorm%2Fb4) You must be signed in to change notification settings + +* [Code](/tangentstorm/b4) +* [Issues + 0](/tangentstorm/b4/issues) +* [Pull requests + 2](/tangentstorm/b4/pulls) +* [Actions](/tangentstorm/b4/actions) +* [Projects + 0](/tangentstorm/b4/projects) +* [Wiki](/tangentstorm/b4/wiki) +* [Security + 0](/tangentstorm/b4/security) +* [Insights](/tangentstorm/b4/pulse) + +Additional navigation options + + +* [Code](/tangentstorm/b4) +* [Issues](/tangentstorm/b4/issues) +* [Pull requests](/tangentstorm/b4/pulls) +* [Actions](/tangentstorm/b4/actions) +* [Projects](/tangentstorm/b4/projects) +* [Wiki](/tangentstorm/b4/wiki) +* [Security](/tangentstorm/b4/security) +* [Insights](/tangentstorm/b4/pulse) + +# tangentstorm/b4 + +main + +[Branches](/tangentstorm/b4/branches)[Tags](/tangentstorm/b4/tags) + +Go to file + +Code + +Open more actions menu + +## Folders and files + +| Name | | Name | Last commit message | Last commit date | +| --- | --- | --- | --- | --- | +| Latest commit History[1,568 Commits](/tangentstorm/b4/commits/main/) 1,568 Commits | | | +| [b3a](/tangentstorm/b4/tree/main/b3a "b3a") | | [b3a](/tangentstorm/b4/tree/main/b3a "b3a") | | | +| [bios](/tangentstorm/b4/tree/main/bios "bios") | | [bios](/tangentstorm/b4/tree/main/bios "bios") | | | +| [doc](/tangentstorm/b4/tree/main/doc "doc") | | [doc](/tangentstorm/b4/tree/main/doc "doc") | | | +| [electron](/tangentstorm/b4/tree/main/electron "electron") | | [electron](/tangentstorm/b4/tree/main/electron "electron") | | | +| [etc](/tangentstorm/b4/tree/main/etc "etc") | | [etc](/tangentstorm/b4/tree/main/etc "etc") | | | +| [jlang](/tangentstorm/b4/tree/main/jlang "jlang") | | [jlang](/tangentstorm/b4/tree/main/jlang "jlang") | | | +| [js](/tangentstorm/b4/tree/main/js "js") | | [js](/tangentstorm/b4/tree/main/js "js") | | | +| [lil](/tangentstorm/b4/tree/main/lil "lil") | | [lil](/tangentstorm/b4/tree/main/lil "lil") | | | +| [mcp-b4i](/tangentstorm/b4/tree/main/mcp-b4i "mcp-b4i") | | [mcp-b4i](/tangentstorm/b4/tree/main/mcp-b4i "mcp-b4i") | | | +| [pas](/tangentstorm/b4/tree/main/pas "pas") | | [pas](/tangentstorm/b4/tree/main/pas "pas") | | | +| [ref](/tangentstorm/b4/tree/main/ref "ref") | | [ref](/tangentstorm/b4/tree/main/ref "ref") | | | +| [.gitignore](/tangentstorm/b4/blob/main/.gitignore ".gitignore") | | [.gitignore](/tangentstorm/b4/blob/main/.gitignore ".gitignore") | | | +| [ASSISTANTS.md](/tangentstorm/b4/blob/main/ASSISTANTS.md "ASSISTANTS.md") | | [ASSISTANTS.md](/tangentstorm/b4/blob/main/ASSISTANTS.md "ASSISTANTS.md") | | | +| [README.org](/tangentstorm/b4/blob/main/README.org "README.org") | | [README.org](/tangentstorm/b4/blob/main/README.org "README.org") | | | +| [b4-tests.org](/tangentstorm/b4/blob/main/b4-tests.org "b4-tests.org") | | [b4-tests.org](/tangentstorm/b4/blob/main/b4-tests.org "b4-tests.org") | | | +| [b4i](/tangentstorm/b4/blob/main/b4i "b4i") | | [b4i](/tangentstorm/b4/blob/main/b4i "b4i") | | | +| [b4i-tests.org](/tangentstorm/b4/blob/main/b4i-tests.org "b4i-tests.org") | | [b4i-tests.org](/tangentstorm/b4/blob/main/b4i-tests.org "b4i-tests.org") | | | +| [b4ix](/tangentstorm/b4/blob/main/b4ix "b4ix") | | [b4ix](/tangentstorm/b4/blob/main/b4ix "b4ix") | | | +| [b4s-tests.org](/tangentstorm/b4/blob/main/b4s-tests.org "b4s-tests.org") | | [b4s-tests.org](/tangentstorm/b4/blob/main/b4s-tests.org "b4s-tests.org") | | | +| [bios-tests.org](/tangentstorm/b4/blob/main/bios-tests.org "bios-tests.org") | | [bios-tests.org](/tangentstorm/b4/blob/main/bios-tests.org "bios-tests.org") | | | +| [goals.org](/tangentstorm/b4/blob/main/goals.org "goals.org") | | [goals.org](/tangentstorm/b4/blob/main/goals.org "goals.org") | | | +| [init.b4i](/tangentstorm/b4/blob/main/init.b4i "init.b4i") | | [init.b4i](/tangentstorm/b4/blob/main/init.b4i "init.b4i") | | | +| [plan.org](/tangentstorm/b4/blob/main/plan.org "plan.org") | | [plan.org](/tangentstorm/b4/blob/main/plan.org "plan.org") | | | +| [pre-tests.org](/tangentstorm/b4/blob/main/pre-tests.org "pre-tests.org") | | [pre-tests.org](/tangentstorm/b4/blob/main/pre-tests.org "pre-tests.org") | | | +| [test](/tangentstorm/b4/blob/main/test "test") | | [test](/tangentstorm/b4/blob/main/test "test") | | | +| [test-b4-b4a](/tangentstorm/b4/blob/main/test-b4-b4a "test-b4-b4a") | | [test-b4-b4a](/tangentstorm/b4/blob/main/test-b4-b4a "test-b4-b4a") | | | +| [test-b4-gd](/tangentstorm/b4/blob/main/test-b4-gd "test-b4-gd") | | [test-b4-gd](/tangentstorm/b4/blob/main/test-b4-gd "test-b4-gd") | | | +| [test-b4-j](/tangentstorm/b4/blob/main/test-b4-j "test-b4-j") | | [test-b4-j](/tangentstorm/b4/blob/main/test-b4-j "test-b4-j") | | | +| [test-b4-js](/tangentstorm/b4/blob/main/test-b4-js "test-b4-js") | | [test-b4-js](/tangentstorm/b4/blob/main/test-b4-js "test-b4-js") | | | +| [test-b4-lil](/tangentstorm/b4/blob/main/test-b4-lil "test-b4-lil") | | [test-b4-lil](/tangentstorm/b4/blob/main/test-b4-lil "test-b4-lil") | | | +| [test-b4-pas](/tangentstorm/b4/blob/main/test-b4-pas "test-b4-pas") | | [test-b4-pas](/tangentstorm/b4/blob/main/test-b4-pas "test-b4-pas") | | | +| [test-b4i-js](/tangentstorm/b4/blob/main/test-b4i-js "test-b4i-js") | | [test-b4i-js](/tangentstorm/b4/blob/main/test-b4i-js "test-b4i-js") | | | +| [test-b4i-lil](/tangentstorm/b4/blob/main/test-b4i-lil "test-b4i-lil") | | [test-b4i-lil](/tangentstorm/b4/blob/main/test-b4i-lil "test-b4i-lil") | | | +| [test-b4i-pas](/tangentstorm/b4/blob/main/test-b4i-pas "test-b4i-pas") | | [test-b4i-pas](/tangentstorm/b4/blob/main/test-b4i-pas "test-b4i-pas") | | | +| [test-b4s](/tangentstorm/b4/blob/main/test-b4s "test-b4s") | | [test-b4s](/tangentstorm/b4/blob/main/test-b4s "test-b4s") | | | +| [test-bios](/tangentstorm/b4/blob/main/test-bios "test-bios") | | [test-bios](/tangentstorm/b4/blob/main/test-bios "test-bios") | | | +| [test-pre](/tangentstorm/b4/blob/main/test-pre "test-pre") | | [test-pre](/tangentstorm/b4/blob/main/test-pre "test-pre") | | | +| View all files | | | + +## Repository files navigation + +* [README](#) + +# The b4 virtual machine + +# Demo + +[![ref/b4ix-rosetta.png](/tangentstorm/b4/raw/main/ref/b4ix-rosetta.png)](/tangentstorm/b4/blob/main/ref/b4ix-rosetta.png) + +The above screenshot is the `b4ix` enhanced interactive shell. The sceen is broken into three sections: + +* on top, a view into the systems video buffer, which is pre-initialized with a logo from the bios. +* in the middle, an interactive shell for the `b4a` assembly language. +* at the bottom, a view of stacks and section of the machine’s ram + +## explanation of the demo code + +``` +# https://rosettacode.org/wiki/Loops/For +:E lb 'e io rt # set up ^E to emit a character +:I cd cd du dc sw dc rt # set up ^I to fetch outer loop counter +:loop du .f du ^I sb c1 ad .f lb '. ^E .n lb '| ^E .n zp rt +5 loop +``` + +The `^E` syntax calls whatever function the `E` register is pointing at, and the assembler assigns it when it sees `:E`. + +Here, `^E` loads the byte `'e` (quoted ascii char) and sends that as a command to the `io` op, which prints the next character on the stack. + +The `^I` definition fetches the outer loop counter in a `.f` … `.n` (“for/next”) loop. + +Since it’s a function call, we have to dig deep into the control stack (`cd` means copy from control stack to data stack), (`du`)plicate the counter, and then (`sw`)ap it with the return address so we can push that back onto the control stack (`dc` means data -> control), and then `rt` (return). + +Then `:loop` dupes its argument and uses it as an argument to the `.f=/`.n= loop. + +During these loops, the loop counter is on the control stack, so `^I` grabs it as explained earlier, but there is also a copy of the original loop length (5 in this case) on the data stack. + +so `du ^I sb` duplicates the 5, subtracts the outer loop counter, and leaves the result on the stack. + +`c1` is an op that adds the constant 1 to the stack, and `ad` adds the top two values, so `c1 ad` adds 1 to the previous expression to get the length of the inner loop. + +`.f lb '. ^E .n` prints that many dots. + +`lb '| ^E .n` prints the pipe character and ends the outer loop. + +then `zp rt` removes that original `5` that’s been sitting on the stack the whole time (passed in when we explicitly called `5 loop`) and returns to the calling function (in this case, the interactive “b4ix” shell.) + +# About b4 + +**b4** is a tiny virtual machine, with a forth-like flavor. + +There are currently five implementations: + +* [./jlang/](/tangentstorm/b4/blob/main/jlang), implemented in [J](https://code.jsoftware.com/wiki/Main_Page). +* [./pas/](/tangentstorm/b4/blob/main/pas), implemented in [free pascal](https://www.freepascal.org/). +* [./lil/](/tangentstorm/b4/blob/main/lil), implemented in [lil](https://beyondloom.com/decker/lil.html). +* [./js/](/tangentstorm/b4/blob/main/js), implemented in javascript. +* [b4-gd](https://github.com/tangentstorm/b4-gd), implemented in GDScript for [Godot 4](https://docs.godotengine.org/en/stable/). + +The implementations are kept in sync through the tests in [./b4-tests.org](/tangentstorm/b4/blob/main/b4-tests.org) + +See [./bios/bios.b4a](/tangentstorm/b4/blob/main/bios/bios.b4a) for an example of b4 assembly language. + +# Links + +* [b4 github repo](https://github.com/tangentstorm/b4) +* twitter: [@tangentstorm](https://twitter.com/tangentstorm) / [#b4lang](https://twitter.com/#!/search/realtime/%23b4lang) +* reddit: [/r/b4lang](http://reddit.com/r/b4lang) + +# Background + +B4 is a forth-like virtual machine. Quick **intros to forth** (free and online): + +* [Programming a Problem-Oriented Language](http://www.colorforth.com/POL.htm) +* [Starting Forth](http://www.forth.com/starting-forth/) + +B4 was strongly influenced by the [ngaro virtual machine](http://retroforth.org/docs/The_Ngaro_Virtual_Machine.html) from retroforth 11, +as well as the [forth chips from greenarrays](https://www.greenarraychips.com/home/documents/index.php#architecture). + +## About + +b4 : a tiny forth-like virtual machine + +[www.reddit.com/r/b4lang/](http://www.reddit.com/r/b4lang/ "http://www.reddit.com/r/b4lang/") + +### Resources + +[Readme](#readme-ov-file) + +### Uh oh! + +There was an error while loading. Please reload this page. + +[Activity](/tangentstorm/b4/activity) + +### Stars + +[**39** +stars](/tangentstorm/b4/stargazers) + +### Watchers + +[**6** +watching](/tangentstorm/b4/watchers) + +### Forks + +[**4** +forks](/tangentstorm/b4/forks) + +[Report repository](/contact/report-content?content_url=https%3A%2F%2Fgithub.com%2Ftangentstorm%2Fb4&report=tangentstorm+%28user%29) + +## [Releases](/tangentstorm/b4/releases) + +No releases published + +## [Packages 0](/users/tangentstorm/packages?repo_name=b4) + +No packages published + +### Uh oh! + +There was an error while loading. Please reload this page. + +## [Contributors 3](/tangentstorm/b4/graphs/contributors) + +### Uh oh! + +There was an error while loading. Please reload this page. + +## Languages + +* [Pascal + 34.8%](/tangentstorm/b4/search?l=pascal) +* [Python + 22.4%](/tangentstorm/b4/search?l=python) +* [JavaScript + 10.7%](/tangentstorm/b4/search?l=javascript) +* [TypeScript + 8.5%](/tangentstorm/b4/search?l=typescript) +* [Forth + 7.8%](/tangentstorm/b4/search?l=forth) +* [J + 5.9%](/tangentstorm/b4/search?l=j) +* Other + 9.9% + +## Footer + +© 2026 GitHub, Inc. + +### Footer navigation + +* [Terms](https://docs.github.com/site-policy/github-terms/github-terms-of-service) +* [Privacy](https://docs.github.com/site-policy/privacy-policies/github-privacy-statement) +* [Security](https://github.com/security) +* [Status](https://www.githubstatus.com/) +* [Community](https://github.community/) +* [Docs](https://docs.github.com/) +* [Contact](https://support.github.com?tags=dotcom-footer) +* Manage cookies +* Do not share my personal information + + + +You can’t perform that action at this time. \ No newline at end of file diff --git a/references/ForthNotes/c2-for-me.md b/references/ForthNotes/c2-for-me.md new file mode 100644 index 0000000..be09876 --- /dev/null +++ b/references/ForthNotes/c2-for-me.md @@ -0,0 +1,12 @@ +# c2-for-me + +**Source:** http://marc.tries.fed.wiki/view/c2-for-me/ward.eu.wiki.org/c2-for-me + +c2 for me + + + +Site Owned by: Marc Pierson + +  +  \ No newline at end of file diff --git a/references/ForthNotes/call_versus_branch-and-link.md b/references/ForthNotes/call_versus_branch-and-link.md new file mode 100644 index 0000000..1f81877 --- /dev/null +++ b/references/ForthNotes/call_versus_branch-and-link.md @@ -0,0 +1,184 @@ +# call versus branch-and-link + +**Source:** https://muforth.dev/call-versus-branch-and-link/ + +Call versus branch-and-link – muforth + + +# Call versus branch-and-link + +--- + +### [What’s the big difference?](#whats-the-big-difference) + +Years ago, while pondering the “nature” of threaded code something struck me: In a threaded code system the *called* routine decides whether or not to push a return address onto the call stack. + +This is in contrast to native code running on “traditional” architectures with “call” instructions. Call instructions *always* push the return address, even when it’s unnecessary. (It’s unnecessary when the code being is called is *leaf* routine – one that makes no further calls. But the caller doesn’t – and can’t! – know this.) + +RISC architects realized that always pushing the return address was inefficient – doing so creates unnecessary memory traffic – and instead of call instructions specified “branch and link” instructions. + +What’s the difference? + +Operationally, a call instruction does two things: + +* pushes onto the stack the address of the following instruction +* jumps to the destination + +A branch-and-link instruction – maybe it should be called link-and-branch? – also does two things: + +* captures in a register (the “link” register) the address of the following instruction +* jumps to the destination + +If the *called* code is a leaf routine, it doesn’t need to push the link register onto the stack. It is careful, however, to preserve its value; then, at exit, it returns to its caller by jumping to the address in the link register. + +If the called code *will* be making calls to other code, on entry it pushes the link register (to preserve it), and on exit it *first* pops and restores it, and then retuns to its caller as above, by jumping to the address in the register. + +### [Not created equal](#not-created-equal) + +There are two variations of branch-and-link: + +* one that always uses the same link register (eg, ARM) +* one that allows specification of the link register (RISC-V, and probably others – I’m not a RISC expert. ;-) + +The latter is much more powerful. If all your code does is “normal” calls and returns, the difference is unimportant. But there is a curious class of uses for which the difference is important: when using a branch-and-link to capture the following address for a purpose *other* than to return to it later. + +Say whaaaaat? Why would you ever do this? + +### [Creative misuse](#creative-misuse) + +I mentioned in my discussion of [threaded code](/threaded-code/) that one can “misuse” a call instruction to capture the following address. This is sometimes useful when writing the “runtime” behaviors of Forth words. But using call in this way is inefficient: you capture the following address by pushing it, but then immediately pop it and do something with it. + +Misusing branch-and-link instructions to do the same thing is much more efficient. The address is captured in a register, and the code moves on. No push and pop. (There *is* a jump involved, so perhaps a pipeline refill occurs.) + +And if, for some reason, we want to do this twice, in immediate succession, we simply specify a different link register in each of the branch-and-links. (Hmm, and now we are perhaps doing *two* pipeline refills in quick succession...) + +But again, why? + +In a non-threaded implementation of Forth’s create/does words, this is *precisely* what happens. I’ll explain how this works by first showing how it works in a ITC (indirect-threaded code) system, and then replace some pointers with jump-and-link instructions. + +We’ll look how three kinds of Forth words are represented: colon words, variables, and “incrementers” (which are going to be defined via create/does). + +Our example colon word was defined in Forth like this: + +``` + : 4* 2* 2* ; +``` + +and its compiled form looks like this: + +``` + 4* + ~~~~~~~~~~~ + addr of NEST ( code field) + addr of 2* ( parameter field) + addr of 2* + addr of UNNEST +``` + +Our variable looks like this: + +``` + radix + ~~~~~~~~~~~ + addr of VARIABLE (code field) + 2 (parameter field) +``` + +And our create’d word – the most complicated of our examples – was created by the following Forth code: + +``` + : incr create , does> @ + ; + 4 incr cell+ +``` + +To further complicate this example – which is really the *key* to my argument – we will assume a tethered cross-compiled Forth, which means that the words `create , does>` execute on the host machine, and the target contains only the *runtime* pieces. `cell+` and `incr` look like this: + +``` + cell+ + +----------+ + | addr |---+ ( code field) + +----------+ | + 4 | ( parameter field) + | + incr | + ~~~~~~~~~~~ | + jal DODOES <-+ + addr of @ + addr of + + addr of UNNEST +``` + +``` + DODOES: Push IP onto R stack + Push pfa onto D stack + Execute NEXT +``` + +Two notes about `incr`. It is *not* a normal Forth word with a code field and a parameter field. It is like the built-in “runtimes” for colon words or variables. In this case – unlike with VARIABLE or NEST – we want to express the runtime in *Forth* code rather than machine code. But runtimes have to *start* with machine code. And a `does>` runtime has to do two things: nest the execution of Forth (just as we would do if we were calling a colon word), and push the pfa of the create’d word (`cell+` in our example.) + +Since this behavior is common to all `does>` runtimes, we compile it *once* and `jal` to it. + +Thus, `incr` *begins* with `jal DODOES`. This is the *one* place in an ITC system where *code* specific to an architecture has to be compiled into a word’s body. The Forth code in a parent (defining) word that specifies the execution behavior of child words – ie, the code following `does>` – has to be *prefixed* by machine code of some kind so that the code field in child words can point to it. Code fields *always* point to machine code. + +Now for the point of this exercise. Let’s convert these three examples to “native” code, using jump-and-link instructions in the bodies of colon words instead of lists of pointers. Note that we use two different link registers: `w` in code fields, and `ra` in colon word bodies. + +``` + 4* + ~~~~~~~~~~~ + jal w NEST (code field) + jal ra 2* (parameter field) + jal ra 2* + jal ra UNNEST +``` + +NEST in this world changes slightly from the ITC version. Notice that the `jal w NEST` captures the pfa – which is the address of the first call to `2*` – in `w`. NEST now looks like this: + +``` + NEST: Push RA onto R stack + jr 0(w) +``` + +That `jr 0(w)` means “return to the body of the colon word and start executing the code there”. + +Our variable looks like this: + +``` + radix + ~~~~~~~~~~~ + jal w VARIABLE (code field) + 2 (parameter field) +``` + +Again, the `jal w VARIABLE` captures the pfa in `w`. + +Since there is one more level of “nesting” in `does>` words, we need a *third* link register. Let’s use x. + +``` + cell+ + ~~~~~~~~~~~ + jal w INCR (code field) + 4 (parameter field) +``` + +``` + INCR: jal x DODOES + jal ra @ + jal ra + + jal ra UNNEST +``` + +``` + DODOES: Push RA onto R stack + Push W (pfa) onto D stack + jr 0(x) +``` + +The `jal w INCR` in `cell+` captures the pfa in `w`. The `jal x DODOES` in INCR captures the address of the Forth code that will be executed after W is pushed onto D stack. DODOES pushes both stacks, and then “returns” to the body of INCR. + +It’s convoluted, and it’s possibly inefficient – because we are executing *three* `jal` instructions in quick succession, and probably causing a series of pipeline refills – but it’s very little code, and it’s elegant in a twisted way. ;-) + +--- + +[Send feedback](/cdn-cgi/l/email-protection#2f0a18180a191a0a191d0a19170a191e0a194b0a181c0a181b0a191a0a181d0a1b1f0a194a0a19160a194b0a191d0a194c0a191a0a194b0a191e0a191c0a19170a19160a194a0a191a0a181c0a1d4a0a191c0a19490a194b105c5a4d454a4c5b120a1a4d425a49405d5b470a1a4b0a1d1f6c4e43430a1d1f594a5d5c5a5c0a1d1f4d5d4e414c47024e414b0243464144) on this page (last edited 2017 May 01) +Browse [all pages](/all-pages/) +Return [home](/) \ No newline at end of file diff --git a/references/ForthNotes/cmFORTH.md b/references/ForthNotes/cmFORTH.md new file mode 100644 index 0000000..b6721d0 --- /dev/null +++ b/references/ForthNotes/cmFORTH.md @@ -0,0 +1,322 @@ +# cmFORTH + +**Source:** https://github.com/ForthHub/cmFORTH + +GitHub - ForthHub/cmFORTH: Copy of cmFORTH + + + +[Skip to content](#start-of-content) + + + + + + + + + + + + + +## Navigation Menu + +Toggle navigation + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2FForthHub%2FcmFORTH) + +Appearance settings + +* Platform + + + AI CODE CREATION + - [GitHub CopilotWrite better code with AI](https://github.com/features/copilot) + - [GitHub SparkBuild and deploy intelligent apps](https://github.com/features/spark) + - [GitHub ModelsManage and compare prompts](https://github.com/features/models) + - [MCP RegistryNewIntegrate external tools](https://github.com/mcp) + + DEVELOPER WORKFLOWS + - [ActionsAutomate any workflow](https://github.com/features/actions) + - [CodespacesInstant dev environments](https://github.com/features/codespaces) + - [IssuesPlan and track work](https://github.com/features/issues) + - [Code ReviewManage code changes](https://github.com/features/code-review) + + APPLICATION SECURITY + - [GitHub Advanced SecurityFind and fix vulnerabilities](https://github.com/security/advanced-security) + - [Code securitySecure your code as you build](https://github.com/security/advanced-security/code-security) + - [Secret protectionStop leaks before they start](https://github.com/security/advanced-security/secret-protection) + + EXPLORE + - [Why GitHub](https://github.com/why-github) + - [Documentation](https://docs.github.com) + - [Blog](https://github.blog) + - [Changelog](https://github.blog/changelog) + - [Marketplace](https://github.com/marketplace) + + [View all features](https://github.com/features) +* Solutions + + + BY COMPANY SIZE + - [Enterprises](https://github.com/enterprise) + - [Small and medium teams](https://github.com/team) + - [Startups](https://github.com/enterprise/startups) + - [Nonprofits](https://github.com/solutions/industry/nonprofits) + + BY USE CASE + - [App Modernization](https://github.com/solutions/use-case/app-modernization) + - [DevSecOps](https://github.com/solutions/use-case/devsecops) + - [DevOps](https://github.com/solutions/use-case/devops) + - [CI/CD](https://github.com/solutions/use-case/ci-cd) + - [View all use cases](https://github.com/solutions/use-case) + + BY INDUSTRY + - [Healthcare](https://github.com/solutions/industry/healthcare) + - [Financial services](https://github.com/solutions/industry/financial-services) + - [Manufacturing](https://github.com/solutions/industry/manufacturing) + - [Government](https://github.com/solutions/industry/government) + - [View all industries](https://github.com/solutions/industry) + + [View all solutions](https://github.com/solutions) +* Resources + + + EXPLORE BY TOPIC + - [AI](https://github.com/resources/articles?topic=ai) + - [Software Development](https://github.com/resources/articles?topic=software-development) + - [DevOps](https://github.com/resources/articles?topic=devops) + - [Security](https://github.com/resources/articles?topic=security) + - [View all topics](https://github.com/resources/articles) + + EXPLORE BY TYPE + - [Customer stories](https://github.com/customer-stories) + - [Events & webinars](https://github.com/resources/events) + - [Ebooks & reports](https://github.com/resources/whitepapers) + - [Business insights](https://github.com/solutions/executive-insights) + - [GitHub Skills](https://skills.github.com) + + SUPPORT & SERVICES + - [Documentation](https://docs.github.com) + - [Customer support](https://support.github.com) + - [Community forum](https://github.com/orgs/community/discussions) + - [Trust center](https://github.com/trust-center) + - [Partners](https://github.com/partners) +* Open Source + + + COMMUNITY + - [GitHub SponsorsFund open source developers](https://github.com/sponsors) + + PROGRAMS + - [Security Lab](https://securitylab.github.com) + - [Maintainer Community](https://maintainers.github.com) + - [Accelerator](https://github.com/accelerator) + - [Archive Program](https://archiveprogram.github.com) + + REPOSITORIES + - [Topics](https://github.com/topics) + - [Trending](https://github.com/trending) + - [Collections](https://github.com/collections) +* Enterprise + + + ENTERPRISE SOLUTIONS + - [Enterprise platformAI-powered developer platform](https://github.com/enterprise) + + AVAILABLE ADD-ONS + - [GitHub Advanced SecurityEnterprise-grade security features](https://github.com/security/advanced-security) + - [Copilot for BusinessEnterprise-grade AI features](https://github.com/features/copilot/copilot-business) + - [Premium SupportEnterprise-grade 24/7 support](https://github.com/premium-support) +* [Pricing](https://github.com/pricing) + +Search or jump to... + + +# Search code, repositories, users, issues, pull requests... + +Search + +Clear + +[Search syntax tips](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax) + +# Provide feedback + +We read every piece of feedback, and take your input very seriously. + + +Include my email address so I can be contacted + +Cancel + Submit feedback + + + + + +# Saved searches + +## Use saved searches to filter your results more quickly + +Name + +Query + +To see all available qualifiers, see our [documentation](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax). + +Cancel + Create saved search + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2FForthHub%2FcmFORTH) + +[Sign up](/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E&source=header-repo&source_repo=ForthHub%2FcmFORTH) + +Appearance settings + +Resetting focus + +You signed in with another tab or window. Reload to refresh your session. +You signed out in another tab or window. Reload to refresh your session. +You switched accounts on another tab or window. Reload to refresh your session. + + + +Dismiss alert + +{{ message }} + +[ForthHub](/ForthHub) +/ +**[cmFORTH](/ForthHub/cmFORTH)** +Public + +* [Notifications](/login?return_to=%2FForthHub%2FcmFORTH) You must be signed in to change notification settings +* [Fork + 8](/login?return_to=%2FForthHub%2FcmFORTH) +* [Star + 40](/login?return_to=%2FForthHub%2FcmFORTH) + +Copy of cmFORTH + +[40 +stars](/ForthHub/cmFORTH/stargazers) [8 +forks](/ForthHub/cmFORTH/forks) [Branches](/ForthHub/cmFORTH/branches) [Tags](/ForthHub/cmFORTH/tags) [Activity](/ForthHub/cmFORTH/activity) + +[Star](/login?return_to=%2FForthHub%2FcmFORTH) + +[Notifications](/login?return_to=%2FForthHub%2FcmFORTH) You must be signed in to change notification settings + +* [Code](/ForthHub/cmFORTH) +* [Issues + 0](/ForthHub/cmFORTH/issues) +* [Pull requests + 0](/ForthHub/cmFORTH/pulls) +* [Actions](/ForthHub/cmFORTH/actions) +* [Projects + 0](/ForthHub/cmFORTH/projects) +* [Wiki](/ForthHub/cmFORTH/wiki) +* [Security + 0](/ForthHub/cmFORTH/security) +* [Insights](/ForthHub/cmFORTH/pulse) + +Additional navigation options + + +* [Code](/ForthHub/cmFORTH) +* [Issues](/ForthHub/cmFORTH/issues) +* [Pull requests](/ForthHub/cmFORTH/pulls) +* [Actions](/ForthHub/cmFORTH/actions) +* [Projects](/ForthHub/cmFORTH/projects) +* [Wiki](/ForthHub/cmFORTH/wiki) +* [Security](/ForthHub/cmFORTH/security) +* [Insights](/ForthHub/cmFORTH/pulse) + +# ForthHub/cmFORTH + +master + +[Branches](/ForthHub/cmFORTH/branches)[Tags](/ForthHub/cmFORTH/tags) + +Go to file + +Code + +Open more actions menu + +## Folders and files + +| Name | | Name | Last commit message | Last commit date | +| --- | --- | --- | --- | --- | +| Latest commit History[2 Commits](/ForthHub/cmFORTH/commits/master/) 2 Commits | | | +| [README](/ForthHub/cmFORTH/blob/master/README "README") | | [README](/ForthHub/cmFORTH/blob/master/README "README") | | | +| [cmforth.fth](/ForthHub/cmFORTH/blob/master/cmforth.fth "cmforth.fth") | | [cmforth.fth](/ForthHub/cmFORTH/blob/master/cmforth.fth "cmforth.fth") | | | +| [cmforth.txt](/ForthHub/cmFORTH/blob/master/cmforth.txt "cmforth.txt") | | [cmforth.txt](/ForthHub/cmFORTH/blob/master/cmforth.txt "cmforth.txt") | | | +| View all files | | | + +## Repository files navigation + +* [README](#) + +``` +Chuck Moore's Forth for the Novix NC4016, dated December 1987. + +Code is in cmforth.fth, shadow blocks in cmforth.txt. They are combined +side-by-side in the 'combined' branch. +``` + +## About + +Copy of cmFORTH + +### Topics + +[forth](/topics/forth "Topic: forth") + +### Resources + +[Readme](#readme-ov-file) + +### Uh oh! + +There was an error while loading. Please reload this page. + +[Activity](/ForthHub/cmFORTH/activity) + +[Custom properties](/ForthHub/cmFORTH/custom-properties) + +### Stars + +[**40** +stars](/ForthHub/cmFORTH/stargazers) + +### Watchers + +[**7** +watching](/ForthHub/cmFORTH/watchers) + +### Forks + +[**8** +forks](/ForthHub/cmFORTH/forks) + +[Report repository](/contact/report-content?content_url=https%3A%2F%2Fgithub.com%2FForthHub%2FcmFORTH&report=ForthHub+%28user%29) + +## [Releases](/ForthHub/cmFORTH/releases) + +No releases published + +## [Packages 0](/orgs/ForthHub/packages?repo_name=cmFORTH) + +No packages published + +## Languages + +* [Forth + 100.0%](/ForthHub/cmFORTH/search?l=forth) + +## Footer + +© 2026 GitHub, Inc. + +### Footer navigation + +* [Terms](https://docs.github.com/site-policy/github-terms/github-terms-of-service) +* [Privacy](https://docs.github.com/site-policy/privacy-policies/github-privacy-statement) +* [Security](https://github.com/security) +* [Status](https://www.githubstatus.com/) +* [Community](https://github.community/) +* [Docs](https://docs.github.com/) +* [Contact](https://support.github.com?tags=dotcom-footer) +* Manage cookies +* Do not share my personal information + + + +You can’t perform that action at this time. \ No newline at end of file diff --git a/references/ForthNotes/deckload.md b/references/ForthNotes/deckload.md new file mode 100644 index 0000000..772eb06 --- /dev/null +++ b/references/ForthNotes/deckload.md @@ -0,0 +1,338 @@ +# deckload + +**Source:** https://github.com/JosephOziel/deckload + +GitHub - JosephOziel/deckload: Compiled functional language + + + +[Skip to content](#start-of-content) + + + + + + + + + + + + + +## Navigation Menu + +Toggle navigation + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2FJosephOziel%2Fdeckload) + +Appearance settings + +* Platform + + + AI CODE CREATION + - [GitHub CopilotWrite better code with AI](https://github.com/features/copilot) + - [GitHub SparkBuild and deploy intelligent apps](https://github.com/features/spark) + - [GitHub ModelsManage and compare prompts](https://github.com/features/models) + - [MCP RegistryNewIntegrate external tools](https://github.com/mcp) + + DEVELOPER WORKFLOWS + - [ActionsAutomate any workflow](https://github.com/features/actions) + - [CodespacesInstant dev environments](https://github.com/features/codespaces) + - [IssuesPlan and track work](https://github.com/features/issues) + - [Code ReviewManage code changes](https://github.com/features/code-review) + + APPLICATION SECURITY + - [GitHub Advanced SecurityFind and fix vulnerabilities](https://github.com/security/advanced-security) + - [Code securitySecure your code as you build](https://github.com/security/advanced-security/code-security) + - [Secret protectionStop leaks before they start](https://github.com/security/advanced-security/secret-protection) + + EXPLORE + - [Why GitHub](https://github.com/why-github) + - [Documentation](https://docs.github.com) + - [Blog](https://github.blog) + - [Changelog](https://github.blog/changelog) + - [Marketplace](https://github.com/marketplace) + + [View all features](https://github.com/features) +* Solutions + + + BY COMPANY SIZE + - [Enterprises](https://github.com/enterprise) + - [Small and medium teams](https://github.com/team) + - [Startups](https://github.com/enterprise/startups) + - [Nonprofits](https://github.com/solutions/industry/nonprofits) + + BY USE CASE + - [App Modernization](https://github.com/solutions/use-case/app-modernization) + - [DevSecOps](https://github.com/solutions/use-case/devsecops) + - [DevOps](https://github.com/solutions/use-case/devops) + - [CI/CD](https://github.com/solutions/use-case/ci-cd) + - [View all use cases](https://github.com/solutions/use-case) + + BY INDUSTRY + - [Healthcare](https://github.com/solutions/industry/healthcare) + - [Financial services](https://github.com/solutions/industry/financial-services) + - [Manufacturing](https://github.com/solutions/industry/manufacturing) + - [Government](https://github.com/solutions/industry/government) + - [View all industries](https://github.com/solutions/industry) + + [View all solutions](https://github.com/solutions) +* Resources + + + EXPLORE BY TOPIC + - [AI](https://github.com/resources/articles?topic=ai) + - [Software Development](https://github.com/resources/articles?topic=software-development) + - [DevOps](https://github.com/resources/articles?topic=devops) + - [Security](https://github.com/resources/articles?topic=security) + - [View all topics](https://github.com/resources/articles) + + EXPLORE BY TYPE + - [Customer stories](https://github.com/customer-stories) + - [Events & webinars](https://github.com/resources/events) + - [Ebooks & reports](https://github.com/resources/whitepapers) + - [Business insights](https://github.com/solutions/executive-insights) + - [GitHub Skills](https://skills.github.com) + + SUPPORT & SERVICES + - [Documentation](https://docs.github.com) + - [Customer support](https://support.github.com) + - [Community forum](https://github.com/orgs/community/discussions) + - [Trust center](https://github.com/trust-center) + - [Partners](https://github.com/partners) +* Open Source + + + COMMUNITY + - [GitHub SponsorsFund open source developers](https://github.com/sponsors) + + PROGRAMS + - [Security Lab](https://securitylab.github.com) + - [Maintainer Community](https://maintainers.github.com) + - [Accelerator](https://github.com/accelerator) + - [Archive Program](https://archiveprogram.github.com) + + REPOSITORIES + - [Topics](https://github.com/topics) + - [Trending](https://github.com/trending) + - [Collections](https://github.com/collections) +* Enterprise + + + ENTERPRISE SOLUTIONS + - [Enterprise platformAI-powered developer platform](https://github.com/enterprise) + + AVAILABLE ADD-ONS + - [GitHub Advanced SecurityEnterprise-grade security features](https://github.com/security/advanced-security) + - [Copilot for BusinessEnterprise-grade AI features](https://github.com/features/copilot/copilot-business) + - [Premium SupportEnterprise-grade 24/7 support](https://github.com/premium-support) +* [Pricing](https://github.com/pricing) + +Search or jump to... + + +# Search code, repositories, users, issues, pull requests... + +Search + +Clear + +[Search syntax tips](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax) + +# Provide feedback + +We read every piece of feedback, and take your input very seriously. + + +Include my email address so I can be contacted + +Cancel + Submit feedback + + + + + +# Saved searches + +## Use saved searches to filter your results more quickly + +Name + +Query + +To see all available qualifiers, see our [documentation](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax). + +Cancel + Create saved search + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2FJosephOziel%2Fdeckload) + +[Sign up](/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E&source=header-repo&source_repo=JosephOziel%2Fdeckload) + +Appearance settings + +Resetting focus + +You signed in with another tab or window. Reload to refresh your session. +You signed out in another tab or window. Reload to refresh your session. +You switched accounts on another tab or window. Reload to refresh your session. + + + +Dismiss alert + +{{ message }} + +[JosephOziel](/JosephOziel) +/ +**[deckload](/JosephOziel/deckload)** +Public + +* [Notifications](/login?return_to=%2FJosephOziel%2Fdeckload) You must be signed in to change notification settings +* [Fork + 1](/login?return_to=%2FJosephOziel%2Fdeckload) +* [Star + 4](/login?return_to=%2FJosephOziel%2Fdeckload) + +Compiled functional language + +### License + +[MIT license](/JosephOziel/deckload/blob/main/LICENSE) + +[4 +stars](/JosephOziel/deckload/stargazers) [1 +fork](/JosephOziel/deckload/forks) [Branches](/JosephOziel/deckload/branches) [Tags](/JosephOziel/deckload/tags) [Activity](/JosephOziel/deckload/activity) + +[Star](/login?return_to=%2FJosephOziel%2Fdeckload) + +[Notifications](/login?return_to=%2FJosephOziel%2Fdeckload) You must be signed in to change notification settings + +* [Code](/JosephOziel/deckload) +* [Issues + 0](/JosephOziel/deckload/issues) +* [Pull requests + 0](/JosephOziel/deckload/pulls) +* [Actions](/JosephOziel/deckload/actions) +* [Projects + 0](/JosephOziel/deckload/projects) +* [Security + 0](/JosephOziel/deckload/security) +* [Insights](/JosephOziel/deckload/pulse) + +Additional navigation options + + +* [Code](/JosephOziel/deckload) +* [Issues](/JosephOziel/deckload/issues) +* [Pull requests](/JosephOziel/deckload/pulls) +* [Actions](/JosephOziel/deckload/actions) +* [Projects](/JosephOziel/deckload/projects) +* [Security](/JosephOziel/deckload/security) +* [Insights](/JosephOziel/deckload/pulse) + +# JosephOziel/deckload + +main + +[Branches](/JosephOziel/deckload/branches)[Tags](/JosephOziel/deckload/tags) + +Go to file + +Code + +Open more actions menu + +## Folders and files + +| Name | | Name | Last commit message | Last commit date | +| --- | --- | --- | --- | --- | +| Latest commit History[69 Commits](/JosephOziel/deckload/commits/main/) 69 Commits | | | +| [backend-c](/JosephOziel/deckload/tree/main/backend-c "backend-c") | | [backend-c](/JosephOziel/deckload/tree/main/backend-c "backend-c") | | | +| [backend-factor](/JosephOziel/deckload/tree/main/backend-factor "backend-factor") | | [backend-factor](/JosephOziel/deckload/tree/main/backend-factor "backend-factor") | | | +| [examples](/JosephOziel/deckload/tree/main/examples "examples") | | [examples](/JosephOziel/deckload/tree/main/examples "examples") | | | +| [ir](/JosephOziel/deckload/tree/main/ir "ir") | | [ir](/JosephOziel/deckload/tree/main/ir "ir") | | | +| [parser](/JosephOziel/deckload/tree/main/parser "parser") | | [parser](/JosephOziel/deckload/tree/main/parser "parser") | | | +| [.gitattributes](/JosephOziel/deckload/blob/main/.gitattributes ".gitattributes") | | [.gitattributes](/JosephOziel/deckload/blob/main/.gitattributes ".gitattributes") | | | +| [LICENSE](/JosephOziel/deckload/blob/main/LICENSE "LICENSE") | | [LICENSE](/JosephOziel/deckload/blob/main/LICENSE "LICENSE") | | | +| [README.md](/JosephOziel/deckload/blob/main/README.md "README.md") | | [README.md](/JosephOziel/deckload/blob/main/README.md "README.md") | | | +| [TODO](/JosephOziel/deckload/blob/main/TODO "TODO") | | [TODO](/JosephOziel/deckload/blob/main/TODO "TODO") | | | +| [deckload.factor](/JosephOziel/deckload/blob/main/deckload.factor "deckload.factor") | | [deckload.factor](/JosephOziel/deckload/blob/main/deckload.factor "deckload.factor") | | | +| [spec.markdown](/JosephOziel/deckload/blob/main/spec.markdown "spec.markdown") | | [spec.markdown](/JosephOziel/deckload/blob/main/spec.markdown "spec.markdown") | | | +| View all files | | | + +## Repository files navigation + +* [README](#) +* [MIT license](#) + +# Deckload + +``` +Best low level language compiling to x86 assembly based on rho calculus (tree rewriting + lambda calculus). also postfix notation. +``` + +## About + +Compiled functional language + +### Resources + +[Readme](#readme-ov-file) + +### License + +[MIT license](#MIT-1-ov-file) + +### Uh oh! + +There was an error while loading. Please reload this page. + +[Activity](/JosephOziel/deckload/activity) + +### Stars + +[**4** +stars](/JosephOziel/deckload/stargazers) + +### Watchers + +[**1** +watching](/JosephOziel/deckload/watchers) + +### Forks + +[**1** +fork](/JosephOziel/deckload/forks) + +[Report repository](/contact/report-content?content_url=https%3A%2F%2Fgithub.com%2FJosephOziel%2Fdeckload&report=JosephOziel+%28user%29) + +## [Releases](/JosephOziel/deckload/releases) + +No releases published + +## [Packages 0](/users/JosephOziel/packages?repo_name=deckload) + +No packages published + +## [Contributors 2](/JosephOziel/deckload/graphs/contributors) + +### Uh oh! + +There was an error while loading. Please reload this page. + +## Languages + +* [Factor + 73.3%](/JosephOziel/deckload/search?l=factor) +* [C + 26.7%](/JosephOziel/deckload/search?l=c) + +## Footer + +© 2026 GitHub, Inc. + +### Footer navigation + +* [Terms](https://docs.github.com/site-policy/github-terms/github-terms-of-service) +* [Privacy](https://docs.github.com/site-policy/privacy-policies/github-privacy-statement) +* [Security](https://github.com/security) +* [Status](https://www.githubstatus.com/) +* [Community](https://github.community/) +* [Docs](https://docs.github.com/) +* [Contact](https://support.github.com?tags=dotcom-footer) +* Manage cookies +* Do not share my personal information + + + +You can’t perform that action at this time. \ No newline at end of file diff --git a/references/ForthNotes/easyforth.md b/references/ForthNotes/easyforth.md new file mode 100644 index 0000000..c38c5fe --- /dev/null +++ b/references/ForthNotes/easyforth.md @@ -0,0 +1,338 @@ +# easyforth + +**Source:** https://github.com/skilldrick/easyforth + +GitHub - skilldrick/easyforth: Learn Forth! + + + +[Skip to content](#start-of-content) + + + + + + + + + + + + + +## Navigation Menu + +Toggle navigation + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2Fskilldrick%2Feasyforth) + +Appearance settings + +* Platform + + + AI CODE CREATION + - [GitHub CopilotWrite better code with AI](https://github.com/features/copilot) + - [GitHub SparkBuild and deploy intelligent apps](https://github.com/features/spark) + - [GitHub ModelsManage and compare prompts](https://github.com/features/models) + - [MCP RegistryNewIntegrate external tools](https://github.com/mcp) + + DEVELOPER WORKFLOWS + - [ActionsAutomate any workflow](https://github.com/features/actions) + - [CodespacesInstant dev environments](https://github.com/features/codespaces) + - [IssuesPlan and track work](https://github.com/features/issues) + - [Code ReviewManage code changes](https://github.com/features/code-review) + + APPLICATION SECURITY + - [GitHub Advanced SecurityFind and fix vulnerabilities](https://github.com/security/advanced-security) + - [Code securitySecure your code as you build](https://github.com/security/advanced-security/code-security) + - [Secret protectionStop leaks before they start](https://github.com/security/advanced-security/secret-protection) + + EXPLORE + - [Why GitHub](https://github.com/why-github) + - [Documentation](https://docs.github.com) + - [Blog](https://github.blog) + - [Changelog](https://github.blog/changelog) + - [Marketplace](https://github.com/marketplace) + + [View all features](https://github.com/features) +* Solutions + + + BY COMPANY SIZE + - [Enterprises](https://github.com/enterprise) + - [Small and medium teams](https://github.com/team) + - [Startups](https://github.com/enterprise/startups) + - [Nonprofits](https://github.com/solutions/industry/nonprofits) + + BY USE CASE + - [App Modernization](https://github.com/solutions/use-case/app-modernization) + - [DevSecOps](https://github.com/solutions/use-case/devsecops) + - [DevOps](https://github.com/solutions/use-case/devops) + - [CI/CD](https://github.com/solutions/use-case/ci-cd) + - [View all use cases](https://github.com/solutions/use-case) + + BY INDUSTRY + - [Healthcare](https://github.com/solutions/industry/healthcare) + - [Financial services](https://github.com/solutions/industry/financial-services) + - [Manufacturing](https://github.com/solutions/industry/manufacturing) + - [Government](https://github.com/solutions/industry/government) + - [View all industries](https://github.com/solutions/industry) + + [View all solutions](https://github.com/solutions) +* Resources + + + EXPLORE BY TOPIC + - [AI](https://github.com/resources/articles?topic=ai) + - [Software Development](https://github.com/resources/articles?topic=software-development) + - [DevOps](https://github.com/resources/articles?topic=devops) + - [Security](https://github.com/resources/articles?topic=security) + - [View all topics](https://github.com/resources/articles) + + EXPLORE BY TYPE + - [Customer stories](https://github.com/customer-stories) + - [Events & webinars](https://github.com/resources/events) + - [Ebooks & reports](https://github.com/resources/whitepapers) + - [Business insights](https://github.com/solutions/executive-insights) + - [GitHub Skills](https://skills.github.com) + + SUPPORT & SERVICES + - [Documentation](https://docs.github.com) + - [Customer support](https://support.github.com) + - [Community forum](https://github.com/orgs/community/discussions) + - [Trust center](https://github.com/trust-center) + - [Partners](https://github.com/partners) +* Open Source + + + COMMUNITY + - [GitHub SponsorsFund open source developers](https://github.com/sponsors) + + PROGRAMS + - [Security Lab](https://securitylab.github.com) + - [Maintainer Community](https://maintainers.github.com) + - [Accelerator](https://github.com/accelerator) + - [Archive Program](https://archiveprogram.github.com) + + REPOSITORIES + - [Topics](https://github.com/topics) + - [Trending](https://github.com/trending) + - [Collections](https://github.com/collections) +* Enterprise + + + ENTERPRISE SOLUTIONS + - [Enterprise platformAI-powered developer platform](https://github.com/enterprise) + + AVAILABLE ADD-ONS + - [GitHub Advanced SecurityEnterprise-grade security features](https://github.com/security/advanced-security) + - [Copilot for BusinessEnterprise-grade AI features](https://github.com/features/copilot/copilot-business) + - [Premium SupportEnterprise-grade 24/7 support](https://github.com/premium-support) +* [Pricing](https://github.com/pricing) + +Search or jump to... + + +# Search code, repositories, users, issues, pull requests... + +Search + +Clear + +[Search syntax tips](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax) + +# Provide feedback + +We read every piece of feedback, and take your input very seriously. + + +Include my email address so I can be contacted + +Cancel + Submit feedback + + + + + +# Saved searches + +## Use saved searches to filter your results more quickly + +Name + +Query + +To see all available qualifiers, see our [documentation](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax). + +Cancel + Create saved search + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2Fskilldrick%2Feasyforth) + +[Sign up](/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E&source=header-repo&source_repo=skilldrick%2Feasyforth) + +Appearance settings + +Resetting focus + +You signed in with another tab or window. Reload to refresh your session. +You signed out in another tab or window. Reload to refresh your session. +You switched accounts on another tab or window. Reload to refresh your session. + + + +Dismiss alert + +{{ message }} + +[skilldrick](/skilldrick) +/ +**[easyforth](/skilldrick/easyforth)** +Public + +* [Notifications](/login?return_to=%2Fskilldrick%2Feasyforth) You must be signed in to change notification settings +* [Fork + 46](/login?return_to=%2Fskilldrick%2Feasyforth) +* [Star + 379](/login?return_to=%2Fskilldrick%2Feasyforth) + +Learn Forth! + +[skilldrick.github.io/easyforth/](http://skilldrick.github.io/easyforth/ "http://skilldrick.github.io/easyforth/") + +[379 +stars](/skilldrick/easyforth/stargazers) [46 +forks](/skilldrick/easyforth/forks) [Branches](/skilldrick/easyforth/branches) [Tags](/skilldrick/easyforth/tags) [Activity](/skilldrick/easyforth/activity) + +[Star](/login?return_to=%2Fskilldrick%2Feasyforth) + +[Notifications](/login?return_to=%2Fskilldrick%2Feasyforth) You must be signed in to change notification settings + +* [Code](/skilldrick/easyforth) +* [Issues + 9](/skilldrick/easyforth/issues) +* [Pull requests + 3](/skilldrick/easyforth/pulls) +* [Actions](/skilldrick/easyforth/actions) +* [Projects + 0](/skilldrick/easyforth/projects) +* [Wiki](/skilldrick/easyforth/wiki) +* [Security + 0](/skilldrick/easyforth/security) +* [Insights](/skilldrick/easyforth/pulse) + +Additional navigation options + + +* [Code](/skilldrick/easyforth) +* [Issues](/skilldrick/easyforth/issues) +* [Pull requests](/skilldrick/easyforth/pulls) +* [Actions](/skilldrick/easyforth/actions) +* [Projects](/skilldrick/easyforth/projects) +* [Wiki](/skilldrick/easyforth/wiki) +* [Security](/skilldrick/easyforth/security) +* [Insights](/skilldrick/easyforth/pulse) + +# skilldrick/easyforth + +gh-pages + +[Branches](/skilldrick/easyforth/branches)[Tags](/skilldrick/easyforth/tags) + +Go to file + +Code + +Open more actions menu + +## Folders and files + +| Name | | Name | Last commit message | Last commit date | +| --- | --- | --- | --- | --- | +| Latest commit History[165 Commits](/skilldrick/easyforth/commits/gh-pages/) 165 Commits | | | +| [\_includes](/skilldrick/easyforth/tree/gh-pages/_includes "_includes") | | [\_includes](/skilldrick/easyforth/tree/gh-pages/_includes "_includes") | | | +| [\_layouts](/skilldrick/easyforth/tree/gh-pages/_layouts "_layouts") | | [\_layouts](/skilldrick/easyforth/tree/gh-pages/_layouts "_layouts") | | | +| [javascripts](/skilldrick/easyforth/tree/gh-pages/javascripts "javascripts") | | [javascripts](/skilldrick/easyforth/tree/gh-pages/javascripts "javascripts") | | | +| [stylesheets](/skilldrick/easyforth/tree/gh-pages/stylesheets "stylesheets") | | [stylesheets](/skilldrick/easyforth/tree/gh-pages/stylesheets "stylesheets") | | | +| [test](/skilldrick/easyforth/tree/gh-pages/test "test") | | [test](/skilldrick/easyforth/tree/gh-pages/test "test") | | | +| [.gitignore](/skilldrick/easyforth/blob/gh-pages/.gitignore ".gitignore") | | [.gitignore](/skilldrick/easyforth/blob/gh-pages/.gitignore ".gitignore") | | | +| [README.md](/skilldrick/easyforth/blob/gh-pages/README.md "README.md") | | [README.md](/skilldrick/easyforth/blob/gh-pages/README.md "README.md") | | | +| [\_config.yml](/skilldrick/easyforth/blob/gh-pages/_config.yml "_config.yml") | | [\_config.yml](/skilldrick/easyforth/blob/gh-pages/_config.yml "_config.yml") | | | +| [index.markdown](/skilldrick/easyforth/blob/gh-pages/index.markdown "index.markdown") | | [index.markdown](/skilldrick/easyforth/blob/gh-pages/index.markdown "index.markdown") | | | +| [params.json](/skilldrick/easyforth/blob/gh-pages/params.json "params.json") | | [params.json](/skilldrick/easyforth/blob/gh-pages/params.json "params.json") | | | +| [todo](/skilldrick/easyforth/blob/gh-pages/todo "todo") | | [todo](/skilldrick/easyforth/blob/gh-pages/todo "todo") | | | +| View all files | | | + +## Repository files navigation + +* [README](#) + +# Easy Forth + +Along the lines of [Easy 6502](http://skilldrick.github.io/easy6502/), Easy +Forth is a small ebook for learning the Forth language. It includes a +JavaScript Forth interpreter inline, making it easy to try writing small Forth +programs. + +## About + +Learn Forth! + +[skilldrick.github.io/easyforth/](http://skilldrick.github.io/easyforth/ "http://skilldrick.github.io/easyforth/") + +### Resources + +[Readme](#readme-ov-file) + +### Uh oh! + +There was an error while loading. Please reload this page. + +[Activity](/skilldrick/easyforth/activity) + +### Stars + +[**379** +stars](/skilldrick/easyforth/stargazers) + +### Watchers + +[**23** +watching](/skilldrick/easyforth/watchers) + +### Forks + +[**46** +forks](/skilldrick/easyforth/forks) + +[Report repository](/contact/report-content?content_url=https%3A%2F%2Fgithub.com%2Fskilldrick%2Feasyforth&report=skilldrick+%28user%29) + +## [Releases](/skilldrick/easyforth/releases) + +No releases published + +## [Packages 0](/users/skilldrick/packages?repo_name=easyforth) + +No packages published + +### Uh oh! + +There was an error while loading. Please reload this page. + +## Languages + +* [JavaScript + 92.7%](/skilldrick/easyforth/search?l=javascript) +* [CSS + 3.5%](/skilldrick/easyforth/search?l=css) +* [HTML + 2.1%](/skilldrick/easyforth/search?l=html) +* [Forth + 1.7%](/skilldrick/easyforth/search?l=forth) + +## Footer + +© 2026 GitHub, Inc. + +### Footer navigation + +* [Terms](https://docs.github.com/site-policy/github-terms/github-terms-of-service) +* [Privacy](https://docs.github.com/site-policy/privacy-policies/github-privacy-statement) +* [Security](https://github.com/security) +* [Status](https://www.githubstatus.com/) +* [Community](https://github.community/) +* [Docs](https://docs.github.com/) +* [Contact](https://support.github.com?tags=dotcom-footer) +* Manage cookies +* Do not share my personal information + + + +You can’t perform that action at this time. \ No newline at end of file diff --git a/references/ForthNotes/fiveth.md b/references/ForthNotes/fiveth.md new file mode 100644 index 0000000..1e8ed81 --- /dev/null +++ b/references/ForthNotes/fiveth.md @@ -0,0 +1,372 @@ +# fiveth + +**Source:** https://github.com/dramforever/fiveth + +GitHub - dramforever/fiveth: A stack-based language implemented in RISC-V assembly + + + +[Skip to content](#start-of-content) + + + + + + + + + + + + + +## Navigation Menu + +Toggle navigation + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2Fdramforever%2Ffiveth) + +Appearance settings + +* Platform + + + AI CODE CREATION + - [GitHub CopilotWrite better code with AI](https://github.com/features/copilot) + - [GitHub SparkBuild and deploy intelligent apps](https://github.com/features/spark) + - [GitHub ModelsManage and compare prompts](https://github.com/features/models) + - [MCP RegistryNewIntegrate external tools](https://github.com/mcp) + + DEVELOPER WORKFLOWS + - [ActionsAutomate any workflow](https://github.com/features/actions) + - [CodespacesInstant dev environments](https://github.com/features/codespaces) + - [IssuesPlan and track work](https://github.com/features/issues) + - [Code ReviewManage code changes](https://github.com/features/code-review) + + APPLICATION SECURITY + - [GitHub Advanced SecurityFind and fix vulnerabilities](https://github.com/security/advanced-security) + - [Code securitySecure your code as you build](https://github.com/security/advanced-security/code-security) + - [Secret protectionStop leaks before they start](https://github.com/security/advanced-security/secret-protection) + + EXPLORE + - [Why GitHub](https://github.com/why-github) + - [Documentation](https://docs.github.com) + - [Blog](https://github.blog) + - [Changelog](https://github.blog/changelog) + - [Marketplace](https://github.com/marketplace) + + [View all features](https://github.com/features) +* Solutions + + + BY COMPANY SIZE + - [Enterprises](https://github.com/enterprise) + - [Small and medium teams](https://github.com/team) + - [Startups](https://github.com/enterprise/startups) + - [Nonprofits](https://github.com/solutions/industry/nonprofits) + + BY USE CASE + - [App Modernization](https://github.com/solutions/use-case/app-modernization) + - [DevSecOps](https://github.com/solutions/use-case/devsecops) + - [DevOps](https://github.com/solutions/use-case/devops) + - [CI/CD](https://github.com/solutions/use-case/ci-cd) + - [View all use cases](https://github.com/solutions/use-case) + + BY INDUSTRY + - [Healthcare](https://github.com/solutions/industry/healthcare) + - [Financial services](https://github.com/solutions/industry/financial-services) + - [Manufacturing](https://github.com/solutions/industry/manufacturing) + - [Government](https://github.com/solutions/industry/government) + - [View all industries](https://github.com/solutions/industry) + + [View all solutions](https://github.com/solutions) +* Resources + + + EXPLORE BY TOPIC + - [AI](https://github.com/resources/articles?topic=ai) + - [Software Development](https://github.com/resources/articles?topic=software-development) + - [DevOps](https://github.com/resources/articles?topic=devops) + - [Security](https://github.com/resources/articles?topic=security) + - [View all topics](https://github.com/resources/articles) + + EXPLORE BY TYPE + - [Customer stories](https://github.com/customer-stories) + - [Events & webinars](https://github.com/resources/events) + - [Ebooks & reports](https://github.com/resources/whitepapers) + - [Business insights](https://github.com/solutions/executive-insights) + - [GitHub Skills](https://skills.github.com) + + SUPPORT & SERVICES + - [Documentation](https://docs.github.com) + - [Customer support](https://support.github.com) + - [Community forum](https://github.com/orgs/community/discussions) + - [Trust center](https://github.com/trust-center) + - [Partners](https://github.com/partners) +* Open Source + + + COMMUNITY + - [GitHub SponsorsFund open source developers](https://github.com/sponsors) + + PROGRAMS + - [Security Lab](https://securitylab.github.com) + - [Maintainer Community](https://maintainers.github.com) + - [Accelerator](https://github.com/accelerator) + - [Archive Program](https://archiveprogram.github.com) + + REPOSITORIES + - [Topics](https://github.com/topics) + - [Trending](https://github.com/trending) + - [Collections](https://github.com/collections) +* Enterprise + + + ENTERPRISE SOLUTIONS + - [Enterprise platformAI-powered developer platform](https://github.com/enterprise) + + AVAILABLE ADD-ONS + - [GitHub Advanced SecurityEnterprise-grade security features](https://github.com/security/advanced-security) + - [Copilot for BusinessEnterprise-grade AI features](https://github.com/features/copilot/copilot-business) + - [Premium SupportEnterprise-grade 24/7 support](https://github.com/premium-support) +* [Pricing](https://github.com/pricing) + +Search or jump to... + + +# Search code, repositories, users, issues, pull requests... + +Search + +Clear + +[Search syntax tips](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax) + +# Provide feedback + +We read every piece of feedback, and take your input very seriously. + + +Include my email address so I can be contacted + +Cancel + Submit feedback + + + + + +# Saved searches + +## Use saved searches to filter your results more quickly + +Name + +Query + +To see all available qualifiers, see our [documentation](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax). + +Cancel + Create saved search + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2Fdramforever%2Ffiveth) + +[Sign up](/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E&source=header-repo&source_repo=dramforever%2Ffiveth) + +Appearance settings + +Resetting focus + +You signed in with another tab or window. Reload to refresh your session. +You signed out in another tab or window. Reload to refresh your session. +You switched accounts on another tab or window. Reload to refresh your session. + + + +Dismiss alert + +{{ message }} + +[dramforever](/dramforever) +/ +**[fiveth](/dramforever/fiveth)** +Public + +* [Notifications](/login?return_to=%2Fdramforever%2Ffiveth) You must be signed in to change notification settings +* [Fork + 0](/login?return_to=%2Fdramforever%2Ffiveth) +* [Star + 17](/login?return_to=%2Fdramforever%2Ffiveth) + +A stack-based language implemented in RISC-V assembly + +[17 +stars](/dramforever/fiveth/stargazers) [0 +forks](/dramforever/fiveth/forks) [Branches](/dramforever/fiveth/branches) [Tags](/dramforever/fiveth/tags) [Activity](/dramforever/fiveth/activity) + +[Star](/login?return_to=%2Fdramforever%2Ffiveth) + +[Notifications](/login?return_to=%2Fdramforever%2Ffiveth) You must be signed in to change notification settings + +* [Code](/dramforever/fiveth) +* [Issues + 0](/dramforever/fiveth/issues) +* [Pull requests + 0](/dramforever/fiveth/pulls) +* [Actions](/dramforever/fiveth/actions) +* [Projects + 0](/dramforever/fiveth/projects) +* [Security + 0](/dramforever/fiveth/security) +* [Insights](/dramforever/fiveth/pulse) + +Additional navigation options + + +* [Code](/dramforever/fiveth) +* [Issues](/dramforever/fiveth/issues) +* [Pull requests](/dramforever/fiveth/pulls) +* [Actions](/dramforever/fiveth/actions) +* [Projects](/dramforever/fiveth/projects) +* [Security](/dramforever/fiveth/security) +* [Insights](/dramforever/fiveth/pulse) + +# dramforever/fiveth + +main + +[Branches](/dramforever/fiveth/branches)[Tags](/dramforever/fiveth/tags) + +Go to file + +Code + +Open more actions menu + +## Folders and files + +| Name | | Name | Last commit message | Last commit date | +| --- | --- | --- | --- | --- | +| Latest commit History[96 Commits](/dramforever/fiveth/commits/main/) 96 Commits | | | +| [docs](/dramforever/fiveth/tree/main/docs "docs") | | [docs](/dramforever/fiveth/tree/main/docs "docs") | | | +| [src](/dramforever/fiveth/tree/main/src "src") | | [src](/dramforever/fiveth/tree/main/src "src") | | | +| [.envrc](/dramforever/fiveth/blob/main/.envrc ".envrc") | | [.envrc](/dramforever/fiveth/blob/main/.envrc ".envrc") | | | +| [.gitignore](/dramforever/fiveth/blob/main/.gitignore ".gitignore") | | [.gitignore](/dramforever/fiveth/blob/main/.gitignore ".gitignore") | | | +| [Makefile](/dramforever/fiveth/blob/main/Makefile "Makefile") | | [Makefile](/dramforever/fiveth/blob/main/Makefile "Makefile") | | | +| [README.md](/dramforever/fiveth/blob/main/README.md "README.md") | | [README.md](/dramforever/fiveth/blob/main/README.md "README.md") | | | +| [config.mk](/dramforever/fiveth/blob/main/config.mk "config.mk") | | [config.mk](/dramforever/fiveth/blob/main/config.mk "config.mk") | | | +| [flake.lock](/dramforever/fiveth/blob/main/flake.lock "flake.lock") | | [flake.lock](/dramforever/fiveth/blob/main/flake.lock "flake.lock") | | | +| [flake.nix](/dramforever/fiveth/blob/main/flake.nix "flake.nix") | | [flake.nix](/dramforever/fiveth/blob/main/flake.nix "flake.nix") | | | +| [shell.nix](/dramforever/fiveth/blob/main/shell.nix "shell.nix") | | [shell.nix](/dramforever/fiveth/blob/main/shell.nix "shell.nix") | | | +| View all files | | | + +## Repository files navigation + +* [README](#) + +# Fiveth + +A stack-based language implemented in RISC-V assembly. + +## Building and running Fiveth + +* Edit `config.mk` to suit your environment +* `make` to build the program + +With the default config this should end a message like: + +``` +* Build complete: build/fiveth +``` + +The default configuration is to run an interactive Fiveth shell that works under +a 64-bit RISC-V Linux environment. You can now: + +* `make qemu` to run it in QEMU user-mode emulation +* `make run` to run it directly, if you are actually on RISC-V + +Try typing some simple Fiveth programs. Outputs are shown after a semicolon. + +``` +0 > 1 2 + . ; 3 +0 > 10 [ . ] count ; 0 1 2 3 4 5 6 7 8 9 +0 > "Hello, world!" s. ; Hello, world! +``` + +Press Ctrl-D to quit. [`docs/shell.md`](/dramforever/fiveth/blob/main/docs/shell.md) has more details on +running and using the Fiveth interactive shell. + +## Installing the required tools + +On Ubuntu 22.04: + +``` +# apt install qemu-user make +# # If using GNU toolchain +# apt install gcc-riscv64-linux-gnu +# # If using LLVM toolchain +# apt install clang lld +``` + +If you have Nix, you can try to use the provided `shell.nix` or `flake.nix`. + +On other systems, you can try to acquire a LLVM toolchain or a RISC-V toolchain, +as well as GNU make. To run Fiveth in an emulator, `qemu-riscv64` can be used to +emulate a Linux binary but is only supported on Linux hosts. + +## About + +A stack-based language implemented in RISC-V assembly + +### Topics + +[assembly](/topics/assembly "Topic: assembly") +[riscv](/topics/riscv "Topic: riscv") +[forth-like](/topics/forth-like "Topic: forth-like") + +### Resources + +[Readme](#readme-ov-file) + +### Uh oh! + +There was an error while loading. Please reload this page. + +[Activity](/dramforever/fiveth/activity) + +### Stars + +[**17** +stars](/dramforever/fiveth/stargazers) + +### Watchers + +[**2** +watching](/dramforever/fiveth/watchers) + +### Forks + +[**0** +forks](/dramforever/fiveth/forks) + +[Report repository](/contact/report-content?content_url=https%3A%2F%2Fgithub.com%2Fdramforever%2Ffiveth&report=dramforever+%28user%29) + +## [Releases](/dramforever/fiveth/releases) + +No releases published + +## Languages + +* [Assembly + 89.1%](/dramforever/fiveth/search?l=assembly) +* [Makefile + 7.1%](/dramforever/fiveth/search?l=makefile) +* [C + 2.5%](/dramforever/fiveth/search?l=c) +* [Nix + 1.3%](/dramforever/fiveth/search?l=nix) + +## Footer + +© 2026 GitHub, Inc. + +### Footer navigation + +* [Terms](https://docs.github.com/site-policy/github-terms/github-terms-of-service) +* [Privacy](https://docs.github.com/site-policy/privacy-policies/github-privacy-statement) +* [Security](https://github.com/security) +* [Status](https://www.githubstatus.com/) +* [Community](https://github.community/) +* [Docs](https://docs.github.com/) +* [Contact](https://support.github.com?tags=dotcom-footer) +* Manage cookies +* Do not share my personal information + + + +You can’t perform that action at this time. \ No newline at end of file diff --git a/references/ForthNotes/formic.md b/references/ForthNotes/formic.md new file mode 100644 index 0000000..6a519e9 --- /dev/null +++ b/references/ForthNotes/formic.md @@ -0,0 +1,5 @@ +# formic + +**Source:** https://formic.id + +formic.id \ No newline at end of file diff --git a/references/ForthNotes/foth_forth_in_go.md b/references/ForthNotes/foth_forth_in_go.md new file mode 100644 index 0000000..b3e7bc1 --- /dev/null +++ b/references/ForthNotes/foth_forth_in_go.md @@ -0,0 +1,821 @@ +# foth (forth in go) + +**Source:** https://github.com/skx/foth + +GitHub - skx/foth: Tutorial-style FORTH implementation written in golang + + + +[Skip to content](#start-of-content) + + + + + + + + + + + + + +## Navigation Menu + +Toggle navigation + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2Fskx%2Ffoth) + +Appearance settings + +* Platform + + + AI CODE CREATION + - [GitHub CopilotWrite better code with AI](https://github.com/features/copilot) + - [GitHub SparkBuild and deploy intelligent apps](https://github.com/features/spark) + - [GitHub ModelsManage and compare prompts](https://github.com/features/models) + - [MCP RegistryNewIntegrate external tools](https://github.com/mcp) + + DEVELOPER WORKFLOWS + - [ActionsAutomate any workflow](https://github.com/features/actions) + - [CodespacesInstant dev environments](https://github.com/features/codespaces) + - [IssuesPlan and track work](https://github.com/features/issues) + - [Code ReviewManage code changes](https://github.com/features/code-review) + + APPLICATION SECURITY + - [GitHub Advanced SecurityFind and fix vulnerabilities](https://github.com/security/advanced-security) + - [Code securitySecure your code as you build](https://github.com/security/advanced-security/code-security) + - [Secret protectionStop leaks before they start](https://github.com/security/advanced-security/secret-protection) + + EXPLORE + - [Why GitHub](https://github.com/why-github) + - [Documentation](https://docs.github.com) + - [Blog](https://github.blog) + - [Changelog](https://github.blog/changelog) + - [Marketplace](https://github.com/marketplace) + + [View all features](https://github.com/features) +* Solutions + + + BY COMPANY SIZE + - [Enterprises](https://github.com/enterprise) + - [Small and medium teams](https://github.com/team) + - [Startups](https://github.com/enterprise/startups) + - [Nonprofits](https://github.com/solutions/industry/nonprofits) + + BY USE CASE + - [App Modernization](https://github.com/solutions/use-case/app-modernization) + - [DevSecOps](https://github.com/solutions/use-case/devsecops) + - [DevOps](https://github.com/solutions/use-case/devops) + - [CI/CD](https://github.com/solutions/use-case/ci-cd) + - [View all use cases](https://github.com/solutions/use-case) + + BY INDUSTRY + - [Healthcare](https://github.com/solutions/industry/healthcare) + - [Financial services](https://github.com/solutions/industry/financial-services) + - [Manufacturing](https://github.com/solutions/industry/manufacturing) + - [Government](https://github.com/solutions/industry/government) + - [View all industries](https://github.com/solutions/industry) + + [View all solutions](https://github.com/solutions) +* Resources + + + EXPLORE BY TOPIC + - [AI](https://github.com/resources/articles?topic=ai) + - [Software Development](https://github.com/resources/articles?topic=software-development) + - [DevOps](https://github.com/resources/articles?topic=devops) + - [Security](https://github.com/resources/articles?topic=security) + - [View all topics](https://github.com/resources/articles) + + EXPLORE BY TYPE + - [Customer stories](https://github.com/customer-stories) + - [Events & webinars](https://github.com/resources/events) + - [Ebooks & reports](https://github.com/resources/whitepapers) + - [Business insights](https://github.com/solutions/executive-insights) + - [GitHub Skills](https://skills.github.com) + + SUPPORT & SERVICES + - [Documentation](https://docs.github.com) + - [Customer support](https://support.github.com) + - [Community forum](https://github.com/orgs/community/discussions) + - [Trust center](https://github.com/trust-center) + - [Partners](https://github.com/partners) +* Open Source + + + COMMUNITY + - [GitHub SponsorsFund open source developers](https://github.com/sponsors) + + PROGRAMS + - [Security Lab](https://securitylab.github.com) + - [Maintainer Community](https://maintainers.github.com) + - [Accelerator](https://github.com/accelerator) + - [Archive Program](https://archiveprogram.github.com) + + REPOSITORIES + - [Topics](https://github.com/topics) + - [Trending](https://github.com/trending) + - [Collections](https://github.com/collections) +* Enterprise + + + ENTERPRISE SOLUTIONS + - [Enterprise platformAI-powered developer platform](https://github.com/enterprise) + + AVAILABLE ADD-ONS + - [GitHub Advanced SecurityEnterprise-grade security features](https://github.com/security/advanced-security) + - [Copilot for BusinessEnterprise-grade AI features](https://github.com/features/copilot/copilot-business) + - [Premium SupportEnterprise-grade 24/7 support](https://github.com/premium-support) +* [Pricing](https://github.com/pricing) + +Search or jump to... + + +# Search code, repositories, users, issues, pull requests... + +Search + +Clear + +[Search syntax tips](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax) + +# Provide feedback + +We read every piece of feedback, and take your input very seriously. + + +Include my email address so I can be contacted + +Cancel + Submit feedback + + + + + +# Saved searches + +## Use saved searches to filter your results more quickly + +Name + +Query + +To see all available qualifiers, see our [documentation](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax). + +Cancel + Create saved search + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2Fskx%2Ffoth) + +[Sign up](/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E&source=header-repo&source_repo=skx%2Ffoth) + +Appearance settings + +Resetting focus + +You signed in with another tab or window. Reload to refresh your session. +You signed out in another tab or window. Reload to refresh your session. +You switched accounts on another tab or window. Reload to refresh your session. + + + +Dismiss alert + +{{ message }} + +This repository was archived by the owner on Sep 10, 2025. It is now read-only. + +[skx](/skx) +/ +**[foth](/skx/foth)** +Public archive + +* [Notifications](/login?return_to=%2Fskx%2Ffoth) You must be signed in to change notification settings +* [Fork + 7](/login?return_to=%2Fskx%2Ffoth) +* [Star + 94](/login?return_to=%2Fskx%2Ffoth) + +Tutorial-style FORTH implementation written in golang + +### License + +[GPL-2.0 license](/skx/foth/blob/master/LICENSE) + +[94 +stars](/skx/foth/stargazers) [7 +forks](/skx/foth/forks) [Branches](/skx/foth/branches) [Tags](/skx/foth/tags) [Activity](/skx/foth/activity) + +[Star](/login?return_to=%2Fskx%2Ffoth) + +[Notifications](/login?return_to=%2Fskx%2Ffoth) You must be signed in to change notification settings + +* [Code](/skx/foth) +* [Issues + 0](/skx/foth/issues) +* [Pull requests + 0](/skx/foth/pulls) +* [Actions](/skx/foth/actions) +* [Security + 0](/skx/foth/security) +* [Insights](/skx/foth/pulse) + +Additional navigation options + + +* [Code](/skx/foth) +* [Issues](/skx/foth/issues) +* [Pull requests](/skx/foth/pulls) +* [Actions](/skx/foth/actions) +* [Security](/skx/foth/security) +* [Insights](/skx/foth/pulse) + +# skx/foth + +master + +[Branches](/skx/foth/branches)[Tags](/skx/foth/tags) + +Go to file + +Code + +Open more actions menu + +## Folders and files + +| Name | | Name | Last commit message | Last commit date | +| --- | --- | --- | --- | --- | +| Latest commit History[128 Commits](/skx/foth/commits/master/) 128 Commits | | | +| [.github](/skx/foth/tree/master/.github ".github") | | [.github](/skx/foth/tree/master/.github ".github") | | | +| [foth](/skx/foth/tree/master/foth "foth") | | [foth](/skx/foth/tree/master/foth "foth") | | | +| [part1](/skx/foth/tree/master/part1 "part1") | | [part1](/skx/foth/tree/master/part1 "part1") | | | +| [part2](/skx/foth/tree/master/part2 "part2") | | [part2](/skx/foth/tree/master/part2 "part2") | | | +| [part3](/skx/foth/tree/master/part3 "part3") | | [part3](/skx/foth/tree/master/part3 "part3") | | | +| [part4](/skx/foth/tree/master/part4 "part4") | | [part4](/skx/foth/tree/master/part4 "part4") | | | +| [part5](/skx/foth/tree/master/part5 "part5") | | [part5](/skx/foth/tree/master/part5 "part5") | | | +| [part6](/skx/foth/tree/master/part6 "part6") | | [part6](/skx/foth/tree/master/part6 "part6") | | | +| [part7](/skx/foth/tree/master/part7 "part7") | | [part7](/skx/foth/tree/master/part7 "part7") | | | +| [.gitignore](/skx/foth/blob/master/.gitignore ".gitignore") | | [.gitignore](/skx/foth/blob/master/.gitignore ".gitignore") | | | +| [LICENSE](/skx/foth/blob/master/LICENSE "LICENSE") | | [LICENSE](/skx/foth/blob/master/LICENSE "LICENSE") | | | +| [README.md](/skx/foth/blob/master/README.md "README.md") | | [README.md](/skx/foth/blob/master/README.md "README.md") | | | +| [go.mod](/skx/foth/blob/master/go.mod "go.mod") | | [go.mod](/skx/foth/blob/master/go.mod "go.mod") | | | +| View all files | | | + +## Repository files navigation + +* [README](#) +* [GPL-2.0 license](#) + +[![GoDoc](https://camo.githubusercontent.com/4204d449c8ac17196f1a3a04ee0beb1b8c1b33e9cc5a11749b70dbac04462146/68747470733a2f2f696d672e736869656c64732e696f2f7374617469632f76313f6c6162656c3d676f646f63266d6573736167653d7265666572656e636526636f6c6f723d626c7565)](https://pkg.go.dev/github.com/skx/foth@v0.3.0/foth?tab=overview) +[![Go Report Card](https://camo.githubusercontent.com/75428032b736d4c96cb10a52bea074f46d24d022713c7391693717e8b7bcc7fa/68747470733a2f2f676f7265706f7274636172642e636f6d2f62616467652f6769746875622e636f6d2f736b782f666f7468)](https://goreportcard.com/report/github.com/skx/foth) +[![license](https://camo.githubusercontent.com/006d1a4a70625534d799b46a49525f5e5be4dc2093a9059bf0fc5e00ce7d566c/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f736b782f666f74682e737667)](https://github.com/skx/foth/blob/master/LICENSE) +[![Release](https://camo.githubusercontent.com/92dbc628aa2ba50da637c4609b1eb0f73eccd0092975d54b431101c557c96a07/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f72656c656173652f736b782f666f74682e737667)](https://github.com/skx/foth/releases/latest) + +* [foth](#foth) + + [Features](#features) + + [Installation](#installation) + + [Embedded Usage](#embedded-usage) + + [Anti-Features](#anti-features) + + [Implementation Approach](#implementation-approach) + + [Implementation Overview](#implementation-overview) + - [Part 1](#part-1) - Minimal initial-implementation. + - [Part 2](#part-2) - Hard-coded recursive word definitions. + - [Part 3](#part-3) - Allow defining minimal words via the REPL. + - [Part 4](#part-4) - Allow defining improved words via the REPL. + - [Part 5](#part-5) - Allow executing loops via `do`/`loop`. + - [Part 6](#part-6) - Allow conditional execution via `if`/`then`. + - [Part 7](#part-7) - Added minimal support for strings. + - [Final Revision](#final-revision) - Idiomatic Go, test-cases, and many new words + + [BUGS](#bugs) + - [loops](#loops) - zero expected-iterations actually runs once + + [See Also](#see-also) + + [Github Setup](#github-setup) + +# foth + +A simple implementation of a FORTH-like language, hence *foth* which is +close to *forth*. + +If you're new to FORTH then [the wikipedia page](https://en.wikipedia.org/wiki/Forth_(programming_language)) is a good starting point, and there are more good reads online such as: + +* [Forth in 7 easy steps](https://jeelabs.org/article/1612b/) + + Just ignore any mention of the return-stack! +* [Starting FORTH](https://www.forth.com/starting-forth/) + + A complete book, but the navigation of this site is non-obvious. + +In brief FORTH is a stack-based language, which uses Reverse Polish notation. The basic *thing* in Forth is the "word", which is a named data item, subroutine, or operator. Programming consists largely of defining new words, which are stored in a so-called "dictionary", in terms of existing ones. Iteratively building up a local DSL suited to your particular task. + +This repository was created by following the brief tutorial posted within the following Hacker News thread, designed to demonstrate how you could implement something *like* FORTH, in a series of simple steps: + +* + +The comment-thread shows example-code and pseudo-code in C, of course this repository is written in Go. + +## Features + +The end-result of this work is a simple scripting-language which you could easily embed within your golang application, allowing users to write simple FORTH-like scripts. We implement the kind of features a FORTH-user would expect: + +* Comments between `(` and `)` are ignored, as expected. + + Single-line comments `\` to the end of the line are also supported. +* Support for floating-point numbers (anything that will fit inside a `float64`). +* Reverse-Polish mathematical operations. + + Including support for `abs`, `min`, `max`, etc. +* Support for printing the top-most stack element (`.`, or `print`). +* Support for outputting ASCII characters (`emit`). +* Support for outputting strings (`." Hello, World "`). + + Some additional string-support for counting lengths, etc. +* Support for basic stack operations (`clearstack`, `drop`, `dup`, `over`, `swap`, `.s`) +* Support for loops, via `do`/`loop`. +* Support for conditional-execution, via `if`, `else`, and `then`. +* Support for declaring variables with `variable`, and getting/setting their values with `@` and `!` respectively. +* Execute files specified on the command-line. + + If no arguments are supplied run a simple REPL instead. +* A standard library is loaded, from the present directory, if it is present. + + See what we load by default in [foth/foth.4th](/skx/foth/blob/master/foth/foth.4th). +* The use of recursive definitions, for example: + + `: factorial recursive dup 1 > if dup 1 - factorial * then ;` + +## Installation + +You can find binary releases of the final-version upon the [project release page](https://github.com/skx/foth/releases), but if you prefer you can install from source easily. + +Either run this to download and install the binary: + +``` +$ go get github.com/skx/foth/foth@v0.5.0 +``` + +Or clone this repository, and build the executable like so: + +``` +cd foth +go build . +./foth +``` + +The executable will try to load [foth.4th](/skx/foth/blob/master/foth/foth.4th) from the current-directory, so you'll want to fetch that too. But otherwise it should work as you'd expect - the startup-file defines several useful words, so running without it is a little annoying but it isn't impossible. + +## Embedded Usage + +Although this is a minimal interpreter it *can* be embedded within a Golang host-application, allowing users to write scripts to control it. + +As an example of this I put together a simple demo: + +* + +This embeds the interpreter within an application, and defines some new words to allow the user to create graphics - in the style of [turtle](https://en.wikipedia.org/wiki/Turtle_graphics). + +## Anti-Features + +The obvious omission from this implementation is support for strings in the general case (string support is pretty limited to calling strlen, and printing strings which are constant and "inline"). + +We also lack the meta-programming facilities that FORTH users would expect, in a FORTH system it is possible to implement new control-flow systems, for example, by working with words and the control-flow directly. Instead in this system these things are unavailable, and the implementation of IF/DO/LOOP/ELSE/THEN are handled in the golang-code in a way users cannot modify. + +Basically we ignore the common FORTH-approach of using a return-stack, and implementing a VM with "cells". Instead we just emulate the *behaviour* of the more advanced words: + +* So we implement `if` or `do`/`loop` in a hard-coded fashion. + + That means we can't allow a user to define `while`, or similar. + + But otherwise our language is flexible enough to allow *real* work to be done with it. + +## Implementation Approach + +The code evolves through a series of simple steps, [contained in the comment-thread](https://news.ycombinator.com/item?id=13082825), ultimately ending with a [final revision](#final-revision) which is actually useful, usable, and pretty flexible. + +While it would certainly be possible to further improve the implementation I'm going to declare this project as "almost complete" for my own tastes: + +* I'll make minor changes, as they occur to me. +* Comments, test-cases, and similar are fair game. +* Outright crashes will be resolved, if I spot any. +* But no major new features will be added. + +If **you** wanted to extend things further then there are some obvious things to work upon: + +* Adding more of the "standard" FORTH-words. + + For example we're missing `pow`, etc. +* Enhanced the string-support, to allow an input/read from the user, and other primitives. + + strcat, strstr, and similar C-like operations would be useful. +* Simplify the conditional/loop handling. + + Both of these probably involve using a proper return-stack. + + This would have the side-effect of allowing new control-flow primitives to be added. + + As well as more meta-programming. + +Pull-requests adding additional functionality will be accepted with thanks. + +## Implementation Overview + +Each subdirectory within this repository gets a bit further down the comment-chain. + +In terms of implementation two files are *largely* unchanged in each example: + +* `stack.go`, which contains a simple stack of `float64` numbers. +* `main.go`, contains a simple REPL/driver. + + The final few examples will also allow loading a startup-file, if present. + +Each example builds upon the previous ones, with a pair of implementation files that change: + +* `builtins.go` contains the forth-words implemented in golang. +* `eval.go` is the workhorse which implements to FORTH-like interpreter. + + This allows executing existing words, and defining new ones. + +### Part 1 + +Part one of the implementation only deals with hard-coded execution +of "words". It only supports the basic mathematical operations, along +with the ability to print the top-most entry of the stack: + +``` + cd part1 + go build . + ./part1 + > 2 3 + 4 5 + * print + 45.000000 + ^D +``` + +See [part1/](/skx/foth/blob/master/part1) for details. + +### Part 2 + +Part two allows the definition of new words in terms of existing ones, +which can even happen recursively. + +We've added `dup` to pop an item off the stack, and push it back twice, which +has the ultimate effect of duplicating it. + +To demonstrate the self-definition there is the new function `square` which +squares the number at the top of the stack. + +``` + cd part2 + go build . + ./part2 + > 3 square . + 9.000000 + > 3 dup + . + 6.000000 + ^D +``` + +See [part2/](/skx/foth/blob/master/part2) for details. + +### Part 3 + +Part three allows the user to define their own words, right from within the +REPL! + +This means we've removed the `square` implementation, because you can add your own: + +``` + cd part3 + go build . + ./part3 + > : square dup * ; + > : cube dup square * ; + > 3 cube . + 27.000000 + > 25 square . + 625.000000 + ^D +``` + +See [part3/](/skx/foth/blob/master/part3) for details. + +**NOTE**: We don't support using numbers in definitions, yet. That will come in part4! + +### Part 4 + +Part four allows the user to define their own words, including the use of numbers, from within the REPL. Here the magic is handling the input of numbers when in "compiling mode". + +To support this we switched our `Words` array from `int` to `float64`, specifically to ensure that we could continue to support floating-point numbers. + +``` + cd part4 + go build . + ./part4 + > : add1 1 + ; + > -100 add1 . + -99.000000 + > 4 add1 . + 5.000000 + ^D +``` + +See [part4/](/skx/foth/blob/master/part4) for details. + +### Part 5 + +This part adds `do` and `loop`, allowing simple loops, and `emit` which outputs the ASCII character stored in the topmost stack-entry. + +Sample usage would look like this: + +``` +> : cr 10 emit ; +> : star 42 emit ; +> : stars 0 do star loop cr ; +> 4 stars +**** +> 5 stars +***** +> 1 stars +* +> 10 stars +********** +^D +``` + +Here we've defined two new words `cr` to print a return, and `star` to output a single star. + +We then defined the `stars` word to use a loop to print the given number of stars. + +(Note that the character `*` has the ASCII code 42). + +`do` and `loop` are pretty basic, allowing only loops to be handled which increment by one each iteration. You cannot use the standard `i` token to get the current index, instead you can see them on the stack: + +* Top-most entry is the current index. +* Second entry is the limit. + +So to write out numbers you could try something like this, using `dup` to duplicate the current offset within the loop: + +``` + > : l 10 0 do dup . loop ; + > l + 0.000000 + 1.000000 + 2.000000 + .. + 8.000000 + 9.000000 + + > : nums 10 0 do dup 48 + emit loop ; + > nums + 0123456789> +``` + +See [part5/](/skx/foth/blob/master/part5) for details. + +### Part 6 + +This update adds a lot of new primitives to our dictionary of predefined words: + +* `drop` - Removes an item from the stack. +* `swap` - Swaps the top-most two stack-items. +* `words` - Outputs a list of all defined words. +* `<`, `<=`, `=` (`==` as a synonym), `>`, `>=` + + Remove two items from the stack, and compare them appropriately. + + If the condition is true push `1` onto the stack, otherwise `0`. +* The biggest feature here is the support for using `if` & `then`, which allow conditional actions to be carried out. + + (These are why we added the comparison operations.) + +In addition to these new primitives the driver, `main.go`, was updated to load and evaluate [foth.4th](/skx/foth/blob/master/part6/foth.4th) on-startup if it is present. + +Sample usage: + +``` +cd part6 +go build . +./part6 +> : hot 72 emit 111 emit 116 emit 10 emit ; +> : cold 67 emit 111 emit 108 emit 100 emit 10 emit ; +> : test_hot 0 > if hot then ; +> : test_cold 0 <= if cold then ; +> : test dup test_hot test_cold ; +> 10 test +Hot +> 0 test +Cold +> -1 test +Cold +> 10 test_hot +Hot +> 10 test_cold +> -1 test_cold +Cold +^D +``` + +See [part6/](/skx/foth/blob/master/part6) for the code. + +**NOTE**: The `if` handler allows: + +``` +: foo $COND IF word1 [word2 .. wordN] then [more_word1 more_word2 ..] ; +``` + +This means if the condition is true then we run `word1`, `word2` .. and otherwise we skip them, and continue running after the `then` statement. Specifically note there is **no support for `else`**. That is why we call the `test_host` and `test_cold` words in our `test` definition. Each word tests separately. + +As an example: + +``` +> : foo 0 > if star star then star star cr ; +``` + +If the test-passes, because you give a positive number, you'll see FOUR stars. if it fails you just get TWO: + +``` + > 2 foo + **** + > 1 foo + **** + > 0 foo + ** + > -1 foo + ** +``` + +This is because the code is synonymous with the following C-code: + +``` + if ( x > 0 ) { + printf("*"); + printf("*"); + } + printf("*"); + printf("*"); + printf("\n"); +``` + +I found this page useful, it also documents `invert` which I added for completeness: + +* + +### Part 7 + +This update adds a basic level of support for strings. + +* When we see a string we store it in an array of strings. +* We then push the offset of the new string entry onto the stack. +* This allows it to be referenced and used. +* Three new words are added: + + `strings` Return the number of strings we've seen/stored. + + `strlen` show the length of the string at the given address. + + `strprn` print the string at the given address. + +Sample usage: + +``` +cd part7 +go build . +./part7 +> : steve "steve" ; +> steve strlen . +5 +> steve strprn . +steve +^D +``` + +See [part7/](/skx/foth/blob/master/part7) for the code. + +### Final Revision + +The final version, stored beneath [foth/](/skx/foth/blob/master/foth), is pretty similar to the previous part from an end-user point of view, however there have been a lot of changes behind the scenes: + +* We've added near 100% test-coverage. +* We've added a simple [lexer](/skx/foth/blob/master/foth/lexer) to tokenize our input. + + This was required to allow us to ignore comments, and handle string literals. + + Merely splitting input-strings at whitespace characters would have made either of those impossible to handle correctly. +* The `if` handling has been updated to support an `else`-branch, the general form is now: + + `$COND IF word1 [ .. wordN ] else alt_word1 [.. altN] then [more_word1 more_word2 ..]` +* It is now possible to use `if`, `else`, `then`, `do`, and `loop` outside word-definitions. + + i.e. Immediately in the REPL. +* `do`/`loop` loops can be nested. + + And the new words `i` and `m` used to return the current index and maximum index, respectively. +* There were many new words defined in the go-core: + + `.s` to show the stack-contents. + + `clearstack` to clear the stack. + + `debug` to change the debug-flag. + + `debug?` to reveal the status. + + `dump` dumps the compiled form of the given word. + - You can view the definitions of all available words this: + - `#words 0 do i dump loop` + + `#words` to return the number of defined words. + + Variables can be declared, by name, with `variable`, and the value of the variable can be set/retrieved with `@` and `!` respectively. + - See this demonstrated in the [standard library](/skx/foth/blob/master/foth/foth.4th) +* There were some new words defined in the [standard library](/skx/foth/blob/master/foth/foth.4th) + + e.g. `abs`, `even?`, `negate`, `odd?`, +* Removed all calls to `os.Exit()` + + We now return `error` objects where appropriate, allowing the caller to detect problems. +* It is now possible to redefine existing words. +* Execute any files specified on the command line. + + If no files are specified run the REPL. +* We've added support for recursive definitions, in #16 for example allowing: + + `: factorial recursive dup 1 > if dup 1 - factorial * then ;` + +See [foth/](/skx/foth/blob/master/foth) for the implementation. + +## BUGS + +A brief list of known-issues: + +### Loops + +The handling of loops isn't correct when there should be zero-iterations: + +``` + > : star 42 emit ; + > : stars 0 do star loop 10 emit ; + > 3 stars + *** + > 1 stars + * + > 0 stars + * + ^D +``` + +**NOTE**: In `gforth` the result of `0 0 do ... loop` is actually an **infinite** loop, which is perhaps worse! + +In our `stars` definition we handle this case by explicitly testing the loop +value before we proceed, only running the loop if the value is non-zero. + +# See Also + +This repository was put together after [experimenting with a scripting language](https://github.com/skx/monkey/), an [evaluation engine](https://github.com/skx/evalfilter/), putting together a [TCL-like scripting language](https://github.com/skx/critical), writing a [BASIC interpreter](https://github.com/skx/gobasic) and creating [yet another lisp](https://github.com/skx/yal). + +I've also played around with a couple of compilers which might be interesting to refer to: + +* Brainfuck compiler: + + +* A math-compiler: + + + +# Github Setup + +This repository is configured to run tests upon every commit, and when pull-requests are created/updated. The testing is carried out via [.github/run-tests.sh](/skx/foth/blob/master/.github/run-tests.sh) which is used by the [github-action-tester](https://github.com/skx/github-action-tester) action. + +## About + +Tutorial-style FORTH implementation written in golang + +### Topics + +[go](/topics/go "Topic: go") +[golang](/topics/golang "Topic: golang") +[tutorial](/topics/tutorial "Topic: tutorial") +[interpreter](/topics/interpreter "Topic: interpreter") +[scripting-language](/topics/scripting-language "Topic: scripting-language") +[forth](/topics/forth "Topic: forth") +[tutorial-code](/topics/tutorial-code "Topic: tutorial-code") +[forth-like](/topics/forth-like "Topic: forth-like") + +### Resources + +[Readme](#readme-ov-file) + +### License + +[GPL-2.0 license](#GPL-2.0-1-ov-file) + +### Uh oh! + +There was an error while loading. Please reload this page. + +[Activity](/skx/foth/activity) + +### Stars + +[**94** +stars](/skx/foth/stargazers) + +### Watchers + +[**0** +watching](/skx/foth/watchers) + +### Forks + +[**7** +forks](/skx/foth/forks) + +[Report repository](/contact/report-content?content_url=https%3A%2F%2Fgithub.com%2Fskx%2Ffoth&report=skx+%28user%29) + +## [Releases 2](/skx/foth/releases) + +[v0.5.0 + +Latest + +Feb 15, 2024](/skx/foth/releases/tag/v0.5.0) + +[+ 1 release](/skx/foth/releases) + +## [Packages 0](/users/skx/packages?repo_name=foth) + +No packages published + +## Languages + +* [Go + 95.3%](/skx/foth/search?l=go) +* [Forth + 4.7%](/skx/foth/search?l=forth) + +## Footer + +© 2026 GitHub, Inc. + +### Footer navigation + +* [Terms](https://docs.github.com/site-policy/github-terms/github-terms-of-service) +* [Privacy](https://docs.github.com/site-policy/privacy-policies/github-privacy-statement) +* [Security](https://github.com/security) +* [Status](https://www.githubstatus.com/) +* [Community](https://github.community/) +* [Docs](https://docs.github.com/) +* [Contact](https://support.github.com?tags=dotcom-footer) +* Manage cookies +* Do not share my personal information + + + +You can’t perform that action at this time. \ No newline at end of file diff --git a/references/ForthNotes/guitarvydasforthish.md b/references/ForthNotes/guitarvydasforthish.md new file mode 100644 index 0000000..d610745 --- /dev/null +++ b/references/ForthNotes/guitarvydasforthish.md @@ -0,0 +1,427 @@ +# guitarvydas/forthish + +**Source:** https://github.com/guitarvydas/forthish + +GitHub - guitarvydas/forthish + + + +[Skip to content](#start-of-content) + + + + + + + + + + + + + +## Navigation Menu + +Toggle navigation + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2Fguitarvydas%2Fforthish) + +Appearance settings + +* Platform + + + AI CODE CREATION + - [GitHub CopilotWrite better code with AI](https://github.com/features/copilot) + - [GitHub SparkBuild and deploy intelligent apps](https://github.com/features/spark) + - [GitHub ModelsManage and compare prompts](https://github.com/features/models) + - [MCP RegistryNewIntegrate external tools](https://github.com/mcp) + + DEVELOPER WORKFLOWS + - [ActionsAutomate any workflow](https://github.com/features/actions) + - [CodespacesInstant dev environments](https://github.com/features/codespaces) + - [IssuesPlan and track work](https://github.com/features/issues) + - [Code ReviewManage code changes](https://github.com/features/code-review) + + APPLICATION SECURITY + - [GitHub Advanced SecurityFind and fix vulnerabilities](https://github.com/security/advanced-security) + - [Code securitySecure your code as you build](https://github.com/security/advanced-security/code-security) + - [Secret protectionStop leaks before they start](https://github.com/security/advanced-security/secret-protection) + + EXPLORE + - [Why GitHub](https://github.com/why-github) + - [Documentation](https://docs.github.com) + - [Blog](https://github.blog) + - [Changelog](https://github.blog/changelog) + - [Marketplace](https://github.com/marketplace) + + [View all features](https://github.com/features) +* Solutions + + + BY COMPANY SIZE + - [Enterprises](https://github.com/enterprise) + - [Small and medium teams](https://github.com/team) + - [Startups](https://github.com/enterprise/startups) + - [Nonprofits](https://github.com/solutions/industry/nonprofits) + + BY USE CASE + - [App Modernization](https://github.com/solutions/use-case/app-modernization) + - [DevSecOps](https://github.com/solutions/use-case/devsecops) + - [DevOps](https://github.com/solutions/use-case/devops) + - [CI/CD](https://github.com/solutions/use-case/ci-cd) + - [View all use cases](https://github.com/solutions/use-case) + + BY INDUSTRY + - [Healthcare](https://github.com/solutions/industry/healthcare) + - [Financial services](https://github.com/solutions/industry/financial-services) + - [Manufacturing](https://github.com/solutions/industry/manufacturing) + - [Government](https://github.com/solutions/industry/government) + - [View all industries](https://github.com/solutions/industry) + + [View all solutions](https://github.com/solutions) +* Resources + + + EXPLORE BY TOPIC + - [AI](https://github.com/resources/articles?topic=ai) + - [Software Development](https://github.com/resources/articles?topic=software-development) + - [DevOps](https://github.com/resources/articles?topic=devops) + - [Security](https://github.com/resources/articles?topic=security) + - [View all topics](https://github.com/resources/articles) + + EXPLORE BY TYPE + - [Customer stories](https://github.com/customer-stories) + - [Events & webinars](https://github.com/resources/events) + - [Ebooks & reports](https://github.com/resources/whitepapers) + - [Business insights](https://github.com/solutions/executive-insights) + - [GitHub Skills](https://skills.github.com) + + SUPPORT & SERVICES + - [Documentation](https://docs.github.com) + - [Customer support](https://support.github.com) + - [Community forum](https://github.com/orgs/community/discussions) + - [Trust center](https://github.com/trust-center) + - [Partners](https://github.com/partners) +* Open Source + + + COMMUNITY + - [GitHub SponsorsFund open source developers](https://github.com/sponsors) + + PROGRAMS + - [Security Lab](https://securitylab.github.com) + - [Maintainer Community](https://maintainers.github.com) + - [Accelerator](https://github.com/accelerator) + - [Archive Program](https://archiveprogram.github.com) + + REPOSITORIES + - [Topics](https://github.com/topics) + - [Trending](https://github.com/trending) + - [Collections](https://github.com/collections) +* Enterprise + + + ENTERPRISE SOLUTIONS + - [Enterprise platformAI-powered developer platform](https://github.com/enterprise) + + AVAILABLE ADD-ONS + - [GitHub Advanced SecurityEnterprise-grade security features](https://github.com/security/advanced-security) + - [Copilot for BusinessEnterprise-grade AI features](https://github.com/features/copilot/copilot-business) + - [Premium SupportEnterprise-grade 24/7 support](https://github.com/premium-support) +* [Pricing](https://github.com/pricing) + +Search or jump to... + + +# Search code, repositories, users, issues, pull requests... + +Search + +Clear + +[Search syntax tips](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax) + +# Provide feedback + +We read every piece of feedback, and take your input very seriously. + + +Include my email address so I can be contacted + +Cancel + Submit feedback + + + + + +# Saved searches + +## Use saved searches to filter your results more quickly + +Name + +Query + +To see all available qualifiers, see our [documentation](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax). + +Cancel + Create saved search + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2Fguitarvydas%2Fforthish) + +[Sign up](/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E&source=header-repo&source_repo=guitarvydas%2Fforthish) + +Appearance settings + +Resetting focus + +You signed in with another tab or window. Reload to refresh your session. +You signed out in another tab or window. Reload to refresh your session. +You switched accounts on another tab or window. Reload to refresh your session. + + + +Dismiss alert + +{{ message }} + +[guitarvydas](/guitarvydas) +/ +**[forthish](/guitarvydas/forthish)** +Public + +* [Notifications](/login?return_to=%2Fguitarvydas%2Fforthish) You must be signed in to change notification settings +* [Fork + 0](/login?return_to=%2Fguitarvydas%2Fforthish) +* [Star + 1](/login?return_to=%2Fguitarvydas%2Fforthish) + +[1 +star](/guitarvydas/forthish/stargazers) [0 +forks](/guitarvydas/forthish/forks) [Branches](/guitarvydas/forthish/branches) [Tags](/guitarvydas/forthish/tags) [Activity](/guitarvydas/forthish/activity) + +[Star](/login?return_to=%2Fguitarvydas%2Fforthish) + +[Notifications](/login?return_to=%2Fguitarvydas%2Fforthish) You must be signed in to change notification settings + +* [Code](/guitarvydas/forthish) +* [Issues + 0](/guitarvydas/forthish/issues) +* [Pull requests + 0](/guitarvydas/forthish/pulls) +* [Actions](/guitarvydas/forthish/actions) +* [Projects + 0](/guitarvydas/forthish/projects) +* [Security + 0](/guitarvydas/forthish/security) +* [Insights](/guitarvydas/forthish/pulse) + +Additional navigation options + + +* [Code](/guitarvydas/forthish) +* [Issues](/guitarvydas/forthish/issues) +* [Pull requests](/guitarvydas/forthish/pulls) +* [Actions](/guitarvydas/forthish/actions) +* [Projects](/guitarvydas/forthish/projects) +* [Security](/guitarvydas/forthish/security) +* [Insights](/guitarvydas/forthish/pulse) + +# guitarvydas/forthish + +main + +[Branches](/guitarvydas/forthish/branches)[Tags](/guitarvydas/forthish/tags) + +Go to file + +Code + +Open more actions menu + +## Folders and files + +| Name | | Name | Last commit message | Last commit date | +| --- | --- | --- | --- | --- | +| Latest commit History[26 Commits](/guitarvydas/forthish/commits/main/) 26 Commits | | | +| [.hg](/guitarvydas/forthish/tree/main/.hg ".hg") | | [.hg](/guitarvydas/forthish/tree/main/.hg ".hg") | | | +| [.obsidian](/guitarvydas/forthish/tree/main/.obsidian ".obsidian") | | [.obsidian](/guitarvydas/forthish/tree/main/.obsidian ".obsidian") | | | +| [assets](/guitarvydas/forthish/tree/main/assets "assets") | | [assets](/guitarvydas/forthish/tree/main/assets "assets") | | | +| [basic](/guitarvydas/forthish/tree/main/basic "basic") | | [basic](/guitarvydas/forthish/tree/main/basic "basic") | | | +| [course](/guitarvydas/forthish/tree/main/course "course") | | [course](/guitarvydas/forthish/tree/main/course "course") | | | +| [frish](/guitarvydas/forthish/tree/main/frish "frish") | | [frish](/guitarvydas/forthish/tree/main/frish "frish") | | | +| [.gitignore](/guitarvydas/forthish/blob/main/.gitignore ".gitignore") | | [.gitignore](/guitarvydas/forthish/blob/main/.gitignore ".gitignore") | | | +| [.hgignore](/guitarvydas/forthish/blob/main/.hgignore ".hgignore") | | [.hgignore](/guitarvydas/forthish/blob/main/.hgignore ".hgignore") | | | +| [INSTALL-hg.md](/guitarvydas/forthish/blob/main/INSTALL-hg.md "INSTALL-hg.md") | | [INSTALL-hg.md](/guitarvydas/forthish/blob/main/INSTALL-hg.md "INSTALL-hg.md") | | | +| [INSTALL.md](/guitarvydas/forthish/blob/main/INSTALL.md "INSTALL.md") | | [INSTALL.md](/guitarvydas/forthish/blob/main/INSTALL.md "INSTALL.md") | | | +| [README.md](/guitarvydas/forthish/blob/main/README.md "README.md") | | [README.md](/guitarvydas/forthish/blob/main/README.md "README.md") | | | +| View all files | | | + +## Repository files navigation + +* [README](#) + +# Forth in $WHATEVER + +This is a collection of Forth (or Forth-like) implementations in various languages. It is intended to provide examples of how you can leverage Forth to simplify and add extensibility to your programs. + +## Python Implementations + +### [simple.py](/guitarvydas/forthish/blob/main/simple.py?rev=tip) + +The simplest thing that could be called a Forth (Mr. Moore will probably disagree with me). However, it provides a useful parser, stack and interface to the host system. Words in this implementation: + +* **+** ( a b -- sum) Add two numbers on top of stack. +* **-** ( a b -- difference) Subtracts top number from next on stack. +* **.** ( n --) Pop top of stack and print it. +* **.s** ( --) Print contents of stack (nondestructive). +* **bye** ( --) Exit interpreter. +* **interpret** ( string --) Execute word on top of stack. +* **swap** ( a b -- b a) Swaps top two items on stack. +* **word** ( c -- string) Collect characters in input stream up to character c. + +### [fram.py](/guitarvydas/forthish/blob/main/fram.py?rev=tip) + +This implements a semi-traditional Forth dictionary in the RAM array. Words are stored with a name field, link field and code field. Instead of finding things directly with a Python dictionary, the `'` word searches for the xt, or "execution token", to be executed. + +In real terms, a little slower, but offers some exciting benefits, which I'll explore later. + +* **'** ( name -- xt) Finds word's xt in dictionary. +* **execute** ( xt --) Executes the code at xt. +* **negate** ( n -- -n) Makes number negative (or positive, if you use it twice). +* **words** ( --) Prints list of all words in dictionary. + +### [fvars.py](/guitarvydas/forthish/blob/main/fvars.py?rev=tip) + +Now we're getting into memory manipulations with variables and such. This introduces some new stuff in the code field -- a constant or variable is just like any other Forth word, except the code retrieves the values (or address of the values, for variables). + +* **!** ( v a --) Store value at address a. +* **,** ( v --) Store v as next value in dictionary. +* **@** ( a -- v) Fetch value from address a. +* **constant** ( name | v --) Create constant with value v. +* **create** ( name | --) Create word name in dictionary. +* **dump** ( start n --) Dump n values starting from RAM address a. +* **variable** ( name | v --) Create variable name, with initial value v. + +### [fcomp.py](/guitarvydas/forthish/blob/main/fcomp.py?rev=tip) + +Stuff is getting tricky now... This implements user definitions. Also reworks some previous words. + +#### Variables + +* **state** Variable for interpreter state -- 0 = interpret, 1 = compile. + +#### Special Words for Compilation + +These words are used during compilation to handle literal values and control flow. You will generally not need to use them. + +* **(literal)** Used when compiling literal values in definitions. +* **branch** Unconditional branch. +* **0branch** Branch on false. + +#### Words for Definitions + +The colon and semicolon begin and end a Forth definition. The if/else/then triad can only be used inside a definition (in traditional Forth). + +* **:** ( name | --) Start compiling new definition. +* **;** ( --) End definition. +* **if** ( f --) Evaluate based on flag f. +* **else** ( --) What to do when if is false. +* **then** ( --) End if/else/then clause, continue with normal execution. + +#### Regular Words + +This is a grab bag of stuff that I found useful as I went. Notably, the `"` (quote) word is state-smart, meaning it can be used outside and inside a definition. Now that you know that, forget it... + +* **find** ( name | -- name 0|xt 1|xt -1) Search for word name. +* **(** ( --) Start inline comment, reads until closing paren. +* **."** ( --) Prints text up to closing quote. +* **"** ( -- s) Reads text up to closing quote as a string, puts on stack. +* **/** ( a b -- div) Divides a by b. +* **\*** ( a b -- product) Multiplies a times b. +* **cr** ( --) Carriage return. +* **emit** ( c --) Prints ascii character c. +* **dup** ( a -- a a) Duplicate TOS. +* **drop** ( a --) Discards TOS. + +If you care, this is effectively a DTC (Direct Threaded Code) implementation. + +*Explanation of how colon definitions work goes here...* + +## References + +Some links to more information that will help in understanding why you might do with this and what to do with it once you've got it. If nothing else, please read Walker's essay at the first link. + +### Essential + +* [ATLAST](https://www.fourmilab.ch/atlast/) -- My first encounter with this concept, written by the legendary John Walker. He explains it better than I can. +* [Starting Forth](https://www.forth.com/starting-forth/) -- Classic Forth tutorial and textbook. Don't be fooled by the illustrations, this book not only teaches you how to use Forth, but actually gives you enough information to write your own as well. +* [Levels of FORTH](https://www.forth.org/literature/forthlev.html) -- Glen Haydon's taxonomy of Forth implementations, slightly outdated, but useful if you're trying to figure out what functionality to implement next. + +### Supplemental + +* [Forth Standard](https://forth-standard.org/standard/words) Yes, Forth has a language standard. Don't feel like you need to follow it slavishly, though... +* [JONESFORTH](https://github.com/nornagon/jonesforth/blob/master/jonesforth.S) -- A full implementation of Forth, in assembly. +* [Thinking Forth -- A Language and Philosophy for Solving Problems](https://www.forth.com/wp-content/uploads/2018/11/thinking-forth-color.pdf) -- Leo Brodie's masterwork, read this to figure out how to *really* use your new Forth implementation. + +### Historical + +* [Forth - The Early Years](https://colorforth.github.io/HOPL.html) -- Potted history of Forth, by its creator, Chuck Moore. +* [Programming a Problem Oriented Language](https://archive.org/details/chuck-moore-forth-book/page/10/mode/2up) -- Unpublished book by Chuck Moore describing early Forth. + +## About + +No description, website, or topics provided. + +### Resources + +[Readme](#readme-ov-file) + +### Uh oh! + +There was an error while loading. Please reload this page. + +[Activity](/guitarvydas/forthish/activity) + +### Stars + +[**1** +star](/guitarvydas/forthish/stargazers) + +### Watchers + +[**0** +watching](/guitarvydas/forthish/watchers) + +### Forks + +[**0** +forks](/guitarvydas/forthish/forks) + +[Report repository](/contact/report-content?content_url=https%3A%2F%2Fgithub.com%2Fguitarvydas%2Fforthish&report=guitarvydas+%28user%29) + +## [Releases](/guitarvydas/forthish/releases) + +No releases published + +## [Packages 0](/users/guitarvydas/packages?repo_name=forthish) + +No packages published + +## Languages + +* [Python + 66.6%](/guitarvydas/forthish/search?l=python) +* [JavaScript + 22.6%](/guitarvydas/forthish/search?l=javascript) +* [HTML + 10.4%](/guitarvydas/forthish/search?l=html) +* Other + 0.4% + +## Footer + +© 2026 GitHub, Inc. + +### Footer navigation + +* [Terms](https://docs.github.com/site-policy/github-terms/github-terms-of-service) +* [Privacy](https://docs.github.com/site-policy/privacy-policies/github-privacy-statement) +* [Security](https://github.com/security) +* [Status](https://www.githubstatus.com/) +* [Community](https://github.community/) +* [Docs](https://docs.github.com/) +* [Contact](https://support.github.com?tags=dotcom-footer) +* Manage cookies +* Do not share my personal information + + + +You can’t perform that action at this time. \ No newline at end of file diff --git a/references/ForthNotes/iNet.md b/references/ForthNotes/iNet.md new file mode 100644 index 0000000..2507305 --- /dev/null +++ b/references/ForthNotes/iNet.md @@ -0,0 +1,5 @@ +# iNet + +**Source:** https://inet.run + +iNet \ No newline at end of file diff --git a/references/ForthNotes/jombloforth_x64_Jonesforth.md b/references/ForthNotes/jombloforth_x64_Jonesforth.md new file mode 100644 index 0000000..234e783 --- /dev/null +++ b/references/ForthNotes/jombloforth_x64_Jonesforth.md @@ -0,0 +1,384 @@ +# jombloforth (x64 Jonesforth) + +**Source:** https://github.com/matematikaadit/jombloforth + +GitHub - matematikaadit/jombloforth: Minimal FORTH interpreter for 64-bit Linux systems. Based on jonesforth. + + + +[Skip to content](#start-of-content) + + + + + + + + + + + + + +## Navigation Menu + +Toggle navigation + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2Fmatematikaadit%2Fjombloforth) + +Appearance settings + +* Platform + + + AI CODE CREATION + - [GitHub CopilotWrite better code with AI](https://github.com/features/copilot) + - [GitHub SparkBuild and deploy intelligent apps](https://github.com/features/spark) + - [GitHub ModelsManage and compare prompts](https://github.com/features/models) + - [MCP RegistryNewIntegrate external tools](https://github.com/mcp) + + DEVELOPER WORKFLOWS + - [ActionsAutomate any workflow](https://github.com/features/actions) + - [CodespacesInstant dev environments](https://github.com/features/codespaces) + - [IssuesPlan and track work](https://github.com/features/issues) + - [Code ReviewManage code changes](https://github.com/features/code-review) + + APPLICATION SECURITY + - [GitHub Advanced SecurityFind and fix vulnerabilities](https://github.com/security/advanced-security) + - [Code securitySecure your code as you build](https://github.com/security/advanced-security/code-security) + - [Secret protectionStop leaks before they start](https://github.com/security/advanced-security/secret-protection) + + EXPLORE + - [Why GitHub](https://github.com/why-github) + - [Documentation](https://docs.github.com) + - [Blog](https://github.blog) + - [Changelog](https://github.blog/changelog) + - [Marketplace](https://github.com/marketplace) + + [View all features](https://github.com/features) +* Solutions + + + BY COMPANY SIZE + - [Enterprises](https://github.com/enterprise) + - [Small and medium teams](https://github.com/team) + - [Startups](https://github.com/enterprise/startups) + - [Nonprofits](https://github.com/solutions/industry/nonprofits) + + BY USE CASE + - [App Modernization](https://github.com/solutions/use-case/app-modernization) + - [DevSecOps](https://github.com/solutions/use-case/devsecops) + - [DevOps](https://github.com/solutions/use-case/devops) + - [CI/CD](https://github.com/solutions/use-case/ci-cd) + - [View all use cases](https://github.com/solutions/use-case) + + BY INDUSTRY + - [Healthcare](https://github.com/solutions/industry/healthcare) + - [Financial services](https://github.com/solutions/industry/financial-services) + - [Manufacturing](https://github.com/solutions/industry/manufacturing) + - [Government](https://github.com/solutions/industry/government) + - [View all industries](https://github.com/solutions/industry) + + [View all solutions](https://github.com/solutions) +* Resources + + + EXPLORE BY TOPIC + - [AI](https://github.com/resources/articles?topic=ai) + - [Software Development](https://github.com/resources/articles?topic=software-development) + - [DevOps](https://github.com/resources/articles?topic=devops) + - [Security](https://github.com/resources/articles?topic=security) + - [View all topics](https://github.com/resources/articles) + + EXPLORE BY TYPE + - [Customer stories](https://github.com/customer-stories) + - [Events & webinars](https://github.com/resources/events) + - [Ebooks & reports](https://github.com/resources/whitepapers) + - [Business insights](https://github.com/solutions/executive-insights) + - [GitHub Skills](https://skills.github.com) + + SUPPORT & SERVICES + - [Documentation](https://docs.github.com) + - [Customer support](https://support.github.com) + - [Community forum](https://github.com/orgs/community/discussions) + - [Trust center](https://github.com/trust-center) + - [Partners](https://github.com/partners) +* Open Source + + + COMMUNITY + - [GitHub SponsorsFund open source developers](https://github.com/sponsors) + + PROGRAMS + - [Security Lab](https://securitylab.github.com) + - [Maintainer Community](https://maintainers.github.com) + - [Accelerator](https://github.com/accelerator) + - [Archive Program](https://archiveprogram.github.com) + + REPOSITORIES + - [Topics](https://github.com/topics) + - [Trending](https://github.com/trending) + - [Collections](https://github.com/collections) +* Enterprise + + + ENTERPRISE SOLUTIONS + - [Enterprise platformAI-powered developer platform](https://github.com/enterprise) + + AVAILABLE ADD-ONS + - [GitHub Advanced SecurityEnterprise-grade security features](https://github.com/security/advanced-security) + - [Copilot for BusinessEnterprise-grade AI features](https://github.com/features/copilot/copilot-business) + - [Premium SupportEnterprise-grade 24/7 support](https://github.com/premium-support) +* [Pricing](https://github.com/pricing) + +Search or jump to... + + +# Search code, repositories, users, issues, pull requests... + +Search + +Clear + +[Search syntax tips](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax) + +# Provide feedback + +We read every piece of feedback, and take your input very seriously. + + +Include my email address so I can be contacted + +Cancel + Submit feedback + + + + + +# Saved searches + +## Use saved searches to filter your results more quickly + +Name + +Query + +To see all available qualifiers, see our [documentation](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax). + +Cancel + Create saved search + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2Fmatematikaadit%2Fjombloforth) + +[Sign up](/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E&source=header-repo&source_repo=matematikaadit%2Fjombloforth) + +Appearance settings + +Resetting focus + +You signed in with another tab or window. Reload to refresh your session. +You signed out in another tab or window. Reload to refresh your session. +You switched accounts on another tab or window. Reload to refresh your session. + + + +Dismiss alert + +{{ message }} + +[matematikaadit](/matematikaadit) +/ +**[jombloforth](/matematikaadit/jombloforth)** +Public + +* [Notifications](/login?return_to=%2Fmatematikaadit%2Fjombloforth) You must be signed in to change notification settings +* [Fork + 5](/login?return_to=%2Fmatematikaadit%2Fjombloforth) +* [Star + 28](/login?return_to=%2Fmatematikaadit%2Fjombloforth) + +Minimal FORTH interpreter for 64-bit Linux systems. Based on jonesforth. + +### License + +[Unlicense license](/matematikaadit/jombloforth/blob/master/UNLICENSE.txt) + +[28 +stars](/matematikaadit/jombloforth/stargazers) [5 +forks](/matematikaadit/jombloforth/forks) [Branches](/matematikaadit/jombloforth/branches) [Tags](/matematikaadit/jombloforth/tags) [Activity](/matematikaadit/jombloforth/activity) + +[Star](/login?return_to=%2Fmatematikaadit%2Fjombloforth) + +[Notifications](/login?return_to=%2Fmatematikaadit%2Fjombloforth) You must be signed in to change notification settings + +* [Code](/matematikaadit/jombloforth) +* [Issues + 0](/matematikaadit/jombloforth/issues) +* [Pull requests + 0](/matematikaadit/jombloforth/pulls) +* [Actions](/matematikaadit/jombloforth/actions) +* [Projects + 0](/matematikaadit/jombloforth/projects) +* [Security + 0](/matematikaadit/jombloforth/security) +* [Insights](/matematikaadit/jombloforth/pulse) + +Additional navigation options + + +* [Code](/matematikaadit/jombloforth) +* [Issues](/matematikaadit/jombloforth/issues) +* [Pull requests](/matematikaadit/jombloforth/pulls) +* [Actions](/matematikaadit/jombloforth/actions) +* [Projects](/matematikaadit/jombloforth/projects) +* [Security](/matematikaadit/jombloforth/security) +* [Insights](/matematikaadit/jombloforth/pulse) + +# matematikaadit/jombloforth + +master + +[Branches](/matematikaadit/jombloforth/branches)[Tags](/matematikaadit/jombloforth/tags) + +Go to file + +Code + +Open more actions menu + +## Folders and files + +| Name | | Name | Last commit message | Last commit date | +| --- | --- | --- | --- | --- | +| Latest commit History[93 Commits](/matematikaadit/jombloforth/commits/master/) 93 Commits | | | +| [debug](/matematikaadit/jombloforth/tree/master/debug "debug") | | [debug](/matematikaadit/jombloforth/tree/master/debug "debug") | | | +| [experiment](/matematikaadit/jombloforth/tree/master/experiment "experiment") | | [experiment](/matematikaadit/jombloforth/tree/master/experiment "experiment") | | | +| [original](/matematikaadit/jombloforth/tree/master/original "original") | | [original](/matematikaadit/jombloforth/tree/master/original "original") | | | +| [tests](/matematikaadit/jombloforth/tree/master/tests "tests") | | [tests](/matematikaadit/jombloforth/tree/master/tests "tests") | | | +| [.gitignore](/matematikaadit/jombloforth/blob/master/.gitignore ".gitignore") | | [.gitignore](/matematikaadit/jombloforth/blob/master/.gitignore ".gitignore") | | | +| [Makefile](/matematikaadit/jombloforth/blob/master/Makefile "Makefile") | | [Makefile](/matematikaadit/jombloforth/blob/master/Makefile "Makefile") | | | +| [README.md](/matematikaadit/jombloforth/blob/master/README.md "README.md") | | [README.md](/matematikaadit/jombloforth/blob/master/README.md "README.md") | | | +| [UNLICENSE.txt](/matematikaadit/jombloforth/blob/master/UNLICENSE.txt "UNLICENSE.txt") | | [UNLICENSE.txt](/matematikaadit/jombloforth/blob/master/UNLICENSE.txt "UNLICENSE.txt") | | | +| [jombloforth.asm](/matematikaadit/jombloforth/blob/master/jombloforth.asm "jombloforth.asm") | | [jombloforth.asm](/matematikaadit/jombloforth/blob/master/jombloforth.asm "jombloforth.asm") | | | +| [jombloforth.f](/matematikaadit/jombloforth/blob/master/jombloforth.f "jombloforth.f") | | [jombloforth.f](/matematikaadit/jombloforth/blob/master/jombloforth.f "jombloforth.f") | | | +| [unistd\_64.inc](/matematikaadit/jombloforth/blob/master/unistd_64.inc "unistd_64.inc") | | [unistd\_64.inc](/matematikaadit/jombloforth/blob/master/unistd_64.inc "unistd_64.inc") | | | +| View all files | | | + +## Repository files navigation + +* [README](#) +* [Unlicense license](#) + +# jombloforth + +Minimal FORTH interpreter for 64-bit Linux systems. Based on +jonesforth tutorial. + +## Compile + +You needs make, nasm, and ld to build the executable. Runs the following to build them + +``` +make jombloforth +``` + +## Running + +For a full forth system, runs: + +``` +make run +``` + +The interpreter will starts accepting input from stdin. + +## Quick Forth Tutorial + +After the interpreter starts, you can execute any forth command defined in the system. For example, adding two number and display it. + +``` +42 24 + . CR +``` + +Will print 66 followed by newline. + +Defining new word and runs it: + +``` +: double DUP + ; +100 double . CR +``` + +Will print 200. + +To exit the program, press CTRL+D + +## License + +UNLICENSE. See [UNLICENSE.txt](/matematikaadit/jombloforth/blob/master/UNLICENSE.txt) + +## About + +Minimal FORTH interpreter for 64-bit Linux systems. Based on jonesforth. + +### Topics + +[assembly](/topics/assembly "Topic: assembly") +[x64](/topics/x64 "Topic: x64") +[x86-64](/topics/x86-64 "Topic: x86-64") +[forth](/topics/forth "Topic: forth") +[nasm](/topics/nasm "Topic: nasm") + +### Resources + +[Readme](#readme-ov-file) + +### License + +[Unlicense license](#Unlicense-1-ov-file) + +### Uh oh! + +There was an error while loading. Please reload this page. + +[Activity](/matematikaadit/jombloforth/activity) + +### Stars + +[**28** +stars](/matematikaadit/jombloforth/stargazers) + +### Watchers + +[**1** +watching](/matematikaadit/jombloforth/watchers) + +### Forks + +[**5** +forks](/matematikaadit/jombloforth/forks) + +[Report repository](/contact/report-content?content_url=https%3A%2F%2Fgithub.com%2Fmatematikaadit%2Fjombloforth&report=matematikaadit+%28user%29) + +## [Releases](/matematikaadit/jombloforth/releases) + +No releases published + +## [Packages 0](/users/matematikaadit/packages?repo_name=jombloforth) + +No packages published + +## Languages + +* [Assembly + 85.7%](/matematikaadit/jombloforth/search?l=assembly) +* [Forth + 13.4%](/matematikaadit/jombloforth/search?l=forth) +* Other + 0.9% + +## Footer + +© 2026 GitHub, Inc. + +### Footer navigation + +* [Terms](https://docs.github.com/site-policy/github-terms/github-terms-of-service) +* [Privacy](https://docs.github.com/site-policy/privacy-policies/github-privacy-statement) +* [Security](https://github.com/security) +* [Status](https://www.githubstatus.com/) +* [Community](https://github.community/) +* [Docs](https://docs.github.com/) +* [Contact](https://support.github.com?tags=dotcom-footer) +* Manage cookies +* Do not share my personal information + + + +You can’t perform that action at this time. \ No newline at end of file diff --git a/references/ForthNotes/kcats.md b/references/ForthNotes/kcats.md new file mode 100644 index 0000000..8b362fb --- /dev/null +++ b/references/ForthNotes/kcats.md @@ -0,0 +1,390 @@ +# kcats + +**Source:** https://github.com/skyrod-vactai/kcats + +GitHub - skyrod-vactai/kcats: A stack-based programming language based on Joy + + + +[Skip to content](#start-of-content) + + + + + + + + + + + + + +## Navigation Menu + +Toggle navigation + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2Fskyrod-vactai%2Fkcats) + +Appearance settings + +* Platform + + + AI CODE CREATION + - [GitHub CopilotWrite better code with AI](https://github.com/features/copilot) + - [GitHub SparkBuild and deploy intelligent apps](https://github.com/features/spark) + - [GitHub ModelsManage and compare prompts](https://github.com/features/models) + - [MCP RegistryNewIntegrate external tools](https://github.com/mcp) + + DEVELOPER WORKFLOWS + - [ActionsAutomate any workflow](https://github.com/features/actions) + - [CodespacesInstant dev environments](https://github.com/features/codespaces) + - [IssuesPlan and track work](https://github.com/features/issues) + - [Code ReviewManage code changes](https://github.com/features/code-review) + + APPLICATION SECURITY + - [GitHub Advanced SecurityFind and fix vulnerabilities](https://github.com/security/advanced-security) + - [Code securitySecure your code as you build](https://github.com/security/advanced-security/code-security) + - [Secret protectionStop leaks before they start](https://github.com/security/advanced-security/secret-protection) + + EXPLORE + - [Why GitHub](https://github.com/why-github) + - [Documentation](https://docs.github.com) + - [Blog](https://github.blog) + - [Changelog](https://github.blog/changelog) + - [Marketplace](https://github.com/marketplace) + + [View all features](https://github.com/features) +* Solutions + + + BY COMPANY SIZE + - [Enterprises](https://github.com/enterprise) + - [Small and medium teams](https://github.com/team) + - [Startups](https://github.com/enterprise/startups) + - [Nonprofits](https://github.com/solutions/industry/nonprofits) + + BY USE CASE + - [App Modernization](https://github.com/solutions/use-case/app-modernization) + - [DevSecOps](https://github.com/solutions/use-case/devsecops) + - [DevOps](https://github.com/solutions/use-case/devops) + - [CI/CD](https://github.com/solutions/use-case/ci-cd) + - [View all use cases](https://github.com/solutions/use-case) + + BY INDUSTRY + - [Healthcare](https://github.com/solutions/industry/healthcare) + - [Financial services](https://github.com/solutions/industry/financial-services) + - [Manufacturing](https://github.com/solutions/industry/manufacturing) + - [Government](https://github.com/solutions/industry/government) + - [View all industries](https://github.com/solutions/industry) + + [View all solutions](https://github.com/solutions) +* Resources + + + EXPLORE BY TOPIC + - [AI](https://github.com/resources/articles?topic=ai) + - [Software Development](https://github.com/resources/articles?topic=software-development) + - [DevOps](https://github.com/resources/articles?topic=devops) + - [Security](https://github.com/resources/articles?topic=security) + - [View all topics](https://github.com/resources/articles) + + EXPLORE BY TYPE + - [Customer stories](https://github.com/customer-stories) + - [Events & webinars](https://github.com/resources/events) + - [Ebooks & reports](https://github.com/resources/whitepapers) + - [Business insights](https://github.com/solutions/executive-insights) + - [GitHub Skills](https://skills.github.com) + + SUPPORT & SERVICES + - [Documentation](https://docs.github.com) + - [Customer support](https://support.github.com) + - [Community forum](https://github.com/orgs/community/discussions) + - [Trust center](https://github.com/trust-center) + - [Partners](https://github.com/partners) +* Open Source + + + COMMUNITY + - [GitHub SponsorsFund open source developers](https://github.com/sponsors) + + PROGRAMS + - [Security Lab](https://securitylab.github.com) + - [Maintainer Community](https://maintainers.github.com) + - [Accelerator](https://github.com/accelerator) + - [Archive Program](https://archiveprogram.github.com) + + REPOSITORIES + - [Topics](https://github.com/topics) + - [Trending](https://github.com/trending) + - [Collections](https://github.com/collections) +* Enterprise + + + ENTERPRISE SOLUTIONS + - [Enterprise platformAI-powered developer platform](https://github.com/enterprise) + + AVAILABLE ADD-ONS + - [GitHub Advanced SecurityEnterprise-grade security features](https://github.com/security/advanced-security) + - [Copilot for BusinessEnterprise-grade AI features](https://github.com/features/copilot/copilot-business) + - [Premium SupportEnterprise-grade 24/7 support](https://github.com/premium-support) +* [Pricing](https://github.com/pricing) + +Search or jump to... + + +# Search code, repositories, users, issues, pull requests... + +Search + +Clear + +[Search syntax tips](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax) + +# Provide feedback + +We read every piece of feedback, and take your input very seriously. + + +Include my email address so I can be contacted + +Cancel + Submit feedback + + + + + +# Saved searches + +## Use saved searches to filter your results more quickly + +Name + +Query + +To see all available qualifiers, see our [documentation](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax). + +Cancel + Create saved search + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2Fskyrod-vactai%2Fkcats) + +[Sign up](/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E&source=header-repo&source_repo=skyrod-vactai%2Fkcats) + +Appearance settings + +Resetting focus + +You signed in with another tab or window. Reload to refresh your session. +You signed out in another tab or window. Reload to refresh your session. +You switched accounts on another tab or window. Reload to refresh your session. + + + +Dismiss alert + +{{ message }} + +[skyrod-vactai](/skyrod-vactai) +/ +**[kcats](/skyrod-vactai/kcats)** +Public + +* [Notifications](/login?return_to=%2Fskyrod-vactai%2Fkcats) You must be signed in to change notification settings +* [Fork + 1](/login?return_to=%2Fskyrod-vactai%2Fkcats) +* [Star + 8](/login?return_to=%2Fskyrod-vactai%2Fkcats) + +A stack-based programming language based on Joy + +### License + +[WTFPL license](/skyrod-vactai/kcats/blob/master/LICENSE-WTFPL) + +[8 +stars](/skyrod-vactai/kcats/stargazers) [1 +fork](/skyrod-vactai/kcats/forks) [Branches](/skyrod-vactai/kcats/branches) [Tags](/skyrod-vactai/kcats/tags) [Activity](/skyrod-vactai/kcats/activity) + +[Star](/login?return_to=%2Fskyrod-vactai%2Fkcats) + +[Notifications](/login?return_to=%2Fskyrod-vactai%2Fkcats) You must be signed in to change notification settings + +* [Code](/skyrod-vactai/kcats) +* [Issues + 0](/skyrod-vactai/kcats/issues) +* [Pull requests + 0](/skyrod-vactai/kcats/pulls) +* [Discussions](/skyrod-vactai/kcats/discussions) +* [Actions](/skyrod-vactai/kcats/actions) +* [Projects + 0](/skyrod-vactai/kcats/projects) +* [Security + 0](/skyrod-vactai/kcats/security) +* [Insights](/skyrod-vactai/kcats/pulse) + +Additional navigation options + + +* [Code](/skyrod-vactai/kcats) +* [Issues](/skyrod-vactai/kcats/issues) +* [Pull requests](/skyrod-vactai/kcats/pulls) +* [Discussions](/skyrod-vactai/kcats/discussions) +* [Actions](/skyrod-vactai/kcats/actions) +* [Projects](/skyrod-vactai/kcats/projects) +* [Security](/skyrod-vactai/kcats/security) +* [Insights](/skyrod-vactai/kcats/pulse) + +# skyrod-vactai/kcats + +master + +[Branches](/skyrod-vactai/kcats/branches)[Tags](/skyrod-vactai/kcats/tags) + +Go to file + +Code + +Open more actions menu + +## Folders and files + +| Name | | Name | Last commit message | Last commit date | +| --- | --- | --- | --- | --- | +| Latest commit History[1,445 Commits](/skyrod-vactai/kcats/commits/master/) 1,445 Commits | | | +| [.cargo](/skyrod-vactai/kcats/tree/master/.cargo ".cargo") | | [.cargo](/skyrod-vactai/kcats/tree/master/.cargo ".cargo") | | | +| [.devcontainer](/skyrod-vactai/kcats/tree/master/.devcontainer ".devcontainer") | | [.devcontainer](/skyrod-vactai/kcats/tree/master/.devcontainer ".devcontainer") | | | +| [.github/workflows](/skyrod-vactai/kcats/tree/master/.github/workflows "This path skips through empty directories") | | [.github/workflows](/skyrod-vactai/kcats/tree/master/.github/workflows "This path skips through empty directories") | | | +| [ai-model-training](/skyrod-vactai/kcats/tree/master/ai-model-training "ai-model-training") | | [ai-model-training](/skyrod-vactai/kcats/tree/master/ai-model-training "ai-model-training") | | | +| [edn-format](/skyrod-vactai/kcats/tree/master/edn-format "edn-format") | | [edn-format](/skyrod-vactai/kcats/tree/master/edn-format "edn-format") | | | +| [emacs](/skyrod-vactai/kcats/tree/master/emacs "emacs") | | [emacs](/skyrod-vactai/kcats/tree/master/emacs "emacs") | | | +| [examples](/skyrod-vactai/kcats/tree/master/examples "examples") | | [examples](/skyrod-vactai/kcats/tree/master/examples "examples") | | | +| [Cargo.toml](/skyrod-vactai/kcats/blob/master/Cargo.toml "Cargo.toml") | | [Cargo.toml](/skyrod-vactai/kcats/blob/master/Cargo.toml "Cargo.toml") | | | +| [LICENSE-WTFPL](/skyrod-vactai/kcats/blob/master/LICENSE-WTFPL "LICENSE-WTFPL") | | [LICENSE-WTFPL](/skyrod-vactai/kcats/blob/master/LICENSE-WTFPL "LICENSE-WTFPL") | | | +| [README.md](/skyrod-vactai/kcats/blob/master/README.md "README.md") | | [README.md](/skyrod-vactai/kcats/blob/master/README.md "README.md") | | | +| [book-of-kcats.org](/skyrod-vactai/kcats/blob/master/book-of-kcats.org "book-of-kcats.org") | | [book-of-kcats.org](/skyrod-vactai/kcats/blob/master/book-of-kcats.org "book-of-kcats.org") | | | +| [build.rs](/skyrod-vactai/kcats/blob/master/build.rs "build.rs") | | [build.rs](/skyrod-vactai/kcats/blob/master/build.rs "build.rs") | | | +| [docs-custom.css](/skyrod-vactai/kcats/blob/master/docs-custom.css "docs-custom.css") | | [docs-custom.css](/skyrod-vactai/kcats/blob/master/docs-custom.css "docs-custom.css") | | | +| [emacs-ide.org](/skyrod-vactai/kcats/blob/master/emacs-ide.org "emacs-ide.org") | | [emacs-ide.org](/skyrod-vactai/kcats/blob/master/emacs-ide.org "emacs-ide.org") | | | +| [export.el](/skyrod-vactai/kcats/blob/master/export.el "export.el") | | [export.el](/skyrod-vactai/kcats/blob/master/export.el "export.el") | | | +| [kcats-repl.gif](/skyrod-vactai/kcats/blob/master/kcats-repl.gif "kcats-repl.gif") | | [kcats-repl.gif](/skyrod-vactai/kcats/blob/master/kcats-repl.gif "kcats-repl.gif") | | | +| [kcats.org](/skyrod-vactai/kcats/blob/master/kcats.org "kcats.org") | | [kcats.org](/skyrod-vactai/kcats/blob/master/kcats.org "kcats.org") | | | +| [kcats.png](/skyrod-vactai/kcats/blob/master/kcats.png "kcats.png") | | [kcats.png](/skyrod-vactai/kcats/blob/master/kcats.png "kcats.png") | | | +| [lexicon.org](/skyrod-vactai/kcats/blob/master/lexicon.org "lexicon.org") | | [lexicon.org](/skyrod-vactai/kcats/blob/master/lexicon.org "lexicon.org") | | | +| [lib-toolchain-env.sh](/skyrod-vactai/kcats/blob/master/lib-toolchain-env.sh "lib-toolchain-env.sh") | | [lib-toolchain-env.sh](/skyrod-vactai/kcats/blob/master/lib-toolchain-env.sh "lib-toolchain-env.sh") | | | +| [production.org\_archive](/skyrod-vactai/kcats/blob/master/production.org_archive "production.org_archive") | | [production.org\_archive](/skyrod-vactai/kcats/blob/master/production.org_archive "production.org_archive") | | | +| [scratch.org](/skyrod-vactai/kcats/blob/master/scratch.org "scratch.org") | | [scratch.org](/skyrod-vactai/kcats/blob/master/scratch.org "scratch.org") | | | +| [tangle.el](/skyrod-vactai/kcats/blob/master/tangle.el "tangle.el") | | [tangle.el](/skyrod-vactai/kcats/blob/master/tangle.el "tangle.el") | | | +| View all files | | | + +## Repository files navigation + +* [README](#) +* [WTFPL license](#) + +# The kcats Programming language + +[Get started!](https://skyrod-vactai.github.io/kcats/book-of-kcats.html) + +# Other Documentation + +* [Lexicon](https://skyrod-vactai.github.io/kcats/lexicon.html) +* [The Implementation](https://skyrod-vactai.github.io/kcats/production.html) + +# Contributing + +## Issue reporting + +Use github issues if that's easiest. + +Recommended: Instead of opening a github issue, create a fork and add a TODO subheading to the Issues heading in the respective `.org` file. You can edit org files right on github, in your own fork. + +* For bugs add issues here under Issues heading in production.org +* For documentation problems add issues here under Issues heading in book-of-kcats.org + +Then submit it as a pull request. + +To see the status, check your PR. It will have more commits by the developers added to it. + +## Other feedback + +Please do report design improvements you'd like to see - for example, inconsistencies in how words expect stack arguments to be, ways to make the standard library easier to work with, etc. + +## About + +A stack-based programming language based on Joy + +### Resources + +[Readme](#readme-ov-file) + +### License + +[WTFPL license](#WTFPL-1-ov-file) + +### Uh oh! + +There was an error while loading. Please reload this page. + +[Activity](/skyrod-vactai/kcats/activity) + +### Stars + +[**8** +stars](/skyrod-vactai/kcats/stargazers) + +### Watchers + +[**1** +watching](/skyrod-vactai/kcats/watchers) + +### Forks + +[**1** +fork](/skyrod-vactai/kcats/forks) + +[Report repository](/contact/report-content?content_url=https%3A%2F%2Fgithub.com%2Fskyrod-vactai%2Fkcats&report=skyrod-vactai+%28user%29) + +## [Releases 26](/skyrod-vactai/kcats/releases) + +[Release v1.0.0-6 + +Latest + +May 16, 2025](/skyrod-vactai/kcats/releases/tag/v1.0.0-6) + +[+ 25 releases](/skyrod-vactai/kcats/releases) + +## [Packages 0](/users/skyrod-vactai/packages?repo_name=kcats) + +No packages published + +### Uh oh! + +There was an error while loading. Please reload this page. + +## [Contributors 2](/skyrod-vactai/kcats/graphs/contributors) + +### Uh oh! + +There was an error while loading. Please reload this page. + +## Languages + +* [Rust + 76.4%](/skyrod-vactai/kcats/search?l=rust) +* [Emacs Lisp + 17.1%](/skyrod-vactai/kcats/search?l=emacs-lisp) +* [CSS + 4.0%](/skyrod-vactai/kcats/search?l=css) +* [Python + 1.6%](/skyrod-vactai/kcats/search?l=python) +* [Shell + 0.9%](/skyrod-vactai/kcats/search?l=shell) + +## Footer + +© 2026 GitHub, Inc. + +### Footer navigation + +* [Terms](https://docs.github.com/site-policy/github-terms/github-terms-of-service) +* [Privacy](https://docs.github.com/site-policy/privacy-policies/github-privacy-statement) +* [Security](https://github.com/security) +* [Status](https://www.githubstatus.com/) +* [Community](https://github.community/) +* [Docs](https://docs.github.com/) +* [Contact](https://support.github.com?tags=dotcom-footer) +* Manage cookies +* Do not share my personal information + + + +You can’t perform that action at this time. \ No newline at end of file diff --git a/references/ForthNotes/kitten.md b/references/ForthNotes/kitten.md new file mode 100644 index 0000000..f829d0b --- /dev/null +++ b/references/ForthNotes/kitten.md @@ -0,0 +1,68 @@ +# kitten + +**Source:** https://kittenlang.org + +Kitten Programming Language + +[Kitten](/) + +* [Introduction](/intro/) +* [FAQ](/faq/) +* [Source](https://github.com/evincarofautumn/kitten/) + +# Learn + +* [FAQ](/faq/) +* [Introduction](/intro/) +* [Tutorial](/tutorial/) +* [Documentation](/documentation/) + +# Contribute + +* [Source](https://github.com/evincarofautumn/kitten) +* [Issues](https://github.com/evincarofautumn/kitten/issues) +* [IRC](irc://freenode.net/#concatenative) + +# [The Kitten Programming Language](#the-kitten-programming-language) + +**Kitten** is a statically typed, stack-based functional programming language designed to be simple and fast. It is a *concatenative* language, combining aspects of imperative and pure functional programming. There is [an introduction](/intro/) available and a [tutorial](/tutorial/) in progress. + +## [Features](#features) + +Concatenative Programming +: A compositional style of programming to make refactoring easier and improve code reuse. + +Static Types +: Type inference based on Hindley–Milner to help improve correctness and performance. + +Permissions +: A system of effect types to control where side-effects are allowed. + +Deterministic Resource Management +: Automatic management of memory and resources with no garbage collector. + +## [Examples](#examples) + +### [Hello world](#hello-world) + +``` +"meow" say // Kittens don't speak English. +``` + +### [Hello user](#hello-user) + +``` +define greet (List -> +IO): + -> name; + ["Hello, ", name, "!"] concat say + +"What is your name? " ask +greet +``` + +### [Larger examples](#larger-examples) + +* [99 Bottles of Beer](https://github.com/evincarofautumn/kitten/blob/129d4bc7e5658a03cc765358ba0a1aba2dbf1c73/examples/beer.ktn) +* [Tic Tac Toe](https://github.com/evincarofautumn/kitten/blob/129d4bc7e5658a03cc765358ba0a1aba2dbf1c73/examples/tictactoe.ktn) + +The [source code](https://github.com/evincarofautumn/kitten) is hosted on GitHub, and you can join [#concatenative on Freenode](irc://freenode.net/#concatenative) to keep up with the latest developments. \ No newline at end of file diff --git a/references/ForthNotes/lbForth.md b/references/ForthNotes/lbForth.md new file mode 100644 index 0000000..27d23f0 --- /dev/null +++ b/references/ForthNotes/lbForth.md @@ -0,0 +1,433 @@ +# lbForth + +**Source:** https://github.com/larsbrinkhoff/lbForth + +GitHub - larsbrinkhoff/lbForth: Self-hosting metacompiled Forth, bootstrapping from a few lines of C; targets Linux, Windows, ARM, RISC-V, 68000, PDP-11, asm.js. + + + +[Skip to content](#start-of-content) + + + + + + + + + + + + + +## Navigation Menu + +Toggle navigation + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2Flarsbrinkhoff%2FlbForth) + +Appearance settings + +* Platform + + + AI CODE CREATION + - [GitHub CopilotWrite better code with AI](https://github.com/features/copilot) + - [GitHub SparkBuild and deploy intelligent apps](https://github.com/features/spark) + - [GitHub ModelsManage and compare prompts](https://github.com/features/models) + - [MCP RegistryNewIntegrate external tools](https://github.com/mcp) + + DEVELOPER WORKFLOWS + - [ActionsAutomate any workflow](https://github.com/features/actions) + - [CodespacesInstant dev environments](https://github.com/features/codespaces) + - [IssuesPlan and track work](https://github.com/features/issues) + - [Code ReviewManage code changes](https://github.com/features/code-review) + + APPLICATION SECURITY + - [GitHub Advanced SecurityFind and fix vulnerabilities](https://github.com/security/advanced-security) + - [Code securitySecure your code as you build](https://github.com/security/advanced-security/code-security) + - [Secret protectionStop leaks before they start](https://github.com/security/advanced-security/secret-protection) + + EXPLORE + - [Why GitHub](https://github.com/why-github) + - [Documentation](https://docs.github.com) + - [Blog](https://github.blog) + - [Changelog](https://github.blog/changelog) + - [Marketplace](https://github.com/marketplace) + + [View all features](https://github.com/features) +* Solutions + + + BY COMPANY SIZE + - [Enterprises](https://github.com/enterprise) + - [Small and medium teams](https://github.com/team) + - [Startups](https://github.com/enterprise/startups) + - [Nonprofits](https://github.com/solutions/industry/nonprofits) + + BY USE CASE + - [App Modernization](https://github.com/solutions/use-case/app-modernization) + - [DevSecOps](https://github.com/solutions/use-case/devsecops) + - [DevOps](https://github.com/solutions/use-case/devops) + - [CI/CD](https://github.com/solutions/use-case/ci-cd) + - [View all use cases](https://github.com/solutions/use-case) + + BY INDUSTRY + - [Healthcare](https://github.com/solutions/industry/healthcare) + - [Financial services](https://github.com/solutions/industry/financial-services) + - [Manufacturing](https://github.com/solutions/industry/manufacturing) + - [Government](https://github.com/solutions/industry/government) + - [View all industries](https://github.com/solutions/industry) + + [View all solutions](https://github.com/solutions) +* Resources + + + EXPLORE BY TOPIC + - [AI](https://github.com/resources/articles?topic=ai) + - [Software Development](https://github.com/resources/articles?topic=software-development) + - [DevOps](https://github.com/resources/articles?topic=devops) + - [Security](https://github.com/resources/articles?topic=security) + - [View all topics](https://github.com/resources/articles) + + EXPLORE BY TYPE + - [Customer stories](https://github.com/customer-stories) + - [Events & webinars](https://github.com/resources/events) + - [Ebooks & reports](https://github.com/resources/whitepapers) + - [Business insights](https://github.com/solutions/executive-insights) + - [GitHub Skills](https://skills.github.com) + + SUPPORT & SERVICES + - [Documentation](https://docs.github.com) + - [Customer support](https://support.github.com) + - [Community forum](https://github.com/orgs/community/discussions) + - [Trust center](https://github.com/trust-center) + - [Partners](https://github.com/partners) +* Open Source + + + COMMUNITY + - [GitHub SponsorsFund open source developers](https://github.com/sponsors) + + PROGRAMS + - [Security Lab](https://securitylab.github.com) + - [Maintainer Community](https://maintainers.github.com) + - [Accelerator](https://github.com/accelerator) + - [Archive Program](https://archiveprogram.github.com) + + REPOSITORIES + - [Topics](https://github.com/topics) + - [Trending](https://github.com/trending) + - [Collections](https://github.com/collections) +* Enterprise + + + ENTERPRISE SOLUTIONS + - [Enterprise platformAI-powered developer platform](https://github.com/enterprise) + + AVAILABLE ADD-ONS + - [GitHub Advanced SecurityEnterprise-grade security features](https://github.com/security/advanced-security) + - [Copilot for BusinessEnterprise-grade AI features](https://github.com/features/copilot/copilot-business) + - [Premium SupportEnterprise-grade 24/7 support](https://github.com/premium-support) +* [Pricing](https://github.com/pricing) + +Search or jump to... + + +# Search code, repositories, users, issues, pull requests... + +Search + +Clear + +[Search syntax tips](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax) + +# Provide feedback + +We read every piece of feedback, and take your input very seriously. + + +Include my email address so I can be contacted + +Cancel + Submit feedback + + + + + +# Saved searches + +## Use saved searches to filter your results more quickly + +Name + +Query + +To see all available qualifiers, see our [documentation](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax). + +Cancel + Create saved search + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2Flarsbrinkhoff%2FlbForth) + +[Sign up](/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E&source=header-repo&source_repo=larsbrinkhoff%2FlbForth) + +Appearance settings + +Resetting focus + +You signed in with another tab or window. Reload to refresh your session. +You signed out in another tab or window. Reload to refresh your session. +You switched accounts on another tab or window. Reload to refresh your session. + + + +Dismiss alert + +{{ message }} + +[larsbrinkhoff](/larsbrinkhoff) +/ +**[lbForth](/larsbrinkhoff/lbForth)** +Public + +* [Notifications](/login?return_to=%2Flarsbrinkhoff%2FlbForth) You must be signed in to change notification settings +* [Fork + 112](/login?return_to=%2Flarsbrinkhoff%2FlbForth) +* [Star + 475](/login?return_to=%2Flarsbrinkhoff%2FlbForth) + +Self-hosting metacompiled Forth, bootstrapping from a few lines of C; targets Linux, Windows, ARM, RISC-V, 68000, PDP-11, asm.js. + +### License + +[GPL-3.0 license](/larsbrinkhoff/lbForth/blob/master/LICENSE) + +[475 +stars](/larsbrinkhoff/lbForth/stargazers) [112 +forks](/larsbrinkhoff/lbForth/forks) [Branches](/larsbrinkhoff/lbForth/branches) [Tags](/larsbrinkhoff/lbForth/tags) [Activity](/larsbrinkhoff/lbForth/activity) + +[Star](/login?return_to=%2Flarsbrinkhoff%2FlbForth) + +[Notifications](/login?return_to=%2Flarsbrinkhoff%2FlbForth) You must be signed in to change notification settings + +* [Code](/larsbrinkhoff/lbForth) +* [Issues + 40](/larsbrinkhoff/lbForth/issues) +* [Pull requests + 1](/larsbrinkhoff/lbForth/pulls) +* [Actions](/larsbrinkhoff/lbForth/actions) +* [Projects + 0](/larsbrinkhoff/lbForth/projects) +* [Wiki](/larsbrinkhoff/lbForth/wiki) +* [Security + 0](/larsbrinkhoff/lbForth/security) +* [Insights](/larsbrinkhoff/lbForth/pulse) + +Additional navigation options + + +* [Code](/larsbrinkhoff/lbForth) +* [Issues](/larsbrinkhoff/lbForth/issues) +* [Pull requests](/larsbrinkhoff/lbForth/pulls) +* [Actions](/larsbrinkhoff/lbForth/actions) +* [Projects](/larsbrinkhoff/lbForth/projects) +* [Wiki](/larsbrinkhoff/lbForth/wiki) +* [Security](/larsbrinkhoff/lbForth/security) +* [Insights](/larsbrinkhoff/lbForth/pulse) + +# larsbrinkhoff/lbForth + +master + +[Branches](/larsbrinkhoff/lbForth/branches)[Tags](/larsbrinkhoff/lbForth/tags) + +Go to file + +Code + +Open more actions menu + +## Folders and files + +| Name | | Name | Last commit message | Last commit date | +| --- | --- | --- | --- | --- | +| Latest commit History[815 Commits](/larsbrinkhoff/lbForth/commits/master/) 815 Commits | | | +| [contrib](/larsbrinkhoff/lbForth/tree/master/contrib "contrib") | | [contrib](/larsbrinkhoff/lbForth/tree/master/contrib "contrib") | | | +| [doc](/larsbrinkhoff/lbForth/tree/master/doc "doc") | | [doc](/larsbrinkhoff/lbForth/tree/master/doc "doc") | | | +| [experiments](/larsbrinkhoff/lbForth/tree/master/experiments "experiments") | | [experiments](/larsbrinkhoff/lbForth/tree/master/experiments "experiments") | | | +| [lib](/larsbrinkhoff/lbForth/tree/master/lib "lib") | | [lib](/larsbrinkhoff/lbForth/tree/master/lib "lib") | | | +| [lisp @ 40b99c0](/larsbrinkhoff/forth-metacompiler/tree/40b99c09628f616d94649009ba9894340088d77c "lisp") | | [lisp @ 40b99c0](/larsbrinkhoff/forth-metacompiler/tree/40b99c09628f616d94649009ba9894340088d77c "lisp") | | | +| [src](/larsbrinkhoff/lbForth/tree/master/src "src") | | [src](/larsbrinkhoff/lbForth/tree/master/src "src") | | | +| [targets](/larsbrinkhoff/lbForth/tree/master/targets "targets") | | [targets](/larsbrinkhoff/lbForth/tree/master/targets "targets") | | | +| [test](/larsbrinkhoff/lbForth/tree/master/test "test") | | [test](/larsbrinkhoff/lbForth/tree/master/test "test") | | | +| [.gdbinit](/larsbrinkhoff/lbForth/blob/master/.gdbinit ".gdbinit") | | [.gdbinit](/larsbrinkhoff/lbForth/blob/master/.gdbinit ".gdbinit") | | | +| [.gitattributes](/larsbrinkhoff/lbForth/blob/master/.gitattributes ".gitattributes") | | [.gitattributes](/larsbrinkhoff/lbForth/blob/master/.gitattributes ".gitattributes") | | | +| [.gitignore](/larsbrinkhoff/lbForth/blob/master/.gitignore ".gitignore") | | [.gitignore](/larsbrinkhoff/lbForth/blob/master/.gitignore ".gitignore") | | | +| [.gitlab-ci.yml](/larsbrinkhoff/lbForth/blob/master/.gitlab-ci.yml ".gitlab-ci.yml") | | [.gitlab-ci.yml](/larsbrinkhoff/lbForth/blob/master/.gitlab-ci.yml ".gitlab-ci.yml") | | | +| [.gitmodules](/larsbrinkhoff/lbForth/blob/master/.gitmodules ".gitmodules") | | [.gitmodules](/larsbrinkhoff/lbForth/blob/master/.gitmodules ".gitmodules") | | | +| [.scrutinizer.yml](/larsbrinkhoff/lbForth/blob/master/.scrutinizer.yml ".scrutinizer.yml") | | [.scrutinizer.yml](/larsbrinkhoff/lbForth/blob/master/.scrutinizer.yml ".scrutinizer.yml") | | | +| [.travis.yml](/larsbrinkhoff/lbForth/blob/master/.travis.yml ".travis.yml") | | [.travis.yml](/larsbrinkhoff/lbForth/blob/master/.travis.yml ".travis.yml") | | | +| [INSTALL](/larsbrinkhoff/lbForth/blob/master/INSTALL "INSTALL") | | [INSTALL](/larsbrinkhoff/lbForth/blob/master/INSTALL "INSTALL") | | | +| [LICENSE](/larsbrinkhoff/lbForth/blob/master/LICENSE "LICENSE") | | [LICENSE](/larsbrinkhoff/lbForth/blob/master/LICENSE "LICENSE") | | | +| [Makefile](/larsbrinkhoff/lbForth/blob/master/Makefile "Makefile") | | [Makefile](/larsbrinkhoff/lbForth/blob/master/Makefile "Makefile") | | | +| [PITCHME.md](/larsbrinkhoff/lbForth/blob/master/PITCHME.md "PITCHME.md") | | [PITCHME.md](/larsbrinkhoff/lbForth/blob/master/PITCHME.md "PITCHME.md") | | | +| [README.md](/larsbrinkhoff/lbForth/blob/master/README.md "README.md") | | [README.md](/larsbrinkhoff/lbForth/blob/master/README.md "README.md") | | | +| [appharbor.sln](/larsbrinkhoff/lbForth/blob/master/appharbor.sln "appharbor.sln") | | [appharbor.sln](/larsbrinkhoff/lbForth/blob/master/appharbor.sln "appharbor.sln") | | | +| [appveyor.yml](/larsbrinkhoff/lbForth/blob/master/appveyor.yml "appveyor.yml") | | [appveyor.yml](/larsbrinkhoff/lbForth/blob/master/appveyor.yml "appveyor.yml") | | | +| [bitrise.yml](/larsbrinkhoff/lbForth/blob/master/bitrise.yml "bitrise.yml") | | [bitrise.yml](/larsbrinkhoff/lbForth/blob/master/bitrise.yml "bitrise.yml") | | | +| [build.md](/larsbrinkhoff/lbForth/blob/master/build.md "build.md") | | [build.md](/larsbrinkhoff/lbForth/blob/master/build.md "build.md") | | | +| [build.vcxproj](/larsbrinkhoff/lbForth/blob/master/build.vcxproj "build.vcxproj") | | [build.vcxproj](/larsbrinkhoff/lbForth/blob/master/build.vcxproj "build.vcxproj") | | | +| [circle.yml](/larsbrinkhoff/lbForth/blob/master/circle.yml "circle.yml") | | [circle.yml](/larsbrinkhoff/lbForth/blob/master/circle.yml "circle.yml") | | | +| [configure](/larsbrinkhoff/lbForth/blob/master/configure "configure") | | [configure](/larsbrinkhoff/lbForth/blob/master/configure "configure") | | | +| [packages.config](/larsbrinkhoff/lbForth/blob/master/packages.config "packages.config") | | [packages.config](/larsbrinkhoff/lbForth/blob/master/packages.config "packages.config") | | | +| View all files | | | + +## Repository files navigation + +* [README](#) +* [GPL-3.0 license](#) + +( Subset of Forth94 ) + +This is a self-hosted implementation of Forth, which can regenerate +itself from Forth source code. The bootstrapping process uses a +[metacompiler written in Lisp](https://github.com/larsbrinkhoff/forth-metacompiler) to target a +small inner interpreter and a handful of code words written in C. A +new [metacompiler written in Forth](/larsbrinkhoff/lbForth/blob/master/lib/meta.fth) generates an x86 +executable using using [assembly language code words](/larsbrinkhoff/lbForth/blob/master/targets/x86/nucleus.fth). + +There are also ARM, RISC-V, Motorola 68000, PDP-11, and asm.js +targets. There is a [cross +compiler](http://github.com/larsbrinkhoff/xForth) for 6502, 8051, AVR, +Cortex-M, MSP430, PDP-8, PIC, and STM8. + +( Continuous integration ) + +The code is continuously built and tested in Linux, MacOS X, and +Windows using several cloud-based continuous integration services. +This is documented in [build.md](/larsbrinkhoff/lbForth/blob/master/build.md). + +( Further reading ) + +[INSTALL](/larsbrinkhoff/lbForth/blob/master/INSTALL) \ How to build. +[doc](/larsbrinkhoff/lbForth/blob/master/doc) \ Classic (and recent) texts not related to this project. +[lib/README](/larsbrinkhoff/lbForth/blob/master/lib/README) \ Information about libraries. +[targets/README.md](/larsbrinkhoff/lbForth/blob/master/targets/README.md) \ Information about current and possibly future targets. + +( Implementation guide ) + +The Forth kernel contains everything needed to read and compile the +rest of the system from source code, and not much else. It's composed +of two parts: a target-specific file nucleus.fth containing all +primitive CODE words, and a [target-independent +kernel.fth](/larsbrinkhoff/lbForth/blob/master/src/kernel.fth). These two are compiled by the +metacompiler. + +The [C target nucleus](/larsbrinkhoff/lbForth/blob/master/targets/c/nucleus.fth) used for bootstrapping +has only twelve proper primitives. There is also the COLD word which +compiles to main(), and four I/O words. + +When the kernel starts, it jumps to the word called WARM. This is +responsible for loading the rest of the system and entering the text +interpreter. The first file loaded by WARM is [core.fth](/larsbrinkhoff/lbForth/blob/master/src/core.fth), +which implements the CORE wordset. Because the kernel only has a bare +minimum of words, the start of core.fth looks a little strange. + +## About + +Self-hosting metacompiled Forth, bootstrapping from a few lines of C; targets Linux, Windows, ARM, RISC-V, 68000, PDP-11, asm.js. + +### Topics + +[linux](/topics/linux "Topic: linux") +[programming-language](/topics/programming-language "Topic: programming-language") +[avr](/topics/avr "Topic: avr") +[arm](/topics/arm "Topic: arm") +[interpreter](/topics/interpreter "Topic: interpreter") +[cortex-m](/topics/cortex-m "Topic: cortex-m") +[compiler](/topics/compiler "Topic: compiler") +[self-hosted](/topics/self-hosted "Topic: self-hosted") +[riscv](/topics/riscv "Topic: riscv") +[forth](/topics/forth "Topic: forth") +[x86](/topics/x86 "Topic: x86") +[msp430](/topics/msp430 "Topic: msp430") +[pdp11](/topics/pdp11 "Topic: pdp11") +[metacompiler](/topics/metacompiler "Topic: metacompiler") +[m68k](/topics/m68k "Topic: m68k") +[asmjs](/topics/asmjs "Topic: asmjs") +[6502](/topics/6502 "Topic: 6502") +[risc-v](/topics/risc-v "Topic: risc-v") +[8051](/topics/8051 "Topic: 8051") + +### Resources + +[Readme](#readme-ov-file) + +### License + +[GPL-3.0 license](#GPL-3.0-1-ov-file) + +### Uh oh! + +There was an error while loading. Please reload this page. + +[Activity](/larsbrinkhoff/lbForth/activity) + +### Stars + +[**475** +stars](/larsbrinkhoff/lbForth/stargazers) + +### Watchers + +[**29** +watching](/larsbrinkhoff/lbForth/watchers) + +### Forks + +[**112** +forks](/larsbrinkhoff/lbForth/forks) + +[Report repository](/contact/report-content?content_url=https%3A%2F%2Fgithub.com%2Flarsbrinkhoff%2FlbForth&report=larsbrinkhoff+%28user%29) + +## [Releases](/larsbrinkhoff/lbForth/releases) + +No releases published + +## [Packages 0](/users/larsbrinkhoff/packages?repo_name=lbForth) + +No packages published + +### Uh oh! + +There was an error while loading. Please reload this page. + +## [Contributors 4](/larsbrinkhoff/lbForth/graphs/contributors) + +### Uh oh! + +There was an error while loading. Please reload this page. + +## Languages + +* [Forth + 96.7%](/larsbrinkhoff/lbForth/search?l=forth) +* [Makefile + 1.0%](/larsbrinkhoff/lbForth/search?l=makefile) +* [Emacs Lisp + 0.8%](/larsbrinkhoff/lbForth/search?l=emacs-lisp) +* [Shell + 0.7%](/larsbrinkhoff/lbForth/search?l=shell) +* [C + 0.4%](/larsbrinkhoff/lbForth/search?l=c) +* [HTML + 0.2%](/larsbrinkhoff/lbForth/search?l=html) +* Other + 0.2% + +## Footer + +© 2026 GitHub, Inc. + +### Footer navigation + +* [Terms](https://docs.github.com/site-policy/github-terms/github-terms-of-service) +* [Privacy](https://docs.github.com/site-policy/privacy-policies/github-privacy-statement) +* [Security](https://github.com/security) +* [Status](https://www.githubstatus.com/) +* [Community](https://github.community/) +* [Docs](https://docs.github.com/) +* [Contact](https://support.github.com?tags=dotcom-footer) +* Manage cookies +* Do not share my personal information + + + +You can’t perform that action at this time. \ No newline at end of file diff --git a/references/ForthNotes/libforth.md b/references/ForthNotes/libforth.md new file mode 100644 index 0000000..e865f5a --- /dev/null +++ b/references/ForthNotes/libforth.md @@ -0,0 +1,2031 @@ +# libforth + +**Source:** https://github.com/howerj/libforth + +GitHub - howerj/libforth: libforth: A small Forth interpreter that can be used as a library written in c99 + + + +[Skip to content](#start-of-content) + + + + + + + + + + + + + +## Navigation Menu + +Toggle navigation + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2Fhowerj%2Flibforth) + +Appearance settings + +* Platform + + + AI CODE CREATION + - [GitHub CopilotWrite better code with AI](https://github.com/features/copilot) + - [GitHub SparkBuild and deploy intelligent apps](https://github.com/features/spark) + - [GitHub ModelsManage and compare prompts](https://github.com/features/models) + - [MCP RegistryNewIntegrate external tools](https://github.com/mcp) + + DEVELOPER WORKFLOWS + - [ActionsAutomate any workflow](https://github.com/features/actions) + - [CodespacesInstant dev environments](https://github.com/features/codespaces) + - [IssuesPlan and track work](https://github.com/features/issues) + - [Code ReviewManage code changes](https://github.com/features/code-review) + + APPLICATION SECURITY + - [GitHub Advanced SecurityFind and fix vulnerabilities](https://github.com/security/advanced-security) + - [Code securitySecure your code as you build](https://github.com/security/advanced-security/code-security) + - [Secret protectionStop leaks before they start](https://github.com/security/advanced-security/secret-protection) + + EXPLORE + - [Why GitHub](https://github.com/why-github) + - [Documentation](https://docs.github.com) + - [Blog](https://github.blog) + - [Changelog](https://github.blog/changelog) + - [Marketplace](https://github.com/marketplace) + + [View all features](https://github.com/features) +* Solutions + + + BY COMPANY SIZE + - [Enterprises](https://github.com/enterprise) + - [Small and medium teams](https://github.com/team) + - [Startups](https://github.com/enterprise/startups) + - [Nonprofits](https://github.com/solutions/industry/nonprofits) + + BY USE CASE + - [App Modernization](https://github.com/solutions/use-case/app-modernization) + - [DevSecOps](https://github.com/solutions/use-case/devsecops) + - [DevOps](https://github.com/solutions/use-case/devops) + - [CI/CD](https://github.com/solutions/use-case/ci-cd) + - [View all use cases](https://github.com/solutions/use-case) + + BY INDUSTRY + - [Healthcare](https://github.com/solutions/industry/healthcare) + - [Financial services](https://github.com/solutions/industry/financial-services) + - [Manufacturing](https://github.com/solutions/industry/manufacturing) + - [Government](https://github.com/solutions/industry/government) + - [View all industries](https://github.com/solutions/industry) + + [View all solutions](https://github.com/solutions) +* Resources + + + EXPLORE BY TOPIC + - [AI](https://github.com/resources/articles?topic=ai) + - [Software Development](https://github.com/resources/articles?topic=software-development) + - [DevOps](https://github.com/resources/articles?topic=devops) + - [Security](https://github.com/resources/articles?topic=security) + - [View all topics](https://github.com/resources/articles) + + EXPLORE BY TYPE + - [Customer stories](https://github.com/customer-stories) + - [Events & webinars](https://github.com/resources/events) + - [Ebooks & reports](https://github.com/resources/whitepapers) + - [Business insights](https://github.com/solutions/executive-insights) + - [GitHub Skills](https://skills.github.com) + + SUPPORT & SERVICES + - [Documentation](https://docs.github.com) + - [Customer support](https://support.github.com) + - [Community forum](https://github.com/orgs/community/discussions) + - [Trust center](https://github.com/trust-center) + - [Partners](https://github.com/partners) +* Open Source + + + COMMUNITY + - [GitHub SponsorsFund open source developers](https://github.com/sponsors) + + PROGRAMS + - [Security Lab](https://securitylab.github.com) + - [Maintainer Community](https://maintainers.github.com) + - [Accelerator](https://github.com/accelerator) + - [Archive Program](https://archiveprogram.github.com) + + REPOSITORIES + - [Topics](https://github.com/topics) + - [Trending](https://github.com/trending) + - [Collections](https://github.com/collections) +* Enterprise + + + ENTERPRISE SOLUTIONS + - [Enterprise platformAI-powered developer platform](https://github.com/enterprise) + + AVAILABLE ADD-ONS + - [GitHub Advanced SecurityEnterprise-grade security features](https://github.com/security/advanced-security) + - [Copilot for BusinessEnterprise-grade AI features](https://github.com/features/copilot/copilot-business) + - [Premium SupportEnterprise-grade 24/7 support](https://github.com/premium-support) +* [Pricing](https://github.com/pricing) + +Search or jump to... + + +# Search code, repositories, users, issues, pull requests... + +Search + +Clear + +[Search syntax tips](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax) + +# Provide feedback + +We read every piece of feedback, and take your input very seriously. + + +Include my email address so I can be contacted + +Cancel + Submit feedback + + + + + +# Saved searches + +## Use saved searches to filter your results more quickly + +Name + +Query + +To see all available qualifiers, see our [documentation](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax). + +Cancel + Create saved search + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2Fhowerj%2Flibforth) + +[Sign up](/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E&source=header-repo&source_repo=howerj%2Flibforth) + +Appearance settings + +Resetting focus + +You signed in with another tab or window. Reload to refresh your session. +You signed out in another tab or window. Reload to refresh your session. +You switched accounts on another tab or window. Reload to refresh your session. + + + +Dismiss alert + +{{ message }} + +[howerj](/howerj) +/ +**[libforth](/howerj/libforth)** +Public + +* [Notifications](/login?return_to=%2Fhowerj%2Flibforth) You must be signed in to change notification settings +* [Fork + 31](/login?return_to=%2Fhowerj%2Flibforth) +* [Star + 200](/login?return_to=%2Fhowerj%2Flibforth) + +libforth: A small Forth interpreter that can be used as a library written in c99 + +### License + +[MIT license](/howerj/libforth/blob/master/LICENSE) + +[200 +stars](/howerj/libforth/stargazers) [31 +forks](/howerj/libforth/forks) [Branches](/howerj/libforth/branches) [Tags](/howerj/libforth/tags) [Activity](/howerj/libforth/activity) + +[Star](/login?return_to=%2Fhowerj%2Flibforth) + +[Notifications](/login?return_to=%2Fhowerj%2Flibforth) You must be signed in to change notification settings + +* [Code](/howerj/libforth) +* [Issues + 0](/howerj/libforth/issues) +* [Pull requests + 0](/howerj/libforth/pulls) +* [Actions](/howerj/libforth/actions) +* [Projects + 0](/howerj/libforth/projects) +* [Wiki](/howerj/libforth/wiki) +* [Security + 0](/howerj/libforth/security) +* [Insights](/howerj/libforth/pulse) + +Additional navigation options + + +* [Code](/howerj/libforth) +* [Issues](/howerj/libforth/issues) +* [Pull requests](/howerj/libforth/pulls) +* [Actions](/howerj/libforth/actions) +* [Projects](/howerj/libforth/projects) +* [Wiki](/howerj/libforth/wiki) +* [Security](/howerj/libforth/security) +* [Insights](/howerj/libforth/pulse) + +# howerj/libforth + +master + +[Branches](/howerj/libforth/branches)[Tags](/howerj/libforth/tags) + +Go to file + +Code + +Open more actions menu + +## Folders and files + +| Name | | Name | Last commit message | Last commit date | +| --- | --- | --- | --- | --- | +| Latest commit History[350 Commits](/howerj/libforth/commits/master/) 350 Commits | | | +| [fth](/howerj/libforth/tree/master/fth "fth") | | [fth](/howerj/libforth/tree/master/fth "fth") | | | +| [libline @ 465e8a5](/howerj/libline/tree/465e8a59a0bfbef625d44ba250cccc60e8fea3be "libline") | | [libline @ 465e8a5](/howerj/libline/tree/465e8a59a0bfbef625d44ba250cccc60e8fea3be "libline") | | | +| [.gitignore](/howerj/libforth/blob/master/.gitignore ".gitignore") | | [.gitignore](/howerj/libforth/blob/master/.gitignore ".gitignore") | | | +| [.gitmodules](/howerj/libforth/blob/master/.gitmodules ".gitmodules") | | [.gitmodules](/howerj/libforth/blob/master/.gitmodules ".gitmodules") | | | +| [.travis.yml](/howerj/libforth/blob/master/.travis.yml ".travis.yml") | | [.travis.yml](/howerj/libforth/blob/master/.travis.yml ".travis.yml") | | | +| [LICENSE](/howerj/libforth/blob/master/LICENSE "LICENSE") | | [LICENSE](/howerj/libforth/blob/master/LICENSE "LICENSE") | | | +| [convert](/howerj/libforth/blob/master/convert "convert") | | [convert](/howerj/libforth/blob/master/convert "convert") | | | +| [dpans94.txt](/howerj/libforth/blob/master/dpans94.txt "dpans94.txt") | | [dpans94.txt](/howerj/libforth/blob/master/dpans94.txt "dpans94.txt") | | | +| [editor.fth](/howerj/libforth/blob/master/editor.fth "editor.fth") | | [editor.fth](/howerj/libforth/blob/master/editor.fth "editor.fth") | | | +| [forth.fth](/howerj/libforth/blob/master/forth.fth "forth.fth") | | [forth.fth](/howerj/libforth/blob/master/forth.fth "forth.fth") | | | +| [length](/howerj/libforth/blob/master/length "length") | | [length](/howerj/libforth/blob/master/length "length") | | | +| [libforth.c](/howerj/libforth/blob/master/libforth.c "libforth.c") | | [libforth.c](/howerj/libforth/blob/master/libforth.c "libforth.c") | | | +| [libforth.h](/howerj/libforth/blob/master/libforth.h "libforth.h") | | [libforth.h](/howerj/libforth/blob/master/libforth.h "libforth.h") | | | +| [main.c](/howerj/libforth/blob/master/main.c "main.c") | | [main.c](/howerj/libforth/blob/master/main.c "main.c") | | | +| [makefile](/howerj/libforth/blob/master/makefile "makefile") | | [makefile](/howerj/libforth/blob/master/makefile "makefile") | | | +| [readme.md](/howerj/libforth/blob/master/readme.md "readme.md") | | [readme.md](/howerj/libforth/blob/master/readme.md "readme.md") | | | +| [unit.c](/howerj/libforth/blob/master/unit.c "unit.c") | | [unit.c](/howerj/libforth/blob/master/unit.c "unit.c") | | | +| [unit.fth](/howerj/libforth/blob/master/unit.fth "unit.fth") | | [unit.fth](/howerj/libforth/blob/master/unit.fth "unit.fth") | | | +| [unit.h](/howerj/libforth/blob/master/unit.h "unit.h") | | [unit.h](/howerj/libforth/blob/master/unit.h "unit.h") | | | +| View all files | | | + +## Repository files navigation + +* [README](#) +* [MIT license](#) + +% FORTH(1) +% Richard Howe +% November 2016 + +# NAME + +forth - a forth interpreter + +# SYNOPSIS + +**forth** [**-s** file] [**-e** string] [**-l** file] [**-m** size] [**-VthvLSnx**] [**-**] [**files**] + +# DESCRIPTION + +A Forth interpreter built around a library, libforth, that implements a +complete Forth interpreter. + +For a much better, albeit 16-bit only, Forth that is also very well documented +and (slightly more) standards compliant, please visit the more up to date +[Embed](https://github.com/howerj/embed) virtual machine. Also of interest is +the [Forth CPU](https://github.com/howerj/forth-cpu) I wrote, in VHDL, for an +FPGA. + +This interpreter is available at [here](https://github.com/howerj/libforth). + +[![Libforth build status](https://camo.githubusercontent.com/2fc05cd9c4e36dbe5aafa595c13716d1ef247c3965e6ecfc83e4811e0a604359/68747470733a2f2f7472617669732d63692e6f72672f686f7765726a2f6c6962666f7274682e7376673f6272616e63683d6d6173746572 "Build Status")](https://camo.githubusercontent.com/2fc05cd9c4e36dbe5aafa595c13716d1ef247c3965e6ecfc83e4811e0a604359/68747470733a2f2f7472617669732d63692e6f72672f686f7765726a2f6c6962666f7274682e7376673f6272616e63683d6d6173746572) + +# OPTIONS + +Command line switches must be given before any files, unless that switch takes +a file as an argument. + +* -s file + +This saves the working memory of the Forth interpreter to a file, +which can later be loaded with the "-l" option. If a core file has been +invalidated this will not be saved, invalidation occurs when an unrecoverable +error has been detected that would prevent any recovery or meaningful +execution with the current image. + +* -e string + +Evaluate a Forth string passed in as an argument. + +* -t + +After all the files have been read from and any core files have been loaded +this will make the Forth interpreter read from [stdin](https://en.wikipedia.org/wiki/Standard_streams), the core file will be +saved after [stdin](https://en.wikipedia.org/wiki/Standard_streams) has been read from and there is no more work to do, if +the "-d" or "-s" flags have been specified. + +* -h + +Print out a short help message and exit unsuccessfully. + +* -v + +Turn verbose mode on, more information will be printed out, to [stderr](https://en.wikipedia.org/wiki/Standard_streams), about +what is happening in the interpreter. Usually the interpreter is as silent as +possible. + +* -m size + +Specify the virtual machines memory size in kilobytes, overriding the default +memory size. This is mutually exclusive with "-l". + +* -l file + +This option loads a forth core file generated from the "-d" option of a +previous run. This core file is not portable and must be generated on the same +platform as it was generated. It can only be specified once per run of the +interpreter. + +* -L + +The same as "-l", however the default core file name is used, "forth.core", so +an argument does not have to be provided. + +* -S + +The same as "-s", however the default core file name is used, "forth.core", so +an argument does not have to be provided. + +* '-' + +Stop processing any more command line options and treat all arguments after +this as files to be executed, if there are any. + +* -V + +Print version and interpreter information and exit successfully. + +* -f file + +Process a file immediately. This allows options and file arguments to be +intermingled. + +* -n + +If the line editing library is compiled into the executable, which is a compile +time option, then when reading from [stdin](https://en.wikipedia.org/wiki/Standard_streams) this will use a [line editor](https://github.com/howerj/libline) +to read in a line at a time. This option implies *-t*. + +* -x + +Enable signal handling, signal handling is experimental and not quite worked +out yet. It is off by default as I find it annoying when programs catch signals +when you really want to program to *die*. This cannot be enabled from within +the Forth interpreter. This option should disappear once signal handling has +been sorted out. + +* file... + +If a file, or list of files, is given, read from them one after another +and execute them. The dictionary and any stored Forth blocks will persist, as +will values on the stack. + +If no files are given to execute [stdin](https://en.wikipedia.org/wiki/Standard_streams) will be read from. + +## EXAMPLES + +``` +./forth +``` + +Execute any commands given from [stdin](https://en.wikipedia.org/wiki/Standard_streams) + +``` +./forth -t file1.4th file2.4th +``` + +Execute file "file1.4th", then "file2.4th", then read from [stdin](https://en.wikipedia.org/wiki/Standard_streams) + +``` +./forth file1.4th +``` + +Execute file "file1.4th". + +``` +./forth -s file1.4th +``` + +Execute file "file1.4th", the produce a "forth.core" save file. + +``` +./forth -s -l forth.core +``` + +Load a "forth.core" file, read from [stdin](https://en.wikipedia.org/wiki/Standard_streams) and execute any commands given, +then dump the new core file to "forth.core". + +The interpreter returns zero on success and non zero on failure. + +# LICENSE + +The Forth interpreter and the library that implements it are released under the +[MIT](https://opensource.org/licenses/MIT) license. Copyright (c) Richard Howe, 2016. + +# EXIT STATUS + +This program will return a non-zero value on failure, and zero on success. + +# SEE ALSO + +libforth(3) + +# BUGS + +If you find a bug, or would like to request a new feature, please Email me at: + +``` + howe.r.j.89 [ at ] gmail . com +``` + +The interpreter has not been battle hardened yet so there is likely behavior +that is non-standard (for no reason) or just outright incorrect. + +# MANUAL + +This small [Forth](https://en.wikipedia.org/wiki/Forth_%28programming_language%29) interpreter is based on a de-obfuscated entrant +into the [IOCCC](http://ioccc.org/winners.html) by *buzzard*. The entry described a [Forth](https://en.wikipedia.org/wiki/Forth_%28programming_language%29) +like language which this derives from. You can use this library to +evaluate [Forth](https://en.wikipedia.org/wiki/Forth_%28programming_language%29) strings or as an embeddable interpreter. Work +would need to be done to get useful information after doing those +evaluations, but the library works quite well. + +*main.c* is simply a wrapper around one the functions that implements +a simple [REPL](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop). + +This project implements a [Forth](https://en.wikipedia.org/wiki/Forth_%28programming_language%29) interpreter library which can be embedded +in other projects, it is incredibly minimalistic, but usable. To build the +project a [C](https://en.wikipedia.org/wiki/C_%28programming_language%29) compiler is needed, and a copy of [Make](https://en.wikipedia.org/wiki/Make_%28software%29), type: + +``` +make help +``` + +For a list of build options. By running: + +``` +make run +``` + +Will build the interpreter and run it, it will then read from [stdin](https://en.wikipedia.org/wiki/Standard_streams). + +To build the documentation other programs may be needed, such as [pandoc](http://pandoc.org/) and +the [markdown script](https://daringfireball.net/projects/markdown/), but these steps are optional. + +[Forth](https://en.wikipedia.org/wiki/Forth_%28programming_language%29) is an odd language that has a loyal following groups, but it +is admittedly not the most practical of language as it lacks nearly everything +the modern programmer wants in a language; safety, garbage collection, +modularity and clarity. It is however possible to implement a fully working +interpreter in a one to two kilobytes of assembly, those kilobytes can make a +functional and interactive programming environment, giving a high ratio of utility +memory used. + +From the [Wikipedia](https://en.wikipedia.org/wiki/Forth_%28programming_language%29) article we can neatly summarize the language: + +``` + "Forth is an imperative stack-based computer programming language + and programming environment. + + Language features include structured programming, reflection (the + ability to modify the program structure during program execution), + concatenative programming (functions are composed with juxtaposition) + and extensibility (the programmer can create new commands). + + ... + + A procedural programming language without type checking, Forth features + both interactive execution of commands (making it suitable as a shell + for systems that lack a more formal operating system) and the ability + to compile sequences of commands for later execution." +``` + +Given the nature of the [Forth](https://en.wikipedia.org/wiki/Forth_%28programming_language%29) language it does not make for a terribly good +embeddable scripting language, but it is simple to implement and can be fun +to use. This interpreter is based off a previous [IOCCC](http://ioccc.org/winners.html) in a file called +[buzzard.2.c](http://www.ioccc.org/1992/buzzard.2.c), it is a descendant of that file. + +Before using and understanding this library/interpreter it is useful to checkout +more literature on [Forth](https://en.wikipedia.org/wiki/Forth_%28programming_language%29) such as [Thinking Forth](http://thinking-forth.sourceforge.net/) by Leo Brodie for a +philosophy of the language, [Starting Forth](http://www.forth.com/starting-forth/) (same Author), [Jonesforth](https://rwmj.wordpress.com/2010/08/07/jonesforth-git-repository/) +which is a specific implementation of the language in x86 assembly and +[Gforth](https://www.gnu.org/software/gforth/), a more modern and portable implementation of the language. + +It is important to realize that [Forth](https://en.wikipedia.org/wiki/Forth_%28programming_language%29) is really more a philosophy and +collection of ideas than a specific reference implementation or standard. +It has been said that an intermediate [Forth](https://en.wikipedia.org/wiki/Forth_%28programming_language%29) user is one who has implemented +a [Forth](https://en.wikipedia.org/wiki/Forth_%28programming_language%29) interpreter, something which cannot be said about other languages +nor is possible given their complexity. + +The saying "if you have seen one Forth implementation, you have seen one Forth +implementation" applies, nearly every single [Forth](https://en.wikipedia.org/wiki/Forth_%28programming_language%29) implementation has its +own idea of how to go about things despite standardization efforts - in keeping +with this, this library has its own idiosyncrasies. + +This implementation, written in [C](https://en.wikipedia.org/wiki/C_%28programming_language%29), can be thought of as a hybrid between a +fairly dumb stack based virtual machine with instructions such as "pop two +values off the stack, add them, and push the result" and a small +interpreter/compiler for the virtual machine. This simple kernel is then used +to build a more compliant and usable [Forth](https://en.wikipedia.org/wiki/Forth_%28programming_language%29) implementation by defining +words that build upon those provided by the base system. + +## Other documentation + +Apart from this file there are other sources of information about the +project: + +As can the code, which is small enough to be comprehensible: + +* [libforth.c](/howerj/libforth/blob/master/libforth.c) (contains the core interpreter) +* [libforth.h](/howerj/libforth/blob/master/libforth.h) (contains the API documentation) + +And the forth startup code: + +* [forth.fth](/howerj/libforth/blob/master/forth.fth) + +The startup code is well commented and shows how the core interpreter is +extended to a more function [Forth](https://en.wikipedia.org/wiki/Forth_%28programming_language%29) environment. + +The source file [libforth.c](/howerj/libforth/blob/master/libforth.c) can be converted to a more readable webpage by +first converting the source to [markdown](https://daringfireball.net/projects/markdown/) with [convert](/howerj/libforth/blob/master/convert) script, the converting +that to HTML in the usual fashion + +## Using the interpreter + +*main.c* simple calls the function *main\_forth()* in *libforth.c*, this function +initializes a [Forth](https://en.wikipedia.org/wiki/Forth_%28programming_language%29) environment and puts the user in a [REPL](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop) where you +can issue commands and define words. See the manual pages for list of command +line options and library calls. All commands are given using +[Reverse Polish Notation](https://en.wikipedia.org/wiki/Reverse_Polish_notation) (or RPN), + +So: + +``` + 2+(2*4) +``` + +Becomes: + +``` + 4 2 * 2 + +``` + +And brackets are no longer needed. Numbers of pushed on to the variable +stack automatically and commands (such as '\*' and '+') take their operands +off the stack and push the result. Juggling variables on the stack becomes +easier over time. To pop a value from the stack and print it there is the +'.' word. + +So: + +``` + 2 2 + . +``` + +Prints: + +``` + 4 +``` + +The simplicity of the language allows for a small interpreter, the +loop looks something like this: + +``` + 1) Read in a space delimited Forth WORD. + 2) Is this WORD in the dictionary? + FOUND) Are we in IMMEDIATE mode? + IMMEDIATE-MODE) Execute WORD. + goto 1; + COMPILE-MODE) Compile WORD into the dictionary. + goto 1; + NOT-FOUND) Is this actually a number? + YES) Are we in IMMEDIATE mode? + IMMEDIATE-MODE) Push Number onto the stack. + goto 1; + COMPILE-MODE) Compile a literal number. + goto 1; + NO) Error! Handle error + goto 1; +``` + +Given that we are reading in *space delimited words* if follows that the +above expression: + +``` + 2 2 + . +``` + +Would not work if we did: + +``` + 2 2+ . +``` + +Or: + +``` + 2 2 +. +``` + +As "2+" and "+." would be parsed as words, which may or may not be defined +and if they are do not have the behavior that we want. This is more apparent +when we do any kind of string handling. + +## A Forth Word + +The Forth execution model uses [Threaded Code](https://en.wikipedia.org/wiki/Threaded_code), the layout of a word +header follows from this. + +A [Forth](https://en.wikipedia.org/wiki/Forth_%28programming_language%29) word is defined in the dictionary and has a particular format that +varies between implementations. A dictionary is simply a linked list of +[Forth](https://en.wikipedia.org/wiki/Forth_%28programming_language%29) words, the dictionary is usually contiguous and can only grow. The +format for our [Forth](https://en.wikipedia.org/wiki/Forth_%28programming_language%29) words is as follows: + +Briefly: + +* Word Header: +* field <0 = Word Name (the name is stored before the main header) +* field 0 = Previous Word +* field 1 = Code Word (bits 0 - 7) | Hidden Flag (bit 8) | Word Name Offset (bit 9 - 14) | Compiling bit (bit 15) +* field 2+ = Data field (if it exists). + +And in more detail: + +``` + .----------------------------------------. + | Word Header | Word Body | + .---------------.-----.------.-----------. + | NAME ... | PWD | MISC | DATA ... | + .---------------.-----.------.-----------. + + ____ + NAME = The name, or the textual representation, of a Forth + word, it is a variable length field that is ASCII NUL + terminated, the MISC field has an offset that points + to the begining of this field if taken off the PWD + position (not value). The offset is in machine words, + not characters. + ___ + PWD = A pointer to the previously declared word. + ____ + MISC = A complex field that can contains a CODE WORD, a + "hide" bit and the offset from the PWD field to the + beginning of NAME, as well as the compiling bit. + ____ + DATA = This could be anything, but it is most likely to be + a list of pointers to CODE WORDs of previously defined + words if this optional DATA field is present. +``` + +All fields are aligned on the [Forth](https://en.wikipedia.org/wiki/Forth_%28programming_language%29) virtual machines word boundaries. + +The MISC field is laid out as so: + +``` + .-------------------------------------------------------------------------------. + | <- Least Significant Bit Most Significant Bit -> | + .-------------------------------------------------------------------------------. + | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | + .-------------------------------------------------------------------------------. + | CODE WORD | HD | NAME OFFSET | CB | + .-------------------------------------------------------------------------------. + _________ + CODE WORD = Bits 0-6 are a code word, this code word is always run + reguardless of whether we are in compiling or command + mode + __ + HD = Bit 7 is the Hide Bit, if this is true then when + compiling or executing words the word will be hidden from the + search. + ___________ + NAME OFFSET = Bits 8 to 15 are the offset to the words name. To find the + beginning of the words name we take this value away from + position of this words PWD header. This value is in + machine words, and so the beginning of the NAME must be aligned + to the virtual machine words boundaries and not character, or byte, + aligned. The length of this field, and the size of the input buffer, + limit the maximum size of a word. +__ +CB = Compiling bit, if set this is a compiling word, if + cleared it is an immediate word. +``` + +Depending on the virtual machine word size, or cell size, there may be more +bits above bit '15', the most significant bit, in the MISC field. These bits +are not used and should be set to zero. + +And the dictionary looks like this: + +``` + [ Special 'fake' word ] + . + /|\ + | + .-------.-----.----------------------. + | NAME | PWD | Rest of the word ... | + .-------.-----.----------------------. + . + /|\ + | + ~~~~~ + The rest of the dictionary + ~~~~~ + | + .-------.-----.----------------------. + | NAME | PWD | Rest of the word ... | + .-------.-----.----------------------. + . + /|\ + | + .-------.-----.----------------------. + | NAME | PWD | Rest of the word ... | + .-------.-----.----------------------. + . + /|\ + | + [ Previous Word Register ] +``` + +Searching of the dictionary starts from the *Previous Word Register* and ends +at a special 'fake' word. + +Defining words adds them to the dictionary, we can defined words with the ':' +words like this: + +``` + : two-times 2 * ; +``` + +Which defined the word "two-times", a word that takes a value from the stack, +multiplies it by two and pushes the results back onto the stack. + +The word ':' performs multiple actions; it is an immediate word that reads in the +next space delimited word from the input stream and creates a header for that +word. It also switches the interpreter into compile mode, compiling words will +be compiled into that word definition instead of being executed, immediate words +are executed as normal. ';' is also an immediate word, it compiles a special +word exit into the dictionary which returns from a word call and switches the +interpreter back into command mode. This type of behavior is typical of +[Forth](https://en.wikipedia.org/wiki/Forth_%28programming_language%29) implementations. + +## Memory Map and Special Registers + +The way this interpreter works is that is emulates an idealized machine, one +built for executing [Forth](https://en.wikipedia.org/wiki/Forth_%28programming_language%29) directly. As such it has to make compromises and +treats certain sectors of memory as being special, as shown below (numbers are +given in *hexadecimal* and are multiples of the virtual machines word-size +which is either 16, 32 or 64 bit depending on compile time options. + +Where the dictionary ends and the variable and return stacks begin depends on +how much memory was allocated to the interpreter (with a minimum of 2048 +words), the default is 32768 words, and the following diagram assumes this: + +``` + .-----------------------------------------------. + | 0-3F | 40-7BFF |7C00-7DFF|7E00-7FFF| + .-----------------------------------------------. + | Registers | Dictionary... | V stack | R stack | + .-----------------------------------------------. + + V stack = The Variable Stack + R stack = The Return Stack +``` + +Each may be further divided into special sections: + +### Registers + +At the beginning of the Forth virtual machine there is a section used for +registers, modifying them arbitrary can cause undefined behavior to occur which +will most likely cause the virtual machine to be terminated. + +``` +NAME LOCATION DESCRIPTION + DECIMAL HEX + 0-1 0-1 Unused + 2-5 2-5 Push integer word +DIC 6 6 Dictionary pointer +RSTK 7 7 Return stack pointer +STATE 8 8 Interpreter state; compile/command mode +BASE 9 9 Base conversion variable +PWD 10 A Pointer to last defined word +SOURCE_ID 11 B Input source selector (-1 = string input, + 0 = file input) +SIN 12 C String input pointer +SIDX 13 D String input index (index into SIN) +SLEN 14 E String input length (length of SIN) +START_ADDR 15 F Pointer to start of VM +FIN 16 10 File input pointer +FOUT 17 11 File output pointer +STDIN 18 12 File pointer to stdin, if available +STDOUT 19 13 File pointer to stdout, if available +STDERR 20 14 File pointer to stderr, if available +ARGC 21 15 Count of arguments passed to program, + if available +ARGV 22 16 An array of pointers to NUL terminated + ASCII strings, if available, of ARGC + length +DEBUG 23 17 Turn debugging on/off if enabled +INVALID 24 18 If non zero, this interpreter is invalid +TOP 25 19 Stored version of top of stack +INSTRUCTION 26 1A Stored version of instruction pointer +STACK_SIZE 27 1B Size of the variable stack +ERROR_HANDLER 28 1C Action to take on error +THROW 29 1D Used for throw/catch +SIGNAL_HANDLER 30 1E Used for signal handling +SCRATCH_X 31 1F Scratch variable for the user +``` + +Some registers will need more explaining. + +* SIGNAL\_HANDLER + +This register is used when a signal is caught, it is up to the C environment to +call *forth\_signal* from a signal handler in the C environment to let the +Forth interpreter know a signal has been caught. + +* SCRATCH\_X + +Scratch X is a variable that can be used by the user, be warned that other +words defined in the base library *might* use this register as well. + +### Dictionary + +Apart from the constraints that the dictionary begins after where the +registers are and before where V stack is there are no set demarcations +for each region, although currently the defined word region ends before +0x200 leaving room between that and 0x7BFF for user defined words. + +``` + .----------------------------------------------------------------. + | 40-??? | ???-??? | ???-7BFF | + .----------------------------------------------------------------. + | Special read word | Interpreter word | Defined word ... | + .----------------------------------------------------------------. + + Special read word = A word called on entrance to the interpreter, + it calls itself recursively (as a tail call). This + word cannot be 'found', it does not have a name. + Interpreter word = Any named (not 'invisible' ones) interpreter word + gets put here. + Defined word = A list of words that have been defined with ':' +``` + +## Glossary of Forth words + +Each word is also given with its effect on the variable stack, any other effects +are documented (including the effects on other stacks). Each entry looks like +this: + +* word ( y -- z ) + +Where 'word' is the word being described, the contents between the parenthesis +describe the stack effects, this word expects one number to be one the stack, +'y', and returns a number to the stack 'z'. + +Some of the descriptions of the variables in the stack effect comment +have a meaning: + +``` +.---------.-------------------------------------------------. +| Name | Meaning | +.---------.-------------------------------------------------. +| addr | An address in cells | +| c-addr | Character address | +| r-addr | A raw address | +| file-id | A file id, used as a handle for file operations | +| ior | A error status returned by file operations | +| char | Single byte / character | +| u | An unsigned value | +| x | A signed value | +| c" xxx" | The word parses a word (not a stack effect) | +.---------.-------------------------------------------------. +``` + +The addressing modes complicate certain operations of Forth words. A normal +Forth address, as passed to words like '!', '@', 'c@' and 'c!' are relative to +the beginning of the start of the Forth cores memory, or at register zero. '!' +and '@' take their addresses in cells (*addr*), whereas 'c@' and 'c!' take +their addresses in character address (*c-addr*). + +Raw addresses are however normal addresses, as understood by [C](https://en.wikipedia.org/wiki/C_%28programming_language%29) programs +and the computer. Operations on raw addresses can possibly result in undefined +behavior, and all objects they may operate on that exists outside of the Forth +core cannot be guaranteed to exists after a core file has been reloaded (that +is pointers to objects outside of Forth core should not be saved for further +use). Raw-addresses are also in character, not cell, units. + +In future revisions of Forth this memory addressing might be simplified, if a +simple way of doing this can be achieved. + +### Internal words + +There are three types of words. + +#### 'Invisible' words + +These invisible words have no name but are used to implement the Forth. They +are all *immediate* words. + +* push ( -- x ) + +Push the next value in the instruction stream onto the variable stack, advancing +the instruction stream. + +* const ( -- x ) + +Push the next location after this instruction, not the instruction stream, onto +the variable stack. + +* run ( -- ) + +Save the current instruction stream pointer onto the return stack and set +the pointer instruction stream pointer to point to value after *run*. + +#### Immediate words + +These words are named and are *immediate* words. + +* ':' ( c" xxx" -- ) + +Read in a new word from the input stream and compile it into the dictionary. + +* 'immediate' ( -- ) + +Make the previously declared word immediate. Unlike in most Forth +implementations this is used after the words name is given not after the +final ';' has been reached. + +So: + +``` + : word immediate ... ; +``` + +Instead of: + +``` + : word ... ; immediate +``` + +* '\' ( c" \n" -- ) + +A comment, ignore everything until the end of the line. + +#### Compiling words + +* 'read' ( c" xxx" -- ) + +*read* is a complex word that implements most of the input interpreter, +it reads in a [Forth](https://en.wikipedia.org/wiki/Forth_%28programming_language%29) *word* (up to 31 characters), if this *word* is in +the *dictionary* it will either execute the word if we are in *command mode* +or compile a pointer to the executable section of the word if in *compile +mode*. If this *word* is not in the *dictionary* it is checked if it is a +number, if it is then in *command mode* we push this value onto the *variable +stack*, if in *compile mode* then we compile a *literal* into the *dictionary*. +If it is none of these we print an error message and attempt to read in a +new word. + +* '@' ( address -- x ) + +Pop an address and push the value at that address onto the stack. + +* '!' ( x address -- ) + +Given an address and a value, store that value at that address. + +* 'c@' ( char-address -- char ) + +Pop a character address and push the character value at that address onto the +stack. Note that this access is not checked for being within range of the +virtual machines memory, but it is still relative to the start address of +virtual machine memory. + +* 'c!' ( char char-address -- ) + +Given a character address, store a character value at that address, like 'c@' +the address is relative to the virtual machines starting address. + +* '-' ( x y -- z ) + +Pop two values, subtract 'y' from 'x' and push the result onto the stack. + +* '+' ( x y -- z ) + +Pop two values, add 'y' to 'x' and push the result onto the stack. + +* 'and' ( x y -- z ) + +Pop two values, compute the bitwise 'AND' of them and push the result on to +the stack. + +* 'or' ( x y -- z ) + +Pop two values, compute the bitwise 'OR' of them and push the result on to +the stack. + +* 'xor' ( x y -- z ) + +Pop two values, compute the bitwise 'XOR' of them and push the result on to +the stack. + +* 'invert' ( x y -- z ) + +Perform a bitwise negation on the top of the stack. + +* 'lshift' ( x y -- z ) + +Pop two values, compute 'y' shifted by 'x' places to the left and push +the result on to the stack. + +* 'rshift' ( x y -- z ) + +Pop two values, compute 'y' shifted by 'x' places to the right and push +the result on to the stack. + +* '\*' ( x y -- z ) + +Pop two values, multiply them and push the result onto the stack. + +* '/' ( x y -- z ) + +Pop two values, divide 'x' by 'y' and push the result onto the stack. If 'y' +is zero and error message is printed and 'x' and 'y' will remain on the +stack, but execution will continue on as normal. + +* 'u<' ( x y -- z ) + +Pop two unsigned values, compare them (y < x) and push the result onto the +stack, the comparison will be unsigned. + +* 'u>' ( x y -- z ) + +Pop two values, compare them (y > x) and push the result onto the stack. The +comparison will be unsigned. + +* '\_exit' ( -- ) + +Pop the return stack and set the instruction stream pointer to that +value. + +* 'exit' ( -- ) + +This does the same as **\_exit**, the reason there are two exits instead +of one is so that the word 'see', defined in **forth.fth** can differentiate +between an exit that occurs in the definition of a word, and one that occurs +at the end of a words definition. ('see' is a decompiler for Forth). + +For example: + +``` +: test 0 begin dup 10 > if exit then dup . cr 1+ again ; +``` + +Gets Compiled to: + +``` +Address Contents + ._____._____._____._____. <- Start of Word + X | 't' | 'e' | 's' | 't' | + ._____._____._____._____. + X+1 | 0 | 0 | 0 | 0 | NUL terminates 'test' string + ._____._____._____._____. + X+2 | Previous Word Pointer | AKA 'PWD' field + ._______________________. + X+3 | MISC Field | <- Execution Starts here + ._______________________. + X+4 | Literal | Literals a compiled as a pointer to + ._______________________. a 'literal' word and the literal in + X+5 | 0 | the next field. + ._______________________. + X+6 | Pointer to 'dup' | + ._______________________. + X+7 | literal | + ._______________________. + X+8 | 10 | + ._______________________. + X+9 | Pointer to '>' | + ._______________________. + X+10 | Pointer to 'branch?' | 'if' gets compiled to 'branch?' + ._______________________. and '2' so it jumps over 'exit' + X+11 | 2 | if the previous test fails. This + ._______________________. is encoded as the jump destination + X+12 | Pointer to 'exit' | less one as an increment happens + ._______________________. after the word is executed. + X+13 | Pointer to 'dup' | + ._______________________. + X+14 | Pointer to '.' | + ._______________________. + X+15 | Pointer to 'cr' | + ._______________________. + X+16 | Pointer to '1+' | + ._______________________. + X+17 | Pointer to 'branch' | + ._______________________. + X+18 | -12 | + ._______________________. + X+19 | Pointer to '_exit' | + ._______________________. <- End of Word +``` + +The decompiler knows that the end of a word is demarcated by a pointer to +**\_exit**, and that pointers to **exit** can occur within the body of the +definition. + +* 'key' ( -- char ) + +Get a value from the input and put it onto the stack. + +* '\_emit' ( char -- status ) + +Put a character to the output stream returning a success value. + +* 'r>' ( -- x ) + +Pop a value from the return stack and push it to the variable stack. + +* '>r' ( x -- ) + +Pop a value from the variable stack and push it to the return stack. + +* 'branch' ( -- ) + +Jump unconditionally to the destination next in the instruction stream. + +* '?branch' ( bool -- ) + +Pop a value from the variable stack, if it is zero the jump to the +destination next in the instruction stream, otherwise skip over it. + +* '(.)' ( x -- status ) + +Pop a value from the variable stack and print it to the output either +as a ASCII decimal or hexadecimal value depending on the BASE register. A +return status is pushed onto the stack, greater or equal to zero is a success, +negative is a failure. Failure can occur because of an invalid base in the BASE +register, or because the output could not be written to. + +* ''' ( -- ) + +Push the next value in the instruction stream onto the variable stack +and advance the instruction stream pointer over it. + +* ',' ( x -- ) + +Write a value into the dictionary, advancing the dictionary pointer. + +* '=' ( x y -- z ) + +Pop two values, perform a test for equality and push the result. + +* 'swap' ( x y -- y z ) + +Swap two values on the stack. + +* 'dup' ( x -- x x ) + +Duplicate a value on the stack. + +* 'drop' ( x -- ) + +Drop a value. + +* 'over' ( x y -- x y x ) + +Duplicate the value that is next on the stack. + +* 'find' ( -- execution-token ) + +Find a word in the dictionary pushing a pointer to that word onto the +variable stack. + +* 'depth' ( -- depth ) + +Push the current stack depth onto the stack, the value is the depth of the +stack before the depth value was pushed onto the variable stack. + +* 'sp@' ( -- addr ) + +Push the address of the stack pointer onto the stack, before **sp@** was +executed: + +``` +1 2 sp@ . . . +``` + +Prints: + +``` +2 2 1 +``` + +* 'sp!' ( addr -- ) + +Set the address of the stack pointer. + +* 'clock' ( -- x ) + +Push the difference between the startup time and now, in milliseconds. This +can be used for timing and implementing sleep functionality, the counter +will not increase the interpreter is blocking and waiting for input, although +this is implementation dependent. + +* 'evaluator' ( c-addr u 0 | file-id 0 1 -- x ) + +This word is a primitive used to implement 'evaluate' and 'include-file', it +takes a boolean to decide whether it will read from a file (1) or a string (0), +and then takes either a forth string, or a **file-id**. + +* 'system' ( c-addr u -- status ) + +Execute a command with the systems command interpreter. + +* 'raise' ( u -- ??? ) + +Raises a signal, what happens after the signal is raised is undefined. + +* 'date' ( -- date ) + +Push the date onto the stack, the order of the arguments are: + +``` +Is day light savings time? +Days since start of year +Week day +Year +Month +Day of month +Hour +Minutes +Seconds (note, this can include lead seconds!) +``` + +The time is in UTC time. + +* 'memory-copy' ( r-addr1 r-addr2 u -- ) + +Operates on two raw addresses. Copy 'u' characters from r-addr2 to r-addr1. + +* 'memory-locate' ( r-addr char u -- r-addr | 0 ) + +Locate a character in a block of memory 'u' characters wide, returning a pointer to +that character or zero if that address cannot be found. + +* 'memory-set' ( r-addr char u -- ) + +Set 'u' character of memory starting at 'r-addr' to 'char'. + +* 'memory-compare' ( r-addr1 r-addr2 u -- x ) + +Compare two blocks of memory 'u' units wide. + +* 'allocate' ( u -- r-addr status ) + +Allocate a block of memory. + +* 'free' ( r-addr -- status ) + +Free a block of memory. + +* 'getenv' ( c-addr u -- r-addr u ) + +Get an [environment variable](https://en.wikipedia.org/wiki/Environment_variable) given a string, it returns '0 0' if the +variable was not found. + +##### File Access Words + +The following compiling words are part of the File Access Word set, a few of +the fields need explaining in the stack comments. "file-id" refers to a +previously opened file as returned by "open-file", "ior" refers to a return +status provided by the file operations. "fam" is a file access method, + +* 'close-file' ( file-id -- ior ) + +Close an already opened file. + +* 'open-file' ( c-addr u fam -- file-id ior ) + +Open a file, given a Forth string (the 'c-addr' and the 'u' arguments), and a +file access method, which is defined within "forth.fth". Possible file access +methods are "w/o", "r/w" and "r/o" for read only, read-write and write only +respectively. + +* 'delete-file' ( c-addr u -- ior ) + +Delete a file on the file system given a Forth string. + +* 'read-file' ( c-addr u file-id -- ior ) + +Read in 'u' characters into 'c-addr' given a file identifier. + +* 'write-file' ( c-addr u file-id -- ior ) + +Write 'u' characters from 'c-addr' to a given file identifier. + +* 'file-position' ( file-id -- ud ior ) + +Get the file position offset from the beginning of the file given a file +identifier. + +* 'reposition-file' ( ud file-id -- ior ) + +Reposition a files offset relative to the beginning of the file given a file +identifier. + +* 'flush-file' ( file-id -- ior ) + +Attempt to flush any buffered information written to a file. + +* 'rename-file' ( c-addr1 u1 c-addr2 u2 -- ior ) + +Rename a file on the file system named by the first string ('c-addr1' and 'u1') +to the second string ('c-addr2' and 'u2'). + +* 'temporary-file' ( -- file-id ior ) + +Open up a new temporary file for writing and reading. + +### Defined words + +Defined words are ones which have been created with the ':' word, some words +get defined before the user has a chance to define their own to make their +life easier. + +* 'state' ( -- addr ) + +Push the address of the register that controls the interpreter state onto +the stack, this value can be written to put the interpreter into compile +or command modes. + +* ';' ( -- ) + +Write 'exit' into the dictionary and switch back into command mode. + +* 'base' ( -- addr ) + +This pushes the address of a variable used for input and output conversion of +numbers, this address can be written to and read, valid numbers to write are 0 +and 2 to 36 (*not* 1). + +* 'pwd' ( -- pointer ) + +Pushes a pointer to the previously define word onto the stack. + +* 'h' ( -- pointer ) + +Push a pointer to the dictionary pointer register. + +* 'r' ( -- pointer ) + +Push a pointer to the register pointer register. + +* 'here' ( -- dictionary-pointer ) + +Push the current dictionary pointer (equivalent to "h @"). + +* '[' ( -- ) + +Immediately switch into command mode. + +* ']' ( -- ) + +Switch into compile mode + +* '>mark' ( -- location ) + +Write zero into the head of the dictionary and advance the dictionary pointer, +push a address to the zero written into the dictionary. This is usually used +after in a word definition that changes the control flow, after a branch for +example. + +* ':noname' ( -- execution-token ) + +This creates a word header for a word without a name and switches to compile +mode, the usual ';' finishes the definition. It pushes a execution token onto +the stack that can be written into the dictionary and run, or executed directly. + +* 'if' ( bool -- ) + +Begin an if-else-then statement. If the top of stack is true then we +execute all between the if and a corresponding 'else' or 'then', otherwise +we skip over it. + +Abstract Examples: + +``` + : word ... bool if do-stuff ... else do-other-stuff ... then ... ; + + : word ... bool if do-stuff ... then ... ; +``` + +and a concrete examples: + +``` + : test-word if 2 2 + . cr else 3 3 * . cr ; + 0 test-word + 4 # prints 4 + 1 test-word + 9 # prints 9 +``` + +Is a simple and contrived example. + +* 'else' ( -- ) + +See 'if'. + +* 'then' ( -- ) + +See 'if'. + +* 'begin' ( -- ) + +This marks the beginning of a loop. + +* 'until' ( bool -- ) + +Loop back to the corresponding 'begin' if the top of the stack is zero, continue +on otherwise. + +* "')'" ( -- char ) + +Push the number representing the ')' character onto the stack. + +* 'tab' ( -- ) + +Print a tab. + +* 'cr' ( -- ) + +Prints a newline. + +* '(' ( -- ) + +This will read the input stream until encountering a ')' character, it +is used for comments. + +* 'allot' ( amount -- ) + +Allocate a number of cells in the dictionary. + +* 'tuck' ( x y -- y x y ) + +The stack comment documents this word entirely. + +* 'nip' ( x y -- y ) + +The stack comment documents this word entirely. + +* 'rot' ( x y z -- z x y ) + +The stack comment documents this word entirely. This word rotates three items +on the variable stack. + +* '-rot' ( x y z -- y z x ) + +The stack comment documents this word entirely. This word rotates three items +on the variable stack, in the opposite direction of "rot". + +* 'emit' ( x -- ) + +Write a single character out to the output stream. + +* '?' ( addr -- ) + +Print the contents of addr to the screen. + +## Library of Forth words + +The file [forth.fth](/howerj/libforth/blob/master/forth.fth) contains many defined words, however those words are +documented within that file and so as to avoid duplication will not be +mentioned here. This file is *not* loaded automatically, and so should be run +like this: + +Unix: + +``` + ./forth -t forth.fth +``` + +Windows + +``` +forth.exe -t forth.fth +``` + +## Glossary of Forth terminology + +* Word vs Machine-Word + +Usually in computing a 'word' refers to the natural length of integer in a +machine, the term 'machine word' is used to invoke this specific meaning, +a word in [Forth](https://en.wikipedia.org/wiki/Forth_%28programming_language%29) is more analogous to a function, but there +are different types of Forth words; *immediate* and *compiling* words, +*internal* and *defined* words and finally *visible* and *invisible* words. + +The distinction between a machine word and a Forth word +can lead to some confusion. + +* *The* dictionary + +There is only one dictionary in a normal [Forth](https://en.wikipedia.org/wiki/Forth_%28programming_language%29) implementation, it is a +data structure that can only grow in size (or at least it can in this +implementation) and holds all of the defined words. + +* *The* stack + +When we referring to a stack, or the stack, we refer to the variable stack +unless otherwise stated (such as the return stack). The variable, or the +stack, holds the result of recent operations such as addition or subtraction. + +* The return stack + +Forth implementations are two (or more) stack machines. The second stack +is the return stack which holds the usual function call return values as +well as temporary variables. + +* Defined Words + +A defined word is one that is not implement directly by the interpreter but +has been create with the ':' word. It can be an *immediate* word, but does +not have to be. + +* Compile mode + +In this mode we *compile* words unless those words are *immediate* words, +if the are then we immediately execute them. + +* Command mode + +In this mode, regardless of whether we are in *command* or *compile* mode +we execute words or push them on to the stack. + +* A block. + +A [Forth](https://en.wikipedia.org/wiki/Forth_%28programming_language%29) block is primitive way of managing persistent storage and this +version of block interface is more primitive than most. A block is a +contiguous range of bytes, usually 1024 of them as in this instance, and +they can be written or read from disk. Flushing of dirty blocks is not +performed in this implementation and must be done 'manually'. + +## Porting this interpreter + +The interpreter code is written in [C99](https://en.wikipedia.org/wiki/C99), and is written to be portable, however +porting it to embedded platforms that lack a C standard library (which is most +of them) would mean replacing the most of the C standard library functions used, +and implementing a new I/O mechanism for reading, printing and block storage. + +The interpreter has been tested on the following platforms: + +* Linux x86-64 with, + + Debian Jessie (8.x) + + GCC version 4.9.2 +* Windows 7 x86-64 (not recently) +* Linux ARM 32-bit Little Endian (not recently) +* OSX Sierra 10.12.1 (tested by Rikard Lang). + +And the different virtual machine word size options (32 and 64 bit machine +words) have been tested. There is no reason it should not also work on 16-bit +platforms. + +libforth is also available as a [Linux Kernel Module](http://tldp.org/LDP/lkmpg/2.6/html/), on a branch of libforth, +see . This is +module is very experimental, and it is quite possible that it will make your +system unstable. + +## Standards compliance + +This Forth interpreter is in no way compliant with any of the standards +relating to Forth, such as [ANS Forth](http://lars.nocrew.org/dpans/dpans.htm), or previous Forth standardization +efforts. However attempts to support words and behavior typical of these +standards are made (although there is still a lot to do). + +Some important deviations are: + +* ok + +'ok' is not printed after a successful command execution , this is for two +reasons, firstly because of limitations in the implementation, and secondly +there is no reason for cluttering up the output window with this. The +implementation should be silent by default. + +* Control structures + +Various control structures in Forth behave slightly differently than in +normal Forths. This should be fixed, given time. + +## forth.core magic + +The [Forth](https://en.wikipedia.org/wiki/Forth_%28programming_language%29) interpreters core files can be detected by the [file](https://linux.die.net/man/1/file) utility +by creating a [magic](https://linux.die.net/man/5/magic) file. + +Save the following file on [Unix](/howerj/libforth/blob/master/www.opengroup.org/unix) systems to */etc/magic*: + +``` +# libforth core files start with 0xFF '4' 'T' 'H' +0 string \xFF\x34\x54\x48 libforth core file +>4 byte 2 16-bit +>4 byte 4 32-bit +>4 byte 8 64-bit +## File version, version 4 is current as of 2017/03/08 +>5 byte x version=[%d] +>5 byte <4 ancient +>5 byte 4 current +>5 byte >4 futuristic +## Endianess test +>6 byte 0 big-endian +>6 byte 1 little-endian +>6 byte >1 INVALID-ENDIANESS +## Size is stored as the base-2 logarithm of the size +>7 byte x size=[2^%d] +## Extra tests could be added, such as whether the core file is still valid +``` + +## Coding Standards + +The coding standards used for both the C and Forth code deviate from what is +normal, the Forth code mostly so. Nonetheless they should be abided by +regardless of what one may think of them. The C code is also written in a +literate style (although the documentation is generated from it, rather than +the code being generated from the documentation), this imposes extra +requirements on comments. + +### C Coding Standards + +The libforth Forth interpreter is primarily a library first and should be +thought of as such, it is possible that multiple instances of the Forth +interpreter are active at the same time, as such absolutely no global state can +be used within the Forth library. Be very careful in what functions you export, +by default all functions should be declared as static. + +Global state can be used in the [main.c][] file which contains a wrapper +around libforth. This wrapper is used to make the **forth** executable, and +there is only ever one instance of the interpreter in use at a time. + +The library is also written in [C99](https://en.wikipedia.org/wiki/C99) and made to be portable. Any +non-portable code should be placed in [main.c][] and should be optionally +compiled only if the correct macro for that functionality is defined. The +macros **\_WIN32** and **\_\_unix\_\_** are currently used to test for the +operating system in use for example. + +The program [doxygen](https://en.wikipedia.org/wiki/Doxygen) is used to extract and built the API documentation for +libforth. At minimum all functions and macros that are exported by the library +should be documented using [doxygen](https://en.wikipedia.org/wiki/Doxygen) style markup. + +All functions exported by [libforth.c](/howerj/libforth/blob/master/libforth.c) should be tested, and should be +prefixed with "forth\_". Unit tests against [libforth.c](/howerj/libforth/blob/master/libforth.c) belong in +[unit.c](/howerj/libforth/blob/master/unit.c). The same portability guidelines that apply to [libforth.c](/howerj/libforth/blob/master/libforth.c) +also apply to [unit.c](/howerj/libforth/blob/master/unit.c). + +Try to use assertions and checks on code liberally, even if the check is +expensive to do. Expensive checks should be disabled with by defining the +**NDEBUG** macro, like **assert** is. + +The Linux kernel coding standards are to be roughly followed. Line lengths +should be limited to 80 characters in length (this is much more important given +documentation is generated from the source). + +The main exception to the rule on code indentation is the **forth\_run** +function, which mostly consists of a large switch statement that implements the +Forth virtual machine. + +Bellow is a cut down version of the switch statement: + +``` +switch(w) { /* switches on instruction */ +/* ...More instructions... */ +case DEFINE: + m[STATE] = 1; /* compile mode */ + if(forth_get_word(o, o->s) < 0) + goto end; + compile(o, RUN, (char*)o->s, true); + break; +/* ...More instructions... */ +case ADD: f = *S-- + f; break; +case AND: f = *S-- & f; break; +case OR: f = *S-- | f; break; +case XOR: f = *S-- ^ f; break; +case INV: f = ~f; break; +/* ...More instructions... */ +} +``` + +Of note is that simple instructions like **ADD** and **OR** take up a single +line, having worked on the virtual machine for a while this aids in readability +for me. The **DEFINE** instruction is a lot longer and so is split up into +multiple lines. + +A [AWK](https://en.wikipedia.org/wiki/AWK) script, specifically [GAWK](https://www.gnu.org/software/gawk/), is used to turn the [C](https://en.wikipedia.org/wiki/C_%28programming_language%29) code into a +single [PDF](https://en.wikipedia.org/wiki/Portable_Document_Format) document, by first generating [markdown](https://daringfireball.net/projects/markdown/) from it. The script, +called [convert](/howerj/libforth/blob/master/convert), is simple. The script by default indents any [C](https://en.wikipedia.org/wiki/C_%28programming_language%29) code +which in [markdown](https://daringfireball.net/projects/markdown/) means it is treated as a code block, to turn the +indentation on or off the commands "/\*\*" turns if off and the command +"\*\*/" turns it back on, these obviously double as both [C](https://en.wikipedia.org/wiki/C_%28programming_language%29) comment blocks, +but also make [doxygen](https://en.wikipedia.org/wiki/Doxygen) look for tags within the comments. The script only +looks for comment commands at the beginning of a line. + +The following [C](https://en.wikipedia.org/wiki/C_%28programming_language%29) program: + +``` +/** +## A title using markdown syntax +This comment will not be indented in the resulting mark down +file and can be used to describe any of the following code. +**/ +int main(void) +{ + printf("Hello, World\n"); /* a normal C comment */ + return 0; +} +``` + +Will be turned into: + +``` +## A title using markdown syntax +This comment will not be indented in the resulting mark down +file and can be used to describe any of the following code. + + int main(void) + { + printf("Hello, World\n"); /* a normal C comment */ + return 0; + } +``` + +The comment blocks are used to explain the code in detail. + +### Forth Coding Standards + +The way code is formatted is idiosyncratic for Forth, the main difference is +that tabs are used to indent code. Spaces and new lines are used to breakup +longer word definitions, for short definitions only the entire definition +should take up only two lines, as so: + +``` +: foo ( n -- n : add bar to 'n') + bar + ; +``` + +All functions exposed to the user should be unit tested (which currently is not +the case, but that is not an excuse not to test them). Unit tests go in the +file [unit.fth](/howerj/libforth/blob/master/unit.fth). + +Sections of related code should be enclosed with decoration that makes it +obvious that the code belongs together, like so: + +``` +( ============ The Foo Library ============ ) +( The Foo library implements the standard +words 'foo', 'bar' and 'foobar' ) +( ... ) +: foo ( n -- n ) + bar + ; +( ... ) +( ============ The Foo Library ============ ) +``` + +The standard way of making a word immediate in Forth is to place the word +**immediate** after a word definition. This is still possible to do in +libforth, however the preferred method is to place it just after the word being +defined: + +``` +: example immediate ; ( preferred way ) +: example ; immediate ( traditional way ) +``` + +I prefer the first way of making a word immediate as it implies that it is part +of the word definition and not something that acts on the word. + +## Bugs + +As mentioned in the standards compliance section, this Forth does things in a +non-standard way. Apart from that: + +* Passing invalid pointers to instructions like **open-file** or **system** can + cause undefined behavior (your program will most likely crash). There is no + simple way to handle this (apart from not doing it). +* The core interpreter does not currently make use of the throw and catch + mechanism when handling certain errors (like division by zero), in effect there + are two error handlers. These mechanisms need unifying. + +## To-Do + +* A few environment variables could be used to specify start up files for the + interpreter and user specific startup files. +* Signal handling should be improved. +* Error handling could be improved - the latest word definition should be + erased if an error occurs before the terminating ';'. And trap handling + should be done in pure forth, instead of as a hybrid which is currently is. +* A series simple Unix utilities, like in + could be made in Forth, this would demonstrate that this Forth is usable + and practical. Tools like "cat", "tr", "grep", and various other text + formatting tools could be done in pure C, others like "kill", "mount" or "ls" + would require operating system dependent code to be added, this would need + to be contained somehow, so the core remains pure C. +* Allow the main memory to be resized. A Forth primitive MORE-CORE could be + added. +* Move the stack space so it is before the dictionary, this would mean we + could write to the end of memory without worrying about hitting the stack. +* Make a debian package for the Forth interpreter. +* For a Forth only related "To-Do" list see the end of the file [forth.fth](/howerj/libforth/blob/master/forth.fth). +* A compiler for the virtual machine itself should be made, as a separate + program. This could be used to make a more advanced read-evaluate loop. +* Core files are currently not portable across machines of different words + sizes or endianess, which needs addressing, or ignoring conclusively. +* Use either liballocs or libffi for adding foreign function interfaces + to programs, see: + + + + +* The Forth could be made to be more standards compliant (especially where it + comes to I/O and addressing (but also things like CASE statements). +* A document (part of this document) for the coding standards used in this + document needs to be created and added here. Things that will need + documenting are: + +* How comments should look like (literate and doxygen comments) +* Tabs vs Spaces (use tabs) +* Levels of indentation +* Coding standards for Forth (stack comments, indentation, etcetera). +* And much more. + +* Improve error handling by adding 'throw' and 'catch' to the virtual + machine as both C functions callable within the confines of 'libforth.c' and + as virtual machine instructions. +* To fix the problem with a mismatching between C addresses and Forth + addresses which currently exists all modes of addressing should be made to + be relative, or fixed up by the **forth\_init**. Currently access to memory + outside of the Forth address space can only be done by copying memory to and + from the C and the Forth addresses spaces with words that accept real addresses + (like **memory-copy**). + +* Branches use relative addressing at the moment. +* Register values are either fixed up at initialization (as in the case + of **stdin**, **stdout** and a few other pointers) or need fixing (like the + variable stack pointer, return stack pointer the HERE pointer and more). +* How the constants are defined will need to be changed (this will be the + most difficult thing to fix). +* See: +* And: + +### Virtual Machine To-Do points + +The virtual machine needs changing, in someways drastically, to accommodate the +following behaviors: + +1. Error handling should be purely Forth based. + +Currently error handling and recovery is a weird mishmash between [C](https://en.wikipedia.org/wiki/C_%28programming_language%29) and +[Forth](https://en.wikipedia.org/wiki/Forth_%28programming_language%29), more of the error handling should be moved to the [Forth](https://en.wikipedia.org/wiki/Forth_%28programming_language%29) +environment using the normal THROW/CATCH mechanisms (which should be turned +into virtual machine instructions and C functions, which can then be called to +make a throw occur. + +2. The virtual machine should use character based addressing. Currently it uses + cell based addressing, which causes all kinds of confusion. +3. Words currently not defined need to be hidden, until the terminating ';'. + +### Submodules + +The [main.c][] file depends, optionally, on various submodules. These +submodules need improving. + +#### libline + +* libline needs porting to Windows +* The API needs improving so there is more control on whether or not raw mode + is turned on or off, whether a terminal is being read from or not, ... + +### Experimental single binary + +The build system can be used to build a single binary which contains the +contents of "forth.fth", with the command "make libforth". This is a +multistage build process that is experimental, so should not be relied upon. It +involves a bootstrapping process using the first forth executable to build a +second. + +The process works like this: + +1. The executable "forth" is made. + + make forth + +or: + +``` +gcc -std=c99 main.c unit.c libforth.c -o forth +``` + +2. The executable is used to generate a code file containing the contents of + "forth.fth" is made. + + ./forth -s forth.core +3. A forth word, *core2c* is used to generate a C file called "core.gen.c": + + ./forth -l forth.core -e 'c" forth.core" c" core.gen.c" core2c' +4. The forth program is recompiled with an extra define, which means that + initialization of a minimal forth environment is replaced with the core file we + just made: + + gcc -DUSE\_BUILT\_IN\_CORE -std=c99 main.c unit.c libforth.c core.gen.c -o libforth + +The new executable, *libforth*, behaves the same as *forth* but with a built in +core file. + +## Notes + +* The compilation should result in a small executable, and when statically + linked against [musl](https://www.musl-libc.org/) under Linux (x86-84), the stripped executable is around + 50kb in size. +* It is quite possible to make Forth programs that corrupt memory that they + should, this is not a design flaw in this interpreter but more part of the + Forth philosophy. If you want memory safety (and most of the time you should) + you should use a different language, or implementation. + + + +## About + +libforth: A small Forth interpreter that can be used as a library written in c99 + +### Topics + +[c](/topics/c "Topic: c") +[interpreter](/topics/interpreter "Topic: interpreter") +[stack](/topics/stack "Topic: stack") +[virtual-machine](/topics/virtual-machine "Topic: virtual-machine") +[forth](/topics/forth "Topic: forth") + +### Resources + +[Readme](#readme-ov-file) + +### License + +[MIT license](#MIT-1-ov-file) + +### Uh oh! + +There was an error while loading. Please reload this page. + +[Activity](/howerj/libforth/activity) + +### Stars + +[**200** +stars](/howerj/libforth/stargazers) + +### Watchers + +[**17** +watching](/howerj/libforth/watchers) + +### Forks + +[**31** +forks](/howerj/libforth/forks) + +[Report repository](/contact/report-content?content_url=https%3A%2F%2Fgithub.com%2Fhowerj%2Flibforth&report=howerj+%28user%29) + +## [Releases](/howerj/libforth/releases) + +[6 +tags](/howerj/libforth/tags) + +## [Packages 0](/users/howerj/packages?repo_name=libforth) + +No packages published + +## Languages + +* [C + 49.2%](/howerj/libforth/search?l=c) +* [Forth + 48.3%](/howerj/libforth/search?l=forth) +* [Makefile + 1.6%](/howerj/libforth/search?l=makefile) +* [Awk + 0.9%](/howerj/libforth/search?l=awk) + +## Footer + +© 2026 GitHub, Inc. + +### Footer navigation + +* [Terms](https://docs.github.com/site-policy/github-terms/github-terms-of-service) +* [Privacy](https://docs.github.com/site-policy/privacy-policies/github-privacy-statement) +* [Security](https://github.com/security) +* [Status](https://www.githubstatus.com/) +* [Community](https://github.community/) +* [Docs](https://docs.github.com/) +* [Contact](https://support.github.com?tags=dotcom-footer) +* Manage cookies +* Do not share my personal information + + + +You can’t perform that action at this time. \ No newline at end of file diff --git a/references/ForthNotes/luaforth.md b/references/ForthNotes/luaforth.md new file mode 100644 index 0000000..5258cbe --- /dev/null +++ b/references/ForthNotes/luaforth.md @@ -0,0 +1,434 @@ +# luaforth + +**Source:** https://github.com/vifino/luaforth + +GitHub - vifino/luaforth: A simple Forth in Lua for embedded usage. + + + +[Skip to content](#start-of-content) + + + + + + + + + + + + + +## Navigation Menu + +Toggle navigation + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2Fvifino%2Fluaforth) + +Appearance settings + +* Platform + + + AI CODE CREATION + - [GitHub CopilotWrite better code with AI](https://github.com/features/copilot) + - [GitHub SparkBuild and deploy intelligent apps](https://github.com/features/spark) + - [GitHub ModelsManage and compare prompts](https://github.com/features/models) + - [MCP RegistryNewIntegrate external tools](https://github.com/mcp) + + DEVELOPER WORKFLOWS + - [ActionsAutomate any workflow](https://github.com/features/actions) + - [CodespacesInstant dev environments](https://github.com/features/codespaces) + - [IssuesPlan and track work](https://github.com/features/issues) + - [Code ReviewManage code changes](https://github.com/features/code-review) + + APPLICATION SECURITY + - [GitHub Advanced SecurityFind and fix vulnerabilities](https://github.com/security/advanced-security) + - [Code securitySecure your code as you build](https://github.com/security/advanced-security/code-security) + - [Secret protectionStop leaks before they start](https://github.com/security/advanced-security/secret-protection) + + EXPLORE + - [Why GitHub](https://github.com/why-github) + - [Documentation](https://docs.github.com) + - [Blog](https://github.blog) + - [Changelog](https://github.blog/changelog) + - [Marketplace](https://github.com/marketplace) + + [View all features](https://github.com/features) +* Solutions + + + BY COMPANY SIZE + - [Enterprises](https://github.com/enterprise) + - [Small and medium teams](https://github.com/team) + - [Startups](https://github.com/enterprise/startups) + - [Nonprofits](https://github.com/solutions/industry/nonprofits) + + BY USE CASE + - [App Modernization](https://github.com/solutions/use-case/app-modernization) + - [DevSecOps](https://github.com/solutions/use-case/devsecops) + - [DevOps](https://github.com/solutions/use-case/devops) + - [CI/CD](https://github.com/solutions/use-case/ci-cd) + - [View all use cases](https://github.com/solutions/use-case) + + BY INDUSTRY + - [Healthcare](https://github.com/solutions/industry/healthcare) + - [Financial services](https://github.com/solutions/industry/financial-services) + - [Manufacturing](https://github.com/solutions/industry/manufacturing) + - [Government](https://github.com/solutions/industry/government) + - [View all industries](https://github.com/solutions/industry) + + [View all solutions](https://github.com/solutions) +* Resources + + + EXPLORE BY TOPIC + - [AI](https://github.com/resources/articles?topic=ai) + - [Software Development](https://github.com/resources/articles?topic=software-development) + - [DevOps](https://github.com/resources/articles?topic=devops) + - [Security](https://github.com/resources/articles?topic=security) + - [View all topics](https://github.com/resources/articles) + + EXPLORE BY TYPE + - [Customer stories](https://github.com/customer-stories) + - [Events & webinars](https://github.com/resources/events) + - [Ebooks & reports](https://github.com/resources/whitepapers) + - [Business insights](https://github.com/solutions/executive-insights) + - [GitHub Skills](https://skills.github.com) + + SUPPORT & SERVICES + - [Documentation](https://docs.github.com) + - [Customer support](https://support.github.com) + - [Community forum](https://github.com/orgs/community/discussions) + - [Trust center](https://github.com/trust-center) + - [Partners](https://github.com/partners) +* Open Source + + + COMMUNITY + - [GitHub SponsorsFund open source developers](https://github.com/sponsors) + + PROGRAMS + - [Security Lab](https://securitylab.github.com) + - [Maintainer Community](https://maintainers.github.com) + - [Accelerator](https://github.com/accelerator) + - [Archive Program](https://archiveprogram.github.com) + + REPOSITORIES + - [Topics](https://github.com/topics) + - [Trending](https://github.com/trending) + - [Collections](https://github.com/collections) +* Enterprise + + + ENTERPRISE SOLUTIONS + - [Enterprise platformAI-powered developer platform](https://github.com/enterprise) + + AVAILABLE ADD-ONS + - [GitHub Advanced SecurityEnterprise-grade security features](https://github.com/security/advanced-security) + - [Copilot for BusinessEnterprise-grade AI features](https://github.com/features/copilot/copilot-business) + - [Premium SupportEnterprise-grade 24/7 support](https://github.com/premium-support) +* [Pricing](https://github.com/pricing) + +Search or jump to... + + +# Search code, repositories, users, issues, pull requests... + +Search + +Clear + +[Search syntax tips](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax) + +# Provide feedback + +We read every piece of feedback, and take your input very seriously. + + +Include my email address so I can be contacted + +Cancel + Submit feedback + + + + + +# Saved searches + +## Use saved searches to filter your results more quickly + +Name + +Query + +To see all available qualifiers, see our [documentation](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax). + +Cancel + Create saved search + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2Fvifino%2Fluaforth) + +[Sign up](/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E&source=header-repo&source_repo=vifino%2Fluaforth) + +Appearance settings + +Resetting focus + +You signed in with another tab or window. Reload to refresh your session. +You signed out in another tab or window. Reload to refresh your session. +You switched accounts on another tab or window. Reload to refresh your session. + + + +Dismiss alert + +{{ message }} + +[vifino](/vifino) +/ +**[luaforth](/vifino/luaforth)** +Public + +* [Notifications](/login?return_to=%2Fvifino%2Fluaforth) You must be signed in to change notification settings +* [Fork + 2](/login?return_to=%2Fvifino%2Fluaforth) +* [Star + 6](/login?return_to=%2Fvifino%2Fluaforth) + +A simple Forth in Lua for embedded usage. + +### License + +[MIT license](/vifino/luaforth/blob/master/LICENSE) + +[6 +stars](/vifino/luaforth/stargazers) [2 +forks](/vifino/luaforth/forks) [Branches](/vifino/luaforth/branches) [Tags](/vifino/luaforth/tags) [Activity](/vifino/luaforth/activity) + +[Star](/login?return_to=%2Fvifino%2Fluaforth) + +[Notifications](/login?return_to=%2Fvifino%2Fluaforth) You must be signed in to change notification settings + +* [Code](/vifino/luaforth) +* [Issues + 0](/vifino/luaforth/issues) +* [Pull requests + 0](/vifino/luaforth/pulls) +* [Actions](/vifino/luaforth/actions) +* [Projects + 0](/vifino/luaforth/projects) +* [Security + 0](/vifino/luaforth/security) +* [Insights](/vifino/luaforth/pulse) + +Additional navigation options + + +* [Code](/vifino/luaforth) +* [Issues](/vifino/luaforth/issues) +* [Pull requests](/vifino/luaforth/pulls) +* [Actions](/vifino/luaforth/actions) +* [Projects](/vifino/luaforth/projects) +* [Security](/vifino/luaforth/security) +* [Insights](/vifino/luaforth/pulse) + +# vifino/luaforth + +master + +[Branches](/vifino/luaforth/branches)[Tags](/vifino/luaforth/tags) + +Go to file + +Code + +Open more actions menu + +## Folders and files + +| Name | | Name | Last commit message | Last commit date | +| --- | --- | --- | --- | --- | +| Latest commit History[27 Commits](/vifino/luaforth/commits/master/) 27 Commits | | | +| [bin](/vifino/luaforth/tree/master/bin "bin") | | [bin](/vifino/luaforth/tree/master/bin "bin") | | | +| [tests](/vifino/luaforth/tree/master/tests "tests") | | [tests](/vifino/luaforth/tree/master/tests "tests") | | | +| [.travis.yml](/vifino/luaforth/blob/master/.travis.yml ".travis.yml") | | [.travis.yml](/vifino/luaforth/blob/master/.travis.yml ".travis.yml") | | | +| [LICENSE](/vifino/luaforth/blob/master/LICENSE "LICENSE") | | [LICENSE](/vifino/luaforth/blob/master/LICENSE "LICENSE") | | | +| [Makefile](/vifino/luaforth/blob/master/Makefile "Makefile") | | [Makefile](/vifino/luaforth/blob/master/Makefile "Makefile") | | | +| [README.md](/vifino/luaforth/blob/master/README.md "README.md") | | [README.md](/vifino/luaforth/blob/master/README.md "README.md") | | | +| [app.lua](/vifino/luaforth/blob/master/app.lua "app.lua") | | [app.lua](/vifino/luaforth/blob/master/app.lua "app.lua") | | | +| [auto-run-tests-on-change.sh](/vifino/luaforth/blob/master/auto-run-tests-on-change.sh "auto-run-tests-on-change.sh") | | [auto-run-tests-on-change.sh](/vifino/luaforth/blob/master/auto-run-tests-on-change.sh "auto-run-tests-on-change.sh") | | | +| [luaforth.lua](/vifino/luaforth/blob/master/luaforth.lua "luaforth.lua") | | [luaforth.lua](/vifino/luaforth/blob/master/luaforth.lua "luaforth.lua") | | | +| View all files | | | + +## Repository files navigation + +* [README](#) +* [MIT license](#) + +# luaforth + +[![Build Status](https://camo.githubusercontent.com/f84f1765e4dc206c95e842195c97624b2fc6309edb929d618d902c914ae3de0e/68747470733a2f2f7472617669732d63692e6f72672f766966696e6f2f6c7561666f7274682e7376673f6272616e63683d6d6173746572)](https://travis-ci.org/vifino/luaforth) [![Coverage Status](https://camo.githubusercontent.com/92a923f80497d3e929dddec4c3199009e5b54f47d881a20b0aad9e406593c60b/68747470733a2f2f636f766572616c6c732e696f2f7265706f732f6769746875622f766966696e6f2f6c7561666f7274682f62616467652e7376673f6272616e63683d6d6173746572)](https://coveralls.io/github/vifino/luaforth?branch=master) + +A simplistic and decently fast base implementation of a Forth parser. + +If you expect a fully featured forth here, you're wrong. + +This is made for people who want to embed a Forth-like into their project. + +# Usage + +1. `require`/load luaforth. +2. Create an environment. +3. Call `new_stack, new_environment = luaforth.eval(program_source, environment[, stack, program_source_start_position])`. + +Tada! + +# Example + +See `luaforth.simple_env` [here](https://github.com/vifino/luaforth/blob/master/luaforth.lua#L246-L253) or below. + +``` +-- Example env that has %L to evaluate the line and [L L] pairs to evaluate a small block of Lua code. +local simple_env = { + ["%L"] = { + _fn=function(stack, env, str) + local f, err = loadstring("return " .. str) + if err then + f, err = loadstring(str) + if err then + error(err, 0) + end + end + return f() + end, + _parse = "line" + }, + ["[L"] = { + _fn=function(stack, env, str) + local f, err = loadstring("return " .. str) + if err then + f, err = loadstring(str) + if err then + error(err, 0) + end + end + return f() + end, + _parse = "endsign", + _endsign = "L]" + } +} + +-- Function creation. +luaforth.simple_env[":"] = { + _fn = function(stack, env, fn) + local nme, prg = string.match(fn, "^(.-) (.-)$") + luaforth.simple_env[nme] = { + _fn = function(stack, env) + return luaforth.eval(prg, env, stack) + end, + _fnret = "newstack" + } + end, + _parse = "endsign", + _endsign = ";" +} +``` + +# Environment + +Contains words, strings, booleans, numbers and other things that the forth instance will be able to use. + +## Word Structure + +Words are Forth jargon for functions. + +Look here or below to see how they are structured in this implementation. + +``` +-- Word structure: +-- env[name] = { +-- _fn = func -- function that runs the logic +-- _fnret = ["pushtostack", "newstack"] -- wether the function's return values should be added to the stack or _be_ the stack. Defaults to pushtostack. +-- _args = n -- number of arguments which are pop'd from the stack, defaults to 0 +-- _parse = ["line"|"word"|"endsign"|"pattern"] -- optional advanced parsing, line passes the whole line to the word, word only the next word, pattern parses given pattern, endsign until... +-- _endsign = string -- the given endsign appears. +-- _pattern = pattern -- pattern for parse option +-- } +``` + +# License + +MIT + +## About + +A simple Forth in Lua for embedded usage. + +### Topics + +[lua-library](/topics/lua-library "Topic: lua-library") +[lua](/topics/lua "Topic: lua") +[forth](/topics/forth "Topic: forth") + +### Resources + +[Readme](#readme-ov-file) + +### License + +[MIT license](#MIT-1-ov-file) + +### Uh oh! + +There was an error while loading. Please reload this page. + +[Activity](/vifino/luaforth/activity) + +### Stars + +[**6** +stars](/vifino/luaforth/stargazers) + +### Watchers + +[**2** +watching](/vifino/luaforth/watchers) + +### Forks + +[**2** +forks](/vifino/luaforth/forks) + +[Report repository](/contact/report-content?content_url=https%3A%2F%2Fgithub.com%2Fvifino%2Fluaforth&report=vifino+%28user%29) + +## [Releases](/vifino/luaforth/releases) + +No releases published + +## [Packages 0](/users/vifino/packages?repo_name=luaforth) + +No packages published + +## [Contributors 2](/vifino/luaforth/graphs/contributors) + +### Uh oh! + +There was an error while loading. Please reload this page. + +## Languages + +* [Lua + 95.7%](/vifino/luaforth/search?l=lua) +* [Forth + 3.0%](/vifino/luaforth/search?l=forth) +* Other + 1.3% + +## Footer + +© 2026 GitHub, Inc. + +### Footer navigation + +* [Terms](https://docs.github.com/site-policy/github-terms/github-terms-of-service) +* [Privacy](https://docs.github.com/site-policy/privacy-policies/github-privacy-statement) +* [Security](https://github.com/security) +* [Status](https://www.githubstatus.com/) +* [Community](https://github.community/) +* [Docs](https://docs.github.com/) +* [Contact](https://support.github.com?tags=dotcom-footer) +* Manage cookies +* Do not share my personal information + + + +You can’t perform that action at this time. \ No newline at end of file diff --git a/references/ForthNotes/meow5.md b/references/ForthNotes/meow5.md new file mode 100644 index 0000000..fe2d892 --- /dev/null +++ b/references/ForthNotes/meow5.md @@ -0,0 +1,199 @@ +# meow5 + +**Source:** https://ratfactor.com/meow5/ + +Meow5: An Extremely Concatenative Programming Language - ratfactor + + + + +[![vector ratfactor rat logo](/images/rat-logo.svg)](/) + +[Home](/) | +[About](/about/) | +[Now](/now) | +[Repos](/repos/) | +[Cards](/cards/) | +[Contact](/contact-me/) | +[RSS![rss feed icon](/images/rss.svg)](/atom.xml) + +# Meow5: An Extremely Concatenative Programming Language + +Created: 2022-11-10 + +Updated: 2023-11-21 + +![meow5 kitty logo is black with two bright teal eyes and a pink nose](meow5.png) + +**Update 2023-11-21:** Meow5 is done! [Read my conclusion here!](done) + +Meow5 is a ["concatenative"](https://en.wikipedia.org/wiki/Concatenative_programming_language) (wikipedia.org) +programming language. I also consider it to be a "Forth-like" language since it follows the same +stack-based value passing method and borrows some of Forth’s syntax and nomenclature. + +Hello world (in cat): + +``` +"Meow!" print +Meow! +``` + +* **The Repo:** [Meow5 Repo](/repos/meow5/) +* **Read more:** [Assembly Nights "Season 2"](../assembly-nights2) + might explain why I would do something like this + +**Update 2023-11-01:** Well, would you look at that? It’s just shy of a year after I started +this and I think I’m actually going to be able to finish [it](done) quite soon. + +(To see where I’m currently at, scroll down to **Current progress** below.) + +It’s unique feature is its "inline all the things!" compiling method. A Meow5 function is +the recursively concatenated machine code of every function it calls. At the bottom are "primitive" functions +written in assembly language, which is where the machine code comes from. + +Wait, you mean every time I call a function in another function, I’m making a complete copy of that +function, which is a complete copy of every function *that* function calls, all the way down? + +Yup! Pretty nuts, right? Feel free to run away from this page screaming now. + +But when a primitive is just a dozen bytes long, you can make quite a few +copies of it before it’s a problem. I’m very curious to see how it benchmarks +against other languages in various ways: size, speed, cuteness. + +## Syntax + +Meow5 borrows heavily from the ur-language **Forth**, which was delivered to our dimension by the +prophet Charles H. Moore in the late 1960s. + +Creating a new function, `meow`, that prints the string "Meow" looks like this: + +``` +: meow "Meow." print ; +``` + +Creating a another function, `meow5`, which executes `meow` five times: + +``` +: meow5 meow meow meow meow meow ; +``` + +Invoke their names to call these functions: + +``` +meow +Meow. + +meow5 +Meow.Meow.Meow.Meow.Meow. +``` + +That’s a lot of meows! Who’s a hungry kitty? + +To drive home an earlier point: the above `meow5` function doesn’t just *call* `meow` five times, it actually *contains* five consecutive copies of `meow`! + +## Current Progress + +Here’s a list of milestones reached. The log text file references are from my +devlog files which I write as I’m creating Meow5. You can find them in the repo! + +(Note to self, when I put the logs up here like I did for [nasmjf](../nasmjf/), link these!) + +* (log01.txt) Executing a *copy* of the machine code to print "Meow" at runtime +* (log01.txt) Programatically inlining multiple copies of the "Meow" printer +* (log02.txt) Added function "tail" metadata for linked list dictionary, to use Forth terminology +* (log02.txt) Added `find` function to lookup functions by name for inlining +* (log03.txt) Figured out how to call these machine code chunks so they can return to the call site +* (log03.txt) Have interpreter parsing tokens from a hard-coded input string and executing them +* (log04.txt) Have COMPILE vs IMMEDIATE modes and functions may opt-in for either +* (log05.txt) Using NASM macros to inline functions at the assembly level to build interpreter +* (log05.txt) **Major:** Finished `:` ("colon") and `;` ("semicolon") for function definitions! +* (log06.txt) Added string literals to the language can do this: `"Meow!" print` +* (log06.txt) Have string literals working in *compiled* functions! +* (log06.txt) DEBUG printing (can be inserted anywhere in the assembly) +* (log06.txt) **Major:** The canonical `meow5` function works as shown on this page! +* (log07.txt) Added `str2num` and `num2str` for numeric input/output +* (log07.txt) Have numeric interpolation in strings with `$` placeholders +* (log07.txt) Have string escape sequences (e.g. `\n`) +* (log07.txt) Functions 'inspect' and 'inspect\_all' print all functions with size in bytes +* (log08.txt) **Major:** Reading interpreter input from STDIN! + +**TODO:** The above are badly in need of updating and links. + +**Update 2023-11-01:** I’ve finished the [mez](/repos/mez/) tools in Zig to +help me understand, create, and debug ELF executables and feel fully capable +of finishing the ELF output of Meow5. Let’s do this! Also: "failed art project" below +was waaay too harsh. It’s going to be a successful art project! + +**Update 2023-10-17:** Five months later, I’m back. I essentially consider +this to be a failed art project, but I am not willing to let it rest until +it compiles an ELF executable that prints "Meow" five times! + +``` +>o.o< --"Why yes, I do speak ASCII!" +``` + +## Technical Details + +**32-bit x86 Linux:** Meow5 is written with the NASM assembler () and targets the +32-bit i386 (x86) architecture. It makes direct Linux syscalls and uses no external +libraries. Portability is not a goal. + +**Stack-oriented:** Meow5 uses the i386 `PUSH` and `POP` instructions in the normal fashion to set/get items +from the stack (a region of memory to which items are added or removed sequentially in +a "first in, last out" fashion). One thing that’s neat about this is that alleviates the difficult task of putting +names to data. It also generally produces compact and uncluttered syntax. + + +**Just in Time Compiled:** The moment you start compiling a new function `foo`, it’s machine code is being +inlined into memory. When you execute `foo`, a `JMP` instruction is issued to its machine code, which then +runs until it hits a chunk of "return code" inlined at the end of the definition, which jumps back to the +call site. It does not use `CALL` and `RET` and there can be only *one* level of direct function call +in this fashion, which, it turns out, is all you need for an interactive Meow5 interpreter. + +**Inline All the Things!:** If you use function `foo` in the definition of a new function `bar`, the machine +code of `foo` (not including the "return code" mentioned above or the "tail" with function metadata) is +inlined into `bar`. + +The logical conclusion is that a Meow5 **program** is a top-level function containing a continuous +stream of concatenated machine code. What I would like to do at some point is write out such a program +with an ELF header and see if I can make stand-alone Linux executables! + +## OpenBSD + +I was really curious what OpenBSD would think of this since my understanding is that it +has [W^X (wrote xor execute)](https://en.wikipedia.org/wiki/W%5EX) by default. + +Sure enough, even the linker catches this: + +``` +ld: error: can't create dynamic relocation R_386_32 against local symbol in +readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' +to allow text relocations in the output +>>> defined in meow5.o +>>> referenced by meow5.asm:167 +>>> meow5.o:(tail_strlen) +``` + +which is in reference to: + +``` +%macro ENDWORD 3 +... +tail_%1: + dd LAST_WORD_TAIL ; <---- this line +``` + +Where I’m putting the address of the previous function in the tail of the +current one to make a linked list. + +I’m not sure what those two suggested options are. I might try them to see how far I get. + +--- + +I made the SVG Meow5 logo in Inkscape 0.92. It uses the **Sazanami Mincho** +font by Yasuyuki Furukawa. +*Mincho* evidently means something very similar to what 'serif' means in Latin typefaces. +See [Ming typefaces](https://en.wikipedia.org/wiki/Ming_(typefaces)) (wikipedia.org). + +This page was last generated 2023-11-21 15:13:54 -0500 +All content © Copyright Dave Gauer \ No newline at end of file diff --git a/references/ForthNotes/milliForth.md b/references/ForthNotes/milliForth.md new file mode 100644 index 0000000..d22632d --- /dev/null +++ b/references/ForthNotes/milliForth.md @@ -0,0 +1,398 @@ +# milliForth + +**Source:** https://github.com/fuzzballcat/milliForth + +GitHub - fuzzballcat/milliForth: A FORTH in 340 bytes — the smallest real programming language ever as of yet. + + + +[Skip to content](#start-of-content) + + + + + + + + + + + + + +## Navigation Menu + +Toggle navigation + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2Ffuzzballcat%2FmilliForth) + +Appearance settings + +* Platform + + + AI CODE CREATION + - [GitHub CopilotWrite better code with AI](https://github.com/features/copilot) + - [GitHub SparkBuild and deploy intelligent apps](https://github.com/features/spark) + - [GitHub ModelsManage and compare prompts](https://github.com/features/models) + - [MCP RegistryNewIntegrate external tools](https://github.com/mcp) + + DEVELOPER WORKFLOWS + - [ActionsAutomate any workflow](https://github.com/features/actions) + - [CodespacesInstant dev environments](https://github.com/features/codespaces) + - [IssuesPlan and track work](https://github.com/features/issues) + - [Code ReviewManage code changes](https://github.com/features/code-review) + + APPLICATION SECURITY + - [GitHub Advanced SecurityFind and fix vulnerabilities](https://github.com/security/advanced-security) + - [Code securitySecure your code as you build](https://github.com/security/advanced-security/code-security) + - [Secret protectionStop leaks before they start](https://github.com/security/advanced-security/secret-protection) + + EXPLORE + - [Why GitHub](https://github.com/why-github) + - [Documentation](https://docs.github.com) + - [Blog](https://github.blog) + - [Changelog](https://github.blog/changelog) + - [Marketplace](https://github.com/marketplace) + + [View all features](https://github.com/features) +* Solutions + + + BY COMPANY SIZE + - [Enterprises](https://github.com/enterprise) + - [Small and medium teams](https://github.com/team) + - [Startups](https://github.com/enterprise/startups) + - [Nonprofits](https://github.com/solutions/industry/nonprofits) + + BY USE CASE + - [App Modernization](https://github.com/solutions/use-case/app-modernization) + - [DevSecOps](https://github.com/solutions/use-case/devsecops) + - [DevOps](https://github.com/solutions/use-case/devops) + - [CI/CD](https://github.com/solutions/use-case/ci-cd) + - [View all use cases](https://github.com/solutions/use-case) + + BY INDUSTRY + - [Healthcare](https://github.com/solutions/industry/healthcare) + - [Financial services](https://github.com/solutions/industry/financial-services) + - [Manufacturing](https://github.com/solutions/industry/manufacturing) + - [Government](https://github.com/solutions/industry/government) + - [View all industries](https://github.com/solutions/industry) + + [View all solutions](https://github.com/solutions) +* Resources + + + EXPLORE BY TOPIC + - [AI](https://github.com/resources/articles?topic=ai) + - [Software Development](https://github.com/resources/articles?topic=software-development) + - [DevOps](https://github.com/resources/articles?topic=devops) + - [Security](https://github.com/resources/articles?topic=security) + - [View all topics](https://github.com/resources/articles) + + EXPLORE BY TYPE + - [Customer stories](https://github.com/customer-stories) + - [Events & webinars](https://github.com/resources/events) + - [Ebooks & reports](https://github.com/resources/whitepapers) + - [Business insights](https://github.com/solutions/executive-insights) + - [GitHub Skills](https://skills.github.com) + + SUPPORT & SERVICES + - [Documentation](https://docs.github.com) + - [Customer support](https://support.github.com) + - [Community forum](https://github.com/orgs/community/discussions) + - [Trust center](https://github.com/trust-center) + - [Partners](https://github.com/partners) +* Open Source + + + COMMUNITY + - [GitHub SponsorsFund open source developers](https://github.com/sponsors) + + PROGRAMS + - [Security Lab](https://securitylab.github.com) + - [Maintainer Community](https://maintainers.github.com) + - [Accelerator](https://github.com/accelerator) + - [Archive Program](https://archiveprogram.github.com) + + REPOSITORIES + - [Topics](https://github.com/topics) + - [Trending](https://github.com/trending) + - [Collections](https://github.com/collections) +* Enterprise + + + ENTERPRISE SOLUTIONS + - [Enterprise platformAI-powered developer platform](https://github.com/enterprise) + + AVAILABLE ADD-ONS + - [GitHub Advanced SecurityEnterprise-grade security features](https://github.com/security/advanced-security) + - [Copilot for BusinessEnterprise-grade AI features](https://github.com/features/copilot/copilot-business) + - [Premium SupportEnterprise-grade 24/7 support](https://github.com/premium-support) +* [Pricing](https://github.com/pricing) + +Search or jump to... + + +# Search code, repositories, users, issues, pull requests... + +Search + +Clear + +[Search syntax tips](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax) + +# Provide feedback + +We read every piece of feedback, and take your input very seriously. + + +Include my email address so I can be contacted + +Cancel + Submit feedback + + + + + +# Saved searches + +## Use saved searches to filter your results more quickly + +Name + +Query + +To see all available qualifiers, see our [documentation](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax). + +Cancel + Create saved search + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2Ffuzzballcat%2FmilliForth) + +[Sign up](/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E&source=header-repo&source_repo=fuzzballcat%2FmilliForth) + +Appearance settings + +Resetting focus + +You signed in with another tab or window. Reload to refresh your session. +You signed out in another tab or window. Reload to refresh your session. +You switched accounts on another tab or window. Reload to refresh your session. + + + +Dismiss alert + +{{ message }} + +[fuzzballcat](/fuzzballcat) +/ +**[milliForth](/fuzzballcat/milliForth)** +Public + +* [Notifications](/login?return_to=%2Ffuzzballcat%2FmilliForth) You must be signed in to change notification settings +* [Fork + 28](/login?return_to=%2Ffuzzballcat%2FmilliForth) +* [Star + 623](/login?return_to=%2Ffuzzballcat%2FmilliForth) + +A FORTH in 340 bytes — the smallest real programming language ever as of yet. + +### License + +[MIT license](/fuzzballcat/milliForth/blob/master/LICENSE) + +[623 +stars](/fuzzballcat/milliForth/stargazers) [28 +forks](/fuzzballcat/milliForth/forks) [Branches](/fuzzballcat/milliForth/branches) [Tags](/fuzzballcat/milliForth/tags) [Activity](/fuzzballcat/milliForth/activity) + +[Star](/login?return_to=%2Ffuzzballcat%2FmilliForth) + +[Notifications](/login?return_to=%2Ffuzzballcat%2FmilliForth) You must be signed in to change notification settings + +* [Code](/fuzzballcat/milliForth) +* [Issues + 6](/fuzzballcat/milliForth/issues) +* [Pull requests + 1](/fuzzballcat/milliForth/pulls) +* [Actions](/fuzzballcat/milliForth/actions) +* [Projects + 0](/fuzzballcat/milliForth/projects) +* [Security + 0](/fuzzballcat/milliForth/security) +* [Insights](/fuzzballcat/milliForth/pulse) + +Additional navigation options + + +* [Code](/fuzzballcat/milliForth) +* [Issues](/fuzzballcat/milliForth/issues) +* [Pull requests](/fuzzballcat/milliForth/pulls) +* [Actions](/fuzzballcat/milliForth/actions) +* [Projects](/fuzzballcat/milliForth/projects) +* [Security](/fuzzballcat/milliForth/security) +* [Insights](/fuzzballcat/milliForth/pulse) + +# fuzzballcat/milliForth + +master + +[Branches](/fuzzballcat/milliForth/branches)[Tags](/fuzzballcat/milliForth/tags) + +Go to file + +Code + +Open more actions menu + +## Folders and files + +| Name | | Name | Last commit message | Last commit date | +| --- | --- | --- | --- | --- | +| Latest commit History[42 Commits](/fuzzballcat/milliForth/commits/master/) 42 Commits | | | +| [.gitignore](/fuzzballcat/milliForth/blob/master/.gitignore ".gitignore") | | [.gitignore](/fuzzballcat/milliForth/blob/master/.gitignore ".gitignore") | | | +| [LICENSE](/fuzzballcat/milliForth/blob/master/LICENSE "LICENSE") | | [LICENSE](/fuzzballcat/milliForth/blob/master/LICENSE "LICENSE") | | | +| [README.md](/fuzzballcat/milliForth/blob/master/README.md "README.md") | | [README.md](/fuzzballcat/milliForth/blob/master/README.md "README.md") | | | +| [bf.FORTH](/fuzzballcat/milliForth/blob/master/bf.FORTH "bf.FORTH") | | [bf.FORTH](/fuzzballcat/milliForth/blob/master/bf.FORTH "bf.FORTH") | | | +| [hello\_world.FORTH](/fuzzballcat/milliForth/blob/master/hello_world.FORTH "hello_world.FORTH") | | [hello\_world.FORTH](/fuzzballcat/milliForth/blob/master/hello_world.FORTH "hello_world.FORTH") | | | +| [makefile](/fuzzballcat/milliForth/blob/master/makefile "makefile") | | [makefile](/fuzzballcat/milliForth/blob/master/makefile "makefile") | | | +| [py\_autotype.py](/fuzzballcat/milliForth/blob/master/py_autotype.py "py_autotype.py") | | [py\_autotype.py](/fuzzballcat/milliForth/blob/master/py_autotype.py "py_autotype.py") | | | +| [sector.asm](/fuzzballcat/milliForth/blob/master/sector.asm "sector.asm") | | [sector.asm](/fuzzballcat/milliForth/blob/master/sector.asm "sector.asm") | | | +| [sector.bin](/fuzzballcat/milliForth/blob/master/sector.bin "sector.bin") | | [sector.bin](/fuzzballcat/milliForth/blob/master/sector.bin "sector.bin") | | | +| View all files | | | + +## Repository files navigation + +* [README](#) +* [MIT license](#) + +# milliForth + +A FORTH in 336 bytes — the smallest real programming language ever, as of yet. + +[![milliFORTH_justhelloworld](https://private-user-images.githubusercontent.com/57006511/280563430-ef3d48cf-1581-4574-8625-8d97b00acaca.gif?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NzE1MzU2MzMsIm5iZiI6MTc3MTUzNTMzMywicGF0aCI6Ii81NzAwNjUxMS8yODA1NjM0MzAtZWYzZDQ4Y2YtMTU4MS00NTc0LTg2MjUtOGQ5N2IwMGFjYWNhLmdpZj9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNjAyMTklMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYwMjE5VDIxMDg1M1omWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTcxNDY0NDE3Y2Y5ZDJlNzZjODJmMzg3Y2UxOTc0YzZkMmRkNTAxYzlhNjlmMzY0M2QwNTI1ZmFlNWZmN2I3MzcmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.i685Rg4zicP8T5zIc3OkurV6p1baueZnnnr_PEWah3c)](https://private-user-images.githubusercontent.com/57006511/280563430-ef3d48cf-1581-4574-8625-8d97b00acaca.gif?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NzE1MzU2MzMsIm5iZiI6MTc3MTUzNTMzMywicGF0aCI6Ii81NzAwNjUxMS8yODA1NjM0MzAtZWYzZDQ4Y2YtMTU4MS00NTc0LTg2MjUtOGQ5N2IwMGFjYWNhLmdpZj9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNjAyMTklMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYwMjE5VDIxMDg1M1omWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTcxNDY0NDE3Y2Y5ZDJlNzZjODJmMzg3Y2UxOTc0YzZkMmRkNTAxYzlhNjlmMzY0M2QwNTI1ZmFlNWZmN2I3MzcmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.i685Rg4zicP8T5zIc3OkurV6p1baueZnnnr_PEWah3c) +*The code in the above gif, that of [an older version of] `hello_world.FORTH`, is a modified version of the hello world program used by sectorFORTH (see below)* + +## bytes? + +Yes, bytes. This is a FORTH so small it fits in a 512-byte boot sector. This isn't new — sectorFORTH[1](#user-content-fn-1-d37e1f81f2eea8c6e7bde869760db32c) successfully fit a FORTH within the boot sector. However, milliFORTH appears to be *the smallest* "real" programming language implementation ever, beating out sectorLISP[2](#user-content-fn-2-d37e1f81f2eea8c6e7bde869760db32c), a mind-blowing 436 byte implementation of LISP, by 96 bytes. ("real" excludes esolangs and other non-production languages - for example, the sectorLISP author's implementation of BF is just 99 bytes, but it clearly isn't used to any serious capacity.) It's now even smaller thanks to some really neat suggestions! + +## Is it turing-complete? + +Yes! This project now includes `bf.FORTH`, a compliant brainfuck interpreter, to illlustrate that this is truly a real language. + +## Language + +sectorFORTH[1](#user-content-fn-1-d37e1f81f2eea8c6e7bde869760db32c) was an extensive guide throughout the process of implementing milliFORTH, and milliFORTH's design actually converged on sectorFORTH unintentionally in a few areas. That said, the language implemented is intentionally very similar, being the 'minimal FORTH'. + +FORTH itself will not be explained here (prior understanding assumed). Being so small, milliFORTH contains just a handful of words: + +| Word | Signature | Function | +| --- | --- | --- | +| `@` | `( addr -- value )` | Get a value at an address | +| `!` | `( value addr -- )` | Store a value at an address | +| `sp@` | `( -- sp )` | Get pointer to top of the data stack | +| `rp@` | `( -- rp )` | Get pointer to top of the return stack | +| `0#` | `( value -- flag )` | Check if a value does not equal zero (-1 = TRUE, 0 = FALSE) | +| `+` | `( a b -- a+b )` | Sum two numbers | +| `nand` | `( a b -- aNANDb )` | NAND two numbers | +| `exit` | `( r:addr -- )` | Pop from the return stack, resume execution at the popped address | +| `key` | `( -- key )` | Read a keystroke | +| `emit` | `( char -- )` | Print out an ASCII character | +| `s@` | `( -- s@ )` | The "state struct" pointer. The cells of this struct are, in order: * `state`: The state of the interpreter (0 = compile words, 1 = execute words) * `>in`: Pointer to the current offset into the terminal input buffer * `latest`: The pointer to the most recent dictionary space * `here`: The pointer to the next available space in the dictionary | + +On a fundamental level, milliFORTH the same FORTH as implemented by sectorFORTH, with a few modifications: + +* All of the interpreter state words are bundled into a single struct (`s@`). +* Words don't get hidden while you are defining them. This doesn't really hinder your actual ability to write programs, but rather makes it possible to hang the interpreter if you do something wrong in this respect. +* There's no `tib` (terminal input buffer) word, because `tib` always starts at `0x0000`, so you can just use `>in` and don't need to add anything to it. +* In the small (production) version, the delete key doesn't work. I think this is fair since sectorLISP doesn't handle backspace either; even if you add it back, milliFORTH is still smaller by a few bytes. +* Error handling is even sparser. Successful input results in nothing (no familiar `ok.`). Erroneous input prints an extra blank line between the previous input and the next prompt. + +## Use + +sector.bin is an assembled binary of sector.asm. You can run it using `make emulate`, which invokes (and thus requires) `qemu-system-i386`, or by using any emulator of your choice. + +Alternatively, `make` will reassemble sector.asm, then run the above qemu emulator. + +Additionally, you can run an example file easily by running `make runfile file=SOURCE_CODE`. Try out `make runfile file=hello_world.FORTH` or `make runfile file=bf.FORTH`! *NOTE: Files run this way currently do not accept user input from stdin, as the file itself is being piped to qemu. Fix coming shortly.* + +`make sizecheck` is a utility which assembles sector.asm into sector.bin and then lists out the size of sector.bin for you. Note that this automatically removes the padding from the .bin (as a working bootloader must be exactly 512 bytes). + +## References + +## Footnotes + +1. The immensely inspirational sectorForth, to which much credit is due: . [↩](#user-content-fnref-1-d37e1f81f2eea8c6e7bde869760db32c) [↩2](#user-content-fnref-1-2-d37e1f81f2eea8c6e7bde869760db32c) +2. Mind-blowing sectorLISP: , . [↩](#user-content-fnref-2-d37e1f81f2eea8c6e7bde869760db32c) + +## About + +A FORTH in 340 bytes — the smallest real programming language ever as of yet. + +### Resources + +[Readme](#readme-ov-file) + +### License + +[MIT license](#MIT-1-ov-file) + +### Uh oh! + +There was an error while loading. Please reload this page. + +[Activity](/fuzzballcat/milliForth/activity) + +### Stars + +[**623** +stars](/fuzzballcat/milliForth/stargazers) + +### Watchers + +[**10** +watching](/fuzzballcat/milliForth/watchers) + +### Forks + +[**28** +forks](/fuzzballcat/milliForth/forks) + +[Report repository](/contact/report-content?content_url=https%3A%2F%2Fgithub.com%2Ffuzzballcat%2FmilliForth&report=fuzzballcat+%28user%29) + +## [Releases](/fuzzballcat/milliForth/releases) + +No releases published + +## [Packages 0](/users/fuzzballcat/packages?repo_name=milliForth) + +No packages published + +## [Contributors 2](/fuzzballcat/milliForth/graphs/contributors) + +* [![@fuzzballcat](https://avatars.githubusercontent.com/u/57006511?s=64&v=4)](https://github.com/fuzzballcat) + + [**fuzzballcat**](https://github.com/fuzzballcat) +* [![@peterferrie](https://avatars.githubusercontent.com/u/7152307?s=64&v=4)](https://github.com/peterferrie) + + [**peterferrie** + Peter Ferrie](https://github.com/peterferrie) + +## Languages + +* [Forth + 53.5%](/fuzzballcat/milliForth/search?l=forth) +* [Assembly + 34.9%](/fuzzballcat/milliForth/search?l=assembly) +* [Makefile + 6.8%](/fuzzballcat/milliForth/search?l=makefile) +* [Python + 4.8%](/fuzzballcat/milliForth/search?l=python) + +## Footer + +© 2026 GitHub, Inc. + +### Footer navigation + +* [Terms](https://docs.github.com/site-policy/github-terms/github-terms-of-service) +* [Privacy](https://docs.github.com/site-policy/privacy-policies/github-privacy-statement) +* [Security](https://github.com/security) +* [Status](https://www.githubstatus.com/) +* [Community](https://github.community/) +* [Docs](https://docs.github.com/) +* [Contact](https://support.github.com?tags=dotcom-footer) +* Manage cookies +* Do not share my personal information + + + +You can’t perform that action at this time. \ No newline at end of file diff --git a/references/ForthNotes/pforth.md b/references/ForthNotes/pforth.md new file mode 100644 index 0000000..1ed6d80 --- /dev/null +++ b/references/ForthNotes/pforth.md @@ -0,0 +1,543 @@ +# pforth + +**Source:** https://github.com/philburk/pforth + +GitHub - philburk/pforth: Portable Forth in C + + + +[Skip to content](#start-of-content) + + + + + + + + + + + + + +## Navigation Menu + +Toggle navigation + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2Fphilburk%2Fpforth) + +Appearance settings + +* Platform + + + AI CODE CREATION + - [GitHub CopilotWrite better code with AI](https://github.com/features/copilot) + - [GitHub SparkBuild and deploy intelligent apps](https://github.com/features/spark) + - [GitHub ModelsManage and compare prompts](https://github.com/features/models) + - [MCP RegistryNewIntegrate external tools](https://github.com/mcp) + + DEVELOPER WORKFLOWS + - [ActionsAutomate any workflow](https://github.com/features/actions) + - [CodespacesInstant dev environments](https://github.com/features/codespaces) + - [IssuesPlan and track work](https://github.com/features/issues) + - [Code ReviewManage code changes](https://github.com/features/code-review) + + APPLICATION SECURITY + - [GitHub Advanced SecurityFind and fix vulnerabilities](https://github.com/security/advanced-security) + - [Code securitySecure your code as you build](https://github.com/security/advanced-security/code-security) + - [Secret protectionStop leaks before they start](https://github.com/security/advanced-security/secret-protection) + + EXPLORE + - [Why GitHub](https://github.com/why-github) + - [Documentation](https://docs.github.com) + - [Blog](https://github.blog) + - [Changelog](https://github.blog/changelog) + - [Marketplace](https://github.com/marketplace) + + [View all features](https://github.com/features) +* Solutions + + + BY COMPANY SIZE + - [Enterprises](https://github.com/enterprise) + - [Small and medium teams](https://github.com/team) + - [Startups](https://github.com/enterprise/startups) + - [Nonprofits](https://github.com/solutions/industry/nonprofits) + + BY USE CASE + - [App Modernization](https://github.com/solutions/use-case/app-modernization) + - [DevSecOps](https://github.com/solutions/use-case/devsecops) + - [DevOps](https://github.com/solutions/use-case/devops) + - [CI/CD](https://github.com/solutions/use-case/ci-cd) + - [View all use cases](https://github.com/solutions/use-case) + + BY INDUSTRY + - [Healthcare](https://github.com/solutions/industry/healthcare) + - [Financial services](https://github.com/solutions/industry/financial-services) + - [Manufacturing](https://github.com/solutions/industry/manufacturing) + - [Government](https://github.com/solutions/industry/government) + - [View all industries](https://github.com/solutions/industry) + + [View all solutions](https://github.com/solutions) +* Resources + + + EXPLORE BY TOPIC + - [AI](https://github.com/resources/articles?topic=ai) + - [Software Development](https://github.com/resources/articles?topic=software-development) + - [DevOps](https://github.com/resources/articles?topic=devops) + - [Security](https://github.com/resources/articles?topic=security) + - [View all topics](https://github.com/resources/articles) + + EXPLORE BY TYPE + - [Customer stories](https://github.com/customer-stories) + - [Events & webinars](https://github.com/resources/events) + - [Ebooks & reports](https://github.com/resources/whitepapers) + - [Business insights](https://github.com/solutions/executive-insights) + - [GitHub Skills](https://skills.github.com) + + SUPPORT & SERVICES + - [Documentation](https://docs.github.com) + - [Customer support](https://support.github.com) + - [Community forum](https://github.com/orgs/community/discussions) + - [Trust center](https://github.com/trust-center) + - [Partners](https://github.com/partners) +* Open Source + + + COMMUNITY + - [GitHub SponsorsFund open source developers](https://github.com/sponsors) + + PROGRAMS + - [Security Lab](https://securitylab.github.com) + - [Maintainer Community](https://maintainers.github.com) + - [Accelerator](https://github.com/accelerator) + - [Archive Program](https://archiveprogram.github.com) + + REPOSITORIES + - [Topics](https://github.com/topics) + - [Trending](https://github.com/trending) + - [Collections](https://github.com/collections) +* Enterprise + + + ENTERPRISE SOLUTIONS + - [Enterprise platformAI-powered developer platform](https://github.com/enterprise) + + AVAILABLE ADD-ONS + - [GitHub Advanced SecurityEnterprise-grade security features](https://github.com/security/advanced-security) + - [Copilot for BusinessEnterprise-grade AI features](https://github.com/features/copilot/copilot-business) + - [Premium SupportEnterprise-grade 24/7 support](https://github.com/premium-support) +* [Pricing](https://github.com/pricing) + +Search or jump to... + + +# Search code, repositories, users, issues, pull requests... + +Search + +Clear + +[Search syntax tips](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax) + +# Provide feedback + +We read every piece of feedback, and take your input very seriously. + + +Include my email address so I can be contacted + +Cancel + Submit feedback + + + + + +# Saved searches + +## Use saved searches to filter your results more quickly + +Name + +Query + +To see all available qualifiers, see our [documentation](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax). + +Cancel + Create saved search + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2Fphilburk%2Fpforth) + +[Sign up](/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E&source=header-repo&source_repo=philburk%2Fpforth) + +Appearance settings + +Resetting focus + +You signed in with another tab or window. Reload to refresh your session. +You signed out in another tab or window. Reload to refresh your session. +You switched accounts on another tab or window. Reload to refresh your session. + + + +Dismiss alert + +{{ message }} + +[philburk](/philburk) +/ +**[pforth](/philburk/pforth)** +Public + +* [Notifications](/login?return_to=%2Fphilburk%2Fpforth) You must be signed in to change notification settings +* [Fork + 114](/login?return_to=%2Fphilburk%2Fpforth) +* [Star + 684](/login?return_to=%2Fphilburk%2Fpforth) + +Portable Forth in C + +### License + +[0BSD license](/philburk/pforth/blob/master/license.txt) + +[684 +stars](/philburk/pforth/stargazers) [114 +forks](/philburk/pforth/forks) [Branches](/philburk/pforth/branches) [Tags](/philburk/pforth/tags) [Activity](/philburk/pforth/activity) + +[Star](/login?return_to=%2Fphilburk%2Fpforth) + +[Notifications](/login?return_to=%2Fphilburk%2Fpforth) You must be signed in to change notification settings + +* [Code](/philburk/pforth) +* [Issues + 26](/philburk/pforth/issues) +* [Pull requests + 5](/philburk/pforth/pulls) +* [Discussions](/philburk/pforth/discussions) +* [Actions](/philburk/pforth/actions) +* [Projects + 0](/philburk/pforth/projects) +* [Wiki](/philburk/pforth/wiki) +* [Security + 0](/philburk/pforth/security) +* [Insights](/philburk/pforth/pulse) + +Additional navigation options + + +* [Code](/philburk/pforth) +* [Issues](/philburk/pforth/issues) +* [Pull requests](/philburk/pforth/pulls) +* [Discussions](/philburk/pforth/discussions) +* [Actions](/philburk/pforth/actions) +* [Projects](/philburk/pforth/projects) +* [Wiki](/philburk/pforth/wiki) +* [Security](/philburk/pforth/security) +* [Insights](/philburk/pforth/pulse) + +# philburk/pforth + +master + +[Branches](/philburk/pforth/branches)[Tags](/philburk/pforth/tags) + +Go to file + +Code + +Open more actions menu + +## Folders and files + +| Name | | Name | Last commit message | Last commit date | +| --- | --- | --- | --- | --- | +| Latest commit History[219 Commits](/philburk/pforth/commits/master/) 219 Commits | | | +| [.github/workflows](/philburk/pforth/tree/master/.github/workflows "This path skips through empty directories") | | [.github/workflows](/philburk/pforth/tree/master/.github/workflows "This path skips through empty directories") | | | +| [csrc](/philburk/pforth/tree/master/csrc "csrc") | | [csrc](/philburk/pforth/tree/master/csrc "csrc") | | | +| [fth](/philburk/pforth/tree/master/fth "fth") | | [fth](/philburk/pforth/tree/master/fth "fth") | | | +| [platforms](/philburk/pforth/tree/master/platforms "platforms") | | [platforms](/philburk/pforth/tree/master/platforms "platforms") | | | +| [.gitattributes](/philburk/pforth/blob/master/.gitattributes ".gitattributes") | | [.gitattributes](/philburk/pforth/blob/master/.gitattributes ".gitattributes") | | | +| [.gitignore](/philburk/pforth/blob/master/.gitignore ".gitignore") | | [.gitignore](/philburk/pforth/blob/master/.gitignore ".gitignore") | | | +| [.travis.yml](/philburk/pforth/blob/master/.travis.yml ".travis.yml") | | [.travis.yml](/philburk/pforth/blob/master/.travis.yml ".travis.yml") | | | +| [CMakeLists.txt](/philburk/pforth/blob/master/CMakeLists.txt "CMakeLists.txt") | | [CMakeLists.txt](/philburk/pforth/blob/master/CMakeLists.txt "CMakeLists.txt") | | | +| [README.md](/philburk/pforth/blob/master/README.md "README.md") | | [README.md](/philburk/pforth/blob/master/README.md "README.md") | | | +| [RELEASES.md](/philburk/pforth/blob/master/RELEASES.md "RELEASES.md") | | [RELEASES.md](/philburk/pforth/blob/master/RELEASES.md "RELEASES.md") | | | +| [license.txt](/philburk/pforth/blob/master/license.txt "license.txt") | | [license.txt](/philburk/pforth/blob/master/license.txt "license.txt") | | | +| View all files | | | + +## Repository files navigation + +* [README](#) +* [License](#) + +# PForth - a Portable ANS-like Forth written in ANSI 'C' + +by Phil Burk +with Larry Polansky, David Rosenboom and Darren Gibbs. +Support for 64-bit cells by Aleksej Saushev. + +Portable Forth written in 'C' for most 32 and 64-bit platforms. + +PForth is written in 'C' and can be easily ported to new 32 and 64-bit platforms. +It only needs character input and output functions to operate and, therefore, does not require an operating system. +This makes it handy for bringing up and testing embedded systems. + +PForth also works on desktops including Windows, Mac and Linux and supports command line history. +This lets you develop hardware tests on a desktop before trying them on your embedded system. +But pForth is not a rich and friendly desktop programming environment. +There are no GUI tools for developing desktop applications. PForth is lean and mean and optimized for portability. + +PForth has a tool for compiling code on a desktop, then exporting the dictionary in big or little endian format as 'C' source code. +This lets you compile tests for an embedded system that does not have file I/O. + +PForth is based on ANSI-Forth but is not 100% compatible. + +Code for pForth is maintained on GitHub at: + +Documentation for pForth at: + +To report bugs or request features please file a GitHub Issue. + +For questions or general discussion please use the pForth forum at: + + +## LEGAL NOTICE + +Permission to use, copy, modify, and/or distribute this +software for any purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL +THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING +FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF +CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +## Contents of SDK + +``` +platforms - tools for building pForth on various platforms +platforms/unix - Makefile for unix + +csrc - pForth kernel in ANSI 'C' +csrc/pf_main.c - main() application for a standalone Forth +csrc/stdio - I/O code using basic stdio for generic platforms +csrc/posix - I/O code for Posix platform +csrc/win32 - I/O code for basic WIN32 platform +csrc/win32_console - I/O code for WIN32 console that supports command line history + +fth - Forth code +fth/util - utility functions +``` + +## How to Build pForth + +Building pForth involves two steps: + +1. building the C based Forth kernel +2. building the Forth dictionary file using: ./pforth -i system.fth +3. optional build of standalone executable with built-in dictionary + +We have provided build scripts to simplify this process. + +On Unix and MacOS using Makefile: + +``` +cd platforms/unix +make all +./pforth_standalone +``` + +For more details, see the [Wiki](https://github.com/philburk/pforth/wiki/Compiling-on-Unix) +Please note that this can help with other platforms as well, see platforms/zig-crossbuild/ for an example. + +Using CMake: + +``` +cmake . +make +cd fth +./pforth_standalone +``` + +For embedded systems, see the pForth reference manual at: + + + +## How to Run pForth + +To run the all-in-one pForth enter: + +``` +./pforth_standalone +``` + +OR, to run using the dictionary file, enter: + +``` +./pforth +``` + +Quick check of Forth: + +``` +3 4 + . +words +bye +``` + +To compile source code files use: + +``` +INCLUDE filename +``` + +To create a custom dictionary enter in pForth: + +``` +c" newfilename.dic" SAVE-FORTH +``` + +The name must end in ".dic". + +To run PForth with the new dictionary enter in the shell: + +``` +pforth -dnewfilename.dic +``` + +To run PForth and automatically include a forth file: +pforth myprogram.fth + +## How to Test pForth + +PForth comes with a small test suite. To test the Core words, +you can use the coretest developed by John Hayes. + +On Unix and MacOS using Makefile: + +``` +cd platforms/unix +make test +``` + +Using CMake: + +``` +cmake . +make +cd fth +./pforth +include tester.fth +include coretest.fth +``` + +To run the other tests, enter: + +``` +pforth t_corex.fth +pforth t_strings.fth +pforth t_locals.fth +pforth t_alloc.fth +``` + +They will report the number of tests that pass or fail. + +You can also test pForth kernel without loading a dictionary using option "-i". +Only the primitive words defined in C will be available. +This might be necessary if the dictionary can't be built. + +``` +./pforth -i +3 4 + . +23 77 swap .s +loadsys +``` + +## About + +Portable Forth in C + +### Topics + +[c](/topics/c "Topic: c") +[forth](/topics/forth "Topic: forth") + +### Resources + +[Readme](#readme-ov-file) + +### License + +[0BSD license](#0BSD-1-ov-file) + +### Uh oh! + +There was an error while loading. Please reload this page. + +[Activity](/philburk/pforth/activity) + +### Stars + +[**684** +stars](/philburk/pforth/stargazers) + +### Watchers + +[**42** +watching](/philburk/pforth/watchers) + +### Forks + +[**114** +forks](/philburk/pforth/forks) + +[Report repository](/contact/report-content?content_url=https%3A%2F%2Fgithub.com%2Fphilburk%2Fpforth&report=philburk+%28user%29) + +## [Releases 2](/philburk/pforth/releases) + +[v2.0.1 + +Latest + +Jan 9, 2023](/philburk/pforth/releases/tag/v2.0.1) + +[+ 1 release](/philburk/pforth/releases) + +## [Packages 0](/users/philburk/packages?repo_name=pforth) + +No packages published + +### Uh oh! + +There was an error while loading. Please reload this page. + +## [Contributors 17](/philburk/pforth/graphs/contributors) + +### Uh oh! + +There was an error while loading. Please reload this page. + +[+ 3 contributors](/philburk/pforth/graphs/contributors) + +## Languages + +* [C + 51.6%](/philburk/pforth/search?l=c) +* [Forth + 43.7%](/philburk/pforth/search?l=forth) +* [Makefile + 3.7%](/philburk/pforth/search?l=makefile) +* Other + 1.0% + +## Footer + +© 2026 GitHub, Inc. + +### Footer navigation + +* [Terms](https://docs.github.com/site-policy/github-terms/github-terms-of-service) +* [Privacy](https://docs.github.com/site-policy/privacy-policies/github-privacy-statement) +* [Security](https://github.com/security) +* [Status](https://www.githubstatus.com/) +* [Community](https://github.community/) +* [Docs](https://docs.github.com/) +* [Contact](https://support.github.com?tags=dotcom-footer) +* Manage cookies +* Do not share my personal information + + + +You can’t perform that action at this time. \ No newline at end of file diff --git a/references/ForthNotes/zForth.md b/references/ForthNotes/zForth.md new file mode 100644 index 0000000..369ba1b --- /dev/null +++ b/references/ForthNotes/zForth.md @@ -0,0 +1,590 @@ +# zForth + +**Source:** https://github.com/zevv/zForth + +GitHub - zevv/zForth: zForth: tiny, embeddable, flexible, compact Forth scripting language for embedded systems + + + +[Skip to content](#start-of-content) + + + + + + + + + + + + + +## Navigation Menu + +Toggle navigation + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2Fzevv%2FzForth) + +Appearance settings + +* Platform + + + AI CODE CREATION + - [GitHub CopilotWrite better code with AI](https://github.com/features/copilot) + - [GitHub SparkBuild and deploy intelligent apps](https://github.com/features/spark) + - [GitHub ModelsManage and compare prompts](https://github.com/features/models) + - [MCP RegistryNewIntegrate external tools](https://github.com/mcp) + + DEVELOPER WORKFLOWS + - [ActionsAutomate any workflow](https://github.com/features/actions) + - [CodespacesInstant dev environments](https://github.com/features/codespaces) + - [IssuesPlan and track work](https://github.com/features/issues) + - [Code ReviewManage code changes](https://github.com/features/code-review) + + APPLICATION SECURITY + - [GitHub Advanced SecurityFind and fix vulnerabilities](https://github.com/security/advanced-security) + - [Code securitySecure your code as you build](https://github.com/security/advanced-security/code-security) + - [Secret protectionStop leaks before they start](https://github.com/security/advanced-security/secret-protection) + + EXPLORE + - [Why GitHub](https://github.com/why-github) + - [Documentation](https://docs.github.com) + - [Blog](https://github.blog) + - [Changelog](https://github.blog/changelog) + - [Marketplace](https://github.com/marketplace) + + [View all features](https://github.com/features) +* Solutions + + + BY COMPANY SIZE + - [Enterprises](https://github.com/enterprise) + - [Small and medium teams](https://github.com/team) + - [Startups](https://github.com/enterprise/startups) + - [Nonprofits](https://github.com/solutions/industry/nonprofits) + + BY USE CASE + - [App Modernization](https://github.com/solutions/use-case/app-modernization) + - [DevSecOps](https://github.com/solutions/use-case/devsecops) + - [DevOps](https://github.com/solutions/use-case/devops) + - [CI/CD](https://github.com/solutions/use-case/ci-cd) + - [View all use cases](https://github.com/solutions/use-case) + + BY INDUSTRY + - [Healthcare](https://github.com/solutions/industry/healthcare) + - [Financial services](https://github.com/solutions/industry/financial-services) + - [Manufacturing](https://github.com/solutions/industry/manufacturing) + - [Government](https://github.com/solutions/industry/government) + - [View all industries](https://github.com/solutions/industry) + + [View all solutions](https://github.com/solutions) +* Resources + + + EXPLORE BY TOPIC + - [AI](https://github.com/resources/articles?topic=ai) + - [Software Development](https://github.com/resources/articles?topic=software-development) + - [DevOps](https://github.com/resources/articles?topic=devops) + - [Security](https://github.com/resources/articles?topic=security) + - [View all topics](https://github.com/resources/articles) + + EXPLORE BY TYPE + - [Customer stories](https://github.com/customer-stories) + - [Events & webinars](https://github.com/resources/events) + - [Ebooks & reports](https://github.com/resources/whitepapers) + - [Business insights](https://github.com/solutions/executive-insights) + - [GitHub Skills](https://skills.github.com) + + SUPPORT & SERVICES + - [Documentation](https://docs.github.com) + - [Customer support](https://support.github.com) + - [Community forum](https://github.com/orgs/community/discussions) + - [Trust center](https://github.com/trust-center) + - [Partners](https://github.com/partners) +* Open Source + + + COMMUNITY + - [GitHub SponsorsFund open source developers](https://github.com/sponsors) + + PROGRAMS + - [Security Lab](https://securitylab.github.com) + - [Maintainer Community](https://maintainers.github.com) + - [Accelerator](https://github.com/accelerator) + - [Archive Program](https://archiveprogram.github.com) + + REPOSITORIES + - [Topics](https://github.com/topics) + - [Trending](https://github.com/trending) + - [Collections](https://github.com/collections) +* Enterprise + + + ENTERPRISE SOLUTIONS + - [Enterprise platformAI-powered developer platform](https://github.com/enterprise) + + AVAILABLE ADD-ONS + - [GitHub Advanced SecurityEnterprise-grade security features](https://github.com/security/advanced-security) + - [Copilot for BusinessEnterprise-grade AI features](https://github.com/features/copilot/copilot-business) + - [Premium SupportEnterprise-grade 24/7 support](https://github.com/premium-support) +* [Pricing](https://github.com/pricing) + +Search or jump to... + + +# Search code, repositories, users, issues, pull requests... + +Search + +Clear + +[Search syntax tips](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax) + +# Provide feedback + +We read every piece of feedback, and take your input very seriously. + + +Include my email address so I can be contacted + +Cancel + Submit feedback + + + + + +# Saved searches + +## Use saved searches to filter your results more quickly + +Name + +Query + +To see all available qualifiers, see our [documentation](https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax). + +Cancel + Create saved search + +[Sign in](/login?return_to=https%3A%2F%2Fgithub.com%2Fzevv%2FzForth) + +[Sign up](/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E&source=header-repo&source_repo=zevv%2FzForth) + +Appearance settings + +Resetting focus + +You signed in with another tab or window. Reload to refresh your session. +You signed out in another tab or window. Reload to refresh your session. +You switched accounts on another tab or window. Reload to refresh your session. + + + +Dismiss alert + +{{ message }} + +[zevv](/zevv) +/ +**[zForth](/zevv/zForth)** +Public + +* [Notifications](/login?return_to=%2Fzevv%2FzForth) You must be signed in to change notification settings +* [Fork + 57](/login?return_to=%2Fzevv%2FzForth) +* [Star + 408](/login?return_to=%2Fzevv%2FzForth) + +zForth: tiny, embeddable, flexible, compact Forth scripting language for embedded systems + +### License + +[MIT license](/zevv/zForth/blob/master/LICENSE) + +[408 +stars](/zevv/zForth/stargazers) [57 +forks](/zevv/zForth/forks) [Branches](/zevv/zForth/branches) [Tags](/zevv/zForth/tags) [Activity](/zevv/zForth/activity) + +[Star](/login?return_to=%2Fzevv%2FzForth) + +[Notifications](/login?return_to=%2Fzevv%2FzForth) You must be signed in to change notification settings + +* [Code](/zevv/zForth) +* [Issues + 1](/zevv/zForth/issues) +* [Pull requests + 2](/zevv/zForth/pulls) +* [Actions](/zevv/zForth/actions) +* [Projects + 0](/zevv/zForth/projects) +* [Security + 0](/zevv/zForth/security) +* [Insights](/zevv/zForth/pulse) + +Additional navigation options + + +* [Code](/zevv/zForth) +* [Issues](/zevv/zForth/issues) +* [Pull requests](/zevv/zForth/pulls) +* [Actions](/zevv/zForth/actions) +* [Projects](/zevv/zForth/projects) +* [Security](/zevv/zForth/security) +* [Insights](/zevv/zForth/pulse) + +# zevv/zForth + +master + +[Branches](/zevv/zForth/branches)[Tags](/zevv/zForth/tags) + +Go to file + +Code + +Open more actions menu + +## Folders and files + +| Name | | Name | Last commit message | Last commit date | +| --- | --- | --- | --- | --- | +| Latest commit History[141 Commits](/zevv/zForth/commits/master/) 141 Commits | | | +| [.github/workflows](/zevv/zForth/tree/master/.github/workflows "This path skips through empty directories") | | [.github/workflows](/zevv/zForth/tree/master/.github/workflows "This path skips through empty directories") | | | +| [forth](/zevv/zForth/tree/master/forth "forth") | | [forth](/zevv/zForth/tree/master/forth "forth") | | | +| [src](/zevv/zForth/tree/master/src "src") | | [src](/zevv/zForth/tree/master/src "src") | | | +| [.gitattributes](/zevv/zForth/blob/master/.gitattributes ".gitattributes") | | [.gitattributes](/zevv/zForth/blob/master/.gitattributes ".gitattributes") | | | +| [.gitignore](/zevv/zForth/blob/master/.gitignore ".gitignore") | | [.gitignore](/zevv/zForth/blob/master/.gitignore ".gitignore") | | | +| [LICENSE](/zevv/zForth/blob/master/LICENSE "LICENSE") | | [LICENSE](/zevv/zForth/blob/master/LICENSE "LICENSE") | | | +| [Makefile](/zevv/zForth/blob/master/Makefile "Makefile") | | [Makefile](/zevv/zForth/blob/master/Makefile "Makefile") | | | +| [README.md](/zevv/zForth/blob/master/README.md "README.md") | | [README.md](/zevv/zForth/blob/master/README.md "README.md") | | | +| [zforth.png](/zevv/zForth/blob/master/zforth.png "zforth.png") | | [zforth.png](/zevv/zForth/blob/master/zforth.png "zforth.png") | | | +| View all files | | | + +## Repository files navigation + +* [README](#) +* [MIT license](#) + +[![zForth](/zevv/zForth/raw/master/zforth.png)](/zevv/zForth/blob/master/zforth.png) + +# zForth + +From Wikipedia: + +*A Forth environment combines the compiler with an interactive shell, where +the user defines and runs subroutines called words. Words can be tested, +redefined, and debugged as the source is entered without recompiling or +restarting the whole program. All syntactic elements, including variables +and basic operators are defined as words. Forth environments vary in how the +resulting program is stored, but ideally running the program has the same +effect as manually re-entering the source.* + +zForth is yet another Forth, but with some special features not found in most +other forths. Note that zForth was written for engineers, not for language +purists or Forth aficionados. Its main intention is to be a lightweight +scripting language for extending embedded applications on small +microprocessors. It is not particularly fast, but should be easy to integrate +on any platform with a few kB's of ROM and RAM. + +Also note that zForth is just *a* forth, but does not specifically implement or +care about any of the standards like ANS Forth - the kernel might or might not +behave as the standard, and the current standard library is rather limited. + +For a lot of programmers Forth seems to belong to the domain of alien +languages: it does not look like any mainstream language most people encounter, +and is built on a number of philosophies that takes some time to get used to. +Still, it is one of the more efficient ways of bringing a interpreter and +compiler to a platform with restricted resources. + +Some of zForth's highlights: + +* **Small dictionary**: instead of relying on a fixed cell size, the dictionary is + written in variable length cells: small and common numbers take less space + then larger, resulting in 30% to 50% space saving +* **Portable**: zForth is written in 100% ANSI C, and runs on virtually all + operating systems and all architectures. Tested on x86 Linux/Win32/MS-DOS + (Turbo-C 1.0!), x86\_64, ARM, ARM thumb, MIPS, Atmel AVR and the 8051. +* **Small footprint**: the kernel C code compiles to about 3 or 4 kB of machine + code, depending on the architecture and chosen cell data types. +* **Support for multiple instances**: The compiler and VM state is stored in a + struct, allowing multiple instances of zForth to run in parallel. +* **Tracing**: zForth is able to show a nice trace of what it is doing under the + hood, see below for an example. +* **VM**: Implemented as a small virtual machine: not the fastest, but safe and + flexible. Instead of having direct access to host memory, the forth VM memory + is abstracted, allowing proper boundary checking on memory accesses and stack + operations. +* **Flexible data types**: at compile time the user is free to choose what C data + type should be used for the dictionary and the stacks. zForth supports signed + integer sizes from 16 to 128 bit, but also works seamlessly with floating point + types like float and double (or even the C99 'complex' type!) +* **Ease interfacing**: calling C code from forth is easy through a host system + call primitive, and code has access to the stack for exchanging data between + Forth and C. Calling forth from C is easy, just one function to evaluate forth + code. + +# Source layout + +``` +./forth : core zforth library and various snippets and examples +./src/zforth : zfort core source; embed these into your program +./src/linux : example linux application +./src/atmega8 : example AVR atmega8 application +``` + +# Usage + +zForth consists of only two files: zforth.c and zforth.h. Add both to your +project and call `zf_init()` and `zf_bootstrap()` during initialisation. Read +forth statements from a file or terminal and pass the strings to `zf_eval()` to +interpret, compile and run the code. Check the embedded documentation in +`zforth.h` for details. + +`zforth.c` depends on a number preprocessor constants for configuration which +you can choose to fit your needs. Documentation is included in the file +`zfconf.h`. + +A demo application for running zForth in linux is provided here, simply run `make` +to build. + +To start zForth and load the core forth code, run: + +``` +./src/linux/zforth forth/core.zf +``` + +And zForth will welcome you with the startup message: + +``` +Welcome to zForth, 786 bytes used +``` + +zForth is now ready to use. Try some of the following: + +Adding one and one or calculate the 144 squared: + +``` +1 1 + . +144 dup * . +``` + +Print the sine of 10 numbers between 0 and PI + +``` +: pi 3.141592654 ; +: demo pi 0 do i sin . pi 10 / loop+ ; +demo +``` + +Load and run the demo Mandelbrot fractal: + +``` +include forth/mandel.zf + +.........................----..................... +.....................----+--...................... +.......................--*-....................... +........................- --.....--............... +...........----........--%---------............... +............-------------#---------............... +.............------------ ---------............... +.............------------ ---------............... +..............---------o o--------.............. +..............---------o =---------------------- +.............----o-oo =o-=--------------.. +...........-------# *------------..... +........--------=-= o-=--------....... +....--------------= =---------........ +......-------------+ +---------......... +.......-------------=# %=-----------........ +........--------=- -=--------....... +.......------= =------------ +.....---o = = =------- +--------- -------- +---------o+ +o-------- +---------o =-------- +---=#=# = = #=#=-- +---= =-- +-=- + + == +o---oo*== -=*=o--- +---------= =-------- +---------#= =#-------- +-----------% %------.... +---...----= =% - #= =----..... +.......---=o----* =+*---------*+- *----o=----..... +........--------------------------------------.... +``` + +# Tracing + +zForth can write verbose traces of the code it is compiling and running. To enable +tracing, run `./zforth` with the `-t` argument. Tracing can be enabled at run time +by writing `1` in the `trace` variable: + +``` +1 trace ! +``` + +Make sure the feature ZF\_ENABLE\_TRACING is enabled in zfconf.h to compile in +tracing support. + +The following symbols are used: + +* stack operations are prefixed with a double arrow, `«` means pop, `»` means push. + for operations on the return stack the arrow is prefixed with an `r` +* the current word being executed is shown in square brackets, the format + is `[/
]` +* lines starting with a + show values being added to the dictionary +* lines starting with a space show the current line being executed, format + `
` +* lines starting with `===` show the creation of a new word + +``` +: square dup * ; +: test 5 square . ; +test +``` + +Executing the word `test`: + +``` +test + +r»0 +[test/0326] + 0326 0001 ┊ (lit) »5 + 0328 031c ┊ square/031c r»810 + 031c 000b ┊ ┊ (dup) «5 »5 »5 + 031d 0007 ┊ ┊ (*) «5 «5 »25 + 031e 0000 ┊ ┊ (exit) r«810 + 032a 0133 ┊ ./0133 r»812 + 0133 0001 ┊ ┊ (lit) »1 + 0135 0019 ┊ ┊ (sys) «1 «25 + 0136 0000 ┊ ┊ (exit) r«812 + 032c 0000 ┊ (exit) r«0 25 +``` + +This is the trace of the definition of the `square` and `test` words + +``` +: square dup * ; + +r»0 +[:/002c] + 002c 0003 ┊ (:) + 002c 0003 ┊ (:) +=== create 'square' ++0313 0006 ¹ ++0314 02eb ² ++0316 0000 s 'square' +=== + 002d 0000 ┊ (exit) r«0 ++031c 000b ¹ +dup ++031d 0007 ¹ +*r»0 +[;/0031] + 0031 0004 ┊ (;) ++031e 0000 ¹ +exit +=== + 0032 0000 ┊ (exit) r«0 + +: test 5 square . ; + +r»0 +[:/002c] + 002c 0003 ┊ (:) + 002c 0003 ┊ (:) +=== create 'test' ++031f 0004 ¹ ++0320 0313 ² ++0322 0000 s 'test' +=== + 002d 0000 ┊ (exit) r«0 ++0326 0001 ¹ +lit ++0327 0005 ¹ ++0328 031c ² +square ++032a 0133 ² +.r»0 +[;/0031] + 0031 0004 ┊ (;) ++032c 0000 ¹ +exit +=== + 0032 0000 ┊ (exit) r«0 +``` + +### Dependencies + +The zForth core itself has no external dependencies, the linux example depends on libreadline-dev. + +## About + +zForth: tiny, embeddable, flexible, compact Forth scripting language for embedded systems + +### Topics + +[scripting-language](/topics/scripting-language "Topic: scripting-language") +[forth](/topics/forth "Topic: forth") + +### Resources + +[Readme](#readme-ov-file) + +### License + +[MIT license](#MIT-1-ov-file) + +### Uh oh! + +There was an error while loading. Please reload this page. + +[Activity](/zevv/zForth/activity) + +### Stars + +[**408** +stars](/zevv/zForth/stargazers) + +### Watchers + +[**21** +watching](/zevv/zForth/watchers) + +### Forks + +[**57** +forks](/zevv/zForth/forks) + +[Report repository](/contact/report-content?content_url=https%3A%2F%2Fgithub.com%2Fzevv%2FzForth&report=zevv+%28user%29) + +## [Releases](/zevv/zForth/releases) + +No releases published + +## [Packages 0](/users/zevv/packages?repo_name=zForth) + +No packages published + +### Uh oh! + +There was an error while loading. Please reload this page. + +## [Contributors 14](/zevv/zForth/graphs/contributors) + +### Uh oh! + +There was an error while loading. Please reload this page. + +## Languages + +* [C + 81.1%](/zevv/zForth/search?l=c) +* [Forth + 15.7%](/zevv/zForth/search?l=forth) +* [Makefile + 3.2%](/zevv/zForth/search?l=makefile) + +## Footer + +© 2026 GitHub, Inc. + +### Footer navigation + +* [Terms](https://docs.github.com/site-policy/github-terms/github-terms-of-service) +* [Privacy](https://docs.github.com/site-policy/privacy-policies/github-privacy-statement) +* [Security](https://github.com/security) +* [Status](https://www.githubstatus.com/) +* [Community](https://github.community/) +* [Docs](https://docs.github.com/) +* [Contact](https://support.github.com?tags=dotcom-footer) +* Manage cookies +* Do not share my personal information + + + +You can’t perform that action at this time. \ No newline at end of file diff --git a/references/Neokineogfx - 4th And Beyond - Transcript.txt b/references/Neokineogfx - 4th And Beyond - Transcript.txt new file mode 100644 index 0000000..30df218 --- /dev/null +++ b/references/Neokineogfx - 4th And Beyond - Transcript.txt @@ -0,0 +1,684 @@ +0:00 +Welcome to fourth and beyond. My name is Timothy Lis and this is the Neoenographics channel. This talk will +0:05 +not be covering standard fourth. Instead, this talk is going to start with the beyond fourth part. Let's +0:10 +begin. What if we didn't actually need Visual Studio? What if we didn't need a separate debugger or even to C language? +0:17 +Let's start with the first principle. Question everything until the problem is truly minimized. Begin by peeling the +0:22 +onion of computing, passing through APIs, compilers, languages, code generation, and so on. Search the +0:28 +alternative realities until greatness is found. And we'll start by rewinding time and learning from the past masters. +0:34 +We'll start with the most basic interactive computer tool, the calculator. My favorite calculator was +0:39 +the HP48. That's what I used. HP48 used reverse Polish notation. This made it +0:45 +very easy to type in math and get answers. You didn't have to mess with parenthesis. The HP48 provided RPL. The +0:53 +later machines provided system RPL which could even assemble machine code with offline tools for the HP48. People even +1:00 +built games for these machines. Now what if we were to take that calculator and evolve it to something more forthlike? +1:06 +We'll start with simple reverse polish notation calculator math. And next we'll introduce a dictionary. The dictionary +1:12 +will point to positions on the data stack. For instance, in the second line here, we have a red word 4k. That 4k +1:19 +word would be pointing to the next stack item. Next stack item we can do some evaluations to come up with the number +1:25 +for. So we type in 1024 then type in four and then type in multiply. And now +1:30 +we have 4096. So the 4k word would point to 4096. This is a basic way of doing a +1:37 +variable. The next thing we could do is we could actually build numbers which represent op codes or multiple numbers +1:43 +which represent op codes. Things that we could actually execute and have do an operation on the machine. So in this +1:50 +case there's drop and drop points to a number on the data stack which disassembles to add ESI, -4 and then +1:59 +returns. Drop would basically drop the top item from the data stack where ESI is pointing to the data stack. And now +2:06 +once we have this in our dictionary, we can continue to do things on the stack and we can use drop if we want to. So +2:12 +now we could write 4k which would pull that number 4096 that we had uh put in +2:18 +the dictionary prior and then do one and then do two and then a plus which would create a three and then we execute drop +2:25 +which will drop the three leaving 4096 on the stack and thus now we've created something quite powerful. So in this +2:31 +context the gold numbers get pushed on the stack the gold words get its value in the dictionary pushed on the stack. +2:37 +The green words are getting a value in the dictionary executed and the red word is putting a pointer to the top of stack +2:44 +in the actual word in the dictionary. In some respects, you can see how this starts to create extremely powerful +2:49 +system. So a fourthlike machine is really the ultimate form of tool building. The language is free form. The +2:55 +dictionary defines words. These words become the language you program in. It enables any kind of factoring of a +3:01 +problem. The language, the assembler, the compiler, the linker, the editor, the debugger, they're all defined in the +3:06 +source itself. And these systems can be tiny. Tiny as in the whole thing fits in the cache. In my opinion, a fourthleike +3:13 +machine would have been a better option than basic for a boot language. A lot of people learn basics cuz they could type +3:18 +in a program from a book, say on the C64. But imagine if it was a fourth machine instead. You have something that +3:25 +runs significantly faster and is significantly more powerful. The irony here is later Apple, IBM, and Sun, they +3:32 +actually used a fourth-based open firmware, but few had programmed in it at the time. So, let's look back at +3:38 +Fourth. Fourth was invented in 1986 by Chuck Moore or Charles Moore. Chuck +3:43 +later focused on building multiple stackbased processors. He used his own VLSI CAD system, Okad for layout and +3:51 +simulation, and these were written in his language. Early it was a sourceless language and later it got moved to color +3:57 +forth from my understanding. The images below show some of the actual editor and simulation. These are from the ultra +4:04 +technology site. What's impressive here is that these were dramatically small systems and yet they were used to do +4:10 +some of the most complicated stuff that humans can do which is design chips that actually got fabricated and got used. +4:16 +Chuck Moore's color forth I think is worth learning about. It's an example of real system minimization. 32-bit reverse +4:23 +Polish notation language. It provides a data stack which gives you memory to work with and note code is compiled onto +4:30 +the data stack too. It provides dictionaries which map a name to a value. The value is typically a 32-bit +4:36 +number or 32-bit address to the source or data stack. The dictionaries are searched in a linear order from last to +4:42 +first defined word. There are two main dictionaries. The fourth one which is used for words to call and macro which +4:49 +is a secondary dictionary used for words that do code generation. Source is broken up into blocks. There is no file +4:56 +system. Inside the source blocks are 32-bit tokens. These tokens contain 28 +5:02 +bits of compressed name or string and four bits of tag. The tag controls how +5:07 +to interpret the source token. Let's go through some of the tags. The white tag means an ignored word. Yellow tag means +5:13 +execute. If it's a number, we append the number on the data stack. If it's a word, we look up the word in the +5:20 +dictionary and then we call the word. If it's a red word, we're doing a definition. We're setting the word in +5:26 +the dictionary to the top of the stack or a pointer to the top of the stack. If it's green, we're compiling. If it's a +5:32 +green number, we're appending a push number onto the stack. Effectively, +5:37 +we're encoding the code, the machine language that would push that number. If +5:43 +we compile a word, if we're in the macro dictionary, we're first going to look up the word in the macro dictionary, and if +5:50 +it exists, we're going to call it. Otherwise, we look up the word in the fourth dictionary, and we append a call +5:56 +to the word itself. Cyan or blue is used to defer words execution. So, we'll look +6:02 +up the word in the macro dictionary, and we will append a call to the word. This way, we can make words that do code +6:09 +generation, that call other words that do code generation. Next is the variable. Variable is used by magenta. +6:16 +Variable sets the dictionary value to the word to it the pointer to the next source token in the source code as it's +6:23 +being evaluated. And then anytime we have a yellow to green transition, we pop a number off the stack and then we +6:30 +append a push number to the data stack, which basically means we're taking a number and we're turning it back into a +6:36 +program, a program that pushes the number. So if we look at some of the blocks inside color forth and notice +6:43 +this one here, block 18. This starts doing the code generation. So it'll push 24 and then it'll load which will take +6:50 +block 24 and actually bring in all the code generation macros. And then the next one 26 load will bring in more +6:56 +quote generation macros from block 26. If you look at block 24, it starts with +7:02 +executing macro which moves us to making defines in the macro dictionary. The +7:07 +first define is swap. Then it does 168B and then it does a two comma. The two +7:13 +comma pushes two bytes onto the data stack. The next one is C28B +7:20 +0689 followed by a comma. The comma pushes four bytes onto the data stack. So +7:26 +effectively what we're doing is we're pushing some bytes to actually create code onto the data stack where swap is +7:33 +defined. And if we disassemble these six bytes, we get move edx, dword ptr esi. +7:40 +So effectively we're pulling from the stack into edx and the stack in this case is the data stack of fourth. The +7:46 +next one is move dword ptr esi, eax. So we're pushing the existing cacheed value +7:53 +of the top of the stack which is in eax. We're pushing that we're putting that on the stack. And then we move edx into eax +8:01 +which is taking the old second value on the stack and pushing it into the cache value which is the top of the stack in +8:07 +color fourth. So basically this whole block is defining op codes that are used for code generation. So let's fast way +8:14 +forward now and let's just critique color forth. Perhaps one of the biggest critiques of color forth is that it's a +8:20 +mismatch to hardware today. It's a stackbased machine and modern machines are register based. Modern machines have +8:26 +really deep pipelines. They don't deal with branching well and fourth is extremely branch friendly. The +8:31 +interpreter costs that you have to do per token are pretty high. We have to branch based on tag. Dictionaries are +8:38 +searched from last added to first added with no hashing or any acceleration. +8:43 +Most commonly every time you do an interpreting after branching on the tag you're going to branch again to another +8:49 +thing which is going to be a mispredicted address. And note, you got an average of 16 clock stall on say Zen +8:55 +2 for a branch misprediction. Of course, the logical response here is if you only have a tiny amount of code, there's no +9:01 +reason it has to be super fast. After all, the most important optimization is doing less total work. For example, an +9:07 +F1 car driving a,000 m is going to be substantially slower than a turtle walking one foot. Well, towards the end +9:14 +of 2025, Chuck Moore said, "I think fate is trying to tell me it's time to move on." +9:20 +And this is in response to Windows auto updating and then breaking his color forth. But I ask, should we actually +9:27 +move on? The world did move on to mass hardware and software complexity, but +9:32 +perhaps Chuck's way of thinking is actually exactly what is needed today. How about a localized reboot? We have a +9:38 +lot of FBGA based systems showing up, and I'm hopeful that they're getting commercial success, but these are +9:44 +effectively all emulators of prior hardware. What about doing something new? Maybe forthinking could be a part +9:49 +of that. What about Neo vintage parallel machines? After all, forthinking is ideal for a fixed hardware platform. +9:56 +FPGA based hardware emulators focus mostly on the serial thinking era. But this is actually a universal speed of +10:02 +light barrier. These product lines are going to stop around N64 and so on because after that serial CPU clock +10:09 +rates cannot be FPGA emulated. But FPGAAS have crazy parallel DSP capabilities. Perhaps we should design +10:16 +for DSPs as the processors and then provide radically parallel but medium +10:21 +clock machines and these are things we could actually drive with fourth style language. There is a challenge of +10:28 +minimalism in a maximalism world. Software is a problem but the root is hardware complexity growth. For example, +10:34 +our DNA4 ISA guide is almost 4 megabytes in itself. And try writing a modern USBC +10:40 +controller driver yourself. And yet, even with all of today's hardware complexity, I still believe fourth +10:45 +inspired software can be quite useful. I spent a lot of time exploring the permutation space around fourth, +10:51 +specifically more around color fourth and seeing what variations could be made. One way I varied from fourth was +10:57 +in an opin coding. I don't necessarily stick with a stackbased language. Sometimes I treat the register file more +11:03 +like a closer highly aliased memory. Sometimes you use a stackbased language however as a macro language say for a +11:10 +native hardware assembler and sometimes I mix a stackbased language with something that has arguments for +11:16 +instance having a word have arguments after the word and still use it like a stackbased language. So I have used +11:22 +forthlike things in commercial products. One example is I used to run a photography business and a software +11:28 +development business and the old business website that I ran in my prior life doing landscape photography was +11:35 +actually generated by a fourthlike language running server side which generated all the HTML pages. It made +11:41 +managing a huge website actually practical. Now I had to use the wayback machine to find this. So sorry in +11:47 +advance for the broken images. And of course, I had a different last name then from a broken marriage, but that's another story. But I did a lot more +11:54 +forthlike things beyond this one. One of the things that got me right away was, of course, the lure to optimize. For +12:00 +example, color forth uses this Huffman style encoding for its names and its tokens. Remember, a source token is a +12:08 +T-bit tag, typically T is 4, with an S bit string where S is 28 bits. We could +12:14 +do a better job of encoding the the 28 bits. For instance, we could split that full number range by some initial +12:20 +probability table of the first character. And then we could split each of those ranges by say a one or two +12:27 +character predictor. And then we train this thing on a giant dictionary. And of course, you're going to have to use +12:32 +lookup tables. And of course, the memory used for the predictor is going to be greater than the rest of this whole +12:38 +system combined. And yeah, it worked. It provided some very interesting stuff. You could put a number in and it would +12:45 +basically BSU a string out which was pretty cool. This journey I think was +12:50 +useful. I learned a lot of things in the process like where to optimize and where not to optimize. Next question is well +12:57 +should we hash or should we not hash? It turns out that a compressed string like in the prior slide is actually a great +13:04 +hash function. I can simply mask off some number of the least significant bits and that becomes my hash function. +13:10 +or for hashing. I always dislike the issue of only part using cache lines. That's not very efficient. And of +13:16 +course, we can try to fix that too. We can check a very tiny hash table first and size that hash table to stay in the +13:23 +cache. And then if we miss on that, we can go to the fulls size one, the one that's going to have pretty poor +13:28 +utilization on cache lines. And assuming lots of reuse, that tiny hash table is going to keep high cache utilization. +13:35 +However, now we've done two stages of optimization. But we really should start asking why are we hashing and why are we +13:42 +compressed? Why are we doing all this overhead? Why do we just not direct map? After all, if we're depending on an +13:48 +editor, we could just direct map or perhaps just address into the dictionary directly. Then we can split off the T- +13:54 +bit tag and the S bit string for editor use. And that can start simplifying things so we don't have all this +14:00 +complexity in the first place. The next thing we can do if we're interpreting is we can solve the problem of branch +14:06 +misses. Normally with an interpreter, you would evaluate the word and then you'd return back to the interpreter. +14:12 +That interpreter would look up another word and do another branch. But that branch would always be mispredicted. One +14:17 +option is we could just fold the interpreter back into the words themselves. But of course, we got to +14:23 +make that interpreter really small, otherwise we're doing a lot of code duplication. Can imagine if you have a +14:28 +thousand words, you're going to embed the interpreter a thousand times. So there's a lot of different ways we can +14:33 +design an interpreter down into a few bytes. For instance, this one is a 8 byte interpreter. This is one I've never +14:40 +used. Actually can do better than 8 bytes and I'll show you that towards the end. So of course the best way to learn +14:45 +is to build stuff. So I built many color forth inspired things over the years. Some like the one to the right here. I +14:52 +got distracted with editor graphics effectively making something extremely nice to use and very pretty. This one +14:58 +was cool. The dictionary I moved into the source itself and I did a direct +15:03 +binary editor. So this thing you'd actually see the cache lines and you're effectively doing a hex editor that uses +15:10 +tags to tell you some contextual information and then each line of course +15:15 +has uh a comment on the top followed by the data on the bottom. And of course I use different fonts because sometimes +15:22 +I'm packing a full number with sometimes I'm packing characters and so on in comments. It was a relatively +15:28 +complicated system, but actually simple when you think about it in the context of what we build today. One of the first +15:35 +questions to ask yourself is whether you want to work with text source versus a binary editor. So sometimes I would work +15:41 +with text source. In order to make this work well, I would have a prefix character in front of every word, which +15:47 +basically would be the tag. And it would also enable me to use very simple syntax +15:52 +coloring inside say nano. Most of these I built they were more like a fourth macro language that was used to create a +15:58 +binary. So what I would do and for instance what you can see on the right is I would define something that would +16:03 +enable me to build the ELF header and then after the ELF header was was built I would actually write the assembler in +16:10 +the source code and then finish off the rest of the binary. These kind of languages are extremely small and the +16:16 +whole thing is in a say a few kilobyte binary. The other thing I do with these is I bootstrap. So the first time I +16:23 +might write the thing in C and then C would evaluate and then I'd run the interpreter in C and then later I would +16:30 +write the rewrite the interpreter inside the source code and then compile that. Now I would be bootstrapped into the +16:36 +language itself. And so by doing that I could actually compare my C code to the the code I wrote inside my own language. +16:43 +And of course I'm faster inside my own language than in the C code. And of course, I'm a lot smaller in the binary +16:48 +as well because I have a very very small ELF header in the binary that I generated compared to the one that say +16:55 +GCC would generate. I built some custom x86 operating systems. It was fun to +17:00 +build custom VGA fonts and of course mess with the pallet entries to improve the initial colors. I did lots of +17:07 +different fourth variations, but typically these projects just got blocked in the mass complexity of +17:13 +today's hardware. Meaning once you get down to the point where you want to say draw something on the screen other than +17:18 +using say the old DOSs VGA frame buffer or if you want to start using input you start needing a USB driver and then all +17:26 +of a sudden everything turns into a nightmare. One thing I mentioned before is it's very nice to use a forthlike language as a macro assembly language. +17:33 +Traditional assembly language you do something like say add ecx edx and then +17:39 +colon advanced pointer by stride. The later part here is heavily commented. In fact, typically assembly is mostly +17:47 +comments otherwise a human can't really understand it. When you start using a fourthlike language as a macro +17:53 +assembler, a lot of times what you do is instead of using the register number, you would just put the register number +17:59 +inside another word and then use that word. So now you start self-documenting. And if you had common blocks of say +18:06 +multiple instructions, you would start defining those in some other word and then you start factoring. And this way +18:11 +you self-document everything and it becomes actually very easy to understand, a lot more easy to +18:17 +understand than say assembler. And on top of this, of course, you can also put comments, but you don't typically need +18:22 +as many. So if we were to look back at some of the lessons of all these projects, I think the key thing is that when your OS is an editor, is a hyper +18:30 +calculator, is a debugger, is a hex editor, you end up with this interactive +18:35 +instant iteration software development and that part is wonderful. The fourth style of thinking keeps source small +18:41 +enough so that it's approachable by a single developer and that I think is very important. You basically build out +18:46 +your own tools for the exactly the way you like to think and that's where its true beauty lies. Others like Onot have +18:53 +built full systems, meaning he is running something that actually works +18:58 +with Vulcan and generates Spear V. So there is another option and that is going sourceless. No language, no +19:05 +assembler. The code is the data or the data is the code. Chuck's okay was a +19:10 +source of inspiration. I've only read about this, but it did send me down a spiral of trying various ideas that are +19:17 +related to what I read. So when we think about sourceless programming, it's best to just work from the opposite extreme. +19:24 +Start with say a hex editor and then work towards what we would need to make that practical for code generation. So I +19:30 +think of a binary as an array of say n 32-bit words and then we could have another thing which is an annotation +19:37 +which is an array of n64-bit words. The annotation could provide a tag which gives context to the data or could +19:44 +control how the editor manipulates the data. The annotation can also provide an 8 character text annotation for the +19:50 +individual binary words which serves as documentation for what the word is for. So part of sourceless programming is how +19:56 +do you generate code and with fourth hand assembling words is actually relatively easy because you don't have +20:02 +that many you don't have that many low-level operations if you're doing a stackbased machine. I invented something +20:09 +called x68 which I'm planning to do a separate talk on. It's a subset of x64 +20:15 +which works with op codes at 32-bit granularity only. Note that x664 +20:21 +supports ignored prefixes which can pad op codes out to 32-bit. And we also have +20:27 +multibite noops which can align the ends too. And we can do things like adding in rex prefixes when we don't need it to +20:34 +again pad out to 32-bit. So for instance, if we wanted to do a 32-bit instruction for return, we might put the +20:41 +return, which is a C3, and then pad the rest of it with a three byte noop. And +20:47 +once we've built this 32-bit return number, which we can an we annotate with, we can insert a return anywhere +20:55 +just by copying and inserting this word in the source code. And later, if we built different op codes and say they +21:00 +were multi-word, we can just use find and replace to change those. Effectively, we're removing compilation +21:05 +into some edit time operations. One of the nice things about being at 32-bit +21:10 +granularity for the instruction is that the 32-bit immediates are now at 32-bit granularity as well. And so now we can +21:18 +just make it so that we have a tag which says this is an op code and a tag which says this is say an immediate hex value. +21:26 +And we could show them separately with different colors. In this case, I have code for setting ESI to a 32-bit +21:32 +immediate. And you'll notice that this one is using the 3E ignored DS segment +21:38 +selector prefix to pad out the op code to 32-bit. And then after that, we have a silly number which we're setting into +21:45 +ESI. That silly number is 1 2 3 4 5 6 7 8 in hex. So it's very easy to do inline +21:51 +data this way. Of course, calls and jumps are another question. And we have an easy solution for that one as well. +21:57 +In x8664, column jump uses a 32-bit relative immediate and that relative is +22:03 +relative to the end of the op code, not the beginning. And so if we want to make an editor support this, we would just +22:09 +tag the relative branch address as a word that is a relative address. And +22:15 +then when we start editing text or say editing the words inside the binary and +22:21 +say we move things around, we would just relink all of the words in the binary that have a relative address. So as code +22:27 +changes, things just get fixed up. And so this effectively solves the call and the jump problem. It's very easy to make +22:34 +an editor which repatches everything. Conditional branches, you might think those are complicated, but they're +22:40 +actually not. Conditional branches is just an 8-bit relative branch address. And so when I make words on these, I +22:46 +would say jump unequal minus two, which would jump unequal to the word that is +22:51 +two words before this one or say j minus 4 for four words minus and so on. And so +22:58 +I can just build a few of these constructs and change the op codes around whenever I need say a jump on +23:03 +zero or so on. Nice thing about this is now you no longer have to label things because you just go and count and when +23:10 +you move it around it's all relative. So you don't need to do any patching. If you want to add more stuff in your loop, +23:16 +you just change, you know, the op code a little. Another option is the editor could have a built-in 32-bit word +23:22 +assembly disassembly. Meaning I could use a shorthand for registers and op codes. And the shorthand that I would +23:28 +use would be labeling the registers starting with G. So that zero through F +23:34 +could be used for hex. So this is an example of how you might want to do it. So in this case I have h + at i08 +23:42 +which is going to disassemble to add rcx quadward pointer rdx + 0x8 +23:51 +which we can shorthand very easily and so I could have an editor that would show you either the disassembly or show +23:57 +the shorthand instruction for it and that would aid in the understanding and ability to insert stuff without using +24:04 +separate tools. So, I did build this sourceless system once in the real. It was back when I was building tiny +24:09 +x86-based operating systems. I built the editor as a console program. So, this +24:15 +would run in Linux and I would build binaries in that console program and +24:20 +then I would use an x86 emulator running in Linux to actually test them. And this was a pretty liberating experience. I +24:27 +learned a lot from there. On the right, I'm showing one of the boot sectors of one of the examples running in the +24:33 +editor. Note with sourceless programming we could extend the annotation quite a bit. For instance, we could have tables +24:38 +that map register numbers to strings and then for each cache line we could have an index of a table. In this way, +24:45 +registers could be automatically annotated. For instance, if register 2 is set to position and register 4 is set +24:52 +to velocity. If we had add R2, comma, R4, we could just put in add POSOS comma +24:58 +velocity, right? And that would make it a lot easier to understand automatically. We could also extend and +25:04 +have each cache line have a string as well. And this way we could automatically annotate say a label. The +25:10 +first word maybe could be the label and the rest of the string could be used for a comment. So there's a lot of ways to +25:16 +do sources programming where we just provide annotation tools to actually make it a practical experience. So let's +25:22 +talk about some of the variations, the pros and cons. The easiest way to perhaps start this would be to work with +25:28 +text source. And usually with text source, you're going to use prefix words for the tag. For instance, slash for +25:35 +comment, colon for define, maybe tick for execute. This does have the slowest runtime, however, because you have a +25:41 +character granularity loop. It does have a benefit in that for you to get started, there is no editor that you +25:47 +have to write. You can use an external text editor and you can do easy custom syntax coloring. You're going to be very +25:53 +easy to understand and to work in. However, I think you're missing a big piece if you go down this path, and that +25:58 +is you don't get any live interaction or debugging. You're basically depending on the fast compile times of your custom +26:04 +language and the fast load times of whatever program you're doing to try to get you in that iteration loop. And you +26:11 +can work this way. I've done it many times, but the experience is nowhere near as good as doing the full +26:16 +interactive one with a binary editor. I guess one of the other benefits here is you got very easy code portability. +26:23 +There's no binary files, just text files. You can copy and paste as you will. Of course, the next jump up from +26:28 +that is going to binary source. This would be middle performance runtime because now you're working at a word +26:34 +granularity inside your interpreter. You have portability because you have code generation that can adapt to the system. +26:41 +Meaning, as you interpret your code, you can look at what's underlying in the hardware and you can make changes to how +26:46 +the code is generated at runtime. You can build just what bits of an assembler are needed. You don't need to build out +26:52 +everything like you would with say a disassembler tool or an assembler tool. So for instance with x86 I don't +26:58 +actually generate much of the ice. I only use a very very tiny subset. You do have to write the binary editor and that +27:04 +can be a lot of work and sometimes that presents a problem with bootstrapping because you don't have the language to +27:10 +write the editor in from the beginning. So you have to write the editor in some other language and then in that language +27:15 +write the editor again and then you know complete the bootstrapping process. The +27:21 +one benefit here is you get interactive development debug from the beginning and also now your source code shows how +27:28 +constructs are built instead of just showing the result as you would get with say source free. One interesting thing +27:33 +about fourth with binary source and this this concept that you can rebuild source +27:39 +code at runtime at any point in execution is now you can start compiling things you load into machine code and +27:46 +then you don't have to run all the overhead. Basically you can bake things into machine code anytime at edit time +27:52 +and that's a very powerful feature. Now if we go and look at sourceless programming there's a bunch of pros and +27:58 +cons. The one pro is that it's the fastest runtime. It's a true noop. You can build things that are highly tightly +28:04 +optimized for a platform and they're as optimized as you could possibly get. You +28:09 +do however lose capacity for showing how constants came to be and you lose the +28:15 +capability of adapting to what the machine is. You can work around this however you can make smaller embedded +28:20 +constants that you write into modified bit fields and instructions but it's +28:26 +really taking a little too far in terms of complexity. You do need to write an editor which includes an opc code +28:31 +assembler and disassembler potentially if you want to go down that route. And if you're going to do CPU and GPU, +28:37 +that's a lot of work. It can be very complicated when systems include auto annotation. For instance, if you want to +28:44 +type in say a string readable register and then have it go and figure out what register number that is. I guess the +28:50 +primary disadvantage here is that there's no possibility for portability. You have a raw binary editor. And today +28:57 +we have a problem with GPUs. Steam Deck is RDNA 2, Steam Machine's RDNA 3, and +29:04 +who knows the future may be RDNA 4 or five or six. Problem with this is that when the ISA changes across those +29:10 +chipsets, that can result in different instruction sizing. So you can't just do +29:16 +simple source free. For example, Mimg in RDNA 2 has a different size than V image +29:22 +in RDNA4. And that's all due to the ISA changes. So if you do sourceful +29:27 +programming, you can port through a compile step. However, source list, you would need to do something else. And +29:33 +perhaps that is just rewriting chipset specific versions of all the shaders, but that may be something that you don't +29:39 +want to do. So thinking ahead on the Steam OS/ Linux project that I'm working on, effectively I'm building an AMD only +29:46 +solution. I don't really have a name for this project, so I'm going to call it fifth. I think for fifth I want a mix of +29:52 +various fourth style concepts and perhaps the best mix would be the best +29:57 +of both worlds. A fast highle interpreter that's intent for doing GPU code generation where I need chipset +30:04 +portability at runtime mixed with low-level sourceless words for the CPU +30:09 +side for simple x664 where I don't need portability at this time. Since this is +30:15 +for Linux, we should think about what we can do on Linux that we might not be able to do on Windows today. We first +30:21 +start thinking about execution. The Linux x8664 ABI when you're running +30:26 +without address space randomization, the execution starts at a fixed 4 megabytes +30:31 +in and you can still do this today if you compile without FPIE. Also note, +30:37 +even if you did get position independent execution, you could effectively just map the where you want your fixed +30:44 +position to be and then just start execution there and just ignore the original mapping that they threw you at. +30:50 +Another thing we can do is we can use page maps. And if we look at Steam Deck, we'll notice that dirty pages get +30:56 +written about as fast as every 30 seconds, which is an important number. Means it won't be overwriting too fast. +31:03 +So, let's look at something we can do on Linux that we're not allowed to do on Windows anymore. The self-modifying +31:08 +binary. The idea here is that we have a cart file. The cart file represents the ROM. Actually, in this case, it's a RAM +31:15 +because we're going to be modifying it. So, first we would execute the cart file. And when the cart file runs, it +31:21 +would realize that it's not aback. And then it would copy itself to a backup file, cart.back, and then it would +31:28 +launch cart. And then exit. This cart.back back would realize that it is the backup file and then it would map +31:35 +the original file cart at say 6 megabytes in and it would provide that mapping and read write and execute and +31:42 +then afterwards it would map an adjustable zero fill and that would be for when we're doing compilation or when +31:48 +we have data that we don't want to be backed up all the time and after that it would jump to the interpreter and so if +31:54 +we look at the memory mapping we'd have at 4 megabytes we would have say a 4 kilobyte boot loader section +32:01 +And then we would have somewhere say at 6 megabytes we'd have the whole file and then after that we would have the zero +32:07 +fill. And the nice thing about this is we automatically create a backup. We don't have to write any code to save the +32:13 +file because it's going to autosave every 30 seconds. Also the data and code is together and we can make a new +32:19 +version just by copying the file itself. Inside the binary we'd have a specific spot for the size of the file and the +32:25 +size of the zero fill. So the process of doing this execution we can resize when +32:31 +we build the cart.back file very easily. So for source code I'm thinking 32-bit +32:36 +words for words they're going to be direct addresses into the binary and the binary is going to be the dictionary. +32:43 +Makes it quite fast to interpret. The nice thing here is they can be direct addresses because we fix the position. +32:50 +We're not using address base randomization. We'll just fix RSI to the interpreter source position and then all +32:56 +the words will contain the next of the interpreter meaning all the words end in the interpreter itself or fold the +33:02 +interpreter in whatever form they want into their own execution. And by doing this we enable lots of branch predictor +33:10 +slots because each of these interpret end of word interpreters are going to be different branch predictors. So we can +33:17 +actually get this down into five bytes if we want to. We can use the LODs to +33:22 +basically load a word from RSI and then advance RSI and we can use two bytes to +33:29 +look up the value in the dictionary and we can use two bytes later to jump to +33:34 +the address for the next thing to run. So now we've gotten down to a five byte interpreter. Another thing I think I +33:40 +would do for variation is I would make source more free form not strict reverse post notation. In other words, with +33:48 +regular reverse pulse notation, you're going to have words that going to push values onto a stack and therefore your +33:53 +granularity is at the word level. If instead we have arguments, we can fetch +33:59 +a bunch of values off the stack right off the bat and we can look them up in the dictionary in parallel. And now our +34:05 +branch granularity is dropping significantly. Maybe say a factor of maybe two or four depending on what our +34:12 +common argument count is. I think this is a better compromise for when you're doing lots of code generation, which is +34:17 +what we'll be doing on the CPU, mostly GPU code generation. So, for the editor, I'll just do an advanced 32-bit hex +34:24 +editor. I'll split the source into blocks, and then each one of those blocks will be split into subblocks. And +34:31 +the subblock will be source and then some annotation blocks. And so for every +34:37 +source 32-bit source word, I'm going to have uh two I'm going to have say 64-bit +34:42 +of annotation information split across two 32-bit words. And that'll give me eight characters. Each of those +34:49 +characters will be 7 bit. And I'll have an 8bit tag for editor. And the tag will give me the format of the 32-bit value +34:56 +in memory and give me whatever else I want in there. So I can adapt, you know, +35:01 +for whatever I feel like doing in the future. And I can make this pretty uniform because I'll mostly have numbers +35:07 +and then I'll have direct addresses to words inside this. So that's it for now. This is a late welcome to 2026. I used +35:15 +the holiday for some deep thinking, but I think it's time now for some more building. Take care. \ No newline at end of file diff --git a/references/Silicon Valley Forth Interest Group - Metaprogramming VAMP in KYRA, a Next-gen Forth-like language --- Onat Türkçüoğlu -- 2025-04-26.txt b/references/Silicon Valley Forth Interest Group - Metaprogramming VAMP in KYRA, a Next-gen Forth-like language --- Onat Türkçüoğlu -- 2025-04-26.txt new file mode 100644 index 0000000..d7e8dc2 --- /dev/null +++ b/references/Silicon Valley Forth Interest Group - Metaprogramming VAMP in KYRA, a Next-gen Forth-like language --- Onat Türkçüoğlu -- 2025-04-26.txt @@ -0,0 +1,2104 @@ +0:00 +thought I was um I was talking. Sorry. It turns out I I was muted. So, hello. Is is is is the +0:08 +screen readable? If you could make it a little larger, +0:14 +that might be helpful. But yes, we can see it. We can read it. Uh making it a +0:19 +little larger might be a bit difficult now because I had to font. Okay. No +0:25 +worries. On with the show. Okay. Great. Thanks. It's it's fine as it is. +0:30 +Great. Thanks. So, um, hello everybody. My name is Onat and, um, I've been +0:36 +working on this language for the last decade. And, um, what you're looking at +0:42 +is a, um, blockbased for I mean, I'm I'm not +0:48 +actually really like, you know, good at presentations and I haven't really prepared for the talk. So, excuse if if +0:55 +the talk is like a little bit um anyway a train wreck, but let's see. Let's see +1:01 +what happens, you know. So, um the thing is this is actually like a +1:09 +Ford editor that's encoded in another Ford editor that look like um hold up +1:17 +that look like this. So um this is a previous version of of +1:24 +that um editor and this is a text base for it. Um so you can just type anywhere +1:31 +on the screen. This is like just um 4K blocks per screen. um 64 by +1:40 +64 and um text base for takes about 60 +1:46 +milliseconds to compile the editor which you're looking at here. So that's number +1:53 +that you're seeing here. That's like 17 um 8 millisecond. That's the textbased +2:00 +performance like you know when you're um processing text uh to +2:07 +compile and this takes 8.24 24 milliseconds for +2:14 +uh two platforms Windows and Linux and I +2:20 +can I cannot I can say like okay let's um let's see let's yeah it takes four +2:28 +milliseconds per uh platform as you can see here um if I don't compile for Windows +2:36 +and 8.2 two milliseconds for the entire program that's looks like this. +2:45 +So um this is vamp and this is the first series program that I um coded in for +2:53 +that's like um you know beyond a certain complexity that like okay this editor uh +3:01 +that we were looking at um was manageable uh in text based for but to +3:07 +do this in text would have been much more difficult for uh a lot of reasons +3:13 +that we're going to get into and um yeah this this is based on uh a binary +3:19 +encoding which is why this is so fast and it gets translated directly into +3:25 +machine code. So um yeah +3:31 +um let's let's start with like why fort uh is actually not um you know um I mean +3:42 +fort does a lot of stuff right but it's actually still um I'm going to create it +3:48 +as a runtime opinionated language and that means the language is u has a +3:55 +defined runtime which is in the case of forge it's it's a data stack and a uh +4:01 +return stack right and um you know anything that you +4:07 +could configure um per your own for of course um like um you know I I like to +4:16 +have global memory for instance so um the thing is how do you run a fort on +4:23 +on a GPU right because like this program that we're looking here, it also has like shaders and like it's it's actually +4:30 +just compute shaders and um rendering text like this and running Fort on the +4:38 +GPU um in the traditional sense is kind of like impossible because um you have +4:45 +to maintain that stack with registers and it it's it's not that you know it's +4:52 +it's not that good. um versus um +4:57 +like because I mean I I've been I I've been uh programming this for 10 years uh +5:04 +more than 10 years actually and um the thing is it it had to be the most +5:12 +performant language ever also and um the fourth overhead just by this example uh +5:19 +the um 16 like 60 milliseconds versus +5:24 +like 4 milliseconds. That's like for difference between using data stack +5:30 +versus using registers only, right? So this for is uh like the stack is just +5:37 +two uh there's there's only two uh items on the stack. So um and you can see the +5:43 +stack is visible on the top left corner here. Um so you can go anywhere in code +5:49 +and say okay what does the stack look like here um or here for instance it's like um all +5:59 +the instances that this definition is is being called from um the stack is +6:05 +visualized but why why do we need stacks right +6:12 +stacks are there so that we can pass information in a convenient way. +6:17 +Otherwise, we would have to use variables and having to name variables all the time is a lot of well, a lot of +6:24 +bookkeeping that you have to do versus just using stacks, right? And um let's +6:30 +see um I mean this +6:36 +is in instead of using stacks, we can just use global memory. Um, for +6:43 +instance, we don't have to use stacks even at the runtime, but I use stacks at +6:48 +the compile time uh because it makes passing arguments a lot easier. +6:56 +Um, sorry. I'm just scrolling through the code to find like +7:02 +um an interesting place, but cuz cuz this this subject is actually like um uh +7:08 +maybe we should just stay on this screen for a while. Um +7:14 +I because this is like the uh the first screen of of this environment and um +7:22 +there's a bunch of numbers here and um like a structure here. So um in in in my +7:33 +in an old forge I I made there was this um like begin and end definitions like +7:41 +um begin definition and end definition like that versus +7:46 +uh this means the beginning of the definition and end of the previous +7:52 +definition. Right? So you don't have to um remember to close your words, right? +8:00 +Uh the definition closes each definition closes itself or if there's no +8:05 +definition, if there's just space um then that means that's an execution which we're going to get also um you +8:14 +know later. Um so actually this is the perfect place to mention execution. +8:22 +So um I think we have to code in the +8:29 +simplest way and I don't think it involves a lot of abstractions right so +8:36 +um I think we should just code everything in assembly including the language and the editor itself um and +8:44 +how do we write that assembly is um of course we don't have to write it like uh +8:50 +we don't have to write it instruction by instruction Actually, we can use a macro language uh like this for to +8:58 +implement that other fort core if we wanted to or other u language extensions +9:05 +if we wanted to because that's the other point, right? Like it it has to be a foundational language that's um that can +9:13 +last um forever because uh it's it's the simplest that it gets. And um the the +9:21 +design space for that um is like two +9:27 +registers is I think the optimal point because if you have four registers that's a lot of shuffling +9:34 +and most operations are like they they just use two um operands. So two +9:42 +registers for stack size at compile time is enough for a program of this +9:48 +complexity. Oh yeah, I could just open this of course. +9:53 +um for for like the um and um this program is +10:01 +um so I can basically title the screen anyway I want and +10:07 +um it does not use stacks at all like I mean it uses stacks at some places but +10:15 +not in the way that you would think like you know uh there there is no like the stack overhead of like you know uh +10:23 +traditional forge it's all compiled down to assembly because in a way it's all programmed in assembly but you know the +10:30 +assembly is um highle macro uh for style and I got uh basically anywhere uh +10:39 +anywhere I have um like okay there we go +10:45 +uh I have like exact assembly output that I'm interested in for the architecture that +10:51 +I'm compiling compiling to. So, um this is x64 for now, but um you could compile +10:58 +to ARM 64 or any of the microcontrollers or whatever. Um you could use any +11:04 +computer to transpile to any other computer. So as long as you can communicate with that other computer via +11:12 +like sending the compiled code that you just wrote uh I mean that you just generated via execution which is like +11:20 +the um yeah the subject that that I wanted to get to is like we don't have to think +11:28 +code as like some complicated um you know like structure. It's it's +11:36 +just pure execution uh that generates a very simple that +11:42 +maps to very simple assembly and then you execute that code. So you have um +11:48 +exact definitions and simple definitions and the execution is also very efficient +11:53 +and um so a question about your your screen is the um the the color is is is +12:00 +uh highlighting or is there is there some encoding for the coloring? Oh yeah, there is um there's semantics +12:08 +associated with color. It's it's like color for but you know um it's it's +12:14 +compile time color for like I mean color for is as far as I know it's still uh +12:20 +text encoding based which is still uh valid by the way it's like it's just +12:26 +slower and it has some disadvantages also but you might want to do text based +12:31 +color for it instead of like this index based color for so the index based part +12:36 +is there is a dictionary that maps each word to you know each of those words is +12:42 +like I mean I could I could just go to this loop and I could call this like uh loop for instance and it will change +12:49 +everywhere because um it's it's like I see so you're storing you're storing a +12:54 +central index for each for each uh word in the I see interesting exactly exactly +13:00 +and how many how many how big are how how big are each is is each word like +13:06 +how big is the index space um Well, there is 24bit indices because +13:12 +I want to pack each instruction to four bytes. So 24 bits of that four bytes is +13:17 +dedicated to that. But in the next iteration actually I'm going to do four bytes for indices and then I'm going to +13:24 +store one byte tag in a separate block. So you have like I mean this is going to +13:31 +get faster you know this is just back baseline. I see. So so it's so it's it's +13:36 +a index and then a tag. Got it. Got it. Thanks. Yes. Yes. Exactly. And um +13:42 +because if you're if you don't have that index, that means you're hashing and then you had to do that hash lookup +13:49 +which gives you like uh dynamic local context. But I I like global context +13:56 +more than local context because I have exact mappings, you know, exact semantics instead of like, oh, maybe I +14:03 +called this word in a different context. So that word has like a different that +14:08 +word maps to a different cell like different index and like you know that kind of like problems I don't want to +14:14 +have to deal with like with text space but uh like still text base is uh valid +14:21 +in certain context like maybe you want to do I don't know +14:28 +um it's I mean it's it maybe you want to do like free form +14:35 +programming I mean without having to require a complex editor because instead +14:40 +of like having the complexity of text in the language, you've embedded that complexity in the editor. Uh because um +14:48 +you know when you're writing you you're like looking up this um you know word +14:53 +like loop for instance and um that's I'm I'm pulling from this concept that I +14:59 +call the deck. So I have like a deck of cards and I have a bunch of words that are like for these are my walcon words +15:07 +for instance and these are ffmpeg words when I'm like dealing with ffmpeg and like a lot of words now I put in a to-do +15:13 +list to implement later and I just never got around to it's not even like a +15:18 +problem and this is just one encoding right this is not central to the +15:24 +execution this is just for printing this is not the core language so In the +15:30 +future, if you're like doing open source for instance, you you have the option to say like um just ship the source but not +15:39 +the symbols, not this like dictionary part. So um in a sense you still have +15:44 +the source and the numbers and um you know but you can still protect your IP +15:51 +and like you know symbols for instance uh for like I don't know and um there is +15:59 +also the possibility of um embedding this whole thing into the program +16:04 +itself. So the core language is 2 to 4 kilobytes. It's actually should be two +16:11 +kilobytes. I haven't checked recently, but yeah. Um it's it's very simple +16:16 +because what I'm doing is I'm just looking um like I'm just generating a +16:23 +template based like um code so that I can execute it +16:29 +efficiently instead of like having to incur the um interpreter cost, right? So +16:36 +um I mean that's like also happening in this textbased language and that's why +16:42 +it's 16 milliseconds. I mean it's still fast but you know having to hash and +16:48 +having to look up that overhead is like easily like yeah +16:54 +uh easily um yeah eight like 12 milliseconds of cost. How how how do you +17:02 +manage the the index space? Like that's the main thing that's kept me from going down that road is sort of like is there +17:09 +a lot of complexity in managing? Yeah, that was um that grew to be a +17:15 +problem because like um after a while there is just a lot of words and like um +17:21 +so I I solved that via like tags. So I have these 16 uh word scrolls and I can +17:30 +paint them with tags and then I can select tags um over here while a deck. +17:36 +So each of those are like tags. I mean it's it's kind of complex. I'm not going +17:42 +to do four tags in the next iteration. I'm going to do just 16 bit index plus some predefined tags instead like API +17:51 +implementation you know uh that sort of thing like um you know this is not the +17:57 +um end iteration I mean there's a lot of UX improvements +18:03 +uh to be you know to to be imagined right there's to +18:10 +be explored I mean that's that's very exciting about this language is like um +18:15 +it's it's also going to run on Steam Deck and also uh VR and also phones and +18:21 +tablets, right? Um because um why not? We we're not like constrained to the +18:28 +keyboard keyboard anymore. It's it's just like picking up symbols. I mean you +18:33 +could essentially draw on the screen instead of like typing on the keyboard. And you said like how do you manage I +18:39 +mean you can just type words like you know let's say ABC +18:44 +DF I mean you could just uh like define words like this you can move them around +18:52 +um you know and then when you when you insert them into the into the source base then you you you have to use the +18:59 +selection on the left or you you can type you do the lookup at that point to yeah I mean um you can actually I mean +19:07 +you used to be able I mean I I used to be uh I used to just have this +19:12 +dictionary space and now I just type something and if I need like something +19:18 +like uh index for instance index for something I just press control space and +19:24 +that gets redefined wherever uh it gets redefined which is like uh configurable +19:30 +like you know I I want to define index ABC here for instance and then it gets +19:36 +defined here. You're kind of consciously pl managing the index space as you place new add new +19:43 +things. And I I see Yeah. Yeah. I mean, it's it's like you you can move stuff +19:49 +around and the only thing that you have to do is like walk through the whole source and patch, you know, numbers. +19:56 +It's it's simple. I mean the editor is also very simple which is um you know +20:02 +important if you want to import the editor for open source programs like you know you don't have to install 4 GB of +20:09 +Visual Studio like 200 megabytes of PHP or whatever it's just 64 kilobytes of +20:15 +editor if even that like and um you know +20:20 +it's it's portable to anywhere because it's it's so simple. Um so yeah there is +20:28 +a lot of stuff here that makes programming easier which you can see as structure in the code um like um a new +20:37 +syntax for like conditionals and loops and like like this loop for instance how +20:44 +it's implemented is like I can jump I got like um jump to definition right so +20:52 +let me what this loop does is like it increments depth by one and whatever +20:57 +depth is like it's usually zeros as you can see over here it's it's like um and +21:04 +then you plus one that and then you see like oh it's plus one I mean you can +21:10 +just see all the code flowing um at compile time right and that's the stack +21:18 +uh over here and what's interesting about this um +21:24 +Like another interesting thing about this language is like um you should be +21:30 +also able to see the data flow as it's happening at runtime right so that's +21:36 +also possible with with this language so I'm just like iterating through +21:42 +um like okay what what was with play um for instance at setup here when I click +21:50 +previous for instance I want to record like uh this with play uh index, right? +21:57 +Uh so and that shows up over here just by by this um corner. So um that's like +22:06 +68 for instance or um we could +22:12 +say okay let's let's let's for instance run this and then like press like +22:18 +previous or next uh three four times I think I pressed five six okay let's +22:25 +let's count it how many times we pressed so okay so let's see one two three four +22:34 +five six seven here we press seven times and you can see like the data flow as +22:41 +it's happening through runtime um and you know this is the most basic form you could imagine like moving over +22:49 +the mouse and seeing the full data flow which I'm going to implement for the next editor and so on but you know it +22:54 +works um and you can even embed more met metadata there and I mean this is +23:02 +essentially free printf like um you don't even have to type print f you just +23:07 +say like okay what was like hot slot as like this code was running and if I'm +23:14 +like creating some stuff then I'm going to +23:20 +yeah so the hotspot was like 3D for instance like you know or 31 3D +23:31 +3D you know it's it's like it's when when you're debugging it's +23:36 +it's instant visualization which is um all you need essentially for fast +23:43 +debugging the um so for the the the index indexes into some sort of a +23:50 +some sort of like a name table. What's do you have how how is how is that built like is it a fixed fixed sized space for +23:59 +the the names or what how do you manage that piece of oh yeah that's eight bytes +24:04 +per um like cell I mean I I I call them cells uh like they have indices right +24:12 +but they're essentially like uh compile time cells right um and you know you're +24:19 +just defining names here you treat them as memory essentially. Uh, +24:25 +and they're eight bytes per cell. Got it. And when you also but the name you +24:31 +could make like 16 bytes if you want and it doesn't have to be but the definition of the language says that each cell is +24:39 +going to be eight bytes per like you know because that's that's the one that +24:44 +uh you know I think that makes sense because u I mean you could put in type +24:49 +information into eight bytes if you you know um take care of it in many ways. I +24:55 +mean um you don't need 16 bytes I think but 16 bytes names I mean sure maybe if +25:01 +you want to let's see and and is the um um let's see when you when you +25:09 +uh what about for like comments are you how do you +25:18 +right um so comments are um I'm so there's 24 bits of data per instruction +25:25 +on this iteration. So it's three characters. So I can just write comments like this. They're essentially like +25:32 +strings, you know, they're just like encoding the string in in the U bite instead of like using like an external +25:39 +string table. I see. So those are stored direct in instead of Right. Right. I see. Yeah. Because you don't want to you +25:45 +don't want to pollute your your dictionary space with I I see. Yeah. Yeah. I mean you could store it in the +25:50 +dictionary also if you want or you could pull it externally. I mean this language is free form. It's implemented in the +25:57 +Sony. So whatever you want to do, you're free. I mean and um it doesn't have to +26:03 +like I mean um I see like you know um I I I didn't want the language to be +26:11 +like rigid like all the other languages out there. Like Rust for instance is is +26:16 +a very rigid language that says like okay you know what this is the language and like you have to fill out these tax +26:22 +forms and these all rules and if you don't abide we don't even compile your code or whatever like it's it's versus +26:30 +you're free to do whatever you want and um you know it's it's like there's so +26:37 +little abstractions that you can implement your own abstractions or like +26:42 +your own um extensions if if you want. I mean it's +26:48 +it's it's like yeah it's it's super simple compared to like all those +26:53 +runtime opinionated languages that are like um that have to cater to all kinds +26:59 +of um concerns, right? versus um +27:04 +defining like a simple language that can still solve all those problems by being flexible enough by thinking about the +27:12 +output instead of like you know being dogmatic about the runtime right +27:19 +um so yeah I mean +27:24 +um there is let's see let's see um there's a lot to talk +27:32 +about for like you know how to program an assembly and um I mean how to like +27:41 +program an assembly efficiently right um assembly for what for +27:48 +well that's what processor are you on um X64 for for this iteration but that's +27:56 +actually like a great question I mean for what is like it could be ARM 64 also +28:02 +And um the portability is one of the um you know concerns in this like style is +28:10 +like um you know each of like all of this is like programmed in x64 assembly +28:17 +but through these um highle words. So I could replace those highle words for ARM +28:23 +64 or Commodore 64 if I had to and emulate uh somehow. On Commodore X64 I'd +28:31 +had to emulate the registers through dedicated memory. On ARM 64 you have so +28:37 +much registers that emulating is not a problem and you're still like you know +28:43 +um within that register budget. So you're still as fast as like +28:48 +um you know uh as if you had like all those registers. It's it's like it +28:55 +doesn't really cost you to not use registers, right? It's so are you are +29:01 +you wanting to uh release this to to uh others or +29:07 +uh Sure. Um I mean um at some like I think +29:14 +um I'm gonna start a stream soon um where I'm going to build this language +29:21 +uh again and this editor uh again for um +29:26 +all kinds of like different stuff like Steam Deck and VR and you know desktop +29:33 +of course and tablets too. Um so yeah this is like +29:40 +um you know it's it's not ready for prime time. There's a lot of like UX +29:46 +improvements to be made to this whole thing is is like you know the the situation but u as also like a +29:56 +um you know proof of concept for like how fast you could compile and how fast you could run. I mean um and also how +30:05 +expressive uh it is and um how debugable it is, how scalable it is, right? This +30:12 +is like a very um I mean it's it's it +30:18 +takes about thousand times more times to compile this program in C +30:25 +um than in this language. So, and also it's more code in C even +30:33 +though C has like all those pre-ompiled headers for walcon +30:39 +ffmpeg and so on. um because this is a um for instance I'm just going to say +30:46 +like um this is a macro language so I can say +30:53 +div I can just have like say 29 device +30:59 +to say we wk device which means like okay what does it mean it means get swap +31:06 +chain images you know which is which gives you the images for the uh you know +31:13 +for the swap chain. So uh in C I would have to write +31:18 +this as like we can get image swap chain get swap chain +31:25 +images car etc etc um and then I would have to say like +31:31 +um GPU because like it's not global and then device versus just you know just +31:39 +device I mean the difference in usability and +31:44 +also readability is u huge compared to like all those other languages that are +31:50 +bound by um having to be text based right instead of like execution based um +31:57 +you know this have you started uh have you started making a manual or documentation +32:04 +well uh the documentation will be the streams that I'm going to do uh as I built the language and the editor you +32:11 +know that's the documentation that's going to be happening that's it's going to be happening live +32:18 +you know um and it it doesn't even need that much documentation the whole thing +32:24 +is so simple so um the thing is okay let's get to the language semantics +32:29 +right so we said like oops there's a here's a bug that sometimes crashes the +32:35 +editor when I go to the top like you know It's It's a stupid thing, but you +32:41 +know, sometimes it happens. I haven't had the motiv motivation to fix it. So, +32:47 +um anyway, oh yeah, there it happened again. +32:53 +Funny. Think I'm not doing like balance checking, which is like happens when you're programming in assembly. +32:58 +Sometimes you forget to do balance checking on somewhere after some subtracting or whatever which is again +33:06 +um you know dependent on how you program assembly right so okay let's let's read +33:14 +this so this means defining right so I'm defining like call first I seem to lost +33:20 +your screen there uh oh okay +33:26 +you still sharing oh Yeah, I think it's okay. It's back, +33:31 +right? Okay, cool. Thanks. Thanks for reminding. I mean, I I thought we were sharing screen still, but yeah. +33:39 +So, Oh, okay. Okay. I think I I know what happened there. It crashes and then +33:46 +I I quit and then that closes the share. So, after Yeah, if you share just the if +33:52 +you share the whole the whole screen then it'll get then it'll stick. But if you skip share just the one window then +33:58 +when that window goes away it will Yeah. Yeah. I I So um so call is like +34:06 +FF0. So what does FF0 right? Let's see. XX +34:12 +FF0. Oops. Oh yeah. I see FFE0. That's jump to racks, right? Um, +34:21 +so call becomes jump to racks because there's already a return address on the +34:27 +stack. So I don't want to call I just want to jump to the top of the stack like that I want to call. So um it means +34:35 +that we're passing um at every word the top of the stack is going to be racks +34:43 +right and the second item on the stack is going to be RDX. So out at looks like +34:50 +48.92. So that's like exchange RDX racks. So that's a +34:58 +trick actually uh that's occurs um everywhere in this um in this code +35:06 +generation. Before I start the definition, I say exchange racks +35:13 +RDX. So depending on which like +35:19 +um which one you're calling which um like +35:27 +um depending on whether RDX is on top of the stack or whether rax is on top of +35:32 +the stack you call um you know just before or just after exchange RDX +35:39 +racks. So that means that each calls are just single instructions instead of requiring a potential exchange +35:46 +instruction to align the racks and RDX for top of stack, +35:52 +right? So um so yeah, all of this is like extremely efficient and +35:58 +um yeah, I mean this is also like in the definition of the language, right? And all of this is like public domain by the +36:05 +way. Um I'm not going to like you know encumber this like with patents and I +36:10 +ask you not to also like this is just pure foundational stuff relates to like +36:17 +public domain for like public uh you know knowledge. I mean uh as far as I +36:23 +know this is like the most fundamental way of like writing in a um JIT style +36:31 +assembly because um yeah every instruction just compiles +36:36 +to a single instruction right like this um load for instance these green words +36:43 +are like just um load from this cell +36:48 +index um into racks or RDX depending on whether RAX is on top of stack or RDX is +36:55 +on top of stack. So, um, +37:01 +yeah. Does that make sense in terms of like semantics, language +37:07 +semantics? I'm a little little fuzzy on on so you're saying you're just you have +37:13 +a two element stack that you're alternating. Maybe I'm not understanding the what if you could go through the +37:18 +register what what the how you're using each register that would be helpful. Uh, yeah. So um racks and RDX are used for +37:27 +um you know those the it's the stack registers and um like +37:35 +top of the stack and a and a stack pointer or some other arrangement. Oh no, they're they're just those two uh +37:42 +stack items. You know there's only two items on the stack. Got it. Got it. +37:48 +And um you know this compiles move rax 256 and this compiles move rdx 512 and +37:56 +this compiles move racks 1024 you know and uh when it's like when you read this +38:05 +um then you know this becomes top of stack and then you can do another like you know uh write into like salt for +38:13 +example or whatever and you know that's I mean it it works you know um it's just +38:19 +you can do this by just using one bit actually is our racks on top of stack or +38:25 +not that's the one bit that you're interested in like it's it's super efficient +38:34 +um so yeah so sorry still not quite get following it you're saying that the so +38:39 +you're keep you're keeping a single bit to keep track of whether rax or rdx is is the top of stack is that Yes. So then +38:47 +so then you you've got a two and you've got a two element stack basically. Is it? Yes. Exactly. Exactly. Got it. Okay. +38:54 +Yeah. I mean um two element stack because uh four elements gets very um +39:02 +yeah I mean if if you're calling with four elements you have to deal with a lot of permutations to align the stack +39:10 +layout you know as you expected. Um, or maybe you could run like two parallel +39:16 +stacks, but I don't see the point. It just makes everything so much more complex than like just having two items. +39:22 +And most of the time, I mean, two two items is just enough for um all the +39:28 +things that you might want to express with this language. And if you need more +39:34 +than two items then you read it into I mean you write it into a variable and then you read it uh when you need it you +39:42 +know like um for example the uh for example there's like this uh free +39:49 +list definition right let's see I think I'm using free list for example oh +39:56 +there it is so um the free list for example uses +40:03 +this variable called stride which is stride in shifts you know uh so you have +40:10 +to define it before you call this word and other than that it takes like okay +40:16 +how much free list items that I'm going to have and that's like 32 kilobytes for directory entries for example and then +40:23 +like free list I define as like I'm going to read into the max like uh I'm +40:29 +going to read top of stack onto max right which is this 33 kilobytes and +40:36 +then into base which is directory entries and then I generate code like +40:42 +for allocation free previous index and append. So that's like five items that I +40:47 +don't have to pass on top of stack that I can read anytime, you know, if if I +40:52 +care to, you know, I don't even have to like deal with it. It's just there if I if I care to like I might care about +40:59 +allocation of free, but maybe not other stuff or whatever for particular um free +41:06 +list, for example. And it it would be helpful if you could go through the the tags that you're using because that's +41:12 +also challenging to Oh yeah, sorry. Sorry. Yeah, that's like um so green is +41:18 +load and red is store. So I'm loading +41:24 +previous onto like or say I'm loading the allocation um function on top of +41:31 +stack and then I'm uh writing that to plus tab which allocates like a tab for +41:37 +instance right which are like you know which happens when you roll a new tab +41:44 +like uh you know like this it allocates like a new tab and we can like verify +41:52 +that when it when this runs by like saying like okay you know what let's look at those variables and +41:59 +see what happens if I allocate one two and three +42:05 +tabs and you know yeah you got like three times +42:14 +the and cx is like one dx is five and +42:19 +you know etc etc So, um, yeah. +42:27 +What about the other? So, red is red is read and and green is or green is right. +42:33 +What what are the other Oh, yeah. Yeah. Sorry. Um, so white is call. So, call +42:40 +means that you compile a call instruction literally uh at uh JIT time +42:48 +though. So um whatever address that you had inside grow like you know which is +42:55 +like eight bytes uh which you can jump to the definition right. So um this +43:01 +address gets compiled in the instruction stream in here +43:07 +and the the the pipe the pipe in front of the definition. So magenta is is uh +43:15 +is definition is is the pipe just styling or is that +43:21 +so that also gets compiled you know that's the definition beginning so that gets compiled to a return because it +43:28 +needs to return from the previous instruction which is setup you know I mean the previous definition which is +43:35 +setup and um and then there's exchange racks rdx X and then um you know that's +43:44 +the definition uh beginning right so and then you compile these you jit these +43:50 +other uh instructions one by one so this this is a compile this is a load this is +43:55 +a number like uh this is a call call and like numbers and this is +44:03 +um this compiles and and sorry the the the number so the the the numbers is +44:09 +there a single the the numbers are the cyan numbers are compile of the number or some +44:16 +other sorry they're compile move into into rax or or rdx depending on +44:23 +who's top of stack oh yeah I mean for example this stuff they generate nothing +44:29 +at the output right but when they get compiled this like this gets translated +44:35 +to uh move rax 4 move rdx 104 for and +44:40 +move rax 32 and then this is like puts cx which is defined here you know it's +44:47 +just um some number that's like 1,003 which is like the +44:54 +type and then like the register which is one you know um and then sorry the +45:01 +yellow the yellow is what again oh the yellow is um runtime okay so +45:09 +That's like runtime store. So that generates a move RCX020 if if you can like you know is +45:16 +there is there a comp is there runtime read? Is that the the blue or no? +45:22 +Uh sorry can you repeat that? U so yellow is runtime runtime write. What's +45:28 +the run is there runtime read? Oh yeah, runtime read is uh CX dot like the dot +45:35 +syntax. Or you could just say CX at you know it's it says like move racks to RDX +45:42 +uh move racks to RCX like or you could say +45:49 +um move RDX or CX if you want like CX at the you know sorry I said run I meant I +45:56 +meant at at u sorry yellow is yellow is is is execute time read or is it it's +46:03 +compile time read? Uh, I'm getting them mixed up. I'm +46:09 +sorry. No, it would be helpful if you could go through each tag one by one so that we Yes. Yes. Yes. Yes. Um, sorry +46:16 +about that because like you know the it can be a bit confusing. Uh, I just got +46:21 +used to it like you know the way it looks. Um, so uh each so +46:28 +if so yeah the the red ones the these are like calls, right? The white ones +46:33 +are calls uh at and they are compile time calls and the red ones are compile +46:38 +time writes. Okay. And green ones are compile time read and yellow ones are +46:46 +execution or rather like runtime uh you know uh so it's so this is indexing. So +46:55 +uh each directory path is like 256 256 characters for instance and um I'm +47:03 +indexing directory path which I've defined here as like maxers which is +47:08 +sorry the yellow the yellow the yellow is execute time read is that is that right or execute time +47:16 +invocation call yellow is used for a bunch of stuff I mean sometimes it's uh +47:23 +there's also So um a prefix like this equals here, you know. Mhm. So or this +47:30 +dot here or postfix when it's a load or it's a prefix. I see. So okay, you've +47:35 +got the color the color is overload. Is that is that all different tags or is that Yes, they're all different. Okay, +47:42 +got it. Okay, so you got you've got several several things that are yellow that depend on the t on the Yes. Yes. +47:48 +Sorry about that. Ran out of colors. Okay. Some Yes. When it's like yellow, then uh +47:55 +if there's like nothing, then that's a um like runtime uh call, you know. So if +48:05 +if if it's like a um so there was like plus tab that Oh, there's also like undo for by the way because you really need +48:12 +undo if you're like doing like a custom editor, right? Yeah. So, so, so why +48:17 +didn't you use the I'm surprised that you use color for compile time read and write, but then you use different +48:24 +prefixes and suffixes for the for execute time. +48:29 +Yeah, because I mean execute time code like you know has to kind of stick out +48:36 +you know because I want to see at a glance which pieces of code are generating code versus like which are +48:43 +like you know um I mean these are all generating code at some point right oh +48:51 +sorry I had to I was doing some steam integration yesterday so that's like +48:56 +undo and and you Haven't Let's see. So, you uh you haven't explained the blue yet. +49:03 +Sorry. You haven't explained blue yet. What's blue? The blue's comments. The blue's comments. Blue +49:09 +comments. Okay. Like um and the green the orange reds are uh +49:19 +strings, right? So, comments and strings can be converted +49:24 +um you know. So this would be like a string um but it's not a runtime string +49:30 +because um I cannot assume anything about the runtime. This is a pure compile time language that you can use +49:37 +to implement any kind of logic to implement whatever you need to generate for at runtime +49:45 +like um so it's omniflexible right like you can um just say like I mean this +49:53 +won't generate anything at all like no assembly you can just you know be +49:59 +irresponsible on the stack and like it won't matter like you can just +50:05 +um you know um let's see and what what are the what +50:12 +are the uh the hard brackets? Oh yeah, the hard brackets are um the +50:18 +notation that I have for managing uh basic blocks as I call them. I mean +50:24 +they're also like terminology but yeah um so the basic blocks are defined here +50:31 +and they're like um they define +50:38 +um ranges of code that like um that you +50:43 +can have like you know a beginning and a link and a end jump targets for. So +50:51 +yeah, so um with this notation, you don't need ifs anymore because you can have an if +51:00 +like conditional anywhere, right? So um let's see a place where +51:09 +um say like a conditional say um for example I'm here decoding like +51:17 +each vi packet at if I'm calling like I'm def okay okay let's look at this actually this is an interesting piece of +51:23 +code like what happens when you flush a video for instance when you have to like flush a video um which means like when +51:31 +you're changing in the video you had to like go through the remaining like uh packets and stuff that ffmpeg has to um +51:40 +you know and release them. Mhm. So what happens here is like I'm looping forever +51:46 +basically which what this loop does until I break and I call V packet decode +51:54 +you know which is like um a Q which gives me a video packet and I assign +52:01 +that to uh video v V packet uh variable you know which generates this code here. +52:08 +Mhm. So, um I'm sorry, what are the curly the curly braces and why are they yellow? +52:17 +So, yeah, these are uh these are lambdas. That's that's a great question +52:22 +actually. Thank you for I mean I haven't I'm doing like a terrible job explaining the language. This is like very all over +52:31 +the place, but thanks for asking these questions about like you know I mean these are lambdas and um you know if you +52:38 +you can call you can choose to call them or not. I mean lambdas in the sense that +52:44 +they that they they they do they bind any variables or they just they're just they're just an invocable thing that +52:51 +leaves an address. Yeah, it's it's just an invocable thing that's an address like you know it jumps over. Got it. Got +52:57 +it. That and like I don't like locals. It's it's everything is global, you +53:03 +know. I mean, got it. Got it. I I figured I just thought I'd ask because L means things to people. Does does the um +53:10 +And sorry, why I'm confused why in that lambda why are you using a yellow a +53:15 +yellow symbol there? Isn't that it that doesn't get happen at runtime because it's in a lambda or what's the +53:22 +uh so yellow is also used for I mean it's not that much stuff you know it's +53:27 +also used for immediate time words I mean um so that's when you invoke that +53:36 +definition when it's like jitting you know and that's like defined outside in the language itself it's it's very +53:43 +simple assembly code you know it's just like appending that um you know um panning like what this +53:51 +does is um basically um say like I want to execute +53:56 +this piece of code um otherwise nothing executes you know only the things that +54:02 +that are like uh within this yellow execute and all of the other ones are like uh definitions right so you know +54:09 +exactly what you're executing if it's like following this um yellow um bar +54:16 +here. Yeah. So, it's either definition or execution. I see. And yeah, I mean +54:23 +you could got a lot of stuff overloaded on the yellow there. Okay. +54:28 +Yeah. I mean, uh I don't know. I I like the color, but you can choose color, you +54:34 +know, it's I mean, if when the editor is released, you'll be able to +54:39 +um well, you'll be able to uh attend +54:45 +like within code, you know? I mean, we can just ditch Zoom and just attend the +54:51 +meeting in inside the code editor, right? Like because you can integrate +54:58 +multiplayer here. um easily and you know um also a multiplayer version control +55:04 +system that's like um you know that's scalable to any kind of users like git +55:12 +is not the end all of like version control systems I think like +55:17 +um but yeah we were looking at with flesh here and like the the code and I +55:24 +mean this calls you know this is just a single call and then this is Um and then +55:30 +the result of that is stored in rax and I move that to we packet and then if rax +55:36 +is zero I break and I move that we packet because ffmpeg requires me to +55:43 +pass it in a pointer. So I have to pass it in a pointer and 18 is like you know +55:49 +what is 18 18 is a packet free which frees the packet right. So I mean I I could just and sir +55:58 +how are you how are you actually hooking you're hooking into to to AV codec and and ffmpeg and stuff like how is that +56:05 +binding how are you how are you bridging that divide? Yeah. Yeah. Well I assume +56:10 +that I don't have any uh floating point arguments. So uh the calling convention +56:18 +is like um just this. So um implement is +56:24 +this. So you have to align the SP which I do by reading SP like the old stack +56:30 +pointer into B. Like this is so stupid you know having to align the SP but you have to do it because the operating +56:38 +system requires you to um I I don't even use stack pointer like for any data +56:45 +anymore. Um I just use it as a call stack. And you know when you think about +56:51 +it um that could have tremendous benefits. You just eliminate a lot of like stack overflow like um uh return +57:01 +oriented programming like right there right. Um it's it's +57:07 +like I this whole program runs without any runtime stacks. It's it's totally +57:13 +possible to program without having to use any stacks at runtime at all. Um +57:21 +yeah, I mean way we could open some demos +57:27 +maybe. So yeah this whole program I mean it's +57:32 +not just also CPU side code right there is also u GPU code which is +57:40 +um like which most other languages for most other languages it's an afterthought right +57:47 +um and in this language it's it's so expressive that you +57:53 +can like define the whole spare wheel like generation in +58:01 +like just this much code essentially like +58:09 +it's it's not that much and by the way even even like the fonts are defined in this language is is my screen showing by +58:15 +the way or is oh okay it's like stuck on my screen so I wasn't sure +58:22 +I'd be curious to to to see that how you define the fonts it looks like they're kind of a bit of a vector something that +58:29 +yes yes so um say we're redefining m for +58:34 +example to be like you know um so m is here so +58:40 +um I start from bottom left right to top left to center to top right to bottom +58:48 +right so what if I went to bottom center but I had to switch to the other uh deck +58:56 +you know. So, yeah. Yeah. So, now it's like, can you +59:03 +see the difference? Maybe I can make it change the font size +59:10 +here. So, yeah, it looks um like this now. Or, you know, I could I could +59:17 +just make it something entirely different. Denmos like it's it's just um encoding stuff at +59:28 +um you know it's it's so simple it's it's like it's just this much code +59:34 +to yeah it's it's just all this code is like this much for for that +59:41 +language and you know yeah and that's like the font definition +59:48 +right I'm going to undo do that. Okay. So, um and that's Are you hitting +59:55 +something to rebuild the system each time? Is that Oh, yeah. It's that's the enter. Okay. Whenever I I press enter, +1:00:02 +uh it rebuilds. You know, you you you get like you get very +1:00:08 +um how to say it, you know, you get very used to it. Like 8 milliseconds is so +1:00:14 +fast. I I I can't even like wait for C to compile anymore. Yeah. It's but yeah +1:00:21 +um it's also includes all this shader stuff also that I'm defining inside the language Paul says he can't Paul can you +1:00:29 +see the screen you were indicating in the chat you couldn't I can currently see it but +1:00:36 +I can't see those on my other stream okay never mind so um yeah I mean that rendering code +1:00:44 +looks like this you know it's a bunch of shader codes which uh um which is not +1:00:50 +that hard to write actually you know and you can do um you know the the the cool thing about +1:00:58 +this language is you can redefine stuff like this for instance and there I just redefined +1:01:05 +filter you know there can be two definitions that's fine and I can say like okay um you know what if I did this +1:01:14 +instead or okay that didn't change anything +1:01:20 +because what if I didn't do okay crash but I +1:01:25 +shouldn't. Yeah, it doesn't look on the stream because like the difference is +1:01:30 +very subtle. Maybe I should see like look at it more. Oh yeah, I I know. I +1:01:36 +know. Hold on. There's like the dark modes here. I can show you dark +1:01:44 +modes which +1:01:50 +or how to implement the dark mode. And this is I assume that little +1:01:55 +green dot is your curs is your mouse cursor. Yes. Yes, that's mouse +1:02:01 +cursor. Where is the dark mode? I'm looking for a comment that looks like +1:02:06 +Oh, there it is. Dark mode. There we go. So, it's not exposed yet, but I just +1:02:13 +enabled dark mode. So I'm going to open graphics conference talks like the +1:02:20 +um you know and if I close dark modes it looks +1:02:26 +like this for instance like a lot brighter you know versus +1:02:34 +um versus with the dark mode. So the way that this dark loop +1:02:42 +works is um I've defined like I have this +1:02:47 +floating um point constant here you know 32 bits but I have 24 bits currently so I have +1:02:54 +to encoded with two items on the stack you know I swap and shift by eight and or oh I was gonna clarify so for for +1:03:03 +compiled numbers you're you're you're just using the one the one 24bit the +1:03:08 +cell with 24 bits of of Yes. Yes. Yes. That means also 24bit floats which has +1:03:15 +precision issues unfortunately but you know whatever it's fine it's um +1:03:23 +so yeah I I I sample from four planes like y u vi and um you know I had +1:03:31 +defined samplers here um as like zero sampler into sampler Y and one sampler +1:03:37 +into sampler U and sampler V and you The sampler at requires a sampler ID you +1:03:45 +know. So uh because you know you have to like like the sampler handler rather. So +1:03:52 +you have to set that and the results like that samples from that +1:03:59 +um like Y plane right the luma plane and the UV chroma planes uh separately. And +1:04:08 +if the chroma is like I mean sorry if the luma is +1:04:13 +um beyond some threshold. Oh wait hold on there it is. +1:04:21 +I'm looking like where wait that that's not that code. So if the luma is beyond +1:04:27 +some threshold if the luma is greater than 0.6 six um which you had to assign as like +1:04:36 +condition. You know in this language before you call ifs you had to assign the conditionals to this condition +1:04:43 +variable. Um you know instead of if you could also call if else but you have to +1:04:49 +pass like two lambdas. Oh okay. So your your your conditional is taking a taking +1:04:54 +lambda's the thing to conditionally. I see. Yes. And the condition is this +1:05:00 +variable here that I read into the condition you know and the the the the +1:05:06 +like GT question for example like that's what can you explain what that's taking where is it where is it doing the +1:05:12 +comparison between and where is it putting its result. Oh yeah. So um the +1:05:18 +same syntax that we used before like the dot syntax I'm reading from the luma +1:05:23 +variable luma dot and then 0.599 f. So in this language you have to +1:05:30 +define your floats. So um f does that and then if luma is greater than 0.6 six +1:05:39 +that generates like this variable you know uh 26E uh that's say uh ID uh and +1:05:47 +that's the condition variable and then you know +1:05:53 +um if if that condition is true this this code gets run which is like inverse +1:05:58 +the luma essentially and sorry the the the red the red is +1:06:06 +reading from the condition variable and then putting it in rx or dx depending on +1:06:11 +the oh the red is re the red is uh storing into the condition variable +1:06:18 +sorry storing into I see and then I see and then if you consumes that yes yes +1:06:23 +yes it consumes the result of the greater than which is like uh generates +1:06:28 +like a spare result and all of that is defined as like you know this is just um +1:06:35 +a binary instruction All right. And I read into source and destination, you +1:06:40 +know, always two stuff like two items on top of stack. And um if I need more than +1:06:47 +that then like condition for example that's fine you know or maybe sampler ID +1:06:53 +that's that's like uh that's actually better because like um you can like +1:07:02 +define this condition programmatically at compile time if you care to without +1:07:07 +having to pass it on stack even right like +1:07:12 +um I the restriction of two stack items is +1:07:19 +definitely worth it. Um in the worst case you just read in I mean you just +1:07:24 +write it into another variable and read it when you have +1:07:30 +to which makes also the code a lot more readable. So +1:07:35 +um so yeah that's like you know a bit about how you can also program shaders +1:07:42 +in this and you know and and and sorry you didn't quite maybe I didn't quite +1:07:48 +follow so you're you're targeting Vulcan um how are you how are you actually getting getting into the formats that +1:07:54 +Vulcan uses and like yeah um the formats that Vulcan +1:08:01 +uses as like like are You are you using a um what what kind of +1:08:08 +a you're you're compiling to to one of the Vulcan shading languages or what's the what's the problem? Oh yeah, this is +1:08:15 +compiling directly into spare. So um okay so you're generating raw spir uh +1:08:22 +bits. Got it. Yes. Otherwise I would depend on another tool the gllang +1:08:28 +compiler which is huge. I mean that's like at least 100 megabytes. I think a +1:08:34 +lot more than that now with all the debug symbols and so on and all of that is unnecessary. The rules are so big +1:08:40 +now. Yeah. I mean in in C only like even though you +1:08:50 +have all those headers and like for you know all those struck +1:08:56 +definitions all all that convenience stuff that you have in C. It was like um +1:09:03 +I think 150 kilobytes of C code for a much more early prototype version of +1:09:09 +this idea. And um this is now around 200 256 kilobytes +1:09:16 +of code including the shader stuff like all that font definition shaders the +1:09:22 +ffmpeg vulcan uh initialization the UI and you know um +1:09:30 +the interaction the folder iteration stuff etc like you know a lot of stuff +1:09:36 +actually in 200 kilobytes I mean the expressivity of fort is insane at +1:09:44 +compile time. It's it's a lot better than like you know um the restraints of +1:09:50 +like runtime for it right which is like I mean it has to pass through the stack +1:09:55 +and like question is like h how how can it run on the GPU right there is like um +1:10:02 +a lot of like expressivity loss just because we want to pass through a stack but that information passing um I mean +1:10:10 +you could also achieve that through like global variables Um and with that it +1:10:16 +becomes much more simpler, faster and it also becomes you know more um how to say +1:10:26 +I forgot it's it's easily it's it's much +1:10:32 +more easily debugable because like um the state is just laid bare you know +1:10:37 +that's that's just like um global state that's not like um you know you're not +1:10:43 +try to uh juggle like local state space at all. So it becomes a lot more +1:10:50 +manageable compared to like you know all the other languages. So um I don't know what else +1:10:58 +can I say actually um the fort stuff for instance for uh sorry the welcome stuff +1:11:05 +is like um Vulcan is walcon usage is mostly like +1:11:10 +filling uh forms right so if I if I look at some walcon stuff +1:11:17 +um like okay for instance I'm creating like images for each um for like 420 20 +1:11:25 +YUV 420 format. +1:11:30 +Nice. So, um the way that I generate this is like +1:11:37 +14 info which is like um which fills the information structure. I mean it selects +1:11:44 +it and then fills the information structure with the type and then what's a dollar what's a dollar sign? +1:11:51 +Um the dollar sign that's just a variable. Okay. Yeah, it's it's all it's +1:11:57 +all cells here, you know. If it's not a string or if it's not in number, then it +1:12:02 +has to be like a cell and the tag is like, you know, if it's red, then it's +1:12:08 +um it's reading into that uh you know, whatever it is. There there's no single +1:12:16 +like end all definition for anything any of this. You know, it's not going to complain like, oh, this was a definition +1:12:22 +before. You can't read it. No, I just I just wasn't quite following like in in this context though, you're so you're +1:12:27 +you're um writing into it. Why are you writing into it at at you're defining these and +1:12:35 +then you're read and then you're reading out of it one like on that lock lock inc +1:12:40 +one? Oh, sure. Yeah. So, let's see. Let's read this code. Uh I was up up at +1:12:46 +the top of the block on Yes. Yes. So uh if I press enter we can +1:12:52 +see like okay it's reading zero mostly and then dollar is like whatever information ID it's it is you know +1:12:59 +because in walcon you have these okay hold on you have these um +1:13:05 +w say so can create info for instance or +1:13:14 +or create info oh wait types populating one of the +1:13:21 +structures that they use and then yes so 14 would be image create info right so +1:13:27 +instead of having to type all of that like we can I I you don't have to import +1:13:32 +that it's just an ID right um I mean this these kind of binary interfaces +1:13:39 +simplify a lot versus like having to you know if if this was like a string based +1:13:46 +interface like open XR that would be awful, right? Could be worse. Could be goods or something, but +1:13:53 +yeah. I mean, uh, in Vulcan, you had to always do this shenanigan where you you +1:13:59 +go like we image create info info equals and then you +1:14:07 +copy this structure type, you know, and then zero. You had to do this for every +1:14:13 +single time versus uh I can just say if in zero for first information or if one +1:14:22 +for the second one. Mhm. Or if because sometimes you need more than one information structures that are +1:14:28 +referring to each other and they're like 256 bytes apart and you know they're +1:14:35 +just a bunch of words. And the last one is info which is like okay if you want any kind of info like you know any kind +1:14:42 +of offset for this like structure that I defined here as like 8 kilobytes you +1:14:48 +know that's all this is like 8 kilobytes of globally accessible data from anywhere essentially and um what I'm +1:14:56 +saying is like okay let's get the in info ID which is mostly zero right so +1:15:02 +and then add that to that address and then load that load that to uh RDI which +1:15:09 +generates this Leah RDI bit here you know and then it writes some index which +1:15:18 +is like in this in this case it's 3B 9A cde 9 you know uh which is like the type +1:15:26 +information what is that 3B 9B +1:15:31 +9 wait what that's weird +1:15:37 +Oh, that's that's interesting actually. What am I even writing here? +1:15:47 +Okay, you're searching in the header for is it is it is it in decimal instead or +1:15:52 +maybe it's in another header. It's but it should be there. Oh, sorry. Did we +1:15:58 +lose? Okay, we lose the screen. Okay. So, +1:16:04 +um, info. So, so actually I when I was asking about the dollar sign, I was actually looking up. Can you go back to +1:16:11 +block 50? I think it was block 54 there with the +1:16:17 +There we go. Yeah. So, up at the very top that lock inc bang uh word. What +1:16:23 +What's going on with the the red dollar sign and the green? Like why why are you you're reading you're you're writing +1:16:28 +into dollars from the and then oh I mean yeah it doesn't have to be it could be +1:16:34 +just this oh okay yeah I see okay +1:16:40 +yeah I was surprised that you needed that seemed like an unnecessary step that was why I was yeah yeah yeah totally totally um and +1:16:48 +just like like it seems like you've got a convention like convention for how you're using dollar sign in several of +1:16:53 +these words is that maybe I'm not getting the the idiom. It's just a temporary variable that I really don't +1:16:59 +care about, you know. Got it. You're good. +1:17:04 +Temporary just just for temporary contextes. And um you know, sometimes that causes troubles too like that +1:17:11 +happened. If you call like two of those words that are like using those variables at the same time, then you +1:17:18 +know it's it could be trouble. But you know, you just define another one. There's there's so many of them like +1:17:24 +those Yeah. And it it really doesn't matter like you can they're essentially free. I mean um if if you were to be +1:17:31 +like um it it doesn't cost anything at runtime. So you can have as many +1:17:38 +variables as you need it. Um and this is also interesting. So this is compile +1:17:46 +like this is defining memory for runtime but all that memory is global +1:17:52 +memory. So uh I dedicate a single register to be able to access all memory +1:17:57 +of the program that are stored in this single register which gives you like +1:18:03 +gigabytes of state which is huge. I mean you shouldn't have to need like +1:18:08 +gigabytes of space actually. Um or you could uh allocate like you know virtual +1:18:14 +memory if you needed to um instead of like using this global +1:18:20 +space which is anti antithetical to all conventional programming wisdom which +1:18:26 +says like don't use globals I mean you know as if like if if if you're like +1:18:34 +accessing them in a responsible manner like I can just say like okay where am I using upload buffers for instance +1:18:41 +And suddenly it's not that like scary, you know, because like I know exactly +1:18:46 +where I'm using those. And um it's not like I mean I I'm very +1:18:53 +critical of Rust's memory safe attitude where you have to fill tax forms to be able to access a piece of memory which +1:19:00 +is just there. Like it's free to access and you don't even have to pass anything on a register to be able to access it. +1:19:06 +It's just like it's just there and somehow like you know people are like oh +1:19:13 +that's unsafe you know pass it in a functional context or whatever. So you +1:19:19 +end up having these like stacks of state you know pass through like 20 30 layers +1:19:27 +of call stack like the same state over and over again which is insane. So, so +1:19:32 +for you're you're going to target uh Sphere V like um I haven't looked deeply +1:19:38 +the how bad is the encoding like is it it it's a fairly simple instruction +1:19:43 +encoding or what how bad is sphere v? Uh sorry what what is encoding for what +1:19:50 +exactly? For for you were going to encode sphere v instructions right? Oh +1:19:55 +yeah. Are are they like I I don't have a good sense. Are they are they hard to encode or is it a fairly straightforward +1:20:02 +format? I mean uh they're they're kind of hard to encode but not really. I mean +1:20:08 +you just have to like define it in a um you know you read the spir spec uh which +1:20:15 +is like spir which looks like +1:20:21 +this. I'm going to save your eyes. So it it defines the whole thing here you know +1:20:28 +uh the binary encoding and all the instructions. So um say like how would +1:20:34 +you encode um an instruction? Let's see bit instructions +1:20:40 +for example shift right logical right let's +1:20:45 +see where are where is shift right +1:20:51 +logical okay there it is so 194 194 not too bad so it's just a it's just a bite +1:20:58 +code kind of okay yes yes I mean once you have like those words it's just like +1:21:03 +194 binary I mean I I get I don't know how much header header header and footer and what all you got to wrap around it. +1:21:09 +But yeah, I mean binary is just this oneliner, right? And vector is just that +1:21:17 +four lines. I mean it's it's very simple code really like and that vector stuff +1:21:24 +is for when you have for instance um when you want to shift right four item +1:21:30 +vectors you know uh by MD vector or by one it like by like uh just a single I +1:21:40 +mean four component vectors by a single component like float for I mean uh single component integer sorry we can't +1:21:46 +shift by float of course got it got like like ver. Yeah, I see. Yeah. Yeah. Yeah. +1:21:52 +And this ve thing is like just that abstraction for that, you know, like reading um like it's just com comparing +1:21:59 +like destination component count with source component count and if they're not equal like I mean that state gets +1:22:06 +written to C CX and this if else works on this condition CX, you know, so +1:22:12 +that's why it's there or like actually that's is is that running even? Oh yeah, +1:22:17 +it's it's a if false within and if else of course. So yeah, how are how are you um +1:22:25 +displaying the state when you're on top of a word? Like what how do you how do you have the opportunity to hook that +1:22:32 +in? Uh sorry, how do you mean you were +1:22:38 +showing this? you're showing the state of the the stacks of the plate when you're sitting on top of a word like +1:22:43 +what how do you actually do that injection of the the instrumentation or +1:22:49 +oh uh well it's the state is just sorting racks and rdx so if you store that in an array you know you you can +1:22:56 +visualize that um in reverse order and you get this but but I mean how are you +1:23:03 +you're doing that only when that word is getting executed right like how do you are you modifying how you compiled it to +1:23:09 +have a moment to update the this update. Oh, right. Right. I forgot. I I've had +1:23:16 +to look how I implemented it, but I'm probably doing like um yeah, code +1:23:21 +injection where if the cursor is here, like the active cursor, +1:23:26 +um do a code injection where you're recording racks and RDX into this global array that's like storing the state of +1:23:33 +the stack. Okay, that that should be it. But I'd have to read the code now. Okay. +1:23:39 +Okay. I was just curious if you were if you +1:23:44 +had some But it's it's all like it's all straight line assembly that's coming out. So you're like you're not actually +1:23:49 +you must something to get get in there, right? Yeah, it's it's all straightforward assembly. Very +1:23:55 +straightforward assembly. It's it's just generating the required instructions in JIT which is compiles to a single call +1:24:03 +for those white words and like you know a return exchange racks RDX for +1:24:09 +definitions and for these it's just a single jump and for loads it's just a +1:24:15 +single move uh to racks or RDX or for writes it's again back to the global +1:24:20 +memory uh a single move um you know it's it's it's all very simple +1:24:27 +So, how do you um how do you keep how do you keep uh flaws and bugs from entering +1:24:34 +your codebase? Do you have tests around it or do you have asserts? I mean, what do you do to to try to um Yeah, don't +1:24:43 +make bugs. That's that's the like um when you have +1:24:49 +bugs uh what I do is like I um I triage +1:24:54 +the bug first by okay let's say like I'm triaging why a shader would be crashing +1:25:01 +you know uh say here so this shader crashes I disabled this and does it still crash uh yes it still crashes okay +1:25:09 +and then I disable this too does it still crash no okay that must be in in color you know does that make sense? I +1:25:17 +mean that's uh the fastest way that I can like there's no reliable way to +1:25:22 +prevent bugs is is like you know my experience you just have to +1:25:29 +um I mean there there are ways that you can use like um I had memory overflows +1:25:35 +um you know where I was corrupting memory and or sometimes I passed the wrong stride or wrong number or whatever +1:25:44 +and it's you learn to discover it at some point. I mean, um, and you fix it. +1:25:53 +Trying to prevent it is more effort than it's worth in my opinion. And a lot of languages try and fail at that because +1:26:00 +like at the end of the day, who's going to prevent logic box? You know, there's no compiler that can execute your code +1:26:07 +for you and tell you like, oh, you know what, that's not what you meant. I mean you just have to +1:26:12 +um you know write simple code and think simple data transformations to express +1:26:18 +your uh code and most of the time you'll be fine and if something goes wrong um +1:26:24 +usually it goes wrong immediately and you know you can just undo and see like okay you know um as as as soon as you +1:26:31 +can replicate the bug then you just do a triage where you can just undo or you can just uh enable disable stuff uh and +1:26:39 +you find uh the source like you know fast and sometimes yeah in uh in um +1:26:48 +sometimes the bugs are like so hard to find it it persists for a while but they're there they're still fixable I +1:26:55 +mean it just I've had good experiences with uh design by contract which is in +1:27:01 +the Eiffel language so um you you you document you you +1:27:09 +basically ally um you do mathematical things with okay what does +1:27:16 +this code need the preconditions and the postcond conditions and the invariance +1:27:22 +and then if something's violated it tells you right away and then uh it's it's a way of +1:27:31 +um injecting integrity into the code that where the code actually sort of +1:27:36 +fixes itself in many ways So, I've had good experiences with that. And I was just wondering if uh anybody +1:27:44 +else did that. So, I mean, if you wanted to, you could still do that kind of stuff also in in this style of +1:27:51 +programming, right? You could just do checks that are like you express with +1:27:56 +macros. Um, and you can compress that whatever you're going to write with this +1:28:02 +very efficiently. And, um, if you want to do contracts, sure, go ahead. I mean this is a um metarogramming language +1:28:09 +that doesn't impose you anything. I mean um you can say like okay you know what +1:28:16 +these are like I have for instance um say these are my +1:28:25 +constraints constraints you know um had to like compress that down to nine +1:28:31 +characters. So um and you can say like okay you know +1:28:38 +the constraint is um a x should be like this b should be that or like you know +1:28:44 +should could be like v 0 should be zero and v1 should be always +1:28:52 +um should be 14 or whatever you know +1:28:58 +like we should be like whatever less than 64. You know, like if if this +1:29:06 +was like your constraint space, you you just like +1:29:11 +um condensed that like constraint that contract stuff that you were talking +1:29:16 +about into work that you can use where you're like, you know, using those +1:29:22 +contracts if if you want to. Um for me, I I just Thank you. I just try to not +1:29:29 +make that many um you know errors instead like and try to maintain the +1:29:35 +state consistent uh all the time instead of like relying on like you know checks +1:29:41 +everywhere like because relying on checks is like you know it's it's kind +1:29:46 +of like uh safe programming um but yeah I mean I I really like L safe +1:29:52 +programming rather than safe programming. I I had a question about the um the +1:29:59 +dictionary visualizer on the left. Um you you said that the the capacity you've got is for eight eight characters +1:30:05 +in the current system. I'm curious why you only show the six the six characters. Is that just a space +1:30:10 +constraint or Yeah, space constraint like uh nine it's actually nine characters and nine characters by seven +1:30:18 +bit and there Yeah. And there are uh other like encodings also that I've um +1:30:26 +come up with that that's not present in this language which is um say 16 bit +1:30:34 +plus 16 bit plus 16 bit plus 15 bit. So that's like that gives you 64k words and +1:30:42 +you can concatenate up to four of them together in just 64 bits like um that's should be a much +1:30:49 +more efficient and much more expressive. Um and the thing is you can also since +1:30:57 +you have defined all words from concatenation of four words that opens +1:31:02 +up the possibility of doing say like voice recognition in the editor. So you can just bring the words on the screen +1:31:09 +and say like oh I want say um instead of having to like say sampler +1:31:17 +ID for instance and then I don't have to go to sampler ID it just selects it and which becomes important because it's not +1:31:24 +going to be um keyboard only or desktop only and also I I also want to port this +1:31:30 +to um phones tablets steam deck likes you know hand handhelds +1:31:36 +um VR headsets everywhere and um even watches or like smart glasses or +1:31:43 +whatever like um you know and it is portable to everywhere I think um just +1:31:49 +the UX changes but the codes and the whole idea remains simple for all kinds +1:31:55 +of environments is um I I'm also curious how how often do you end up using the +1:32:01 +facility to to uh rename uh to rename name words as you refactor things. Oh, +1:32:09 +renaming, right? Yeah. So, um for instance, non ouiji is like nonwork +1:32:16 +groups, but it's like, you know, non work G, let's say. It's just as simple +1:32:22 +as that. I'm curious how often you find yourself using that. I It's a new facility. Like, +1:32:29 +is it Right. Right. Sometimes, I mean, sometimes I come up with a better um +1:32:35 +like better name. You know, naming is hard and you can say like, "Okay, you +1:32:40 +know, I'm just going to name this temporarily and then come up with a better name later." But yeah, it doesn't +1:32:45 +happen that often. You're right. Well, yeah. I was I was curious because it it seems like a neat facility that Yeah. I +1:32:52 +I guess you on the other hand, like once you're used to a name, you're used to a name. Cool. Yeah. Yeah. It's that's the +1:32:58 +thing. I mean um it has downsides to compare to text. I mean text would be contextual right? So you can just type +1:33:05 +anywhere. So um and with this you had to bring up like the dictionary that you +1:33:12 +want because like otherwise it's a huge search space that you have to search through like at scale right if you build +1:33:19 +like more and more complex software with this. I mean um you're going to need more dictionary space or maybe not even +1:33:26 +that. I mean, all of this is like how many words? It's not even that many +1:33:31 +words. I mean, I noticed you very carefully kind of curated the layout of it. How much do you find yourself +1:33:37 +fussing fussing with that? That's actually It's kind of interesting stylistically, though, to be that +1:33:43 +they're laid out in in an ordered way. Oh, yeah. Yeah, that was intentional. +1:33:49 +Um, so 16 per scroll, 16 words per scroll, which is like this. And +1:33:56 +um so thing is I I I I'm not really sure about any of this. +1:34:04 +So this is uh where it's it's like you know more open to um imagination, +1:34:10 +reimagination perhaps. And um the way that I like the way that I +1:34:17 +organize those scrolls is like I have tags per scroll. So this is like packs +1:34:24 +and to-do and I can just go around and say like what are XAs words which are +1:34:30 +like uh the x64 assembly and these are X assembly API words for instance right +1:34:37 +and what are like the free rewards are here for instance like this uh yeah it's +1:34:45 +surprisingly organized like I I I think when I've thought of using indexes before I've always feared that it if I +1:34:51 +just sort of randomly dump dump them in in the order I created things that would be disorganized, but this idea of +1:34:56 +placing them explicitly is is pretty cool. That's that's really neat idea. Oh, thanks. Yeah, I mean, um, +1:35:03 +organization with indexing is like, you know, the the hard part. I I thought a +1:35:09 +lot about this problem. Uh, it's it's it's I was thinking about 64 verse +1:35:14 +scrolls and maybe I will go back to 64 scrolls. I mean, it gets a lot of like +1:35:22 +Maybe this was too granular. I I don't know. All all of this is like open to +1:35:28 +you know re reimagination basically by anyone. Uh because the language doesn't +1:35:33 +depend on it. The specific editor does right. So you can have as many editors +1:35:39 +as you want and code interrupt without having to explicitly say like okay you +1:35:44 +know uh this has to be that and that. If you're like mixing source, I mean, uh, +1:35:50 +they can interrupt at the source level, but not at the editor level. But that's fine. I mean, you know, +1:35:56 +um, I I think, um, this language can +1:36:01 +host any kind of like language um because it offers u pure assembly +1:36:08 +execution, right? there's no um blocks there that you have to like go through +1:36:14 +or that I have to define uh so that you can do whatever you want if you can +1:36:20 +express that logic in assembly then which is like you know which you compile through this macro assembly right uh so +1:36:26 +it's not like you know pure like hardcore assembly that we're used to it's much more uh approachable and +1:36:35 +um yeah what was I saying I I forgot That's where I was going with this. I I +1:36:41 +I think I I asked a question. I I had a different question. I'm curious how you bootstrapped the system. +1:36:47 +All right. Um bootstrap the system. I mean, it used to be this and then um +1:36:57 +from that system I I mean it still uses C unfortunately, but the next version is +1:37:03 +going to be standalone and entirely self uh Bootstrap. So um this is this +1:37:09 +compiles into assembly um and I host that in a C project to uh +1:37:18 +make this editor which compiles uh you know web and all the other stuff and uh +1:37:26 +the next version is going to be also programmed in this and like it's we're going to program +1:37:32 +program it live basically uh all of it so that um you know it can +1:37:39 +a something that can be like passed on from generation to generation, you know, +1:37:44 +like as foundational bootstrapping knowledge like okay, you know, this is how you can build this uh editor uh if +1:37:51 +you had to. It's it's so simple. Um and language is much simpler than the editor +1:37:57 +of course like all the complexity is just just editor. Uh and you know um other +1:38:05 +than that like um yeah the the font +1:38:10 +rendering but you can also have the editor stand alone which means like if +1:38:16 +you want to embed the editor to say into a game you can have the game have its own +1:38:23 +text rendering and just expose the editor and its interaction and so on. So +1:38:28 +yeah, I mean I expect a ton of editors for this programming language for sure. Like +1:38:34 +hopefully I mean if people find it +1:38:39 +interesting. So what else I can say like about so what have you built games or or +1:38:46 +like what what are the things that you build with this? So I built before vamp I built um this +1:38:55 +going to go back and wait did I open the tab there? No sorry. So I built those u +1:39:04 +biological um stuff um that's going to ship also in web. So +1:39:13 +um this was also done in the previous iteration. So which looks like this. +1:39:28 +Okay, hold on. All +1:39:35 +right. Okay. So, yeah, +1:39:41 +it's it's like this galaxy like structure that expands. Um, it's it's +1:39:48 +just a shader. Um, unfortunately, it's it's running a bit slow because I'm trying to stream it +1:39:54 +at the same time. So, sorry about that. Maybe I can open +1:40:00 +up. And other than other than that, the editor itself like this. So, this was +1:40:05 +the previous version. And you can see like I don't know if you can read the text, but I was still opening and +1:40:12 +closing definitions back then. So, there's that. And if I change this to something much +1:40:22 +more dynamic so that we don't have to wait so much. Oh, okay. Let's +1:40:30 +this. So, yeah. Is that +1:40:39 +Yeah. So, you can use this philosophy for any kind of like coding I think. +1:40:46 +Um it's like what you can do with this is boundless. You just think about +1:40:52 +what's the code that I want to generate and what's the logic that's required to +1:40:57 +generate that code. You know that's that's all that's required. That's all this is. Uh all the rest is just +1:41:04 +implementation details. I mean you could still have a stack larger than two. it's +1:41:09 +going to run slower because you have to manage all that stack back and forth all +1:41:14 +the time versus you could have it in global memory which works a lot better in my opinion. +1:41:22 +um like just do exact opposite of programming knowledge and you know +1:41:30 +um you you'll do fine basically like uh +1:41:35 +don't do locals or don't do like I mean you can still do locals if you had to +1:41:40 +but um yeah I just like passing stuff globally instead of +1:41:47 +um having to red like reaccess the in context locally all the time and you +1:41:55 +know programming assembly gives you a lot of uh freedom. So compared to like +1:42:03 +um so that's that's like the new stuff and that's the older stuff +1:42:09 +basically. So um assembly is essentially much more +1:42:16 +free form than uh dealing with compilers. So, Spurby is dealing with +1:42:21 +compilers, right? So, I had to be explicit about everything. I had to read stuff into variables and I had to um you +1:42:30 +know, if I had to use a result, there is no implicit place I can go for that +1:42:36 +result versus an assembly um all the registers are passed all the time. So, +1:42:42 +you don't have to pass stuff on the stack. it's implicitly passed for you by +1:42:47 +the processor for free. Right? So, um that's the major difference between a +1:42:53 +server and compiler. Like apart from the whole complexity difference, +1:42:59 +um there's also a lot of implicitness uh intrinsic to the assembly language +1:43:06 +for you know I mean I target x64 you could target another architecture. +1:43:12 +Ultimately, it depends on where you're going to run this code. Like I highly doubt that I'm going to run the same +1:43:18 +code on a like a Commodore 64 on a 6502 or like you know um but if I had to I +1:43:26 +could totally emulate it you know um it's just like going to be slower than +1:43:33 +having like programming directly to the specific architecture. Um but you know +1:43:40 +you can do binary retargeting or in this case execution retargeting because you +1:43:46 +haven't produced the binary yet. you're like you can execute logic before you produce the binary uh instead of like +1:43:53 +having to translate back from you know binary and um so yeah there is that +1:44:00 +implicitness about assembly and um it makes stuff a lot less code than uh if +1:44:08 +you had to write everything with a compiler where you had to pass all all +1:44:13 +the values explicitly instead of like in assembly +1:44:18 +I can just say cursor at b and then bx greater than oh I know that I read bx +1:44:24 +here I don't I didn't have to pass it you know I didn't have to define like a new variable it's just bx I mean and +1:44:32 +that generates like just a compare and a jump um it's all super efficient +1:44:40 +um yeah I mean let me look at my notes to see if if we miss something uh I +1:44:47 +think we got to the most important stuff. Anyway, do we have questions, comments? You know, +1:44:56 +it's it it's a really neat system. I a lot of cool ideas, a lot of uh stuff +1:45:01 +that it's very thoughtprovoking. Thank you. Thank you. Oh, I just thought +1:45:07 +something that we didn't get to was conditionals, right? How do conditionals with the block like basic block? I love +1:45:14 +the look of it. It's uh it's a really cool system and I like how responsive it is. Thank you. I mean +1:45:23 +um it's I I didn't actual motivation was +1:45:29 +I I wanted like a system that looked super cool when I was um you know dropping acid +1:45:37 +basically. I mean um like it had to be simple enough. It had to be like, you +1:45:43 +know, um it had to also look cool. And this is +1:45:48 +going to look even cooler than this. I mean, this is um like the the font +1:45:55 +here. It looks like, you know, you can get many different +1:46:00 +looks. This style of like, you know, font design or my favorite look is like +1:46:07 +this. There you go. Yeah, kind of +1:46:17 +like and um okay, how do we do +1:46:23 +conditionals? So um the conditionals work within basic +1:46:29 +blocks and um so you can open up a basic block and +1:46:35 +it will constrain the um it will constrain the assembly output +1:46:41 +to that basic block. So for instance here I'm loading the temporary address +1:46:46 +which is just this top me layout to rax and then I'm reading that into R11. Um, +1:46:56 +and if if I didn't have this, then the assembly output would get like very +1:47:03 +um I mean the like it's it's it's nice you know because you can see within a +1:47:09 +single basic block what's what's the generate assembly for this basic block right and +1:47:15 +um within a basic block as soon as you do a conditional if that conditional +1:47:22 +passes then the block continues, you know. So, um let's +1:47:28 +see. For instance, if okay, let's let's find a conditional. +1:47:35 +It's like +1:47:45 +okay. Okay. Yeah. Let's let's go back here. So if the packet is not zero then +1:47:52 +I free that packet you know if if there was like more conditionals after this +1:47:58 +um you know I I I see that if it if it's +1:48:03 +not if the focus video is not zero then I execute this rest of the code until I +1:48:11 +encounter this here which is the link you know which is the else part. So +1:48:17 +instead of else's I have these uh you know links here that are like all across +1:48:23 +the code actually um that can be also used for se calls +1:48:28 +can be used for conditionals uh they can be overridden um you know hold on I'm going +1:48:35 +to try to find like a conditional most of the time it's used for C calls which +1:48:41 +is which confuses right now but yeah so right Here for example I'm I'm saying +1:48:48 +like if I'm full screen I'm not going to do anything and if I'm not full screen I'm going to call this function called +1:48:54 +UI tally and then I'm going to call setup which sets the slot ID to zero and +1:49:00 +then slot live count to zero and then it iterates through all the slots and then +1:49:06 +it does a check you know and the check is like if this is live you know if this +1:49:11 +slot is live uh you increment the slots live count by one and +1:49:18 +then if this slot is a leaf you know so you keep filtering. So if this is live +1:49:24 +then it's it's passed this filter you know and then you check for leaf and you +1:49:31 +know uh if that if it's also leaf then I check uh I decode the balance you know I +1:49:38 +I get the balance of the slot and then I decode it which um you know reads it +1:49:43 +into local variables and then um and then I do a hot check which is like +1:49:50 +doing like a mouse check for between the mouse and the slots bounce you know and +1:49:57 +um if if it's hot then the hot slot index is the slot ID which I passed +1:50:04 +implicitly by the way this is R12D you know it's R12 passed implicitly I didn't +1:50:11 +have to define the slot index for this function um it's it's just there it's global and +1:50:18 +this hot slot is also global so Um you don't have to define these you know +1:50:26 +arguments all the time. You can just you know um use stuff anywhere use memory any +1:50:33 +memory anywhere basically. And so yeah I set the hot slot and then I get the video of the +1:50:39 +slot and then I set it as a hot bit and then I return one in a or zero if if it +1:50:47 +was not hot you know. So yeah, it it basically checks +1:50:53 +all the slots if I'm not full screen and so I can get the hot slot index which +1:50:58 +gives me like what my mouse is hovering, right? So I can do stuff with it. But I +1:51:04 +I don't have to pass that like everywhere in code, you know, all the time. It's it's it's just free. I mean +1:51:12 +um it's it's a lot faster and simpler to pass it globally unlike you know what +1:51:19 +everybody else does um you know C rust um +1:51:25 +yeah so yeah that's that's uh basically how I do conditionals +1:51:32 +um and how I pass state around I mean like using uh state everywhere I can um +1:51:40 +you know and yes you had to care about lifetimes. If you modify the same states +1:51:46 +from like multiple threads, you're going to have troubles, especially on like +1:51:51 +platforms where you have to synchronize that access. But you know, I I care +1:51:56 +about lifetimes. I'm just accessing this data from a single thread. there cannot be like a um race condition because like +1:52:05 +I'm not writing it from two threads like reads from multiple threads is fine but +1:52:12 +as soon as it's right from multiple threads then you have to use like um locks and you know stuff like that um +1:52:21 +you know locks as in just this keyword called lock I +1:52:28 +mean wait what where's lock. Oh, I'm I'm looking at I still have the square. Um +1:52:35 +yeah, so lock is just a single um bite on x64 and you can use it on a bunch of +1:52:42 +instructions including bit test reset. So if you have to set or reset like a single bit from multiple uh threads then +1:52:50 +yeah that's totally possible. Um I mean in C you would have to like +1:52:58 +ask the compiler specifically to generate it or use like intrinsics. +1:53:03 +Um, yeah. I like I like being able to just say like Oh, not this. Sorry. I +1:53:09 +like being able to just say like lock just being able to append like you know +1:53:14 +if if I append this then it becomes a lock lock ad you +1:53:20 +know if I don't call that then it's just a single ad. +1:53:29 +So yeah, it's it's very powerful, but you're responsible for all the code +1:53:36 +generated. Um, you know, you can still use compilers like uh like in spare. Um, +1:53:43 +but yeah, I I prefer to use assembly because I like the full control and the freedom that assembly gives instead of +1:53:49 +like compilers and explicit parameter passing. So yeah, that was a lot of +1:53:57 +stuff. Let me check my notes if we missed anything. Um, I have like I have like a word here +1:54:05 +called stack fetishism which we didn't get to like I +1:54:12 +I just don't use any stack juggling words except for swap which you need. Right. So you're you're releasing it +1:54:19 +tomorrow. Is that what you said? Um, not tomorrow. Um, I'm gonna start a +1:54:27 +live stream where we build live on live stream and then we're going to release it after we're building we're building +1:54:34 +it on live stream, you know, because it's it's not uh like I just need one +1:54:40 +last iteration, but I can I can u maybe release it earlier than like it's it's +1:54:48 +going to take one month I think to recode this uh live. Maybe a lot less +1:54:54 +than that. I don't know. We'll we'll see. Not too +1:55:02 +long. And the application itself is Yeah, right now I'm waiting for Steam to +1:55:08 +review it. Um but yeah, um the thing +1:55:14 +is there are like when I like this is not the final +1:55:20 +form also. This is the 24-bit version. Uh but it's going to be 32 bits plus uh +1:55:27 +8 bits for tags and you know um stuff. Um, +1:55:33 +so yeah, there there you know it it wasn't the final form like this this was +1:55:41 +I knew that I this wouldn't be the final form and like because this was my first +1:55:46 +binary attempt um before this I had like two other text fors and this this was +1:55:53 +the first like binary form and I thought 24 bits would be enough but you know uh +1:55:59 +in the end it's slower. than using 32 bits. Um, and the reason +1:56:06 +for that is if you have tags together side by side like compact on an array, +1:56:13 +single bite tags, um, then you get fast skips, you know, so empty blocks you can +1:56:20 +skip super fast by just reading eight eight tags at a time and check for a zero. Like read eight bytes and check +1:56:27 +for a zero and if it's zero, then you can skip it. There are no instructions there versus you had to read 32 bytes +1:56:33 +and do like eight compares to see at least if this was like a um yeah comment +1:56:39 +or not, you know, basically because tag zero is essentially comments. Yeah. +1:56:49 +Cool. Well, that that was really awesome. Um thank you. All right. Um +1:56:55 +well, I I think that concludes our our meeting. I I'm going to hit the stop button on the recording and uh see you +1:57:03 +all next month. diff --git a/references/TimothyLottesBlog.csv b/references/TimothyLottesBlog.csv new file mode 100644 index 0000000..3c39260 --- /dev/null +++ b/references/TimothyLottesBlog.csv @@ -0,0 +1,22 @@ +"20070910 - 2 4th | !2 4th","https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20070910.html" +"20070912 - The Making of a Font","https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20070912.html" +"20070915 - Building the Chicken Without an Egg","https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20070915.html" +"20070919 - Editor Working","https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20070919.html" +"20070921 - Assembler in Atom4th","https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20070921.html" +"20140816 - Vintage Programming","https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20140816.html" +"20141231 - Continued Notes on Custom Language","https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20141231.html" +"20150414 - From Scratch Bug","https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20150414.html" +"20150420 - From Scratch Bug 2 : Source-Less Programming","https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20150420.html" +"20150422 - Source-Less Programming : 2","https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20150422.html" +"20150423 - Source-Less Programming : 3","https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20150423.html" +"20150424 - Source-Less Programming : 4","https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20150424.html" +"20150426 - Source-Less Programming : 5","https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20150426.html" +"20150710 - Inspiration Reboot","https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20150710.html" +"20150714 - 1536-1 : The Programmer Addiction = Feedback","https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20150714.html" +"20150715 - 1536-2 : Assembling From the Nothing","https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20150715.html" +"20150722 - 1536-3 : Simplify, Repeat","https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20150722.html" +"20150809 - 1536-4 : Coloring","https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20150809.html" +"20150810 - 1536-5 : Keys","https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20150810.html" +"20151113 - Rethinking the Symbolic Dictionary","https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20151113.html" +"20151222 - Random Holiday 2015","https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20151222.html" +"20161113 - Vintage Programming 2","https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20161113.html" \ No newline at end of file diff --git a/references/TimothyLottesBlog/20070910_-_2_4th__2_4th.md b/references/TimothyLottesBlog/20070910_-_2_4th__2_4th.md new file mode 100644 index 0000000..0367dfc --- /dev/null +++ b/references/TimothyLottesBlog/20070910_-_2_4th__2_4th.md @@ -0,0 +1,90 @@ +# 20070910 - 2 4th | !2 4th + +**Source:** https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20070910.html + +# 20070910 - 2 4th | !2 4th + + +![](20070910-A.jpg) + +After just finishing up the last show of the season for my Photography Business (lighting shot above from Monument Valley), +I will again soon have time to really push to finish Atom. + + +Besides working on optimization of the engine, I've flushed out the scripting language I'm going to use as a rapid development tool to produce the game. +Since I'm going solo on this endeavor, I'm fully taking advantage of the fact that I can deviate from the common C/C++ standard which would be a practical requirement of working in a large team. + + +One notable, successful, and practical use of non-C like languages for game development is the [Game Object Assembly Lisp (GOAL)](http://www.gamasutra.com/features/20020710/white_02.htm) +used to build Jax and Daxter for the PS2. With inline assembly and runtime code generation, +looks like they found a perfect mix of both a very high and very low level programming language. + + +**Forth** + +Similar in concept to GOAL, I've decided upon a Color Forth like rapid development programming tool for Atom which has the following advantages. + + + +1. Run-time x86/x86-64 binary code generation. Can code the game from inside the game itself. +2. Ability to natively mix low level assembly, mid-level systems programming, and high level scripting all in the same source code. + Full forth like factoring of code at any level. +3. Compiler which has no need of lexical analysis, preprocessing, parsing, or semantic analysis. + Code is in a binary form with near direct factored translation to machine code. + So full re-compile of the entire source base in less than a second, from within the game itself. +4. Built-in in-game console, code/data editor, scripting, and debug tool. Editor works somewhat like a mix between a console, text editor, spreadsheet, and a debugger. +5. Data mixed in code in native binary form. No need for serialization code, simply save the program's code and the program's data is "serialized" as it is saved to disk. +6. Insane ease of use, code is color syntax highlighted, tab completion, multiple views, auto lookup and view of code/data definitions/values as cursor moves from word to word, and more. +7. And most importantly, it is amazingly simple. Current prototype of the built-in x86/SSE assembler is less than 4K of code/data. + + +I'll be posting more as I work on this production tool. + + +For those who know about Color Forth here is a quick preview. I've deviated quite far. +For instance my dictionary is embedded in the code itself, and as you edit (moving the memory locations of words around), +dictionary pointers are automatically re-linked. So the dictionary is direct, there is no need for hashing or searching to lookup a word. +My cell size is 16 bytes (supports SSE vectors) for the stacks and the dictionary, but source code is still in 32-bit tokens. +I'm supporting floating point single and double precision. Source code is similar to Color Forth, with many exceptions. +I've split the tag bits into 2 blocks. So code tokens still have a "color" tag, but data is embedded directly in code tokens without any tag bits. +In order to know if the source token is code or just raw data, the shadows blocks now contain extra tags fields which note code vs data and if data, +the type of the data (text, bytes, words, float, double, vector etc). So shadow blocks no longer contain comments, +instead they contain tag bits and are used to encode the dictionary directly (holding the strings to name words). + + +More later ... but for now, here is a shot as I was prototyping the language, prior to deciding to embed the dictionary in the source code. +**Of course, I've already changed all this but it will give you an idea.** +At this point in the development the colors were as follows, + + + +1. DEFINE-TOKEN: Copy address of this token into dictionary word indexed by tag index field. +2. DEFINE-COMPILED: Copy memory stack top pointer into dictionary word indexed by tag index field. +3. DEFINE-VARIABLE: Copy data from token (or vector of 2 or 4 tokens based on tag type field) into dictionary word indexed by tag index field. +4. COMMENT: If tag is not set to define then tag index field is a comment. +5. JUMP: Dictionary word indexed by token is a pointer to a code token, jump interpreter to that point. +6. INTERPRET: Dictionary word indexed by token is a pointer to a code token, push current interpreter position on interpreter return stack, + then jump interpreter to that point. +7. EXECUTE: Dictionary word indexed by token is a function pointer, call that function. +8. COMPILE: Dictionary word indexed by token is a function pointer, compile a call to that function at the current memory stack top. + Advance the memory stack top to point to after the compiled CALL opcode. +9. PUSH-TOKEN: Push data from token (or vector of 2 or 4 tokens based on tag type field) into data stack. +10. PUSH-WORD: Push cell value from dictionary word indexed by token onto data stack. +11. POP-WORD: Pop cell top of data stack into dictionary word indexed by token. +12. IGNORE: Ignore token. Used for extra comments, and defining data. + + + +The shot shows part of the assembler code block. If you read enough to decode it, you will notice that I was assembling with interpreted instead of compiled code. +Click on the image to see the full size version which is actually readable... + +[![](20070910-B.jpg)](20070910-B.jpg) + +**Interested in "Moore" Forth?** + +Check out the evolution of Forth and the work of Chuck Moore (Forth's Inventor), specifically +[Color Forth](http://www.colorforth.com/cf.html) and +[Jeff Fox's](http://www.ultratechnology.com/dindex.htm) writings. +Moore's ideas are simply revolutionary, asynchronous massively multi-processing ultra-low power (24 billion operations / second at 450mW, yes thats mW!) +[18-bit forth based processor](http://www.intellasys.net/products/index.php?target=seaforth/SEAforth24A.txt) +designed for embedded DSP and more. \ No newline at end of file diff --git a/references/TimothyLottesBlog/20070912_-_The_Making_of_a_Font.md b/references/TimothyLottesBlog/20070912_-_The_Making_of_a_Font.md new file mode 100644 index 0000000..200e5d9 --- /dev/null +++ b/references/TimothyLottesBlog/20070912_-_The_Making_of_a_Font.md @@ -0,0 +1,31 @@ +# 20070912 - The Making of a Font + +**Source:** https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20070912.html + +# 20070912 - The Making of a Font + + +Yes the font looks tiny on the web, but at its 640x480 target resolution it is 100% readable. + + +*(Lost Image)* + + +For the Atom Forth Editor I needed a raster font which met a very specific set of constraints. + + + +* The font must work perfect at 640x480.* It must support 64 characters in 640 pixels wide.* It must also support 9 characters in 40 pixels wide.* It must be readable when drawn over the same color background. + + +The editor is displaying 16 32-bit tokens per line, with each line containing 2 sub-lines. The top sub-line shows 4 characters, and the bottom shows data, which can be formated with up to 9 characters. So the font was built exactly for these guidelines. I also went with lowercase as just smaller uppercase letters, in order to remove the need for any descending pixels, and thus pack in more lines per screen. + + +**Building the Font** + +For the font texture I'm using the Red channel as a font shadow mask, and the Green channel as the font, hence the red background and green lettering at the top. The extra spacing is so that texture interpolation works correctly. In order to have anti-aliasing and font features on exact pixel boundaries for great readability, I started with drawing an aliased version of the font at its native size. Then nearest-up-sized to 4x its original size, and cleaned the bitmap. Then finally bilinear downsized to the native resolution to have perfect anti-aliasing and readability. + + +**Why 640x480?** + +Ever watch a HDTV broadcast of a home Celtics basketball game? The MPEG artifacting during any motion is horrendous, especially on the wood grain of the court. It is so bad and distracting, I'd rather watch it on regular TV or even TV resolution DirectTV. The point? Technology is pushing huge resolution, but image quality is suffering. As like HDTV, what is the point of HD games with such bad aliasing problems? Personally I prefer a perfectly anti-aliased 640x480. So for Atom I am targeting 640x480 as the midrange resolution. Sure 1024 and larger if you have a fast GPU, and also 512 and smaller if you have a really slow GPU. But regardless of the resolution, Atom is always going to have perfect anti-aliasing. \ No newline at end of file diff --git a/references/TimothyLottesBlog/20070915_-_Building_the_Chicken_Without_an_Egg.md b/references/TimothyLottesBlog/20070915_-_Building_the_Chicken_Without_an_Egg.md new file mode 100644 index 0000000..52c1891 --- /dev/null +++ b/references/TimothyLottesBlog/20070915_-_Building_the_Chicken_Without_an_Egg.md @@ -0,0 +1,32 @@ +# 20070915 - Building the Chicken Without an Egg + +**Source:** https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20070915.html + +# 20070915 - Building the Chicken Without an Egg + + +The classic Chicken and Egg problem, I really did want to write the editor for Atom Forth in the Atom Forth language, but atlas, it is hard to edit a binary source format without the editor. My solution was to get the editor up quickly using C, and add some "syscall" hooks in Atom Forth for controlling the editor. Later when I have the time, I will port the editor over to Atom Forth. + + +**Random Progress** + +Just finished up the display code, screen shot below shows formatting of completely random data. Got the initial coloring somewhat where I want it. Already moved on to the editing code. Soon this will actually be usable. With the help of objdump -d and gas wrote the initial interpreter, using the dis-assembly to grab the byte stream for various interpreted opcodes like, + + + +``` + +0000000000400745 SAdd: +400745: 48 03 47 00 :: add 0x0(%rdi),%rax +400749: 48 83 c7 f0 :: add $0xfffffffffffffff0,%rdi +40074d: c3 :: retq +``` + + +Also this is my first time really getting into the binary opcode details of the 64bit extension to the x86 instruction set for my assembler and the differences between the C ABI between Linux and Windows for my C "syscall" interface. I've noticed Microsoft made a subtle but important optimization error in their C calling convention concerning how SSE values are saved and restored during function calls. The problem is that they have SSE regs xmm6-xmm15 as callee saved. Of course the callee doesn't know the type of data in the SSE regs, it could be scaler float, scaler double, vector float, vector double, and vector integer, all of which have separate load and store opcodes. On the Core Duo 2 and newer Intel processors, there is a performance penalty for using instructions which don't match the type of data currently in the SSE regs. This is caused by the processor having to do an extra internal conversion (probably because the register file is not stored in exact binary format, i.e. different radix between int and float for low latency ALU operations). + + +Well I am on day 5 of designing and writing a new language plus its interpreter, compiler, assembler, and runtime source editing tool. Not bad for just 5 days. More later when this thing actually works... + + +*(Lost Image)* \ No newline at end of file diff --git a/references/TimothyLottesBlog/20070919_-_Editor_Working.md b/references/TimothyLottesBlog/20070919_-_Editor_Working.md new file mode 100644 index 0000000..19873a3 --- /dev/null +++ b/references/TimothyLottesBlog/20070919_-_Editor_Working.md @@ -0,0 +1,10 @@ +# 20070919 - Editor Working + +**Source:** https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20070919.html + +# 20070919 - Editor Working + + +![](20070919.jpg) + +Got the editor fully working, 1800 lines of highly factored dense C code (I put multiple statements on one line). Now moving into incorporating the Atom Forth interpreter (which is only one page of assembly), followed by writing the assembler in Atom Forth, and lastly porting the editor and interpreter over to Atom Forth. Will then be able to edit the source code of the editor from within the editor itself, which is great for extending/modifying the editor when I need new keyboard shortcuts or other features! \ No newline at end of file diff --git a/references/TimothyLottesBlog/20070921_-_Assembler_in_Atom4th.md b/references/TimothyLottesBlog/20070921_-_Assembler_in_Atom4th.md new file mode 100644 index 0000000..27fc87a --- /dev/null +++ b/references/TimothyLottesBlog/20070921_-_Assembler_in_Atom4th.md @@ -0,0 +1,26 @@ +# 20070921 - Assembler in Atom4th + +**Source:** https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20070921.html + +# 20070921 - Assembler in Atom4th + + +![](20070921.jpg) + +Nearly finished with writing a x86-32/64 bit assembler in the Atom4th language. The shot above shows about 50% of the code, excluding the opcode tables. In the process, I've changed a few things about the editor and fine-tuned the programming style. The final code for the assembler (which I still have to test) is nearly the same as what I had prototyped in Excel, see the screen shot from [20070910](20070910.html), except I've moved the assembler over to being fully compiled instead of interpreted. + + +**Again, Why Atom4th?** + +The way I like to think about this is like the difference between your average bland front wheel drive car which might be able to do a one wheel burnout if you mash the gas pedal, and a raw striped down vintage road racing prototype race car. + + +99.99999% of people enjoy the comfort of knowing absolutely nothing about their car (after all, what the hell is a one wheel burn out anyway?), it gets good gas millage and goes from A to B. This front drive car is like C and other common languages. It is the work horse of near the entire world. + + +For the other 0.00001% there is the need for something different, something that requires intimate knowledge of the machine, purpose built to extract extreme performance, and yet simple enough to work on. This is the essence of vintage. To go back to simpler times, and have the freedom and access to do awesome things. Atom4th is that exotic vintage race car designed for those who get an adrenaline rush from the chest pounding 100+ decibel exhaust note and taste of ultra high octane leaded race gas. + + +**So What's Next** + +Building this beast is taking longer than I expected, but with the assembler soon done, I'll be back onto the game engine, porting it to and optimizing it in Atom4th. I'm guessing the 4000 lines of C game engine code will factor out and simplify into about 32 Atom4th pages (at 32 line pairs per page). Porting the Atom4th editor into Atom4th is about 1800 lines of C code to port, so I'm going to skip that until way later, so I can get back to work on the actual game. \ No newline at end of file diff --git a/references/TimothyLottesBlog/20140816_-_Vintage_Programming.md b/references/TimothyLottesBlog/20140816_-_Vintage_Programming.md new file mode 100644 index 0000000..0367ab0 --- /dev/null +++ b/references/TimothyLottesBlog/20140816_-_Vintage_Programming.md @@ -0,0 +1,62 @@ +# 20140816 - Vintage Programming + +**Source:** https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20140816.html + +# 20140816 - Vintage Programming + + +A photo (not a screenshot) of one of my home vintage development environments running on modern fast PCs. Shot shows colored syntax highlighted source to the compiler of the language I use most often (specifically the part which generates the ELF header for Linux). More on this below. + +![](20140816-A.png) + +This is running 640x480 on a small mid 90's VGA CRT which supports around 1000 lines. So no garbage double scan and no horrible squares for pixels. Instead a high quality analog display running at 85 Hz. The font is my 6x11 fixed size programming font. + +![](20140816-B.png) + +This specific compiler binary on x86-64 Linux is under 1700 bytes. + +**A Language** + +The language is ultra primitive, it does not include a linker, or anything to do code generation, there is no debugger (and it frankly is not needed as debuggers are slower than instant run-time recompile/reload style development). Instead the ELF (or platform) header for the binary, and the assembler or secondary language which actually describes the program, is written in the language itself. + +Over the years I've been playing with either languages which are in classic text form, and languages which require custom editors and are in a binary form. This A language is the classic text source form. All the variations of languages I've been interested in are heavily influenced by [Color Forth](http://www.colorforth.com/). + +This A compiler works in 2 passes, the first both parses and translates the source into x86-64 machine code. Think of this as factoring out the interpreter into the parser. The second pass simply calls the entry point of the source code to interpret the source (by running the existing generated machine code). After that whatever is written in the output buffer gets saved to a file. + +Below is the syntax for the A language. A symbol is an untyped 64-bit value in memory. Like Forth there is a separate data and return stack. + + +\comment\ +012345- \compile: push -0x12345 on the data stack\ +,c3 \write a literal byte into the compile stream\ +symbol \compile: call to symbol, symbol value is a pointer to function\ +'symbol \compile: pop top of data stack, if value is true, call symbol\ +`symbol \copy the symbol data into the compile stream, symbol is {32-bit pointer, 32-bit size}\ +:symbol \compile: pop data stack into symbol value\ +.symbol \compile: push symbol value onto data stack\ +%symbol \compile: push address of symbol value onto data stack\ +"string" \compile: push address of string, then push size of string on the data stack\ +{ symbol ... } \define a function, symbol value set to head of compile stream\ + +And that is the A language. The closing "}" writes out the 32-bit size to the packed {32-bit pointer, 32-bit size} symbol value, and also adds an extra RET opcode to avoid needing to add one at the end of every define. There is one other convention missing in the above description, there is a hidden register used for the pointer to the output buffer. + +**Writing Parts of the Language in the Language** + +The first part of any source file is a collection of opcodes, like the *{ xor ,48 ... }* at the top of the image which is the raw x86-64 machine code to do the following in traditional assembly language (rax = top of data stack, rbx points to second data stack entry), + + +XOR rax, [rbx] +SUB rbx, 8 + +These collection of opcodes generate symbols which form the stack based language the interpreter uses. They would get used like *`xor* in the code (the copy symbol to compile stream syntax). For instance *`long* pops the top of the data stack and writes out 8-bytes to the output buffer, and *`asm* pushes the output buffer pointer onto the data stack. + +I use this stack based language to then define an assembler (in the source code), and then I write code in the assembler using the stack based language as effectively the ultimate macro language. For instance if I was to describe the *`xor* command in the assembly it would look like follows, + + +{ xor .top .stk$ 0 X@^ .stk$ 8 #- } + +Which is really hard to read without syntax coloring (sorry my HTML is lazy). For naming, the "X" = 64-bit extended, the "@" = load, and the "#" = immediate. So the "X@^" means assemble "XOR reg,[mem+imm]". The symbols "top" and "stk$" contain the numbers of the registers for the top of the stack and the pointer to the second item on the stack respectively. + +**Compiler Parser** + +The compiler parsing pass is quite easy, just a character jump table based on prefix character to a function which parses the {symbol, number, comment, white space, etc}. These functions don't return, they simply jump to the next thing to parse. As symbol strings are read they are hashed into a register and bit packed into two extra 64-bit registers (lower 4-bits/character in one register, upper 3-bits/character in another register). This packing makes string compare easy later when probing. Max symbol string is 16 characters. Hash table is a simple linear probing style, but with an array 2 of entries per hash value filling one cacheline. Each hash table entry has the following 8-byte values {lower bits of string, upper bits of string, pointer to symbol storage, unused}. The symbol storage is allocated from another stack (which only grows). Upon lookup, if a symbol isn't in the hash table it is added with new storage. Symbols never get deleted. \ No newline at end of file diff --git a/references/TimothyLottesBlog/20141231_-_Continued_Notes_on_Custom_Language.md b/references/TimothyLottesBlog/20141231_-_Continued_Notes_on_Custom_Language.md new file mode 100644 index 0000000..255da2c --- /dev/null +++ b/references/TimothyLottesBlog/20141231_-_Continued_Notes_on_Custom_Language.md @@ -0,0 +1,249 @@ +# 20141231 - Continued Notes on Custom Language + +**Source:** https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20141231.html + +# 20141231 - Continued Notes on Custom Language + + +*Continuing notes on portable development for Linux and Windows using a custom language...* + +Using [WINE](https://www.winehq.org/) on Linux for Windows development is working great: ability to use OpenGL 4.x in native 64-bit WIN32 binaries on Linux. Using the same compiler to build both Linux and Windows binaries which can both be run from the same Linux box. + +**Forth-like Language as a Pre-Processor for Code-Generation** + +My 1706 byte compiler takes a stream of prefixed text: mostly {optional prefix character, then word, then space} repeated... + +\comment\ +word \compile call to address at word\ +:word \compile pop data stack into word\ +.word \compile push 64-bit value at word onto data stack\ +'word \compile conditional call to address at word if pop top of stack is non-zero\ +`word \copy opcodes at word into compile stream\ +%word \compile push address of word, still haven't used this\ +{ word \define word, stores compile address in word, then at closing stores size (used for opcodes)\ } +34eb- \compile push hex number negated\ +,c3 \write raw byte into compile stream, x86 ret opcode in this example\ +"string" \compile push address of string, then push size of string\ + +Compiler strips whitespace and comments while converting the input words into machine code (using the conventions above), then executes the machine code. +There is no "interpreter" as would normally be used in a Forth based language. +The compiler does not even have the standard Forth opcodes, +these are instead just specified in the input source file. For example ADD, + +{ add ,48 ,03 ,03 ,83 ,eb ,08 } + +Which is the raw opcode stream for "MOV rax,[rbx]; ADD rbx,8" where "rax" is the top of the data stack, and "rbx" points to the 2nd item on the data stack. Since Forth opcodes are zero operand, it is trival to just write them in source code directly (language is easily extendable). I use under 30 forth style opcodes. After an opcode is defined, it can be used. For example, + +10 20 `add + +Which pushes 16 then 32 on the data stack (numbers are all in hex), then adds them. To do anything useful, words are added which pop a value from the data stack and write them to a buffer. For example write a byte, + +{ byte ,40 ,88 ,07 ,83 ,c7 ,01 ,48 ,8b ,03 ,83 ,eb ,08 } + +Once the compiler is finished executing the machine code generated by the source, which in turn is used to write a binary into a buffer, the compiler stores that buffer to disk and exits. In order to do anything useful the next step is to use the language and source opcodes which extend the language to build an assembler. Some bits of my assembler (enough for the ADD opcodes), + +\setup words for integer registers\ +0 :rax 1 :rcx 02 :rdx 03 :rbx 04 :rsp 05 :rbp 06 :rsi 07 :rdi +8 :r8 9 :r9 0a :r10 0b :r11 0c :r12 0d :r13 0e :r14 0f :r15 + +\words used to generate the opcode\ +{ REXw 40 `add `byte } +{ REX .asmR 1 `shr 4 `and .asmRM 3 `shr `add `dup 'REXw `drp } +{ REXx .asmR 1 `shr 4 `and .asmRM 3 `shr `add 48 `add `byte } +{ MOD .asmR 7 `and 8 `mul .asmRM 7 `and `add .asmMOD `add `byte } +{ OP .asmOP 8 `shr 'OPh .asmOP `byte } +{ OP2 :asmOP :asmRM :asmR 0c0 :asmMOD REX OP MOD } +{ OP2x :asmOP :asmRM :asmR 0c0 :asmMOD REXx OP MOD } + +\implementation of 32-bit and 64-bit ADD\ +{ + 03 OP2 } { X+ 03 OP2x } + +Afterwords it is possible to write assembly like, + +.rax .rbx + \32-bit ADD eax,ebx\ +.rax .rbx X+ \64-bit ADD rax,rbx\ + +Due to the complexity of x86-64 ISA, I used roughly 300 lines to get a full assembler (sans vector opcodes). With a majority of those opcodes not even getting used in practice. The [ref.x86asm.net/coder64.html](http://ref.x86asm.net/coder64.html) site is super useful as an opcode reference. + +**Binary Header** + +Next step is writing source to generate either a PE (Windows) or ELF (Linux) binary header. ELF with "dlsym" symbol used roughly 70 lines (mostly comments to describe the mess of structure required for an ELF). The PE header I generate for WIN32 binaries looks similar to [this example from Peter Ferrie](http://pferrie.host22.com/misc/pehdr.htm) +which is a rather minimal header with non-standard overlapping structures. +I added an import table for base Kernel32 functions like "LoadLibraryA", +because of fear that manual run-time "linking" via PEB would trigger virus warnings on real Windows boxes. +I'm not really attempting to hit a minimum size (like a 4KB demo), but rather just attempting to limit complexity. +WINE handles my non-standard PE with ease. + +If I was to write an OS, I wouldn't have binary headers (PE/ELF complexity just goes away). Instead I would just load the binary at zero, with execution starting at 4 with no stack setup, with binary pages loaded with read+write+execute, and then some defined fixed address to grab any system related stuff (same page always mapped to all processes as read-only). This has an interesting side effect that JMP/CALL to zero would just restart the program (if nop filled) or do exception (if invalid opcode filled). Program start would map zero-fill and setup stack. I'd also implement thread local storage as page mapping specific to a thread (keeping it simple). + +**ABI: Dealing With the Outside World** + +Having your own language is awesome ... dealing with the C based Linux/Windows OS is a pain. I use a 8-byte stack alignment convention. The ABI uses a 16-byte stack alignment convention. The ABI for Linux Kernel, Linux C export libraries, and 64-bit Windows is different. Here is a rough breakdown of register usage, + +\_ \_\_\_ \_ LXK LXU WIN +0 rax . +1 rcx . k0 a3 a0 +2 rdx . a2 a2 a1 +3 rbx . s0 s0 s0 +4 rsp X +5 rbp X t0 t0 t0 +6 rsi . a1 a1 a4 <- stored before call on WIN +7 rdi . a0 a0 a5 <- stored before call on WIN +8 r8\_ . a4 a4 a2 +9 r9\_ . a5 a5 a3 +a r10 . a3 k0 k0 +b r11 . k1 k1 k1 +c r12 X t1 t1 t1 +d r13 X t2 t2 t2 +e r14 . s1 s1 s1 +f r15 . s2 s2 s2 + +rax = return value (or syscall index in Linux) +rsp = hardware stack +a# = register argument (where Windows 64-bit a4 and a5 are actually on the stack) +t# = temp register saved by callee, but register requires SIB byte for immediate indexed addressing +s# = register saved by callee, no SIB required for immediate indexed addressing +k# = register saved by caller if required (callee can kill the register) + +I use a bunch of techniques to manage portability. Use a set of words {abi0, abi1, abi2 ... } and {os0, os1, os2 ... } (for things which map to Linux system calls) which map to different registers based on platform. Use word "ABI(" to store the stack into R13, then align the stack to 16-bytes, then setup a stack frame for the ABI safe for any amount of arguments. Words "ABI", "ABI5", "ABI6+" to do ABI based calls based on the number of integer arguments needed for the call. This is needed because Linux supports 6 arguments in registers, and Windows only supports 4. Then later ")ABI" to get my 8-byte aligned stack back, + +{ ABI( .abiT2 .rsp X= .rsp 0fffffffffffffff0 X#& .rsp 50- X#+ } +{ ABI \imm\ #@CAL } \call with up to 4 arguments\ +{ ABI5 \imm\ #@CAL } \call with 5 arguments\ +{ ABI6+ \imm\ #@CAL } \call with 6 or more arguments\ +{ )ABI .rsp .abiT2 X= } + +With the following words overriding some of the above words on Windows (slighly more overhead on Windows), + +{ ABI(.W .abiT2 .rsp X= .rsp 0fffffffffffffff0 X#& .rsp 80- X#+ } +{ ABI5.W .abi4 .abiW4 PSH! \imm\ #@CAL } +{ ABI6+.W .abi4 .abiW4 PSH! .abi5 .abiW5 PSH! \imm\ #@CAL } + +So a C call to something like glMemoryBarrier would end up being something like, + +ABI( .abi0 \GL\_BUFFER\_UPDATE\_BARRIER\_BIT\ 200 # .GlMemoryBarrier ABI )ABI + +And in practice the "ABI(" and ")ABI" would be factored out to a much larger group of work. The "#@CAL" translates to call to "CALL [RIP+disp32]", since all ABI calls are manual dynamic linking the ".GlMemoryBarrier" is the address which holds the address to the external function (in practice I rename long functions into something smaller). Since both Windows and Linux lack any way to force libraries into the lower 32-bits of address space, and x86-64 has no "CALL [RIP+disp64]", I decided against run-time code modification patching due to complexity (would be possible via "MOV rax,imm64; CALL rax"). Both Windows and Linux require slightly different stack setup. Convention used for Linux (arg6 is the 7th argument), + +-58 pushed return +-50 arg6 00 <---- aligned to 16-bytes, ABI base +-48 arg7 08 +-40 arg8 10 +-38 arg9 18 +-30 argA 20 +-28 argB 28 +-20 argC 30 +-18 argD 38 +-10 argE 40 +-08 argF 48 ++00 aligned base + +Convention used for Windows, + +-88 pushed return +-80 .... 00 <---- aligned to 16-bytes, ABI base +-78 .... 08 +-70 .... 10 +-68 .... 18 +-60 arg4 20 +-58 arg5 28 +-50 arg6 30 +-48 arg7 38 +-40 arg8 40 +-38 arg9 48 +-30 argA 50 +-28 argB 58 +-20 argC 60 +-18 argD 68 +-10 argE 70 +-08 argF 78 ++00 aligned base + +The C based ABI and associated +"{{save state, call, ... nesting ..., return, load state} small amount of code} repeat ...}" pattern +forces inefficient code in the form of code bloat and constant shuffling around data between functional interfaces. +Some percentage of callee-save registers are often used to shadow arguments, +often data is loaded to register arguments +only to be saved in memory again for the next call, +caller saves happen even when the callee does not modify, etc. + + +I'd much rather be using a "have command structures in memory, fire-and-forget array of pointers to commands" model. +The fire-and-forget model is more parallel friendly (no return), +and provides ability for reuse of command data (patching). +The majority of system calls or ABI library calls could just be baked command data which exists in the binary. +Why do I need to generate complex code to do constant run-time generation and movement of mostly static data? + + +I conceptionally treat registers as a tiny fast compile-time immediate-indexed RAM (L0$). +Register allocation is a per-task process, not a per-function process. +There is no extra shuffling of data. No push/pop onto stack frames, etc. +For example register allocation is fixed purpose during the two passes +of the compiler, + +\\_\_\_\_REGISTERS\_DURING\_COMPILE\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\ +.rax :chr \input character\ .rax :dic \dictionary entry address\ .rax :str# +.rcx :hsh \hash value\ .rcx :jmp \jump address\ .rcx :num .rcx :str$ +.rdx :pck1 \string packing 1\ .rdx :num- .rdx :siz +.rbx :pck2 \string packing 2\ .rbx :chr$1 +.rbp :dic$ \dictionary top pointer, not addressed from\ +.rsi :chr$ \input pointer\ +.rdi :mem$ \memory stack, compile stack\ +.r8 :def$ \define stack\ +.r15 :zero \set to zero\ +\\_\_\_\_REGISTERS\_DURING\_EXECUTE\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\ +.rax :top \rax used for .dic only at launch\ +.rcx :cnt \counter on text copy\ +.rdx :fsk$ \float stack pointer, points to 2nd entry\ +.rbx :stk$ \data stack pointer, points to 2nd entry\ +.rsi :txt$ \used for source on text copy\ +.rdi :out$ \output pointer, points to next empty byte\ + +**Debugging** + +My dev environment is basically two side by side terminal windows per virtual desktop with a easy switch to different virtual desktops. +I'm using nano as a text editor and have some rather simple color syntax highlighting for my language. +No IDE no debugger. Proper late stone-age development. + +To port to WIN32 I did have to fix some code generation bugs with regard to having a non-zero ORG. +On Linux I load the binary at zero, so file offset and loaded offsets are the same. +This is not possible in Windows. +IMO there is more utility in keeping it simple than having zero page fault. +When tracking down bugs in code generation or binary headers I just use "hexdump -C binary". +My language supports injection of any kind of data during code generation, +so it is trivial to just wrap an instruction or bit of code or data with something like "--------" +which is easy to find via "hexdump -C binary | less". + +The Forth inspired language I use has only one possible error, attempting to call a word which has not been defined (which calls zero). +My compiler does not print any error messages, it simply crashes on that error. +Since in practice this effectively almost never happens, I've never bothered to have it write out an error message. +The last time I misspelled a word, it was a super quick manual log search (commenting out code) to find the error. +When compiling and testing is perceptually instant, lots of traditional complexity is just not needed. + +As for regular development, I started programming when a bug would take down the entire machine (requiring reboot). +Being brought up in that era quickly instills a different kind of development process +(one that does not generate bugs often). +Most bugs I have are opcode mistakes (misspellings), like load "@" instead of store "!", or using a 32-bit form of an opcode instead of the 64-bit form. +The only pointers which are 64-bit in my binaries are pointers to library functions (Linux loads libraries outside the 32-bit address space), +the stack (I'm still using the OS default instead of moving to the lower 32-bit address space), or pointers returned by a library. +When dealing with bugs with an instant iteration cycle, "printf" style debug is the fast path. +I've built some basic constructs for debugging, + +BUG( "message" )BUG \writes message to console\ +.bugN .rax = 10 BUG# \example: prints the hex value in RAX to 16 digits to console\ + +Adding something to my "watch window" is just adding the code to output the value to the console. +This ends up being way better than a traditional debug tool because console output provides +both the history and timeline of everything being "watched". + +**Misc** + +In the past I had a practice of building a custom editor and run-time for each language. +The idea being that it was more efficient to compile from a binary representation, +which has a dictionary embedded in the source code (no parsing, no hashing). +Ultimately I moved away from that approach due to the complexity involved in building the editor that I wanted for the language. +Mostly due to the complexity of interfacing with the OS. +It is really easy to fall in the trap of building a tool which is many times more complex than the problem the tool is engineered to solve. + +Decoupling from the dependency of a typical compiler and toolchain on modern systems has been a great learning experience. +If FPGA perf/$ was competitive with GPUs I'd probabably move on to building at the hardware level instead... \ No newline at end of file diff --git a/references/TimothyLottesBlog/20150414_-_From_Scratch_Bug.md b/references/TimothyLottesBlog/20150414_-_From_Scratch_Bug.md new file mode 100644 index 0000000..01ff774 --- /dev/null +++ b/references/TimothyLottesBlog/20150414_-_From_Scratch_Bug.md @@ -0,0 +1,16 @@ +# 20150414 - From Scratch Bug + +**Source:** https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20150414.html + +# 20150414 - From Scratch Bug + + +Inspired by Jaymin's [JayStation2](http://jaystation2.maisonikkoku.com/JayStation2/JayStation2.html) effort and remembering a past life building custom OSs for early x86 machines, haven't been able to avoid the custom OS bug any longer. It starts easy with a harmless QEMU install, followed by a 512-byte bootloader switching to 80x50 text mode and installing a custom 48 character Forth font, then bring up of a Forth assembler/editor, then on to the pain of modern PCI and USB driver bring-up... with the eventual goal of a tiny bootable USB thumb system. + +Amazingly refreshing to not have the OS telling you NO. Or the API telling you NO. Modern systems are all about the NO. Systems I grew up on were all about the YES. + +Reworking my language from scratch, trying something new, replacing the Forth data stack with a new concept, but maintaining zero operand opcodes. Not sure if the idea will pan out. Dropping everything but 32-bit word support from the language, no need to interop with other software. No more 8/16/64-bit loads or stores (can still just inline machine code if required). Still running in x86-64 64-bit mode, so return stack PUSH/POP/CALL/RET is still a 64-bit stack operation, just don't need that 64-bit address space or 64-bit pointers anywhere else. Trying padding out all x86 opcodes to 32-bit alignment. This makes the 32-bit immediate 32-bit aligned. Wastes space, gives up some perf? Why would I care when most of the CPU side of the system fits in the L1 cache. Dropping paging, dropping interrupts, dropping everything, none of that stuff is needed. + +Reworking an editor and binary source encoding. Switching to 32-bit tokens with 5 character max strings. 48 character character-set. Doing something horrible with font design: 1=I, 0=O, 2=Z, 5=S, etc. All caps font with no non-vertical or non-horizonal lines. Actually looks awesome. When you don't have to interop with the NO machine, long symbol names are not required. Color Forth like editors have almost no state. It is magical how they function simultaneously as an editor/assembler/console/debugger/UI/etc. Take the idea of "editor-time-words", words embedded in the source code which are evaluated when the block of source is drawn to the screen. Becomes possible to build out UI tools in the source. Can have an editor-time word read system data and draw in real-time updates in the source code itself. Editor-time words are just like any other word in the system, just color tagged to only be evaluated at draw time. + +Minimal systems are a blessing, more so when you have only minimal free time to work on them. \ No newline at end of file diff --git a/references/TimothyLottesBlog/20150420_-_From_Scratch_Bug_2__Source-Less_Programming.md b/references/TimothyLottesBlog/20150420_-_From_Scratch_Bug_2__Source-Less_Programming.md new file mode 100644 index 0000000..c486568 --- /dev/null +++ b/references/TimothyLottesBlog/20150420_-_From_Scratch_Bug_2__Source-Less_Programming.md @@ -0,0 +1,40 @@ +# 20150420 - From Scratch Bug 2 : Source-Less Programming + +**Source:** https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20150420.html + +# 20150420 - From Scratch Bug 2 : Source-Less Programming + + +*This is a disruptive idea which comes back periodically: source-less programming. +Is it possible to efficiently program at a level even lower than an assembler?* + +The general idea is that the editor is now something similar to an enhanced hex editor which edits a binary image directly. +Lowest memory is split into three parts {{running image, annotations for edit image}, edit image}. +The {running image, annotations for edit image} is the boot image. +The {edit image} is working space which gets snapshot replacement for {running image} on a safe transition zone. +The "annotation" section is what enables human understanding of the binary image. + +**Words** + +One way to keep the system very simple is to always work in 32-bit words. +A 32-bit word in memory is one of four things {data, opcode, absolute address, rip relative address}. +Data is easily handled by the hex editor part. +The annotation could provide a name for the data or a comment. +Opcodes in x86 can be complex but it is easy to simplify. +Start with something similar to forth zero-operand and one-operand operations (calls, etc). +Make all operations padded to 32-bit alignment (x86-64 can use the 2e ignored prefix to pad). +A call for instance becomes {32-bit opcode for call, 32-bit rip relative branch address}. +Or a global load becomes {32-bit opcode for load, 32-bit rip relative branch address}. +Annotation memory can provide a name for the opcode. +Annotation can provide a tag for each word in memory which marks +if the memory is a relative or absolute address (word gets a different color based on tag similar to color forth). +Addresses can be auto annotated by displaying the annotation associated with the destination. +Editor works on the {edit image}, +with insert and delete of words automatically adjusting all the words tagged as address +(effectively relinking at edit time). +The {edit image} can also keep a mapping of original {running image} address +so that it is possible to view the live values of any data. +Editor provides something to easily be able to write an annotation +and have the associated opcode or address automatically get updated. +For example type the opcode name and the 32-bit value is automatically updated. +Very simple and yet powerful minimal tool. \ No newline at end of file diff --git a/references/TimothyLottesBlog/20150422_-_Source-Less_Programming__2.md b/references/TimothyLottesBlog/20150422_-_Source-Less_Programming__2.md new file mode 100644 index 0000000..8776a1a --- /dev/null +++ b/references/TimothyLottesBlog/20150422_-_Source-Less_Programming__2.md @@ -0,0 +1,72 @@ +# 20150422 - Source-Less Programming : 2 + +**Source:** https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20150422.html + +# 20150422 - Source-Less Programming : 2 + + +*Continuing with what will either be an insanely great or amazingly stupid project...* + +Making slow progress with bits of free-time after work, far enough thinking through the full editor design to continue building. Decided to ditch 64-bit long mode for 32-bit protected mode. Not planning on using the CPU for much other than driving more parallel friendly hardware... so this is mostly a question of limiting complexity. +Don't need 16 registers and the REX prefix is too ugly for me to waste time on any more. +The 32-bit mode uses much more friendly mov reg,[imm32] absolute addressing, +also with ability to use [EBP+imm32] without an SIB byte (another thing I mostly avoid). +Unfortunately still need relative addresses for branching. +32-bit protected mode thankfully doesn't require page tables unlike 64-bit long mode. +Can still pad out instructions to 32-bits via reduntant segment selectors. + +**Source-Less Analog to Compile-Time Math?** + +Compile-time math is mostly for the purpose of self-documenting code: +"const uint32\_t willForgetHowICameUpWithThisNumber = startHere + 16 \* sizeof(lemons);". +The source-less analog is to write out the instructions to compute the value, +execute that code at edit time, then have anotations +for 32-bit data words which automatically pull from the result when building 32-bit words for opcode immediates for the new binary image. + +**Reduced Register Usage Via Self Modifying Code** + +Sure, kills the trace cache in two ways, what do I care. +Sometimes the easist way to do something complex is to +just modify the opcode immediates before calling into the function... + + +**What Will Annotations Look Like?** + +The plan so far is for the editor to display a grid of 8x8 32-bit words. +Each word is colored according to a tag annotation +{data, absolute address, relative address, pull value}. +Each word has two extra associated annotations {LABEL, NOTE}. +Both are 5 6-bit character strings. +Words in grid get drawn showing {LABEL, HEX VALUE, NOTE} as follows, + + +LABEL +00000000 +NOTE + +The LABEL provides a name for an address in memory (data or branch address). +Words tagged with absolute or relative addresses or pull value show in the NOTE field +the LABEL of the memory address they reference. +Words tagged with data use NOTE to describe the opcode, or the immediate value. +Editor when inserting a NOTE can grab the data value from other words +with the same NOTE (so only need to manually assemble an opcode once). +Edit-time insert new words, delete words, and move blocks of words, +all just relink the entire edit copy of the binary image. +ESC key updates a version number in the edit copy, +which the excuting copy sees triggering it to replace itself +with the edit copy. + + +**Boot Strapping** + +I'm bootstrapping the editor in NASM in a way that I'll be able +to see and edit later at run-time. +This is a time consuming process to get started +because instead of using NASM to assemble code, +I need to manually write the machine code to get the 32-bit padded opcodes. +Once enough of the editor is ready, +I need a very tiny IDE/PATA driver to be able to store to the disk image. +Then I can finish the rest of the editor in the editor. +Then I'll also be self hosted outside the emulator +and running directly on an old PC with a non-USB keyboard, +but with a proper PCIe slot... \ No newline at end of file diff --git a/references/TimothyLottesBlog/20150423_-_Source-Less_Programming__3.md b/references/TimothyLottesBlog/20150423_-_Source-Less_Programming__3.md new file mode 100644 index 0000000..e4aa121 --- /dev/null +++ b/references/TimothyLottesBlog/20150423_-_Source-Less_Programming__3.md @@ -0,0 +1,34 @@ +# 20150423 - Source-Less Programming : 3 + +**Source:** https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20150423.html + +# 20150423 - Source-Less Programming : 3 + + +**Annotation Encoding** + +Refined from last post, two 32-bit annotation words per binary image word, + +FEDCBA9876543210FEDCBA9876543210 +================================ +00EEEEEEDDDDDDCCCCCCBBBBBBAAAAAA - LABEL : 5 6-bit chr string ABCDE + +FEDCBA9876543210FEDCBA9876543210 +================================ +..............................00 - DAT : hex data +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA01 - GET : get word from address A\*4 +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA02 - ABS : absolute address to A\*4 +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA03 - REL : relative address to A\*4 + +Going to switch to just 2 lines per word displayed in the editor, +Only DAT annotations show hex value, other types show LABEL of referenced address +in the place of the hex value. So no need for an extra note. +In practice will be using some amount of binary image memory to build up +a dictionary of DAT words representing all the common somewhat forth like opcodes, +then GET words in the editor to build up source. + +Need to redo the bootloader from floppy to harddrive usage, +and switch even the bootloader's 16-bit x86 code to 32-bit aligned +LABEL'ed stuff so the final editor can edit the bootloader. +Prior was avoiding manually assembling the 16-bit x86 code in the boot loader, +but might as well ditch NASM and use something else to bootstrap everything. \ No newline at end of file diff --git a/references/TimothyLottesBlog/20150424_-_Source-Less_Programming__4.md b/references/TimothyLottesBlog/20150424_-_Source-Less_Programming__4.md new file mode 100644 index 0000000..a66c3ef --- /dev/null +++ b/references/TimothyLottesBlog/20150424_-_Source-Less_Programming__4.md @@ -0,0 +1,61 @@ +# 20150424 - Source-Less Programming : 4 + +**Source:** https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20150424.html + +# 20150424 - Source-Less Programming : 4 + + +*Still attempting to fully vet the design +before the bootstrap reboot...* + +DAT words in the edit image need to maintain +their source address in the live image +This way on reload the live data can be copied over, +and persistent data gets saved to disk. +DAT annotations no longer have 30 bits of free space, +instead they have a live address. +When live address is zero. then DAT words +won't maintain live data. +This way read-only data can be self-repairing +(as long as the annotations don't get modified). +Going to use a different color for read-only DAT words. +New persistent data DAT words +will reference their edit-image hex value +before reload (then get updated to the live address). + + +REL words always get changed on reload (self repairing). +No need to keep the live address. +REL is only used for relative branching x86 opcodes. +Don't expect to have any run-time (non-edit-time) +self-modifying of relative branch addresses. +Given that branching to a relative branch opcode immedate +is not useful, the LABEL of a REL word is only useful +as a comment. + + +GET words also get changed on reload (self repairing). +GET is only designed for opcodes and labeled constants. +GET words will often be LABELed as a named branch/call target. +Been thinking about removing GET, and instead making a new +self-annotating word (display searches for a LABELed DAT +word with the same image value, then displays the +LABEL instead of HEX). +This opens up the implicit possibility of mis-annotations. +Would be rare for opcodes given they are large 32-bit values. +But for annotating things like data structure immediate offsets, +this will be a problem +(4 is the second word offset in any structure). + + +ABS words always get changed on reload (self repairing). +ABS words are targets for self-modifying code/data, +so they also need LABELs. +Reset on reload presents a problem in that +ABS cannot be used to setup persistent data +unless that persistent data is constant +or only built/changed in the editor. +But this limitation makes sense in the context +that ABS addresses in live data structures +can get invalidated by moving stuff around in memory. +The purpose of ABS is edit-time relinking. \ No newline at end of file diff --git a/references/TimothyLottesBlog/20150426_-_Source-Less_Programming__5.md b/references/TimothyLottesBlog/20150426_-_Source-Less_Programming__5.md new file mode 100644 index 0000000..51395b7 --- /dev/null +++ b/references/TimothyLottesBlog/20150426_-_Source-Less_Programming__5.md @@ -0,0 +1,84 @@ +# 20150426 - Source-Less Programming : 5 + +**Source:** https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20150426.html + +# 20150426 - Source-Less Programming : 5 + + +**Boot Loader Bring-up** + +Managed to get the boot loader done, which includes the following steps, + +(1.) Move the stack seg:pointer (since next step overwrites it). +(2.) Use BIOS to read the other 62 512-byte sectors for the first track. +(3.) Use BIOS to switch to 80x50 text mode and load custom character glyphs. +(4.) Use BIOS to set EGA text palette to 0-15 with 0 for overscan. +(5.) Program VGA palette registers for those 16 colors. +(6.) Use BIOS to enable A20. +(7.) Turn off interrupts, and relocate the image's 63 sectors to zero. +(8.) Load zero entry IDT, minimal 3 entry GDT. +(9.) Enable protected mode and jump to the 3rd sector. + +The 2nd 512-byte sector contains the 8x8 character bitmaps for the first 64 characters. +The majority of the time was spent making a nice font, +getting colors the way I wanted, +and prototyping editor look and feel (without building it). + +Didn't feel like fully hand assembling 16-bit x86 machine code for the boot loader, +so I used NASM and hexdump to accellerate the process +(to provide machine code I could pad out to 32-bit alignment). +Also wrote a quick C based tool to bootstrap the process of building the loader. +Something which would enable me to easily build out an annotated image, +and show a print out in the console of what I'd be seeing in the editor. +Here is a shot of a bit of the scratch C code I used to make the font, + +![](20150426-A.png) + +Here is a shot in QEMU of the loader displaying the font, + +![](20150426-B.png) + +And another shot from QEMU showing the pallet, + +![](20150426-C.png) + +**What the Current Annotated Image Looks Like** + +Below is a shot captured from the terminal window output of the C tool. +I'm using 3 cache lines for the loader code. + +![](20150426-D.png) + +Grey lines separate the 512-byte sectors. +Memory address on the left in grey. +Each pair of lines shows half a x86 cacheline. +The blue to white shows the 5 character/word annotation strings +(now using the extra 2 bits of the label for color). +The red hex show the image data. +Not using {GET,ABS,REL} tagged words in this part, +so everything in the bootloader is just hand assembled 16-bit machine code, +and this is not representative of what the rest of the system will look like. +The rest of the system will have {GET opcode} followed by {HEX} or {ABS} +for opcode immediates (easy to write). +The 16-bit code is {HEX} mixed opcode and immediates, quite a bit different (hard to write). + +Some hints on the annotations, + +Everything is in base 16. +AX is TOP so I don't bother with "A=9000" (which wouldn't fit anyway), +instead I just write "9000" (the A= is implied). +The "!" means store so "SSSP!" is storing TOP (or AX) into both SS and SP. +The "B=200" means BX=200h. +In this 16-bit x86 case I use 3E to pad out opcodes to 32-bit. +The "X" = SI, "Y" = DI, "F" = BP. + +**Next Step** + +Ground work is done, +next step is to bring up the opcode dictionary for {GET} words, +then write a little IDE driver to get access to load the rest of the image, +and to be able to save in the editor. +After that, write the drawing code for the editor, +then a mini PS/2 driver for the input, +then write editor input handling. +Then I have a full OS ready to start on a real machine. \ No newline at end of file diff --git a/references/TimothyLottesBlog/20150710_-_Inspiration_Reboot.md b/references/TimothyLottesBlog/20150710_-_Inspiration_Reboot.md new file mode 100644 index 0000000..4f0a0af --- /dev/null +++ b/references/TimothyLottesBlog/20150710_-_Inspiration_Reboot.md @@ -0,0 +1,67 @@ +# 20150710 - Inspiration Reboot + +**Source:** https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20150710.html + +# 20150710 - Inspiration Reboot + + +*Quite inspired by the insane one still or video per day at [beeple.tumblr.com](http://beeple.tumblr.com/). +Attempting to get back in the grove of consistently taking a small amount of non-work time every day to reboot fun projects. +I'm on week 2 now of probably a three month process of healing from a torn lower back, +sitting in front of a computer is now low enough pain to have fun again...* + +**1536** + +Setting a new 1536-byte (3x 512-byte sector) constraint for a bootloader + source interpreter +which brings up a PC in 64-bit long-mode with a nice 8x8 pix VGA font +and with 30720-bytes (60 sectors, to fill out one track) of source text for editor and USB driver. +USB providing thumb drive access to load in more stuff. +Have 1st sector bringing up VGA and long mode, +2nd sector with 64-character font, +and last 512-byte sector currently in progress as the interpreter. +Went full circle back to something slow, but dead simple: +interpreter works on bytes as input. +The following selection of characters appends simultaneously to a 60-bit 10 6-bit/char word string, +and a 64-bit number, + + +``` +0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ#$@!+*-^&|=?<>_ +``` + + +Then giving a "color forth tag" like meaning to another fixed set of characters, + +~ - Negate the 64-bit number. +. - Lookup word in dictionary, and push 64-bit value onto data stack. +, - Push 64-bit number on data stack. +: - Lookup word in dictionary, pop 64-bit value from data stack to word. +; - Write 32-bit number at compile position. +" - Lookup word in dictionary, interpret the string at address stored in word. +[ - Lookup word in dictionary, store compile position in word, append string from [ to ] compile position. +] - When un-matched with ], this ends interpretation via RET. +\ - Ignore text until the next \. +` - Lookup word in dictionary, call to address stored in word. + +Those set of characters replace the "space" character in forth, and work like a post-fix tag working on either the string or number just parsed from input. +The set of tags is minimal but flexible enough to build up a forth style macro language assembler, +with everything defined in the source itself. +More on this next time. +One nice side effect of post-fix tags is that syntax highlight is trivial by reading characters backwards starting at the end of the block. + +**Sony Wega CRT HDTVs** + +The old Wega CRT HDTVs work quite well. +They apparently are nearly fixed frequency 1080 interlaced with around 540 lines (or fields) per ~60 Hz frame, +and unlike prior NTSC CRT TVs, they seem to not do any real progressive scanning. +Taking a working 1080i modeline and converting it to 540p and driving the CRT +results in the Wega initiating a "mode-reset" when it doesn't see the interlaced fields for the 2nd frame. +However 480p modes do work (perhaps with an internal conversion to 1080i). +Given that 1080i modes are totally useless as the 60Hz interlace flicker is horrible, +and 540p won't work, these HDTVs should be complete garbage. +However 720p works awesome as the TV's processing to re-sample to 1080i does not flicker any worse than 60Hz already does. +In theory the even and odd fields (in alternating frames) share around 75% of an input line (540/720), +and likely more if the re-sampling has some low-pass filtering. +Drop in a PS4 game which has aliasing problems, and the CRT HDTV works like magic. +These late model "hi-scan" Wega CRTs only had roughly 853 pixel width aperture grille: +853x540 from what was a 1920x1080 render is a good amount of super-sampling... \ No newline at end of file diff --git a/references/TimothyLottesBlog/20150714_-_1536-1__The_Programmer_Addiction__Feedback.md b/references/TimothyLottesBlog/20150714_-_1536-1__The_Programmer_Addiction__Feedback.md new file mode 100644 index 0000000..d73f050 --- /dev/null +++ b/references/TimothyLottesBlog/20150714_-_1536-1__The_Programmer_Addiction__Feedback.md @@ -0,0 +1,50 @@ +# 20150714 - 1536-1 : The Programmer Addiction = Feedback + +**Source:** https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20150714.html + +# 20150714 - 1536-1 : The Programmer Addiction = Feedback + + +Continuing on the 1536-byte loader based system. +Interpreter finished, under the 1536-byte goal. +Second major goal is to get to the instant feedback productivity addiction loop going: modify, get feedback, repeat. +Have simple ASCII to custom 64-character set encoding converter, +and way to include the converter source text starting at sector 3 in the boot loader. +First major test, getting an infinite loop or infinite reboot working. +Source without any syntax coloring, + + +``` + +\1536-1 --- BOOTUP INTO SPIN OR REBOOT LOOP\ + +800000, \PUSH BOOT-UP COMPILE POSITION\ +BOOT: \STORE IN BOOT WHICH GETS CALLED TO RUN SYSTEM\ +FEEBFEEB,/ \WRITE OPCODE TO JUMP TO SELF\ +EAEAEAEA,/ \OR WRITE OPCODE TO CRASH ON INVALID INSTRUCTION\ +] \END COMPILE - LOADER WILL THEN JMP TO BOOT WORD\ +``` + + +Loader sets up memory with dictionary at 1MB (2MB chunk with 1MB overflow), copies source to 4MB (4MB chunk maximum), then starts the compile position at 8MB (so 8MB and on is the rest of the memory on the system). Had one major bug getting the interpreter up, forgot that \ in NASM results in a line continuation even when in a comment, removing a line of a lookup table resulting in a crash. +Tracking down bugs is very easy, add "JMP $" or "db 0xEA" in NASM to hang or reboot respectively. + +**Adjustments** + +Adjusted the character syntax. + +- - Negate the 64-bit number, add dash to the string. +. - Lookup word in dictionary, and push 64-bit value from word entry onto data stack. +, - Push 64-bit number on data stack. +: - Lookup word in dictionary, pop 64-bit value from data stack to word entry. +; - Lookup word in dictionary, interpret string starting at address stored in word entry. +[ - Lookup word in dictionary, store pointer to source after the [ in the word entry, skip past next ]. +] - When un-matched with ], this ends interpretation via RET. +\ - Ignore text until the next \. +/ - Lookup word in dictionary, call to address stored in dictionary entry. +` - Lookup word in dictionary, push address of word on data stack. + +Space and every character above except the - char, clear the working word string and number. +So , results in pushing a zero on the data stack. +And / results in calling the empty word, which I've setup as a word that pops from the data stack and writes a 32-bit word to the compile position, then advances the compile position. +This provides the base mechanics to start to create opcodes via manual hand assembly and build out an assembler \ No newline at end of file diff --git a/references/TimothyLottesBlog/20150715_-_1536-2__Assembling_From_the_Nothing.md b/references/TimothyLottesBlog/20150715_-_1536-2__Assembling_From_the_Nothing.md new file mode 100644 index 0000000..717c530 --- /dev/null +++ b/references/TimothyLottesBlog/20150715_-_1536-2__Assembling_From_the_Nothing.md @@ -0,0 +1,126 @@ +# 20150715 - 1536-2 : Assembling From the Nothing + +**Source:** https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20150715.html + +# 20150715 - 1536-2 : Assembling From the Nothing + + +*Started bringing up a limited subset x86-64 assembler. +The full x86-64 opcode encoding space is an unfortunate beast of complexity which I'd like to avoid. +So I did...* + +**Compromises** + +This prototype sticks to only exactly 4-byte or 8-byte instructions +(8-byte only if the instruction contains a 32-bit immediate/displacement). +The native x86-64 opcodes are prefix padded to fill the full 4-byte word. +Given that x86-64 CPUs work in chunks of 16-bytes of instruction fetch, +this makes it easy to maintain branch alignment visually in the code. +Since x86-64 float opcodes are natively 4-bytes without the REX prefix, +I'm self limiting to only 8 registers for this assembler, +which is good enough for the intended usage. +I'm not doing doubles and certainly not wasting time on vector instructions (have an attached GPU for that!). +Supported opcode forms in classic Intel syntax, + + +op; +op reg; +op reg,reg; +op reg,imm32; +op reg,[reg]; +op reg,[reg+imm8]; +op reg,[reg+imm32]; +op reg,[imm32]; +op reg,[reg+reg]; <- For LEA only. + +This is a bloody ugly list +which needed translation into some kind of naming +in which "op" changes based on the form. +I borrowed some forthisms: +@ for load, ! for store. +Then added ' for imm8, +" for imm32, and # for RIP relative [imm32]. +A 32-bit ADD and LEA ends up with this mess of options +(note . pushes word value on the stack, so A. pushes 0 for EAX in this context, +and , pushes a hex number, and / executes the opcode word which assembles the instruction to the current assembly write position), + +A.B.+/ .......... add eax,ebx; +A.1234,"+/ ...... add eax,0x1234; +A.B.@+/ ......... add eax,[rbx]; +A.B.12,'@+/ ..... add eax,[rbx+0x12]; +A.B.1234,"@+/ ... add eax,[rbx+0x1234]; +A.LABEL.#@+/ .... add eax,[LABEL]; <- RIP relative +A.B.12,'+=/ ..... lea eax,[rbx+0x12]; +A.B.C.+=/ ....... lea eax,[rbx+rcx\*1]; + +Then using L to expand from 32-bit operand to 64-bit operand, + +A.B.L+/ .......... add rax,rbx; +A.1234,L"+/ ...... add rax,0x1234; +A.B.L@+/ ......... add rax,[rbx]; +A.B.12,L'@+/ ..... add rax,[rbx+0x12]; +A.B.1234,L"@+/ ... add rax,[rbx+0x1234]; +A.LABEL.L#@+/ .... add rax,[LABEL]; <- RIP relative +A.B.12,L'+=/ ..... lea rax,[rbx+0x12]; +A.B.C.L+=/ ....... lea rax,[rbx+rcx\*1]; + +**Source Example With Google Docs Mockup Syntax Highlighting** + +Font and colors are not what I'm going for, just enough to get to the next step. +This is an expanded example which starts building up enough of an assembler +to boot and clear the VGA text screen. +Some of this got copied from older projects in which I used "X" instead of "L" to mark the 64-bit operand +(just noticed I need to fix the shifts...). +I just currently copy from this to a text file which gets included into the boot loader on build. + +*(Lost Image Here When Minus Went Down)* + +**From Nothing to Something** + +This starts by semi-self-documenting hand assembled x86 instructions via macros. +So "YB8-L'![F87B8948,/]" reads like this, + +(1.) Y.B.8-,L'! packed to a word name YB8-L'! with tag characters removed. +(2.) [ which starts the macro. +(3.) F87B8948 which is {48 (REX 64-bit operand), 89 (store version of MOV), 79 (modrm byte: edi,[rbx+imm8]), F8 (-8)}. +(4.) , which pushes the number on the data stack. +(5.) / which after , executes the empty word, which pops the data stack and writes 32-bit to the asm position. +(6.) ] which ends the macro. + +Later YB8-L'! with ; appended can be used to assemble that instruction by interpreting the macro. + +The first assembled words are $ which pushes the current assembly position on the stack, +and $DRP (which is actually a bug which needs to be removed). +The $! pops an address from the data stack, and stores the current assembly position to given address. +This is later used for instruction build macros which do things like PSH` where the ` results in the dictionary address for the PSH word to be placed on the data stack. +The end game is getting to the point where given one of the opcode forms, +it is possible to write the following to produce a function which compiles an opcode, + +C033403E,^`\_; + +Which pushes the 4-byte opcode base 0xC033403E, then the opcode name ^ for XOR, then runs the \_ macro which assembles this into: + +MOV eax,0xC033403E; +JMP X86-RM; + +Immediately afterwards it is possible to execute the ^ word (call it) and assemble an XOR instruction. +The X86-RM expects to get the REG and RM operands from the data stack with base instruction opcode data in EAX. + +**Making a Mess to Clean Up** + +This about concludes the worst part of getting going from nothing, +except for the PTSD dreams where people only speak in mixed hex and x86 machine code: FUCOM! REX DA TEST JO. +When placed into final context there will be a few KB of source to build an assembler which covers all functionality I need for the rest of the system. +At this point I can easily add instructions and a few more of the opcode forms as they are they are needed. +And it becomes very easy to write assembly like this, + +A.A.^/ Y.B8000,"/ C.1F40,"/ L!REP/ + +Which is this in Intel syntax, + + +xor eax,eax; <- set eax to zero +mov edi,0xB8000; <- VGA text memory start address +mov ecx,0x1F40; <- 80x50 times two bytes per character +cld; +rep storq; <- using old CISC style slow form to "do:mov [edi],rax;add rdi,8;dec rcx;jnz do;" \ No newline at end of file diff --git a/references/TimothyLottesBlog/20150722_-_1536-3__Simplify_Repeat.md b/references/TimothyLottesBlog/20150722_-_1536-3__Simplify_Repeat.md new file mode 100644 index 0000000..6dd17ab --- /dev/null +++ b/references/TimothyLottesBlog/20150722_-_1536-3__Simplify_Repeat.md @@ -0,0 +1,28 @@ +# 20150722 - 1536-3 : Simplify, Repeat + +**Source:** https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20150722.html + +# 20150722 - 1536-3 : Simplify, Repeat + + +Night 3 on the 1536 project, decided to make some changes before going full ahead with writing an editor. + +(1.) Switched the boot loader to not relocate to zero. +Now leaving the BIOS areas alone, I doubt I'll ever go back to real mode after switching to long mode, +this ends up making the code easier, and provides room for the next change. + +(2.) Switched the boot loader to fetch the first 15 tracks instead of just 1 track. +Now have a little over 472KB of source to work with on boot, +which is effectively infinite for this project. +The motivation for this change was the realization that x86-64 assembly source would get big. +Don't want to change this later. 472KB is close to the maximum without checking for things like EBA, or handling non-full-track reads. + +(3.) Switched to an easier source model. Lines are now always 64 characters long. +Comments are switch to a single \ which functions like the C // style comment, ignoring the rest of the line. +Since lines are always 64 bytes (cacheline sized and aligned), +the interpreter can quickly skip over comments. +This is a trade in increased source size, for simplification of the editor: +fixed size lines makes everything trivial. + +(4.) Making a convention that syntax highlighting with color only has a line of context. +Which translates into don't let things wrap. Easy. \ No newline at end of file diff --git a/references/TimothyLottesBlog/20150809_-_1536-4__Coloring.md b/references/TimothyLottesBlog/20150809_-_1536-4__Coloring.md new file mode 100644 index 0000000..4e8751d --- /dev/null +++ b/references/TimothyLottesBlog/20150809_-_1536-4__Coloring.md @@ -0,0 +1,41 @@ +# 20150809 - 1536-4 : Coloring + +**Source:** https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20150809.html + +# 20150809 - 1536-4 : Coloring + + +Night 4 on 1536. +Brought up most of the "x56-40" (x86-64 in hex) assembler now. +Also have majority of the forth-like words needed to assemble self-documenting constants {add,mul,neg,not,and,or,xor,...}. + +*(Lost Image When Minus Went Down)* + +Started on the editor. +Just enough of a quick prototype to render the text view in the editor (sans cursor for now). +All screens on this post are captured from the editor running in an x86-64 emulator. +Keeping the fixed 64 character lines makes everything very simple. +Syntax highlighting was carefully designed to only need one line of context. +Just a simple backward sweep to color, then a forward sweep to correct the color for comments (the \ marks rest of line as comment). +Adjusted the font, {\_,-,=} all now extend out full font cell width so they can double as lines. +Adjusted the colors closer to what I like for syntax highlighting. +Still experimenting with how to comment and arrange source. + +![](20150809.png) + +Have 16 characters to the right of the source window to use for real-time debug data. +Like viewing values of registers, memory, etc. +Thinking through details in the background. +Next step is to bring up the non-USB throw-away keyboard driver, +then get the editor functional. + +**Bugs** + +Still finding the no-errors, no-tools, know-everything path, easy to work with. +This time lost some time to an opcode assembly bug. +A full class of opcodes was broken, something never validated from last time, just forgot to make a RIP relative offset RIP relative for non-branch instructions. +Everything else working out of the box with no human errors. +When the mind can reason about the entire system, +and the edit/execute loop is near instant, +bugs normally are instant fix. +Quite satisfying to work this way. \ No newline at end of file diff --git a/references/TimothyLottesBlog/20150810_-_1536-5__Keys.md b/references/TimothyLottesBlog/20150810_-_1536-5__Keys.md new file mode 100644 index 0000000..5e92476 --- /dev/null +++ b/references/TimothyLottesBlog/20150810_-_1536-5__Keys.md @@ -0,0 +1,15 @@ +# 20150810 - 1536-5 : Keys + +**Source:** https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20150810.html + +# 20150810 - 1536-5 : Keys + + +Evening 5 on 1536. Wrote a mini PS/2 keyboard driver (source below) based on prior work. Ran out of time for testing, got distracted by SIGGRAPH slides. +Only supporting 64 keys (bit array in register), good enough to run arcade controllers which alias as keyboards. +Only supporting driver key release on {shift, control, alt}, allowing application to clear bits for release for other keys. +Had an interesting bug today: forgot to implement the "MOV REG,REG" opcode, surprised got this far in 1536 without register to register move. +Manually keeping 16-byte groupings for instructions has some interesting side effects on coding style... + + +![](20150810.png) \ No newline at end of file diff --git a/references/TimothyLottesBlog/20151113_-_Rethinking_the_Symbolic_Dictionary.md b/references/TimothyLottesBlog/20151113_-_Rethinking_the_Symbolic_Dictionary.md new file mode 100644 index 0000000..4faa7c1 --- /dev/null +++ b/references/TimothyLottesBlog/20151113_-_Rethinking_the_Symbolic_Dictionary.md @@ -0,0 +1,98 @@ +# 20151113 - Rethinking the Symbolic Dictionary + +**Source:** https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20151113.html + +# 20151113 - Rethinking the Symbolic Dictionary + + +*Another permutation of dictionary implementation for forth like languages...* + +**Source** + +Exported source is composed of two parts, + +(1.) Token array, where tokens can reference a local symbol by index into local hash table. +(2.) Local symbol hash table, has string for each entry. + +Strings are 64-bits maximum and are stored in a reversible nearly pre-hashed form. +So hashing of a string is just an AND operation. +Tokens are 32-bits. +Local symbol hash is after the token array, so it can be trivially discarded after import. + +**Global Dictionary** + +Global dictionary maps 32-bit index to 32-bit value. +Each 32-bit index has an associated 64-bit string stored in the same reversible nearly pre-hashed form. +Dictionary entries are allocated by just taking the next entry in a line. +There is no deletion. Just two arrays (32-bit value array, and 32-bit string array), and an index for the top. + + +**Source Import** + +Starts with loaded source in memory and allocated space for one extra array, + +(1.) Source token array, gets translated to loaded-in-memory form. +(2.) Source local symbol hash table, with each entry being a 64-bit string. +(3.) Remap space, extra zeroed array with a 32-bit value per entry in local hash table. + +Import streams through the global dictionary, +checking for a match in the source's local symbol hash table. +Upon finding a match, it writes the global index for the symbol into the associated remap space entry. +Import next streams through the source token array, +replacing the local symbol index +with the global index from the remap space entry. +When the remap space entry is zero, +a new symbol is allocated in the global dictionary +(this involves adding a symbol to the end of the dictionary, +and coping over the string from the local symbol hash table to the global dictionary string array). +After import the local symbol hash table and remap space are discarded. + + +This solves many of the core problems from a more conventional design where the global dictionary is a giant hash table. +That conventional design suffers from bad cache locality (because of the huge hash table). +This new design maintains a cache packed global dictionary (no gaps). +That conventional design can have worst case first load behavior, +each initial lookup of a new word in the dictionary on load would miss through to DRAM, +adding 100 ns per lookup. +This new design is composed of either linear streaming operations for big data +(global dictionary, source token array, etc) all of which get hardware auto-prefetch. +The source local symbol hash table is expected to be not too big and easily stay in cache (the only thing with random access). + + +Note with this new design, interpreting source at run-time no longer has any hash lookup, +just a direct lookup. + +**First Source Import** + +First source import (after machine reboot) has effectively an empty dictionary, +so import can be optimized. + +**Editing** + +Edit time operations, such as find the index for an existing symbol, +check if a symbol already exists, +or tab complete a symbol, +is done via a full stream through the global dictionary string table. +This is a linear operation with full auto-prefetch, so expected to be quite fast in practice. +Edit time operations are limited by human factors, so not a problem. + + +**Source Export** + +Source export requires first checking how many unique symbols are in the chunk of source. +Use a bit array with one bit per global dictionary entry. +Zero the bit array. +Stream through the chunk of source tokens and check for a clear bit in the bit array. +For each clear bit, set the bit, and advance the count of unique words. + + +Setup space for the local symbol hash. +Scale up the unique symbol count to make sure the hashing is efficient. +Pad up to the next power of 2 in size. +Stream through the source tokens, +using the token index to get a global dictionary string, +hash the string into the local symbol hash, writing the associated string if new entry, +and remapping the source token index to the local hash. + + +Export is the most complex part of the design, but still quite simple. \ No newline at end of file diff --git a/references/TimothyLottesBlog/20151222_-_Random_Holiday_2015.md b/references/TimothyLottesBlog/20151222_-_Random_Holiday_2015.md new file mode 100644 index 0000000..668f536 --- /dev/null +++ b/references/TimothyLottesBlog/20151222_-_Random_Holiday_2015.md @@ -0,0 +1,189 @@ +# 20151222 - Random Holiday 2015 + +**Source:** https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20151222.html + +# 20151222 - Random Holiday 2015 + + +**Google Photos = Actually Working (edit) Fail Great** + +Minus has basically imploded loosing a lot of the image content on this blog, +unfortunately Google Photos is not a great alternative, +while it seems to support original quality, it does not, see the 2nd image (got low-passed)! +EDIT: turns out Blogger is the source of this problem, the preview sends back re-compressed images, +but after the initial posting, the original quality file is actually presented. +So Google Photos seems to be good, and it's a quality bug in Blogger Preview which was the source of the problem. + + +![](20151222-A.png) + +**Vintage Interactive Realtime Operating System** + +Taking part of my Christmas vacation time +to reboot my personal console x86-64 OS project. +I've rebooted this project more times than I'm willing to disclose on this blog. +Hopefully this reboot will stick long enough to build something real with it. +Otherwise it's been great practice, and the evolution of ideas has certainly been enlightening. +Here is a shot of the binary data for the boot sector in the editor, + + +![](20151222-B.png) + +My goal is to rewind to the principals of the Commodore 64, +just applied to modern x86-64 hardware and evolved down a different path. +In my case to build a free OS with open source code which boots into a programming interface, +which fully exposes the machine, and provides some minimal interface to access hardware +including modern AMD GPUs. +With a feature list which is the inverse of a modern operating system: +single-user, single-tasking, no paging, no memory protection ... +the application gets total control over the machine, +free to use parallel CPU cores and GPU(s) for whatever it wants. +Ultimately manifesting as a thumb drive which can be plugged into a x86-64 machine +with compatible hardware and boot the OS to run 100% from RAM, to run software. + + +**A Tale of Two Languages** + +C64 provided Basic at boot, I'm doing something vastly different. +Booting into an editor +which is a marriage +between +a spreadsheet, hex editor, +raw memory view, debugging tool, +interactive live programming environment, +annotated sourceless binary editor with automatic relink on edit, +and a forth-like language. +Effectively I've embedded a forth-like language in a sourceless binary framework. +The editor runs in a virtualized console +which can easily be embedded inside an application. +The editor shows 8 32-bit "cells" of memory per line (half cacheline), +with a pair of rows per cell. +Top row has a 10-character annotation (with automatic green highlight if the cell is referenced in the binary), +the botton row shows the data formatted based on a 4-bit tag stored in the annotation. +Note the screen shot showing the boot sector +was hand assembled 8086 (so is embedded data), +built from bits of NASM code chunks then disassembled +(it's not showing any of the embedded language source). +Tags are as follows, + + +unsigned 32-bit word +signed 32-bit word +four unsigned 8-bit bytes +32-bit floating point value +----- +unsigned 32-bit word with live update +signed 32-bit word with live update +four unsigned 8-bit bytes with live update +32-bit floating point value with live update +----- +32-bit absolute memory address +32-bit relative memory address [RIP+imm32] +toe language (subset of x86-64 with 32-bit padded opcodes) +ear language (forth-like language, encoded in binary form) +----- +5-character word (6-bits per character) +last 3 saved for GPU binary disassembly + +Editor designed to edit an annotated copy of the live binary, +with a frameword designed to allow realtime update of the live binary as a snapshot of the edited copy. +The "with live update" tags +mean that the editor copy saves a 32-bit address to the live data +in it's copy of the binary (instead of the data itself). +This allows for direct edit and visualization of the live data, +with ability to still move bits of the binary around in memory. + +The "toe" and "ear" tagged cells show editable disassembled x86-64 code +in the form of these languages. +The "ear" language is a zero-operand forth-like language. +Current design, + + + +``` +regs +---- +rax = top +rcx = temp for shift +rbx = 2nd item on data stack, grows up +rbp = 4 +rdi = points to last written 32-bit item on compile stack + +bin word name x86-64 meaning +-------- ---- ---------------------------- +0389dd03 , add ebx,ebp; mov [rbx],eax; +dd2b3e3e \ sub ebx,ebp; +c3f2c3f2 ; ret; +dd2b0303 add\ add eax,[rbx]; sub ebx,ebp; +dd2b0323 and\ and eax,[rbx]; sub ebx,ebp; +07c7fd0c dat# add edi,ebp; mov [rdi],imm; +d0ff3e3e cal call rax; +15ff3e3e cal# call [rip+imm]; +058b3e3e get# mov eax,[rip+imm]; +890fc085 jns# test eax,eax; jns imm; +850fc085 jnz# test eax,eax; jnz imm; +880fc085 js# test eax,eax; js imm; +840fc085 jz# test eax,eax; jz imm; +c0c73e3e lit# mov eax,imm; +03af0f3e mul imul eax,[rbx]; +d8f73e3e neg neg eax; +00401f0f nop nop; +d0f73e3e not not eax; +dd2b030b or\ or eax,[rbx]; sub ebx,ebp; +05893e3e put# mov [rip+imm],eax; +f8d20b8b sar mov ecx,[rbx]; sar eax,cl; +e0d20b8b shl mov ecx,[rbx]; shl eax,cl; +e8d20b8b shr mov ecx,[rbx]; shr eax,cl; +dd2b032b sub\ sub eax,[rbx]; sub ebx,ebp; +dd2b0333 xor\ xor eax,[rbx]; sub ebx,ebp; +``` + + +For symbols the immediate operands are all 32-bit +and use "absolute" or "relative" tagged cells following the "ear" tagged cell. +Likewise for "dat#" which pushes an immediate on the compile stack, +and "lit#" which pushes an immediate data on the data stack, +the following cell would have a data tag. +The dictionary is directly embedded in the binary, +using the edit-time relinking support. +No interpretation is done at run-time, +only edit-time, +as the language is kept in an executable form. + + +After building so many prototypes which "compile" +source to a binary form, +I've come to the conclusion that it is many times easier +to just keep the source in the binary form, +then disassemble and reassemble in the editor on edit. +The "toe" subset of x64-64 uses 32-bit opcodes +with null "3e" prefix to pad to alignment. +Disassembly/reassembly uses a table with, + + +{opcode form index, 32-bit opcode base, 32-bit 5-character name} + +Then under 16 opcode forms, +which use a pair of functions, +one for disassembly to a common {name,r,rm,s/imm8} form, +and the other for assembly. +Other than entering data for the table it was trivial engineering work. + +**A Tale of Two Editors** + +To fast track this reboot +I've built the first editor +as a fully non-live prototype of the editor for the OS. +This enables me to bring up the OS using an emulator +with the standard pass/fail instant debug method +(it works if the emulator doesn't enter in the infinite reboot loop). +I'm using the same custom VGA font, +just different colors because of the bad 256-color palette in xterm. +The C based version of the editor +was built using the "as a child would do it" method of development over a few days, +just start building without any planning, +writing code as fast as possible to bring up a prototype. +See what works, refine, repeat. +It took around 1900 lines total, +and produces an insanely large "gcc -Os" compiled binary (optimized for smallest size) at around 160 KB. +Later will see how this compares to the editor fully re-written in the "toe/ear" language in the editor itself... \ No newline at end of file diff --git a/references/TimothyLottesBlog/20161113_-_Vintage_Programming_2.md b/references/TimothyLottesBlog/20161113_-_Vintage_Programming_2.md new file mode 100644 index 0000000..8099b81 --- /dev/null +++ b/references/TimothyLottesBlog/20161113_-_Vintage_Programming_2.md @@ -0,0 +1,60 @@ +# 20161113 - Vintage Programming 2 + +**Source:** https://refined-github-html-preview.kidonng.workers.dev/gomson/TimothyLottes.github.io/raw/refs/heads/master/20161113.html + +# 20161113 - Vintage Programming 2 + + +This is a follow-up to the [20140816 - Vintage Programming](20140816.html) post talking about this, + + +![](20140816-A.png) + +**Retrospective** + +Was thinking about resurecting the Atom project now that Vulkan supports what I would need to complete it, +and had to decide upon what language to write the reboot in. +Looking back at all my language and compiler experiments on PC over the years, +the A Language as described in that prior post from 2014 had the most utility +and was the easiest to be productive on in current PC style operating systems. + + +**Adjustments** + +First implementation of compiler took ANSI text source file and output a binary. +The source had to build the ELF or PE header for the binary (similar to an assembler running without a linker). +This round, the compiler is the platform executable, +and programs will run directly from source (JITing themselves). +Compiler will be built around interactive run-time edit/recompile/retry loop which maintains existing program state in memory during the process. + + + +* Start: Read the source file into the top of the memory stack.* Interpret the source into binary code.* Loop: Call the binary code entry point, if source file timestamp changed exit loop.* Jump to Start. + + +Source can thus be edited in the background in any text editor while the program runs. +Save the source file, and the program reloads itself while it runs. +Likewise the source could be edited inside the program itself. +Lots of flexibility. + + +**Portability and Distribution** + +One source file for any platform, source adapts to the platform as it JITs itself into binary code at run-time. +Distribution is just pairing the platform specific compiler binary (which can be renamed to the program name), +and the source file (which will have a set name like "rom.a", so a double click of the renamed compiler runs the application without any arguments). +Platform specific compilers will be a few K executable depending on how minimal the ELF or PE is. +For a secondary option at some point I'll make something which can build a single executable with the compiler embedded with source. + + +**Open Source** + +I'm going fully open-source for this project. +Compiler is being written in NASM assembly with embedded PE/ELF so there is no need for any kind of linker to build the compiler. +Thus far got a 1st draft on the PE done with all the Kernel32 symbols I believe I need, +with an executable which loads and then spins forever. +Will continue to bring up on Windows first to verify PE works on real Windows boxes, +before migrating back to Linux and Wine. More later as this project continues ... + + +Work in progress here: [github.com/TimothyLottes/A](https://github.com/TimothyLottes/A) \ No newline at end of file diff --git a/references/X.com - Onat & Lottes Interaction 1.png b/references/X.com - Onat & Lottes Interaction 1.png new file mode 100644 index 0000000..d3d2368 Binary files /dev/null and b/references/X.com - Onat & Lottes Interaction 1.png differ diff --git a/references/X.com - Onat & Lottes Interaction 1.png.ocr.md b/references/X.com - Onat & Lottes Interaction 1.png.ocr.md new file mode 100644 index 0000000..1b8c295 --- /dev/null +++ b/references/X.com - Onat & Lottes Interaction 1.png.ocr.md @@ -0,0 +1,113 @@ +# OCR Thread: X.com - Onat & Lottes Interaction 1.png + +Post +OnatTurkcuoglu @onattØ • Apr 30 +Reply +Forgot to mention in the heat of presentation, the initial textual language +was heavily influenced by one of your past forth-like languages. +Though I've built upon that foundation, I would have taken many wrong +turns without your guidance, thank you so much. +$4 +NOTimothyLottes @NOTimothyLottes • Apr 28 +Onat demos his radical language/editor/system for CPU+GPU +programming: youtube.com/watch?FJ9U_5t„. +01 +NOTimothyLottes @NOTimothyLottes • Apr 30 +Related thoughts/ +253 +[O] Having a low upper bound on the maximum complexity allowed in a +program enables so much simplification. One can always move complexity +into data, while keeping tight codebases. +01 +NOTimothyLottes @NOTimothyLottes • Apr 30 +[1] Seems like you group symbols into pages where each page can have a +string (shared with all symbols in the page), which when pared with limited +fixed maximum symbol string size, is an elegant way of effectively +supporting larger naming [I'll probably steal that idea next time] +02 +NOTimothyLottes @NOTimothyLottes • Apr 30 +[2] I'm also a big fan of how you used 16:9 aspect to auto render all the +debug info, symbol tables, disassembly, etc, alongside the source. I think +many people are probably lost in the speed at which you can manipulate +and test ideas while working on the source +01 +NOTimothyLottes @NOTimothyLottes • Apr 30 +[3] I got side tracked by building a language that could be assembled from +on the GPU in SIMD. However now I ask myself if that is just adding +"complexity", because if programs are bounded in size, why not just focus +on CPU non-parallel nested factoring (aka the forth-like way) +02 +NOTimothyLottes @NOTimothyLottes • Apr 30 +[4] 2-item data stack is an interesting compromise. Something I never +considered. I left off ripping out the data stack completely. +01 +NOTimothyLottes @NOTimothyLottes • Apr 30 +[5] Can do this instead, +a. Track a "top" register (number) +b. Use symbols to override top register +c. Have push (store) just advance top to next reg (in circular queue) +Gets to easy unnamed arguments +02 +NOTimothyLottes @NOTimothyLottes • Apr 30 +[6] You mentioned VK is most "form filling" which I think is an accurate +description. For most "C" like APIs I like to just lay out all the arguments in +memory like a tape drive in the order that functions get called and source +that tape at runtime for the calls +01 +NOTimothyLottes @NOTimothyLottes • Apr 30 +[7] They key concept here is that "common" arguments like the device are +pushed onto the tape using store duplication when they are known (after +device creation). So it's preemptive scatter, so later at call time there is no +argument gather. +01 +NOTimothyLottes @NOTimothyLottes • Apr 30 +[8] Likely the majority of C/C++/OOP/bloatware is just shuffling data +around in argument gather to support the concept of data stacks on HW +that has no physical data stack. +02 +Onat Turkcuoglu +@onattØ +holy truthnuke - and people think C is the optimal state of possible +runtimes when it's a very limited runtime to have state mixed call/data- +stacks +not only you have to keep the whole stack around with replicated state, +it limits to serialized execution instead of parallel +2:53 PM Apr 30, 2025 57 Views +Post your reply +NOTimothyLottes @NOTimothyLottes • Apr 30 +Reply +I laugh when people say C is like assembly, they are missing what we +actually did in assembly back then, which was all registers and globals and +gotos, no stacks. It's radically different than good assembly. +01 +OnatTurkcuoglu @onattØ • Apr 30 +when C became •the* execution model, it restricted all future hardware, HW +gets built with how the C compiler will compile to it instead of what's +ultimately a good design and a malleable macro-lang to map to HW +ofc a lot of people want portability so we went the boring route +01 +NOTimothyLottes @NOTimothyLottes • Apr 30 +The big industry mistake was factoring into thousands of functions in code, +instead of just baking all that into a "protocol" of data structures in memory. +Like OOP member functions to load or mutate one variable = vomit. +01 +NOTimothyLottes @NOTimothyLottes • Apr 30 +138 +I do all my custom CPU side stuff more like treating the register file like a +"memory" of which the contents are aliased to different shared structures +for different purposes across time +01 +NOTimothyLottes @NOTimothyLottes • Apr 30 +So the register file is more like an aliased global namespace. And +"functions" are free of arguments and free of returns. This way of working +with the HW is way better and easier than the 'C' model. +01 +NOTimothyLottes @NOTimothyLottes • Apr 30 +In the few cases where you need to reuse small code patterns, those end +up a compile time macros that inline to different registers, larger pattems +are already better factored to data +01 +OnatTurkcuoglu @onattØ • Apr 30 +this is the galaxy-brain take on register-allocation right here - radically +simpler than what I had in mind:) +0 \ No newline at end of file diff --git a/references/grok_search_query_1.md b/references/grok_search_query_1.md new file mode 100644 index 0000000..2b8ac4c --- /dev/null +++ b/references/grok_search_query_1.md @@ -0,0 +1,62 @@ +Here is a curated list of **additional** highly relevant technical resources I scavenged (beyond the presentations, Twitter interactions, and Lottes blog archives you already OCR’d/analyzed). I focused strictly on alignments with your paradigm: zero-overhead x86-64, sourceless ColorForth-derivative, 32-bit aligned token/opcode arrays, hex-editor IDEs (Lottes x68/Neokineogfx style), 2-item register stack (RAX/RDX + xchg, aliased globals per Onat), preemptive scatter/tape-drive args, instant <5 ms compilation/live reload, and no runtime data stack. + +I prioritized deep architectural explanations, editor/token mechanics, and live machine-code manipulation. No public full code dumps or C-emitters for x68/KYRA were found (Onat’s repos are unrelated minimal C samples; Lottes keeps x68 details in talks). But the sources below give precise implementation blueprints, quotes, and diagrams-in-text that match your model exactly. + +### 1. Lottes x68 / Neokineogfx (32-bit opcode padding, hex-editor frontend, token arrays) +- **"4th And Beyond" video (Neokineogfx / Timothy Lottes, uploaded Jan 14 2026)** + https://www.youtube.com/watch?v=Awkdt30Ruvk + Direct deep-dive on x68 as x64 subset using **only 32-bit granularity opcodes** (ignored prefixes + multibyte NOP padding for alignment). + Key excerpts (from auto-transcript): + - "x68 … subset of x64 which works with op codes at 32-bit granularity only. … x86-64 supports ignored prefixes which can pad op codes out to 32-bit. … if we wanted to do a 32-bit instruction for return, we might put the return, which is a C3, and then pad the rest of it with a three byte noop." + - "Source … 32-bit tokens. … 28 bits of compressed name or string and four bits of tag. The tag controls how to interpret the source token." + - Editor: "advanced 32-bit hex editor. … split the source into blocks … subblocks … source and then some annotation blocks. … for every … 32-bit source word, … 64-bit of annotation information … eight characters … 7 bit … 8bit tag for editor. And the tag will give me the format of the 32-bit value in memory." + - Dictionary: "32-bit words for words … direct addresses into the binary and the binary is going to be the dictionary. … fix the position … no address base randomization." + - Philosophy: "When your OS is an editor, is a hyper calculator, is a debugger, is a hex editor, you end up with this interactive instant iteration software development." + This is the strongest new source for your hex-frontend + annotation overlay + 32-bit padding helpers. He explicitly plans a separate x68 talk (not yet released as of Feb 2026). + +- **Additional clarification from his archived "From Scratch Bug 2: Source-Less Programming" (20150420) and ": 2" (20150422)** (you have the raw HTML, but these sections align 1:1 with the 2026 video): + - Memory model: running image + parallel annotations + edit image; live swap at safe points. + - 32-bit word types: data / opcode / abs addr / RIP-rel addr. + - Editor grid: per-word LABEL (5×6-bit chars), HEX value, NOTE. Auto-relink on insert/delete for all address-tagged words. Version number in image triggers self-replacement. + - Padding example (x86-64): "Call = [32b call opcode] + [32b RIP-rel addr]". + These flesh out the exact visual editor mechanics you need for sourceless 32-bit token manipulation without string parsing. + +- **"Scatter-Only Gather-Free Machines" (20161014 post title in archive)** + Direct match to your "preemptive scatter" for function arguments. (Thin content in the fetch, but the title + context from 1536 series points to static pre-placement of args in a linear memory "tape" arena before calls — no runtime stack ops.) + +### 2. Onat’s KYRA/VAMP (global load/store, token dictionary indexing, 2-reg stack) +- **lang.html (Bit Test Complement)** – https://onatto.github.io/lang.html + (You linked it before; here are the exact matching specs you asked for): + - 1800-byte x64 compiler, 192-line x64 asm (RIP-rel, heavy RAX/RDX + xchg for 2-item stack). + - Sub-5 ms SPIR-V, 1-2 ms total compile. Flat global namespace (aliased registers/memory). + - Binary encoding → direct machine code (no strings at runtime). Custom Vulkan IDE with instant feedback, 512 undo, crash-resilient. + Matches your model perfectly; no deeper public code/template dumps exist (his GitHub has only unrelated bare-metal C). + +- **"Metaprogramming VAMP in KYRA" SVFIG talk (Apr 2025)** – https://www.youtube.com/watch?v=J9U_5tjdegY + + Forth Day 2020 preview (x64 + ColorForth + SPIR-V). + Covers binary token encoding, global namespace mapping, and the exact register/stack philosophy you described. No slides/code in meeting notes, but the video is the canonical deep-dive. + +### 3. Ecosystem Parallels (minimalist zero-dep x86-64 machine code gen + instant live-reloaded sourceless) +- **Andreas Fredriksson – "Hot Runtime Linking" (2012)** – https://deplinenoise.wordpress.com/2012/02/11/hot-runtime-linking/ + Exact match for instant compilation (<5 ms delta) + live-reloaded machine-code manipulation without restart. + Architecture: + - Linker daemon (host) does in-memory symbol resolution + relocations on changed .o files only. + - Target process parks at safe points (e.g., main loop), receives delta patches over socket. + - Conservative pointer scan + GC for old code blocks (retains if dangling refs). + - Zero-downtime atomic swap; handles function pointers via opt-in callback. + Quote: "The host garbage collects stale code and data … scanning the target process memory … If so, a warning is printed and the blocks are retained." + His Tundra build system (same author) is the zero-dep fast incremental piece. Perfect bridge to your sourceless live IDE. + +- **Chuck Moore OKAD (sourceless precursor)** – https://www.ultratechnology.com/okad.htm + Direct philosophical/technical ancestor: + - "Structure of the programs looks like Forth code, but there was no Forth compiler … Chuck himself [entered the kernel using a debugger]." + - Tools: hex memory editor + instruction decompiler/editor. All editing direct on bytecode (no source). + - "Collection of about a dozen 1K programs." Bootstrapped repeatedly without source. + Matches your bound-complexity + visual sourceless editor exactly. + +### 4. Data Structures (tape-drive args + sourceless 32-bit token dictionary) +- Lottes model (synthesized from video + 2015 posts): + - **Token array**: flat 32-bit words in blocks (no filesystem). Each word = value + 4-bit tag (data/opcode/abs/rel/immediate). + - **Sourceless editor**: parallel annotation overlay (64-bit per token in 2026 design: 8×7-bit chars + 8-bit format tag). Editor reads/writes the token array directly; tags drive display (color/name/hex) with zero string parsing. Auto-relink addresses on edit. + - **Tape-drive / preemptive scatter**: Linear memory arena. Compiler statically scatters args into fixed slots before a call (gather-free). No data stack at runtime — registers + pre-placed tape slots only. (Explains your "memory tape-drive" for arguments + bound complexity forcing data structures.) + \ No newline at end of file diff --git a/references/grok_search_query_2.md b/references/grok_search_query_2.md new file mode 100644 index 0000000..2502d7a --- /dev/null +++ b/references/grok_search_query_2.md @@ -0,0 +1,40 @@ +Here’s **more** highly relevant additions (scavenged fresh, strictly aligned to your zero-overhead sourceless x86-64 ColorForth-derivative: 32-bit token arrays, hex/sourceless editor, tape-drive scatter, 2-reg stack, instant compile/live reload). Strong focus on **WebAssembly** (binary format, linear memory tape parallels, dynamic emission, structured binary editors) plus other immediately useful tooling. No direct new Lottes/Onat Wasm material, but Wasm/SPIR-V binary parallels are explicit. + +### WebAssembly Core Parallels & Tooling +Wasm’s binary section format + single growable linear memory (fixed-offset load/store, no runtime stack) is an almost 1:1 match for your 32-bit aligned tokens + preemptive scatter “tape drive” args. Decode/JIT is designed for <5 ms instantiation. + +- **WAForth** (dynamic Forth-to-Wasm compiler written entirely in raw .wat) + https://github.com/remko/waforth + https://mko.re/waforth/ (live demo console) + ~14 KB (7 KB gz) complete minimal Forth interpreter + **dynamic compiler** that emits new Wasm bytecode on-the-fly (LEB128 append, function table + indirect calls for words). Uses linear memory for 4-byte aligned stack/tape. CODE word for raw Wasm opcodes. Jonesforth-inspired. FOSDEM 2023 talk slides (hand-written minimal Wasm Forth system): https://archive.fosdem.org/2023/schedule/event/webassemblyforth/attachments/slides/5876/export/events/attachments/webassemblyforth/slides/5876/Exploring_WebAssembly_With_Forth.pdf + Direct blueprint for your token → machine-code emission loop and live reload. + +- **ImHex** (star for your sourceless hex-editor frontend) + https://github.com/WerWolv/ImHex + https://web.imhex.werwolv.net/ (browser version runs via Wasm) + Professional hex editor with **Pattern Language** (.hexpat – C-like DSL). Define custom 32-bit token structs (value + tag + annotation overlay) → automatic parse, highlight, tree view, colors, names, disassembly. Live patching, huge files, zero string parsing. Patterns repo: https://github.com/WerWolv/ImHex-Patterns (hundreds of examples). + Fork this for exact Lottes-style annotation overlay on your token array. Native + web versions both zero-dep. + + Tiny example pattern snippet you can drop in (for a 32-bit token + 4-bit tag + 64-bit annotation block): + ```c + struct Token { + u32 value; + u8 tag : 4; + u8 padding : 4; + char name[7]; // 7×7-bit compressed like Lottes + u64 annotation; // editor overlay (color/format) + }; + Token tokens[$ / sizeof(Token)]; + ``` + +- **WABT / wasm-tools** (low-level binary manipulation) + https://github.com/WebAssembly/wabt + Official toolkit: wat2wasm / wasm2wat / disassembly / validation. Use for fast token-dictionary ↔ binary round-tripping or hex-patching prototypes. Pairs perfectly with ImHex. + +- **Visual Wasm Structure Editor** (sourceless module building) + https://www.youtube.com/watch?v=liJg6rzXnPg + Visual (non-text) editor for adding instructions/sections directly to Wasm binary. Exact parallel to hex-editor + annotation for token arrays. + +### Other Immediately Helpful +- **Wasm linear memory as tape-drive reference** + Wasm’s flat byte array with fixed-offset access is the cleanest public example of “preemptive scatter” without a runtime data stack. See practical buffer/tape examples: https://blog.jeremylikness.com/blog/2019-04-22_play-the-chaos-game-to-understand-webassembly-memory-management/ (passing pre-placed arrays between host and Wasm with zero copying). diff --git a/references/jombloforth/jombloforth.asm b/references/jombloforth/jombloforth.asm new file mode 100644 index 0000000..f306381 --- /dev/null +++ b/references/jombloforth/jombloforth.asm @@ -0,0 +1,1054 @@ +;; -*- nasm -*- +;; +;; Minimal FORTH interpreter for 64-bit Linux systems. +;; Based on jonesforth +;; +;; compile it with: +;; +;; nasm -g -F dwarf -f elf64 -o jombloforth.o jombloforth.asm +;; ld -o jombloforth jombloforth.o +;; +;; +;; UNLICENSE +;; --------- +;; +;; This is free and unencumbered software released into the public +;; domain. +;; +;; Anyone is free to copy, modify, publish, use, compile, sell, or +;; distribute this software, either in source code form or as a compiled +;; binary, for any purpose, commercial or non-commercial, and by any +;; means. +;; +;; In jurisdictions that recognize copyright laws, the author or authors +;; of this software dedicate any and all copyright interest in the +;; software to the public domain. We make this dedication for the benefit +;; of the public at large and to the detriment of our heirs and +;; successors. We intend this dedication to be an overt act of +;; relinquishment in perpetuity of all present and future rights to this +;; software under copyright law. +;; +;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +;; IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +;; OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +;; ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +;; OTHER DEALINGS IN THE SOFTWARE. +;; +;; For more information, please refer to + + +;; syscall number, generated using this command: +;; +;; sed 's_#_%_;s_/\*_;_;s_ \*/__' /usr/include/x86_64-linux-gnu/asm/unistd_64.h > unistd_64.inc +;; +%include "unistd_64.inc" + +;; see buffer allocation +%define RETURN_STACK_SIZE 8192 +%define BUFFER_SIZE 4096 + + + +;; MACRO DEFINITION +;; ---------------- + +;; The version of this program, not to be mistaken as how many years the +;; author has been single. Please increment this number each time one year +;; passed. +%assign JOMBLO_VERSION 2 +;; (that's a joke, btw) + +;; Our first word +%macro NEXT 0 + lodsq + jmp [rax] +%endmacro + +;; Helper for pushing/popping from the return stack + +%macro PUSHRSP 1 + lea rbp, [rbp-8] + mov [rbp], %1 +%endmacro + +%macro POPRSP 1 + mov %1, [rbp] + lea rbp, [rbp+8] +%endmacro + +;; First Non-Macro Word +section .text +DOCOL: + PUSHRSP rsi + add rax, 8 + mov rsi, rax + NEXT + + +global _start +_start: + cld ; Clear direction flag + ; Save the initial data stack pointer in variable S0 + mov [var_S0], rsp + mov rbp, return_stack_top ; Initialize the return stack + call set_up_data_segment + mov rsi, cold_start + NEXT + +section .rodata +cold_start: + dq QUIT + +;; Various flags for the dictionary word header +%define F_IMMED 0x80 +%define F_HIDDEN 0x20 +%define F_LENMASK 0x1f + +;; Holds previously defined word +;; Starts as null/zero +%define link 0 + +;; Macro for defining forth word +;; +;; defword name, label, flag +;; +%macro defword 2-3 0 + %strlen name_len %1 + + ;; dictionary word header + section .rodata + + align 8, db 0 + global name_%2 + name_%2: + dq link + db name_len + %3 + db %1 + + ;; update link to point to this word's header + %define link name_%2 + + ;; word definitions, starts with DOCOL + align 8, db 0 + global %2 + %2: + dq DOCOL +%endmacro + + +;; Macro for defining native word +;; +;; defcode name, label, flag +;; +%macro defcode 2-3 0 + %strlen name_len %1 + + ;; dictionary word header + section .rodata + align 8, db 0 + global name_%2 + name_%2: + dq link + db name_len + %3 + db %1 + + ;; update link to point to this word's header + %define link name_%2 + + ;; word definition, link to the native code + align 8, db 0 + global $%2 ; fix error for `WORD` which isn't valid label + $%2: + dq code_%2 + + ;; native code + section .text + align 8 + global code_%2 + code_%2: +%endmacro + +defcode "DROP", DROP + pop rax + NEXT + +defcode "SWAP", SWAP + pop rax + pop rbx + push rax + push rbx + NEXT + +defcode "DUP", DUP + mov rax, [rsp] + push rax + NEXT + +defcode "OVER", OVER + mov rax, [rsp+8] + push rax + NEXT + +defcode "ROT", ROT + pop rax + pop rbx + pop rcx + push rbx + push rax + push rcx + NEXT + +defcode "-ROT", NROT + pop rax + pop rbx + pop rcx + push rax + push rcx + push rbx + NEXT + +defcode "2DROP", TWODROP + pop rax + pop rax + NEXT + +defcode "2DUP", TWODUP + mov rax, [rsp] + mov rbx, [rsp+8] + push rbx + push rax + NEXT + +defcode "2SWAP", TWOSWAP + pop rax + pop rbx + pop rcx + pop rdx + push rbx + push rax + push rdx + push rcx + NEXT + +defcode "?DUP", QDUP + mov rax, [rsp] + test rax, rax + jz .next + push rax +.next NEXT + +defcode "1+", INCR + inc qword [rsp] + NEXT + +defcode "1-", DECR + dec qword [rsp] + NEXT + +defcode "8+", INCR8 + add qword [rsp], 8 + NEXT + +defcode "8-", DECR8 + sub qword [rsp], 8 + NEXT + +defcode "+", ADD + pop rax + add [rsp], rax + NEXT + +defcode "-", SUB + pop rax + sub [rsp], rax + NEXT + +defcode "*", MUL + pop rax + pop rbx + imul rax, rbx + push rax + NEXT + +defcode "/MOD", DIVMOD + xor rdx, rdx + pop rbx + pop rax + idiv rbx + push rdx + push rax + NEXT + +;;;; Comparison Words + +%macro defcmp 3 + defcode %1, %2 + pop rax + pop rbx + cmp rbx, rax + set%+3 al + movzx rax, al + push rax + NEXT +%endmacro + +defcmp "=", EQU, e +defcmp "<>", NEQ, ne +defcmp "<", LT, l +defcmp ">", GT, g +defcmp "<=", LE, le +defcmp ">=", GE, ge + +%macro deftest 3 + defcode %1, %2 + pop rax + test rax, rax + set%+3 al + movzx rax, al + push rax + NEXT +%endmacro + +deftest "0=", ZEQU, z +deftest "0<>", ZNEQU, nz +deftest "0<", ZLT, l +deftest "0>", ZGT, g +deftest "0<=", ZLE, le +deftest "0>=", ZGE, ge + +defcode "AND", AND + pop rax + and [rsp], rax + NEXT + +defcode "OR", OR + pop rax + or [rsp], rax + NEXT + +defcode "XOR", XOR + pop rax + xor [rsp], rax + NEXT + +defcode "INVERT", INVERT + not qword [rsp] + NEXT + +;;;; Exiting a Word + +defcode "EXIT", EXIT + POPRSP rsi + NEXT + +;; Literal + +defcode "LIT", LIT + lodsq + push rax + NEXT + +;;;; MEMORY + +defcode "!", STORE + pop rbx + pop rax + mov [rbx], rax + NEXT + +defcode "@", FETCH + pop rbx + mov rax, [rbx] + push rax + NEXT + +defcode "+!", ADDSTORE + pop rbx + pop rax + add [rbx], rax + NEXT + +defcode "-!", SUBSTORE + pop rbx + pop rax + sub [rbx], rax + NEXT + +defcode "C!", STOREBYTE + pop rbx + pop rax + mov [rbx], al + NEXT + +defcode "C@", FETCHBYTE + pop rbx + xor rax, rax + mov al, [rbx] + push rax + NEXT + +defcode "C@C!", CCOPY + mov rbx, [rsp+8] + mov al, [rbx] + pop rdi + stosb + push rdi + inc qword [rsp+8] + NEXT + +defcode "CMOVE", CMOVE + mov rdx, rsi + pop rcx + pop rdi + pop rsi + rep movsb + mov rsi, rdx + NEXT + +;;;; BUILT-IN VARIABLE + +%macro defvar 2-4 0, 0 + defcode %1, %2, %4 + push var_%2 + NEXT + + ;; data storage + section .data + align 8, db 0 + var_%2: + dq %3 +%endmacro + +defvar "STATE", STATE +defvar "HERE", HERE +defvar "LATEST", LATEST, name_SYSCALL0 +defvar "S0", S0 +defvar "BASE", BASE, 10 + +%macro defconst 3-4 0 + defcode %1, %2, %4 + push %3 + NEXT +%endmacro + +defconst "VERSION", VERSION, JOMBLO_VERSION +defconst "R0", R0, return_stack_top +defconst "DOCOL", __DOCOL, DOCOL + +defconst "F_IMMED", __F_IMMED, F_IMMED +defconst "F_HIDDEN", __F_HIDDEN, F_HIDDEN +defconst "F_LENMASK", __F_LENMASK, F_LENMASK + +%macro defsys 2 + %defstr name SYS_%1 + defconst name, SYS_%1, __NR_%2 +%endmacro + +defsys EXIT, exit +defsys OPEN, open +defsys CLOSE, close +defsys READ, read +defsys WRITE, write +defsys CREAT, creat +defsys BRK, brk + +%macro defo 2 + %defstr name O_%1 + defconst name, __O_%1, %2 +%endmacro + +defo RDONLY, 0o +defo WRONLY, 1o +defo RDWR, 2o +defo CREAT, 100o +defo EXCL, 200o +defo TRUNC, 1000o +defo APPEND, 2000o +defo NONBLOCK, 4000o + +;;;; RETURN STACK + +defcode ">R", TOR + pop rax + PUSHRSP rax + NEXT + +defcode "R>", FROMR + POPRSP rax + push rax + NEXT + +defcode "RSP@", RSPFETCH + push rbp + NEXT + +defcode "RSP!", RSPSTORE + pop rbp + NEXT + +defcode "RDROP", RDROP + add rbp, 8 + NEXT + + +;;;; PARAMETER (DATA) STACK + +defcode "DSP@", DSPFETCH + mov rax, rsp + push rax + NEXT + +defcode "DSP!", DSPSTORE + pop rsp + NEXT + +;;;; INPUT OUTPUT + +defcode "KEY", KEY + call _KEY + push rax + NEXT +_KEY: + mov rbx, [currkey] + cmp rbx, [bufftop] + jge .full + xor rax, rax + mov al, [rbx] + inc rbx + mov [currkey], rbx + ret + +.full: + push rsi ; save rsi temporarily + push rdi ; and rdi + xor rdi, rdi ; stdin (0) + mov rsi, buffer ; pointer to the buffer + mov [currkey], rsi + mov rdx, BUFFER_SIZE ; how many bytes to read max + mov rax, __NR_read ; read(0, buffer, size) + syscall + test rax, rax + jbe .eof + add rsi, rax + mov [bufftop], rsi + pop rdi ; restore + pop rsi ; and restore + jmp _KEY + +.eof: + xor rdi, rdi + mov rax, __NR_exit + syscall + +section .data +align 8, db 0 +currkey: + dq buffer +bufftop: + dq buffer + +defcode "EMIT", EMIT + pop rax + call _EMIT + NEXT +_EMIT: + mov rdi, 1 ; stdout (1) + mov [emit_scratch], al ; save the byte to scratch buffer + push rsi ; save rsi temporarily + mov rsi, emit_scratch + mov rdx, 1 ; how many bytes to write + mov rax, __NR_write ; write(1, scratch, 1) + syscall + pop rsi ; restore it + ret + +section .data +emit_scratch: db 0 + +defcode "WORD", WORD + call _WORD + push rdi + push rcx + NEXT + +_WORD: +.ws: + call _KEY + cmp al, '\' + je .comment + cmp al, ' ' + jbe .ws + + mov rdi, word_buffer +.word: + stosb + call _KEY + cmp al, ' ' + ja .word + + sub rdi, word_buffer + mov rcx, rdi + mov rdi, word_buffer + ret + +.comment: + call _KEY + cmp al, 0x0A + jne .comment + jmp .ws + +section .data +word_buffer: times 32 db 0 + +defcode "NUMBER", NUMBER + pop rcx + pop rdi + call _NUMBER + push rax + push rcx + NEXT + +_NUMBER: + xor rax, rax + xor rbx, rbx + + test rcx, rcx ; trying to parse zero-length string is an error, but will return 0. + jz .ret + + mov rdx, [var_BASE] ; get BASE (in dl) + mov bl, [rdi] ; bl = first character in string + inc rdi + push rax ; push 0 on stack + cmp bl, '-' ; negative number? + jnz .convert + pop rax + push rbx ; push <> 0 on stack, indicating negative + dec rcx + jnz .loop + pop rbx + mov rcx, 1 + ret + + ; Loop reading digits. +.loop: + imul rax, rdx ; rax *= BASE + mov bl, [rdi] ; bl = next character in string + inc rdi + +.convert: + sub bl, '0' ; < '0'? + jb .finish + cmp bl, 10 ; <= '9'? + jb .numeric + sub bl, 17 ; < 'A'? (17 is 'A'-'0') + jb .finish + add bl, 10 + +.numeric: + cmp bl, dl ; >= BASE? + jge .finish + + ; OK, so add it to rax and loop + add rax, rbx + dec rcx + jnz .loop + + ; Negate the result if the first character was '-' (saved on the stack) +.finish: + pop rbx + test rbx, rbx + jz .ret + neg rax + +.ret: + ret + + +;;;; Dictionary Looks Ups + +defcode "FIND", FIND + pop rcx + pop rdi + call _FIND + push rax + NEXT + +_FIND: + push rsi ; save rsi so that we can use it in string comparison + + ; now we start searching the dictionary for this word + mov rdx, [var_LATEST] ; LATEST points to name header of the latest word in the dictionary +.loop: + test rdx, rdx ; NULL pointer? + je .notfound + + ; Compare the length expected and the length of the word. + ; Note that if the F_HIDDEN flag is set on the word, then by a bit of trickery + ; this won't pick the word (the length will appear to be wrong). + xor rax,rax + mov al, [rdx+8] ; al = flags+length field + and al, F_HIDDEN | F_LENMASK ; al = name length + cmp al, cl ; Length is the same? + jne .next + + ; Compare the strings in detail. + push rcx ; Save the length + push rdi ; Save the address (repe cmpsb will move this pointer) + lea rsi, [rdx+9] ; Dictionary string we are checking against. + repe cmpsb ; Compare the strings. + pop rdi + pop rcx + jne .next ; Not the same. + + ; The strings are the same - return the header pointer in rax + pop rsi + mov rax, rdx + ret + +.next: + mov rdx, [rdx] ; Move back through the link field to the previous word + jmp .loop ; .. and loop. + +.notfound: + pop rsi + xor rax,rax ; Return zero to indicate not found. + ret + +defcode ">CFA", TCFA + pop rdi + call _TCFA + push rdi + NEXT + +_TCFA: + xor rax, rax + add rdi, 8 ; skip link pointer + mov al, [rdi] ; load flags+len into al + inc rdi ; skip flags+len byte + and al, F_LENMASK ; just the length, not the flags + add rdi, rax ; skip the name + add rdi, 0b111 ; the codeword is 8-byte aligned + and rdi, ~0b111 + ret + +defword ">DFA", TDFA + dq TCFA + dq INCR8 + dq EXIT + +;;;; Compiling + +defcode "CREATE", CREATE + ; Get the name length and address. + pop rcx ; rcx = length + pop rbx ; rbx = address of name + + ; Link pointer. + mov rdi, [var_HERE] ; rdi is the address of the header + mov rax, [var_LATEST] ; Get link pointer + stosq ; and store it in the header. + + ; Length byte and the word itself. + mov al, cl ; Get the length. + stosb ; Store the length/flags byte. + push rsi + mov rsi, rbx ; rsi = word + rep movsb ; Copy the word + pop rsi + add rdi, 0b111 ; Align to next 8 byte boundary. + and rdi, ~0b111 + + ; Update LATEST and HERE. + mov rax, [var_HERE] + mov [var_LATEST], rax + mov [var_HERE], rdi + NEXT + +defcode ",", COMMA + pop rax + call _COMMA + NEXT + +_COMMA: + mov rdi, [var_HERE] ; HERE + stosq ; Store it. + mov [var_HERE], rdi ; Update HERE (incremented) + ret + +defcode "[", LBRAC, F_IMMED + xor rax, rax + mov [var_STATE], rax + NEXT + +defcode "]", RBRAC + mov qword [var_STATE], 1 + NEXT + +defword ":", COLON + dq $WORD + dq CREATE + dq LIT, DOCOL, COMMA + dq LATEST, FETCH, HIDDEN + dq RBRAC + dq EXIT + +defword ";", SEMICOLON, F_IMMED + dq LIT, EXIT, COMMA + dq LATEST, FETCH, HIDDEN + dq LBRAC + dq EXIT + + +defcode "IMMEDIATE", IMMEDATE, F_IMMED + mov rdi, [var_LATEST] + add rdi, 8 + xor byte [rdi], F_IMMED + NEXT + +defcode "HIDDEN", HIDDEN + pop rdi + add rdi, 8 + xor byte [rdi], F_HIDDEN + NEXT + +defword "HIDE", HIDE + dq $WORD + dq FIND + dq HIDDEN + dq EXIT + +defcode "'", TICK + lodsq + push rax + NEXT + +;;;; Branching + +defcode "BRANCH", BRANCH + add rsi, [rsi] + NEXT + +defcode "0BRANCH", ZBRANCH + pop rax + test rax, rax + jz code_BRANCH + lodsq + NEXT + +;;;; Literal String + +defcode "LITSTRING", LITSTRING + lodsq + push rsi + push rax + add rsi, rax + add rsi, 0b111 + and rsi, ~0b111 + NEXT + +defcode "TELL", TELL + mov rcx, rsi ; save temporarily + mov rdi, 1 ; 1st param = stdout(1) + pop rdx ; 3nd param = length of string + pop rsi ; 2nd param = the string + mov rax, __NR_write + push rcx ; save previous value of rsi in the stack + syscall + pop rsi ; restore rsi + NEXT + +;;;; Part of Testing + +defword "FORTYTWO", FORTYTWO + dq LIT + dq 42 + dq EXIT + +;;;; Quit and Interpret + +defword "QUIT", QUIT + dq R0, RSPSTORE + dq INTERPRET + dq BRANCH, -16 + +defcode "INTERPRET", INTERPRET + call _WORD ; return rcx = length, rdi = pointer to word + + ; Is it in the dictionary? + xor rax, rax + mov [interpret_is_lit], rax ; Not a literal number (not yet anyway ...) + call _FIND ; Return rax = pointer to header or 0 if not found + test rax, rax ; Found? + jz .number + + ; In the dictionary. Is it an IMMEDIATE codeword? + mov rdi, rax ; rdi = dictionary entry + mov al, [rdi+8] ; Get name+flags. + push ax ; Just save it for now + call _TCFA ; Convert dictionary entry in rdi to codeword pointer + pop ax + and al, F_IMMED ; Is IMMED flag set? + mov rax, rdi + jnz .exec ; If IMMED, jump straight to executing + + jmp .main + + ; Not in the dictionary (not a word) so assume it's a literal number. +.number: + inc qword [interpret_is_lit] + call _NUMBER ; Returns the parsed number in rax, rcx > 0 if error + test rcx, rcx + jnz .numerror + mov rbx, rax + mov rax, LIT ; The word is LIT + + ; Are we compiling or executing? +.main: + mov rdx, [var_STATE] + test rdx, rdx + jz .exec ; Jump if executing. + + ; Compiling - just append the word to the current dictionary definition. + call _COMMA + mov rcx, [interpret_is_lit] ; Was it a literal? + test rcx, rcx + jz .next + mov rax, rbx ; Yes, so LIT is followed by a number. + call _COMMA +.next: + NEXT + + ; Executing - run it! +.exec: + mov rcx, [interpret_is_lit] ; Literal? + test rcx, rcx ; Literal? + jnz .litexec + + ; Not a literal, execute it now. This never returns, but the codeword will + ; eventually call NEXT which will reenter the loop in QUIT. + jmp [rax] + + ; Executing a literal, which means push it on the stack. +.litexec: + push rbx + NEXT + + ; Parse error (not a known word or a number in the current BASE). +.numerror: + ; Print an error message followed by up to 40 characters of context. + push rsi + + mov rdi, 2 ; 1st param: stderr(2) + mov rsi, errmsg ; 2nd param: error message + mov rdx, errmsglen ; 3rd param: length of string + mov rax, __NR_write ; write syscall + syscall + + mov rsi, [currkey] ; the error occurred just before currkey position + mov rdx, rsi + sub rdx, buffer ; rdx = currkey - buffer (length in buffer before currkey) + cmp rdx, 40 ; if > 40, then print only 40 characters + jle .le + mov rdx, 40 +.le: + sub rsi, rdx ; rcx = start of area to print, rdx = length + mov rax, __NR_write ; write syscall + syscall + + mov rsi, errmsgnl ; newline + mov rdx, 1 + mov rax, __NR_write ; write syscall + syscall + pop rsi + + NEXT + +section .rodata +errmsg: db "PARSE ERROR: " +errmsglen: equ $ - errmsg +errmsgnl: db 0x0A + +section .data ; NB: easier to fit in the .data section +align 8 +interpret_is_lit: + dq 0 ; Flag used to record if reading a literal + +;;;; Odds and Ends + +defcode "CHAR", CHAR + call _WORD ; Returns rcx = length, rdi = pointer to word. + xor rax, rax + mov al, [rdi] ; Get the first character of the word. + push rax ; Push it onto the stack. + NEXT + +defcode "EXECUTE", EXECUTE + pop rax ; Get xt into rax + jmp [rax] ; and jump to it. + ; After xt runs its NEXT will continue executing the current word. + +defcode "SYSCALL3", SYSCALL3 + mov rcx, rsi ; Save rsi + pop rax ; System call number (see ) + pop rdi ; First parameter. + pop rsi ; Second parameter + pop rdx ; Third parameter + push rcx ; Save previous value of rsi on stack + syscall + pop rsi ; restore + push rax ; Result (negative for -errno) + NEXT + +defcode "SYSCALL2", SYSCALL2 + mov rcx, rsi + pop rax ; System call number (see ) + pop rdi ; First parameter. + pop rsi ; Second parameter + push rcx + syscall + pop rsi + push rax ; Result (negative for -errno) + NEXT + +defcode "SYSCALL1", SYSCALL1 + pop rax ; System call number (see ) + pop rdi ; First parameter. + syscall + push rax ; Result (negative for -errno) + NEXT + +defcode "SYSCALL0", SYSCALL0 + pop rax ; System call number (see ) + syscall + push rax ; Result (negative for -errno) + NEXT + + +;;;; Data Segment +%define INITIAL_DATA_SEGMENT_SIZE 65536 + +section .text +set_up_data_segment: + xor rdi, rdi + mov rax, __NR_brk ; brk(0) + syscall + mov [var_HERE], rax + add rax, INITIAL_DATA_SEGMENT_SIZE + mov rdi, rax + mov rax, __NR_brk + syscall + ret + +;;;; buffers allocation + +section .bss +align 4096 +return_stack: + resb RETURN_STACK_SIZE +return_stack_top: + +align 4096 +buffer: + resb BUFFER_SIZE \ No newline at end of file diff --git a/references/jombloforth/jombloforth.f b/references/jombloforth/jombloforth.f new file mode 100644 index 0000000..276f1ba --- /dev/null +++ b/references/jombloforth/jombloforth.f @@ -0,0 +1,859 @@ +\ Part 2 of the JonesForth tutorial. +\ This one is added word-by-word as they are succesfully executed + +\ Define / and MOD in terms of /MOD +: / /MOD SWAP DROP ; +: MOD /MOD DROP ; + +\ Some char constant +: '\n' 10 ; +: BL 32 ; \ BL (blank) is standard FORTH word for space. + +: CR '\n' EMIT ; +: SPACE BL EMIT ; + +: NEGATE 0 SWAP - ; + +: TRUE 1 ; +: FALSE 0 ; +: NOT 0= ; + +\ LITERAL takes whatever on the stack and compiles LIT +: LITERAL IMMEDIATE + ' LIT , + , +; + +: ':' + [ + CHAR : + ] + LITERAL +; + +: ';' [ CHAR ; ] LITERAL ; +: '(' [ CHAR ( ] LITERAL ; +: ')' [ CHAR ) ] LITERAL ; +: '"' [ CHAR " ] LITERAL ; +: 'A' [ CHAR A ] LITERAL ; +: '0' [ CHAR 0 ] LITERAL ; +: '-' [ CHAR - ] LITERAL ; +: '.' [ CHAR . ] LITERAL ; + +: [COMPILE] IMMEDIATE + WORD + FIND + >CFA + , +; + +: RECURSE IMMEDIATE + LATEST @ + >CFA + , +; + +\ Conditionals Statements + +: IF IMMEDIATE + ' 0BRANCH , + HERE @ + 0 , +; + +: THEN IMMEDIATE + DUP + HERE @ SWAP - + SWAP ! +; + +: ELSE IMMEDIATE + ' BRANCH , + HERE @ + 0 , + SWAP + DUP + HERE @ SWAP - + SWAP ! +; + +: UNLESS IMMEDIATE + ' NOT , + [COMPILE] IF +; + +\ Loop Construct + +: BEGIN IMMEDIATE + HERE @ +; + +: UNTIL IMMEDIATE + ' 0BRANCH , + HERE @ - + , +; + +: AGAIN IMMEDIATE + ' BRANCH , + HERE @ - + , +; + +: WHILE IMMEDIATE + ' 0BRANCH , + HERE @ + 0 , +; + +: REPEAT IMMEDIATE + ' BRANCH , + SWAP + HERE @ - , + DUP + HERE @ SWAP - + SWAP ! +; + +\ Comments +: ( IMMEDIATE + 1 + BEGIN + KEY + DUP '(' = IF + DROP + 1+ + ELSE + ')' = IF + 1- + THEN + THEN + DUP 0= UNTIL + DROP +; + +( Now we can nest ( ... ) as much as we want ) + +\ Stack Manipulation +: NIP ( x y -- y ) SWAP DROP ; +: TUCK ( x y -- y x y ) SWAP OVER ; +: PICK ( x_u ... x_1 x_0 u -- x_u ... x_1 x_0 x_u ) + 1+ + 8 * ( multiply by the word size ) + DSP@ + + @ +; + +\ Writes N spaces to stdout +: SPACES ( n -- ) + BEGIN + DUP 0> + WHILE + SPACE + 1- + REPEAT + DROP +; + +\ EXTRA: Writes N zeroes to stdout +: ZEROES ( n -- ) + BEGIN + DUP 0> + WHILE + '0' EMIT + 1- + REPEAT + DROP +; + +\ Standard word for manipulating BASE. +: DECIMAL ( -- ) 10 BASE ! ; +: HEX ( -- ) 16 BASE ! ; + +( Printing Numbers ) + +: U. ( u -- ) + BASE @ /MOD + ?DUP IF ( if quotient <> 0 then ) + RECURSE ( print the quotient ) + THEN + + ( print the remainder ) + DUP 10 < IF + '0' + ELSE + 10 - + 'A' + THEN + + + EMIT +; + +( Printing the content of the stack ) +: .S ( -- ) + DSP@ + BEGIN + DUP S0 @ < + WHILE + DUP @ U. + SPACE + 8+ + REPEAT + DROP +; + +( Returns the width of an unsigned number (in characters) in the current base ) +: UWIDTH + BASE @ / + ?DUP IF + RECURSE 1+ + ELSE + 1 + THEN +; + +: U.R ( u width -- ) + SWAP + DUP + UWIDTH + ROT + SWAP - + SPACES + U. +; + +\ EXTRA, print zeroes padded unsigned number +: ZU.R ( u width -- ) + SWAP + DUP + UWIDTH + ROT + SWAP - + ZEROES + U. +; + +: .R ( n width -- ) + SWAP ( width n ) + DUP 0< IF + NEGATE ( width u ) + 1 ( save flag to remember that it was negative | width u 1 ) + SWAP ( width 1 u ) + ROT ( 1 u width ) + 1- ( 1 u width-1 ) + ELSE + 0 ( width u 0 ) + SWAP ( width 0 u ) + ROT ( 0 u width ) + THEN + SWAP ( flag width u ) + DUP ( flag width u u ) + UWIDTH ( flag width u uwidth ) + ROT ( flag u uwidth width ) + SWAP - ( flag u width-uwidth ) + + SPACES ( flag u ) + SWAP ( u flag ) + + IF + '-' EMIT + THEN + U. +; + +( Finally ) +: . 0 .R SPACE ; + +( The real U. ) +: U. U. SPACE ; + +: ? ( addr -- ) @ . ; + +: WITHIN ( c a b - f ) + -ROT ( b c a ) + OVER ( b c a c ) + <= IF + > IF ( b c ) + TRUE + ELSE + FALSE + THEN + ELSE + 2DROP + FALSE + THEN +; + +: DEPTH ( -- n ) + S0 @ DSP@ - + 8- +; + +: ALIGNED ( addr -- addr ) + 7 + 7 INVERT AND +; + +: ALIGN HERE @ ALIGNED HERE ! ; + +: C, + HERE @ C! + 1 HERE +! +; + +: S" IMMEDIATE ( -- addr len ) + STATE @ IF + ' LITSTRING , + HERE @ + 0 , + BEGIN + KEY + DUP '"' <> + WHILE + C, + REPEAT + DROP + DUP + HERE @ SWAP - + 8- + SWAP ! + ALIGN + ELSE + HERE @ + BEGIN + KEY + DUP '"' <> + WHILE + OVER C! + 1+ + REPEAT + DROP + HERE @ - + HERE @ + SWAP + THEN +; + +: ." IMMEDIATE + STATE @ IF + [COMPILE] S" + ' TELL , + ELSE + BEGIN + KEY + DUP '"' = IF + DROP + EXIT + THEN + EMIT + AGAIN + THEN +; + +( Constant and Variables ) + +: CONSTANT + WORD + CREATE + DOCOL , + ' LIT , + , + ' EXIT , +; + +: ALLOT ( n -- addr ) + HERE @ SWAP + HERE +! +; + +: CELLS ( n -- n ) 8 * ; + +: VARIABLE + 1 CELLS ALLOT + WORD CREATE + DOCOL , + ' LIT , + , + ' EXIT , +; + +: VALUE ( n -- ) + WORD CREATE + DOCOL , + ' LIT , + , + ' EXIT , +; + +: TO IMMEDIATE ( n -- ) + WORD + FIND + >DFA + 8+ + STATE @ IF + ' LIT , + , + ' ! , + ELSE + ! + THEN +; + +: +TO IMMEDIATE + WORD + FIND + >DFA + 8+ + STATE @ IF + ' LIT , + , + ' +! , + ELSE + +! + THEN +; + +: ID. ( addr -- ) + 8+ + DUP C@ + F_LENMASK AND + BEGIN + DUP 0> + WHILE + SWAP 1+ + DUP C@ + EMIT + SWAP 1- + REPEAT + 2DROP ( len addr -- ) +; + +: ?HIDDEN + 8+ + C@ + F_HIDDEN AND +; + +: ?IMMEDIATE + 8+ + C@ + F_IMMED AND +; + +: WORDS + LATEST @ + BEGIN + ?DUP + WHILE + DUP ?HIDDEN NOT IF + DUP ID. + SPACE + THEN + @ + REPEAT + CR +; + +: FORGET + WORD FIND + DUP @ LATEST ! + HERE ! +; + +: DUMP ( addr len -- ) + BASE @ -ROT + HEX + + BEGIN + ?DUP ( while len > 0 ) + WHILE + OVER 8 ZU.R ( print the address ) + SPACE + ( print up to 16 words on this line ) + 2DUP ( addr len addr len ) + 1- 15 AND 1+ ( addr len addr linelen ) + BEGIN + ?DUP ( while linelen > 0 ) + WHILE + SWAP ( addr len linelen addr ) + DUP C@ ( addr len linelen addr byte ) + 2 ZU.R SPACE ( print the byte ) + 1+ SWAP 1- ( addr len linelen addr -- addr len addr+1 linelen-1 ) + REPEAT + DROP ( addr len ) + + ( print the ASCII equivalents ) + 2DUP 1- 15 AND 1+ ( addr len addr linelen ) + BEGIN + ?DUP + WHILE + SWAP ( addr len linelen addr ) + DUP C@ ( addr len linelen addr byte ) + DUP 32 128 WITHIN IF ( 32 <= c < 128? ) + EMIT + ELSE + DROP '.' EMIT + THEN + 1+ SWAP 1- + REPEAT + DROP + CR + DUP 1- 15 AND 1+ + TUCK + - + >R + R> + REPEAT + DROP + BASE ! +; + +: CASE IMMEDIATE + 0 +; + +: OF IMMEDIATE + ' OVER , + ' = , + [COMPILE] IF + ' DROP , +; + +: ENDOF IMMEDIATE + [COMPILE] ELSE +; + +: ENDCASE IMMEDIATE + ' DROP , + BEGIN + ?DUP + WHILE + [COMPILE] THEN + REPEAT +; + +: CFA> + LATEST @ + BEGIN + ?DUP + WHILE + 2DUP SWAP + < IF + NIP + EXIT + THEN + @ + REPEAT + DROP + 0 +; + +: SEE + WORD FIND + HERE @ + LATEST @ + + BEGIN + 2 PICK + OVER + <> + WHILE + NIP + DUP @ + REPEAT + + DROP + SWAP + + ':' EMIT SPACE DUP ID. SPACE + DUP ?IMMEDIATE IF ." IMMEDIATE " THEN + + >DFA + + BEGIN ( end start ) + 2DUP > + WHILE + DUP @ ( end start codeword ) + CASE + ' LIT OF ( is it LIT ? ) + 8 + DUP @ ( get next word ) + . ( and print it ) + ENDOF + ' LITSTRING OF + [ CHAR S ] LITERAL EMIT '"' EMIT SPACE ( print S" ) + 8 + DUP @ ( get the length ) + SWAP 8 + SWAP ( end start+8 length ) + 2DUP TELL ( print the string ) + '"' EMIT SPACE + + ALIGNED ( end start+8+len, aligned ) + 8 - ( because we're about to add 8 below ) + ENDOF + ' 0BRANCH OF + ." 0BRANCH ( " + 8 + DUP @ + . + ." ) " + ENDOF + ' BRANCH OF + ." BRANCH ( " + 8 + DUP @ + . + ." ) " + ENDOF + ' ' OF + [ CHAR ' ] LITERAL EMIT SPACE + 8 + DUP @ + CFA> + ID. SPACE + ENDOF + ' EXIT OF + 2DUP + 8 + + <> IF + ." EXIT " + THEN + ENDOF + DUP + CFA> + ID. SPACE + ENDCASE + 8 + + REPEAT + ';' EMIT CR + 2DROP +; + +: :NONAME + 0 0 CREATE + HERE @ + DOCOL , + ] +; + +: ['] IMMEDIATE + ' LIT , +; + + +( Exception ) +: EXCEPTION-MARKER + RDROP + 0 +; + +: CATCH + DSP@ 8+ >R + ' EXCEPTION-MARKER 8+ + >R + EXECUTE +; + +: THROW + ?DUP IF + RSP@ + BEGIN + DUP R0 8- < + WHILE + DUP @ + ' EXCEPTION-MARKER 8+ = IF + 8+ + RSP! + DUP DUP DUP + R> + 8- + SWAP OVER + ! + DSP! EXIT + THEN + 8+ + REPEAT + DROP + CASE + 0 1- OF ( ABORT ) + ." ABORTED" CR + ENDOF + ." UNCAUGHT THROW " + DUP . CR + ENDCASE + QUIT + THEN +; + +: ABORT + 0 1- THROW +; + +: PRINT-STACK-TACE + RSP@ + BEGIN + DUP R0 8- < + WHILE + DUP @ + CASE + ' EXCEPTION-MARKER 8+ OF + ." CATCH ( DSP=" + 8+ DUP @ U. + ." ) " + ENDOF + DUP + CFA> + ?DUP IF + 2DUP + ID. + [ CHAR + ] LITERAL EMIT + SWAP >DFA 8+ - . + THEN + ENDCASE + 8+ + REPEAT + DROP + CR +; + +( C String ) + +: Z" IMMEDIATE + STATE @ IF + ' LITSTRING , + HERE @ + 0 , + BEGIN + KEY + DUP '"' <> + WHILE + HERE @ C! + 1 HERE +! + REPEAT + 0 HERE @ C! + 1 HERE +! + DROP + DUP + HERE @ SWAP - + 8- + SWAP ! + ALIGN + ' DROP , + ELSE + HERE @ + BEGIN + KEY + DUP '"' <> + WHILE + OVER C! + 1+ + REPEAT + DROP + 0 SWAP C! + HERE @ + THEN +; + +: STRLEN + DUP + BEGIN + DUP C@ 0<> + WHILE + 1+ + REPEAT + SWAP - +; + +: CSTRING + SWAP OVER + HERE @ SWAP + CMOVE + HERE @ + + 0 SWAP C! + HERE @ +; + +( The Environment ) + +: ARGC S0 @ @ ; + +: ARGV ( n -- str u ) + 1+ CELLS S0 @ + + @ + DUP STRLEN +; + +: ENVIRON + ARGC + 2 + + CELLS + S0 @ + +; + +: BYE 0 SYS_EXIT SYSCALL1 ; + +: GET-BRK ( -- brkpoint ) 0 SYS_BRK SYSCALL1 ; + +: UNUSED ( -- n ) GET-BRK HERE @ - 8 / ; + +: BRK ( brkpoint -- ) SYS_BRK SYSCALL1 ; + +: MORECORE ( cells -- ) CELLS GET-BRK + BRK ; + +: R/O ( -- fam ) O_RDONLY ; +: R/W ( -- fam ) O_RDWR ; + +: OPEN-FILE ( addr u fam -- fd 0 (if successful) | c-addr u fam -- fd errno (if there was an error) ) + -ROT + CSTRING + SYS_OPEN SYSCALL2 + DUP + DUP 0< IF + NEGATE + ELSE + DROP 0 + THEN +; + +: CREATE-FILE ( similar to OPEN-FILE ) + O_CREAT OR + O_TRUNC OR + -ROT + CSTRING + 420 -ROT + SYS_OPEN SYSCALL3 + DUP + DUP 0< IF + NEGATE + ELSE + DROP 0 + THEN +; + +: CLOSE-FILE + SYS_CLOSE SYSCALL1 + NEGATE +; + +: READ-FILE + >R SWAP R> + SYS_READ SYSCALL3 + DUP + DUP 0< IF + NEGATE + ELSE + DROP 0 + THEN +; + +: PERROR + TELL + ':' EMIT SPACE + ." ERRNO=" + . CR +; + +( TODO: translate jonesforth x86 assembler into x64 ) + +: WELCOME + S" TEST-MODE" FIND NOT IF + ." Jombloforth version " VERSION . CR + UNUSED . ." cells remaining" CR + ." ok " CR + THEN +; + +WELCOME +HIDE WELCOME \ No newline at end of file diff --git a/references/jonesforth/jonesforth.s b/references/jonesforth/jonesforth.s new file mode 100644 index 0000000..4ba9d2e --- /dev/null +++ b/references/jonesforth/jonesforth.s @@ -0,0 +1,2314 @@ +/* A sometimes minimal FORTH compiler and tutorial for Linux / i386 systems. -*- asm -*- + By Richard W.M. Jones http://annexia.org/forth + This is PUBLIC DOMAIN (see public domain release statement below). + $Id: jonesforth.S,v 1.47 2009-09-11 08:33:13 rich Exp $ + + gcc -m32 -nostdlib -static -Wl,-Ttext,0 -Wl,--build-id=none -o jonesforth jonesforth.S +*/ + .set JONES_VERSION,47 +/* + INTRODUCTION ---------------------------------------------------------------------- + + FORTH is one of those alien languages which most working programmers regard in the same + way as Haskell, LISP, and so on. Something so strange that they'd rather any thoughts + of it just go away so they can get on with writing this paying code. But that's wrong + and if you care at all about programming then you should at least understand all these + languages, even if you will never use them. + + LISP is the ultimate high-level language, and features from LISP are being added every + decade to the more common languages. But FORTH is in some ways the ultimate in low level + programming. Out of the box it lacks features like dynamic memory management and even + strings. In fact, at its primitive level it lacks even basic concepts like IF-statements + and loops. + + Why then would you want to learn FORTH? There are several very good reasons. First + and foremost, FORTH is minimal. You really can write a complete FORTH in, say, 2000 + lines of code. I don't just mean a FORTH program, I mean a complete FORTH operating + system, environment and language. You could boot such a FORTH on a bare PC and it would + come up with a prompt where you could start doing useful work. The FORTH you have here + isn't minimal and uses a Linux process as its 'base PC' (both for the purposes of making + it a good tutorial). It's possible to completely understand the system. Who can say they + completely understand how Linux works, or gcc? + + Secondly FORTH has a peculiar bootstrapping property. By that I mean that after writing + a little bit of assembly to talk to the hardware and implement a few primitives, all the + rest of the language and compiler is written in FORTH itself. Remember I said before + that FORTH lacked IF-statements and loops? Well of course it doesn't really because + such a lanuage would be useless, but my point was rather that IF-statements and loops are + written in FORTH itself. + + Now of course this is common in other languages as well, and in those languages we call + them 'libraries'. For example in C, 'printf' is a library function written in C. But + in FORTH this goes way beyond mere libraries. Can you imagine writing C's 'if' in C? + And that brings me to my third reason: If you can write 'if' in FORTH, then why restrict + yourself to the usual if/while/for/switch constructs? You want a construct that iterates + over every other element in a list of numbers? You can add it to the language. What + about an operator which pulls in variables directly from a configuration file and makes + them available as FORTH variables? Or how about adding Makefile-like dependencies to + the language? No problem in FORTH. How about modifying the FORTH compiler to allow + complex inlining strategies -- simple. This concept isn't common in programming languages, + but it has a name (in fact two names): "macros" (by which I mean LISP-style macros, not + the lame C preprocessor) and "domain specific languages" (DSLs). + + This tutorial isn't about learning FORTH as the language. I'll point you to some references + you should read if you're not familiar with using FORTH. This tutorial is about how to + write FORTH. In fact, until you understand how FORTH is written, you'll have only a very + superficial understanding of how to use it. + + So if you're not familiar with FORTH or want to refresh your memory here are some online + references to read: + + http://en.wikipedia.org/wiki/Forth_%28programming_language%29 + + http://galileo.phys.virginia.edu/classes/551.jvn.fall01/primer.htm + + http://wiki.laptop.org/go/Forth_Lessons + + http://www.albany.net/~hello/simple.htm + + Here is another "Why FORTH?" essay: http://www.jwdt.com/~paysan/why-forth.html + + Discussion and criticism of this FORTH here: http://lambda-the-ultimate.org/node/2452 + + ACKNOWLEDGEMENTS ---------------------------------------------------------------------- + + This code draws heavily on the design of LINA FORTH (http://home.hccnet.nl/a.w.m.van.der.horst/lina.html) + by Albert van der Horst. Any similarities in the code are probably not accidental. + + Some parts of this FORTH are also based on this IOCCC entry from 1992: + http://ftp.funet.fi/pub/doc/IOCCC/1992/buzzard.2.design. + I was very proud when Sean Barrett, the original author of the IOCCC entry, commented in the LtU thread + http://lambda-the-ultimate.org/node/2452#comment-36818 about this FORTH. + + And finally I'd like to acknowledge the (possibly forgotten?) authors of ARTIC FORTH because their + original program which I still have on original cassette tape kept nagging away at me all these years. + http://en.wikipedia.org/wiki/Artic_Software + + PUBLIC DOMAIN ---------------------------------------------------------------------- + + I, the copyright holder of this work, hereby release it into the public domain. This applies worldwide. + + In case this is not legally possible, I grant any entity the right to use this work for any purpose, + without any conditions, unless such conditions are required by law. + + SETTING UP ---------------------------------------------------------------------- + + Let's get a few housekeeping things out of the way. Firstly because I need to draw lots of + ASCII-art diagrams to explain concepts, the best way to look at this is using a window which + uses a fixed width font and is at least this wide: + + <------------------------------------------------------------------------------------------------------------------------> + + Secondly make sure TABS are set to 8 characters. The following should be a vertical + line. If not, sort out your tabs. + + | + | + | + + Thirdly I assume that your screen is at least 50 characters high. + + ASSEMBLING ---------------------------------------------------------------------- + + If you want to actually run this FORTH, rather than just read it, you will need Linux on an + i386. Linux because instead of programming directly to the hardware on a bare PC which I + could have done, I went for a simpler tutorial by assuming that the 'hardware' is a Linux + process with a few basic system calls (read, write and exit and that's about all). i386 + is needed because I had to write the assembly for a processor, and i386 is by far the most + common. (Of course when I say 'i386', any 32- or 64-bit x86 processor will do. I'm compiling + this on a 64 bit AMD Opteron). + + Again, to assemble this you will need gcc and gas (the GNU assembler). The commands to + assemble and run the code (save this file as 'jonesforth.S') are: + + gcc -m32 -nostdlib -static -Wl,-Ttext,0 -Wl,--build-id=none -o jonesforth jonesforth.S + cat jonesforth.f - | ./jonesforth + + If you want to run your own FORTH programs you can do: + + cat jonesforth.f myprog.f | ./jonesforth + + If you want to load your own FORTH code and then continue reading user commands, you can do: + + cat jonesforth.f myfunctions.f - | ./jonesforth + + ASSEMBLER ---------------------------------------------------------------------- + + (You can just skip to the next section -- you don't need to be able to read assembler to + follow this tutorial). + + However if you do want to read the assembly code here are a few notes about gas (the GNU assembler): + + (1) Register names are prefixed with '%', so %eax is the 32 bit i386 accumulator. The registers + available on i386 are: %eax, %ebx, %ecx, %edx, %esi, %edi, %ebp and %esp, and most of them + have special purposes. + + (2) Add, mov, etc. take arguments in the form SRC,DEST. So mov %eax,%ecx moves %eax -> %ecx + + (3) Constants are prefixed with '$', and you mustn't forget it! If you forget it then it + causes a read from memory instead, so: + mov $2,%eax moves number 2 into %eax + mov 2,%eax reads the 32 bit word from address 2 into %eax (ie. most likely a mistake) + + (4) gas has a funky syntax for local labels, where '1f' (etc.) means label '1:' "forwards" + and '1b' (etc.) means label '1:' "backwards". Notice that these labels might be mistaken + for hex numbers (eg. you might confuse 1b with $0x1b). + + (5) 'ja' is "jump if above", 'jb' for "jump if below", 'je' "jump if equal" etc. + + (6) gas has a reasonably nice .macro syntax, and I use them a lot to make the code shorter and + less repetitive. + + For more help reading the assembler, do "info gas" at the Linux prompt. + + Now the tutorial starts in earnest. + + THE DICTIONARY ---------------------------------------------------------------------- + + In FORTH as you will know, functions are called "words", and just as in other languages they + have a name and a definition. Here are two FORTH words: + + : DOUBLE DUP + ; \ name is "DOUBLE", definition is "DUP +" + : QUADRUPLE DOUBLE DOUBLE ; \ name is "QUADRUPLE", definition is "DOUBLE DOUBLE" + + Words, both built-in ones and ones which the programmer defines later, are stored in a dictionary + which is just a linked list of dictionary entries. + + <--- DICTIONARY ENTRY (HEADER) -----------------------> + +------------------------+--------+---------- - - - - +----------- - - - - + | LINK POINTER | LENGTH/| NAME | DEFINITION + | | FLAGS | | + +--- (4 bytes) ----------+- byte -+- n bytes - - - - +----------- - - - - + + I'll come to the definition of the word later. For now just look at the header. The first + 4 bytes are the link pointer. This points back to the previous word in the dictionary, or, for + the first word in the dictionary it is just a NULL pointer. Then comes a length/flags byte. + The length of the word can be up to 31 characters (5 bits used) and the top three bits are used + for various flags which I'll come to later. This is followed by the name itself, and in this + implementation the name is rounded up to a multiple of 4 bytes by padding it with zero bytes. + That's just to ensure that the definition starts on a 32 bit boundary. + + A FORTH variable called LATEST contains a pointer to the most recently defined word, in + other words, the head of this linked list. + + DOUBLE and QUADRUPLE might look like this: + + pointer to previous word + ^ + | + +--|------+---+---+---+---+---+---+---+---+------------- - - - - + | LINK | 6 | D | O | U | B | L | E | 0 | (definition ...) + +---------+---+---+---+---+---+---+---+---+------------- - - - - + ^ len padding + | + +--|------+---+---+---+---+---+---+---+---+---+---+---+---+------------- - - - - + | LINK | 9 | Q | U | A | D | R | U | P | L | E | 0 | 0 | (definition ...) + +---------+---+---+---+---+---+---+---+---+---+---+---+---+------------- - - - - + ^ len padding + | + | + LATEST + + You should be able to see from this how you might implement functions to find a word in + the dictionary (just walk along the dictionary entries starting at LATEST and matching + the names until you either find a match or hit the NULL pointer at the end of the dictionary); + and add a word to the dictionary (create a new definition, set its LINK to LATEST, and set + LATEST to point to the new word). We'll see precisely these functions implemented in + assembly code later on. + + One interesting consequence of using a linked list is that you can redefine words, and + a newer definition of a word overrides an older one. This is an important concept in + FORTH because it means that any word (even "built-in" or "standard" words) can be + overridden with a new definition, either to enhance it, to make it faster or even to + disable it. However because of the way that FORTH words get compiled, which you'll + understand below, words defined using the old definition of a word continue to use + the old definition. Only words defined after the new definition use the new definition. + + DIRECT THREADED CODE ---------------------------------------------------------------------- + + Now we'll get to the really crucial bit in understanding FORTH, so go and get a cup of tea + or coffee and settle down. It's fair to say that if you don't understand this section, then you + won't "get" how FORTH works, and that would be a failure on my part for not explaining it well. + So if after reading this section a few times you don't understand it, please email me + (rich@annexia.org). + + Let's talk first about what "threaded code" means. Imagine a peculiar version of C where + you are only allowed to call functions without arguments. (Don't worry for now that such a + language would be completely useless!) So in our peculiar C, code would look like this: + + f () + { + a (); + b (); + c (); + } + + and so on. How would a function, say 'f' above, be compiled by a standard C compiler? + Probably into assembly code like this. On the right hand side I've written the actual + i386 machine code. + + f: + CALL a E8 08 00 00 00 + CALL b E8 1C 00 00 00 + CALL c E8 2C 00 00 00 + ; ignore the return from the function for now + + "E8" is the x86 machine code to "CALL" a function. In the first 20 years of computing + memory was hideously expensive and we might have worried about the wasted space being used + by the repeated "E8" bytes. We can save 20% in code size (and therefore, in expensive memory) + by compressing this into just: + + 08 00 00 00 Just the function addresses, without + 1C 00 00 00 the CALL prefix. + 2C 00 00 00 + + On a 16-bit machine like the ones which originally ran FORTH the savings are even greater - 33%. + + [Historical note: If the execution model that FORTH uses looks strange from the following + paragraphs, then it was motivated entirely by the need to save memory on early computers. + This code compression isn't so important now when our machines have more memory in their L1 + caches than those early computers had in total, but the execution model still has some + useful properties]. + + Of course this code won't run directly on the CPU any more. Instead we need to write an + interpreter which takes each set of bytes and calls it. + + On an i386 machine it turns out that we can write this interpreter rather easily, in just + two assembly instructions which turn into just 3 bytes of machine code. Let's store the + pointer to the next word to execute in the %esi register: + + 08 00 00 00 <- We're executing this one now. %esi is the _next_ one to execute. + %esi -> 1C 00 00 00 + 2C 00 00 00 + + The all-important i386 instruction is called LODSL (or in Intel manuals, LODSW). It does + two things. Firstly it reads the memory at %esi into the accumulator (%eax). Secondly it + increments %esi by 4 bytes. So after LODSL, the situation now looks like this: + + 08 00 00 00 <- We're still executing this one + 1C 00 00 00 <- %eax now contains this address (0x0000001C) + %esi -> 2C 00 00 00 + + Now we just need to jump to the address in %eax. This is again just a single x86 instruction + written JMP *(%eax). And after doing the jump, the situation looks like: + + 08 00 00 00 + 1C 00 00 00 <- Now we're executing this subroutine. + %esi -> 2C 00 00 00 + + To make this work, each subroutine is followed by the two instructions 'LODSL; JMP *(%eax)' + which literally make the jump to the next subroutine. + + And that brings us to our first piece of actual code! Well, it's a macro. +*/ + +/* NEXT macro. */ + .macro NEXT + lodsl + jmp *(%eax) + .endm + +/* The macro is called NEXT. That's a FORTH-ism. It expands to those two instructions. + + Every FORTH primitive that we write has to be ended by NEXT. Think of it kind of like + a return. + + The above describes what is known as direct threaded code. + + To sum up: We compress our function calls down to a list of addresses and use a somewhat + magical macro to act as a "jump to next function in the list". We also use one register (%esi) + to act as a kind of instruction pointer, pointing to the next function in the list. + + I'll just give you a hint of what is to come by saying that a FORTH definition such as: + + : QUADRUPLE DOUBLE DOUBLE ; + + actually compiles (almost, not precisely but we'll see why in a moment) to a list of + function addresses for DOUBLE, DOUBLE and a special function called EXIT to finish off. + + At this point, REALLY EAGLE-EYED ASSEMBLY EXPERTS are saying "JONES, YOU'VE MADE A MISTAKE!". + + I lied about JMP *(%eax). + + INDIRECT THREADED CODE ---------------------------------------------------------------------- + + It turns out that direct threaded code is interesting but only if you want to just execute + a list of functions written in assembly language. So QUADRUPLE would work only if DOUBLE + was an assembly language function. In the direct threaded code, QUADRUPLE would look like: + + +------------------+ + | addr of DOUBLE --------------------> (assembly code to do the double) + +------------------+ NEXT + %esi -> | addr of DOUBLE | + +------------------+ + + We can add an extra indirection to allow us to run both words written in assembly language + (primitives written for speed) and words written in FORTH themselves as lists of addresses. + + The extra indirection is the reason for the brackets in JMP *(%eax). + + Let's have a look at how QUADRUPLE and DOUBLE really look in FORTH: + + : QUADRUPLE DOUBLE DOUBLE ; + + +------------------+ + | codeword | : DOUBLE DUP + ; + +------------------+ + | addr of DOUBLE ---------------> +------------------+ + +------------------+ | codeword | + | addr of DOUBLE | +------------------+ + +------------------+ | addr of DUP --------------> +------------------+ + | addr of EXIT | +------------------+ | codeword -------+ + +------------------+ %esi -> | addr of + --------+ +------------------+ | + +------------------+ | | assembly to <-----+ + | addr of EXIT | | | implement DUP | + +------------------+ | | .. | + | | .. | + | | NEXT | + | +------------------+ + | + +-----> +------------------+ + | codeword -------+ + +------------------+ | + | assembly to <------+ + | implement + | + | .. | + | .. | + | NEXT | + +------------------+ + + This is the part where you may need an extra cup of tea/coffee/favourite caffeinated + beverage. What has changed is that I've added an extra pointer to the beginning of + the definitions. In FORTH this is sometimes called the "codeword". The codeword is + a pointer to the interpreter to run the function. For primitives written in + assembly language, the "interpreter" just points to the actual assembly code itself. + They don't need interpreting, they just run. + + In words written in FORTH (like QUADRUPLE and DOUBLE), the codeword points to an interpreter + function. + + I'll show you the interpreter function shortly, but let's recall our indirect + JMP *(%eax) with the "extra" brackets. Take the case where we're executing DOUBLE + as shown, and DUP has been called. Note that %esi is pointing to the address of + + + The assembly code for DUP eventually does a NEXT. That: + + (1) reads the address of + into %eax %eax points to the codeword of + + (2) increments %esi by 4 + (3) jumps to the indirect %eax jumps to the address in the codeword of +, + ie. the assembly code to implement + + + +------------------+ + | codeword | + +------------------+ + | addr of DOUBLE ---------------> +------------------+ + +------------------+ | codeword | + | addr of DOUBLE | +------------------+ + +------------------+ | addr of DUP --------------> +------------------+ + | addr of EXIT | +------------------+ | codeword -------+ + +------------------+ | addr of + --------+ +------------------+ | + +------------------+ | | assembly to <-----+ + %esi -> | addr of EXIT | | | implement DUP | + +------------------+ | | .. | + | | .. | + | | NEXT | + | +------------------+ + | + +-----> +------------------+ + | codeword -------+ + +------------------+ | + now we're | assembly to <-----+ + executing | implement + | + this | .. | + function | .. | + | NEXT | + +------------------+ + + So I hope that I've convinced you that NEXT does roughly what you'd expect. This is + indirect threaded code. + + I've glossed over four things. I wonder if you can guess without reading on what they are? + + . + . + . + + My list of four things are: (1) What does "EXIT" do? (2) which is related to (1) is how do + you call into a function, ie. how does %esi start off pointing at part of QUADRUPLE, but + then point at part of DOUBLE. (3) What goes in the codeword for the words which are written + in FORTH? (4) How do you compile a function which does anything except call other functions + ie. a function which contains a number like : DOUBLE 2 * ; ? + + THE INTERPRETER AND RETURN STACK ------------------------------------------------------------ + + Going at these in no particular order, let's talk about issues (3) and (2), the interpreter + and the return stack. + + Words which are defined in FORTH need a codeword which points to a little bit of code to + give them a "helping hand" in life. They don't need much, but they do need what is known + as an "interpreter", although it doesn't really "interpret" in the same way that, say, + Java bytecode used to be interpreted (ie. slowly). This interpreter just sets up a few + machine registers so that the word can then execute at full speed using the indirect + threaded model above. + + One of the things that needs to happen when QUADRUPLE calls DOUBLE is that we save the old + %esi ("instruction pointer") and create a new one pointing to the first word in DOUBLE. + Because we will need to restore the old %esi at the end of DOUBLE (this is, after all, like + a function call), we will need a stack to store these "return addresses" (old values of %esi). + + As you will have seen in the background documentation, FORTH has two stacks, an ordinary + stack for parameters, and a return stack which is a bit more mysterious. But our return + stack is just the stack I talked about in the previous paragraph, used to save %esi when + calling from a FORTH word into another FORTH word. + + In this FORTH, we are using the normal stack pointer (%esp) for the parameter stack. + We will use the i386's "other" stack pointer (%ebp, usually called the "frame pointer") + for our return stack. + + I've got two macros which just wrap up the details of using %ebp for the return stack. + You use them as for example "PUSHRSP %eax" (push %eax on the return stack) or "POPRSP %ebx" + (pop top of return stack into %ebx). +*/ + +/* Macros to deal with the return stack. */ + .macro PUSHRSP reg + lea -4(%ebp),%ebp // push reg on to return stack + movl \reg,(%ebp) + .endm + + .macro POPRSP reg + mov (%ebp),\reg // pop top of return stack to reg + lea 4(%ebp),%ebp + .endm + +/* + And with that we can now talk about the interpreter. + + In FORTH the interpreter function is often called DOCOL (I think it means "DO COLON" because + all FORTH definitions start with a colon, as in : DOUBLE DUP + ; + + The "interpreter" (it's not really "interpreting") just needs to push the old %esi on the + stack and set %esi to the first word in the definition. Remember that we jumped to the + function using JMP *(%eax)? Well a consequence of that is that conveniently %eax contains + the address of this codeword, so just by adding 4 to it we get the address of the first + data word. Finally after setting up %esi, it just does NEXT which causes that first word + to run. +*/ + +/* DOCOL - the interpreter! */ + .text + .align 4 +DOCOL: + PUSHRSP %esi // push %esi on to the return stack + addl $4,%eax // %eax points to codeword, so make + movl %eax,%esi // %esi point to first data word + NEXT + +/* + Just to make this absolutely clear, let's see how DOCOL works when jumping from QUADRUPLE + into DOUBLE: + + QUADRUPLE: + +------------------+ + | codeword | + +------------------+ DOUBLE: + | addr of DOUBLE ---------------> +------------------+ + +------------------+ %eax -> | addr of DOCOL | + %esi -> | addr of DOUBLE | +------------------+ + +------------------+ | addr of DUP | + | addr of EXIT | +------------------+ + +------------------+ | etc. | + + First, the call to DOUBLE calls DOCOL (the codeword of DOUBLE). DOCOL does this: It + pushes the old %esi on the return stack. %eax points to the codeword of DOUBLE, so we + just add 4 on to it to get our new %esi: + + QUADRUPLE: + +------------------+ + | codeword | + +------------------+ DOUBLE: + | addr of DOUBLE ---------------> +------------------+ +top of return +------------------+ %eax -> | addr of DOCOL | +stack points -> | addr of DOUBLE | + 4 = +------------------+ + +------------------+ %esi -> | addr of DUP | + | addr of EXIT | +------------------+ + +------------------+ | etc. | + + Then we do NEXT, and because of the magic of threaded code that increments %esi again + and calls DUP. + + Well, it seems to work. + + One minor point here. Because DOCOL is the first bit of assembly actually to be defined + in this file (the others were just macros), and because I usually compile this code with the + text segment starting at address 0, DOCOL has address 0. So if you are disassembling the + code and see a word with a codeword of 0, you will immediately know that the word is + written in FORTH (it's not an assembler primitive) and so uses DOCOL as the interpreter. + + STARTING UP ---------------------------------------------------------------------- + + Now let's get down to nuts and bolts. When we start the program we need to set up + a few things like the return stack. But as soon as we can, we want to jump into FORTH + code (albeit much of the "early" FORTH code will still need to be written as + assembly language primitives). + + This is what the set up code does. Does a tiny bit of house-keeping, sets up the + separate return stack (NB: Linux gives us the ordinary parameter stack already), then + immediately jumps to a FORTH word called QUIT. Despite its name, QUIT doesn't quit + anything. It resets some internal state and starts reading and interpreting commands. + (The reason it is called QUIT is because you can call QUIT from your own FORTH code + to "quit" your program and go back to interpreting). +*/ + +/* Assembler entry point. */ + .text + .globl _start +_start: + cld + mov %esp,var_S0 // Save the initial data stack pointer in FORTH variable S0. + mov $return_stack_top,%ebp // Initialise the return stack. + call set_up_data_segment + + mov $cold_start,%esi // Initialise interpreter. + NEXT // Run interpreter! + + .section .rodata +cold_start: // High-level code without a codeword. + .int QUIT + +/* + BUILT-IN WORDS ---------------------------------------------------------------------- + + Remember our dictionary entries (headers)? Let's bring those together with the codeword + and data words to see how : DOUBLE DUP + ; really looks in memory. + + pointer to previous word + ^ + | + +--|------+---+---+---+---+---+---+---+---+------------+------------+------------+------------+ + | LINK | 6 | D | O | U | B | L | E | 0 | DOCOL | DUP | + | EXIT | + +---------+---+---+---+---+---+---+---+---+------------+--|---------+------------+------------+ + ^ len pad codeword | + | V + LINK in next word points to codeword of DUP + + Initially we can't just write ": DOUBLE DUP + ;" (ie. that literal string) here because we + don't yet have anything to read the string, break it up at spaces, parse each word, etc. etc. + So instead we will have to define built-in words using the GNU assembler data constructors + (like .int, .byte, .string, .ascii and so on -- look them up in the gas info page if you are + unsure of them). + + The long way would be: + + .int + .byte 6 // len + .ascii "DOUBLE" // string + .byte 0 // padding +DOUBLE: .int DOCOL // codeword + .int DUP // pointer to codeword of DUP + .int PLUS // pointer to codeword of + + .int EXIT // pointer to codeword of EXIT + + That's going to get quite tedious rather quickly, so here I define an assembler macro + so that I can just write: + + defword "DOUBLE",6,,DOUBLE + .int DUP,PLUS,EXIT + + and I'll get exactly the same effect. + + Don't worry too much about the exact implementation details of this macro - it's complicated! +*/ + +/* Flags - these are discussed later. */ + .set F_IMMED,0x80 + .set F_HIDDEN,0x20 + .set F_LENMASK,0x1f // length mask + + // Store the chain of links. + .set link,0 + + .macro defword name, namelen, flags=0, label + .section .rodata + .align 4 + .globl name_\label +name_\label : + .int link // link + .set link,name_\label + .byte \flags+\namelen // flags + length byte + .ascii "\name" // the name + .align 4 // padding to next 4 byte boundary + .globl \label +\label : + .int DOCOL // codeword - the interpreter + // list of word pointers follow + .endm + +/* + Similarly I want a way to write words written in assembly language. There will be quite a few + of these to start with because, well, everything has to start in assembly before there's + enough "infrastructure" to be able to start writing FORTH words, but also I want to define + some common FORTH words in assembly language for speed, even though I could write them in FORTH. + + This is what DUP looks like in memory: + + pointer to previous word + ^ + | + +--|------+---+---+---+---+------------+ + | LINK | 3 | D | U | P | code_DUP ---------------------> points to the assembly + +---------+---+---+---+---+------------+ code used to write DUP, + ^ len codeword which ends with NEXT. + | + LINK in next word + + Again, for brevity in writing the header I'm going to write an assembler macro called defcode. + As with defword above, don't worry about the complicated details of the macro. +*/ + + .macro defcode name, namelen, flags=0, label + .section .rodata + .align 4 + .globl name_\label +name_\label : + .int link // link + .set link,name_\label + .byte \flags+\namelen // flags + length byte + .ascii "\name" // the name + .align 4 // padding to next 4 byte boundary + .globl \label +\label : + .int code_\label // codeword + .text + //.align 4 + .globl code_\label +code_\label : // assembler code follows + .endm + +/* + Now some easy FORTH primitives. These are written in assembly for speed. If you understand + i386 assembly language then it is worth reading these. However if you don't understand assembly + you can skip the details. +*/ + + defcode "DROP",4,,DROP + pop %eax // drop top of stack + NEXT + + defcode "SWAP",4,,SWAP + pop %eax // swap top two elements on stack + pop %ebx + push %eax + push %ebx + NEXT + + defcode "DUP",3,,DUP + mov (%esp),%eax // duplicate top of stack + push %eax + NEXT + + defcode "OVER",4,,OVER + mov 4(%esp),%eax // get the second element of stack + push %eax // and push it on top + NEXT + + defcode "ROT",3,,ROT + pop %eax + pop %ebx + pop %ecx + push %ebx + push %eax + push %ecx + NEXT + + defcode "-ROT",4,,NROT + pop %eax + pop %ebx + pop %ecx + push %eax + push %ecx + push %ebx + NEXT + + defcode "2DROP",5,,TWODROP // drop top two elements of stack + pop %eax + pop %eax + NEXT + + defcode "2DUP",4,,TWODUP // duplicate top two elements of stack + mov (%esp),%eax + mov 4(%esp),%ebx + push %ebx + push %eax + NEXT + + defcode "2SWAP",5,,TWOSWAP // swap top two pairs of elements of stack + pop %eax + pop %ebx + pop %ecx + pop %edx + push %ebx + push %eax + push %edx + push %ecx + NEXT + + defcode "?DUP",4,,QDUP // duplicate top of stack if non-zero + movl (%esp),%eax + test %eax,%eax + jz 1f + push %eax +1: NEXT + + defcode "1+",2,,INCR + incl (%esp) // increment top of stack + NEXT + + defcode "1-",2,,DECR + decl (%esp) // decrement top of stack + NEXT + + defcode "4+",2,,INCR4 + addl $4,(%esp) // add 4 to top of stack + NEXT + + defcode "4-",2,,DECR4 + subl $4,(%esp) // subtract 4 from top of stack + NEXT + + defcode "+",1,,ADD + pop %eax // get top of stack + addl %eax,(%esp) // and add it to next word on stack + NEXT + + defcode "-",1,,SUB + pop %eax // get top of stack + subl %eax,(%esp) // and subtract it from next word on stack + NEXT + + defcode "*",1,,MUL + pop %eax + pop %ebx + imull %ebx,%eax + push %eax // ignore overflow + NEXT + +/* + In this FORTH, only /MOD is primitive. Later we will define the / and MOD words in + terms of the primitive /MOD. The design of the i386 assembly instruction idiv which + leaves both quotient and remainder makes this the obvious choice. +*/ + + defcode "/MOD",4,,DIVMOD + xor %edx,%edx + pop %ebx + pop %eax + idivl %ebx + push %edx // push remainder + push %eax // push quotient + NEXT + +/* + Lots of comparison operations like =, <, >, etc.. + + ANS FORTH says that the comparison words should return all (binary) 1's for + TRUE and all 0's for FALSE. However this is a bit of a strange convention + so this FORTH breaks it and returns the more normal (for C programmers ...) + 1 meaning TRUE and 0 meaning FALSE. +*/ + + defcode "=",1,,EQU // top two words are equal? + pop %eax + pop %ebx + cmp %ebx,%eax + sete %al + movzbl %al,%eax + pushl %eax + NEXT + + defcode "<>",2,,NEQU // top two words are not equal? + pop %eax + pop %ebx + cmp %ebx,%eax + setne %al + movzbl %al,%eax + pushl %eax + NEXT + + defcode "<",1,,LT + pop %eax + pop %ebx + cmp %eax,%ebx + setl %al + movzbl %al,%eax + pushl %eax + NEXT + + defcode ">",1,,GT + pop %eax + pop %ebx + cmp %eax,%ebx + setg %al + movzbl %al,%eax + pushl %eax + NEXT + + defcode "<=",2,,LE + pop %eax + pop %ebx + cmp %eax,%ebx + setle %al + movzbl %al,%eax + pushl %eax + NEXT + + defcode ">=",2,,GE + pop %eax + pop %ebx + cmp %eax,%ebx + setge %al + movzbl %al,%eax + pushl %eax + NEXT + + defcode "0=",2,,ZEQU // top of stack equals 0? + pop %eax + test %eax,%eax + setz %al + movzbl %al,%eax + pushl %eax + NEXT + + defcode "0<>",3,,ZNEQU // top of stack not 0? + pop %eax + test %eax,%eax + setnz %al + movzbl %al,%eax + pushl %eax + NEXT + + defcode "0<",2,,ZLT // comparisons with 0 + pop %eax + test %eax,%eax + setl %al + movzbl %al,%eax + pushl %eax + NEXT + + defcode "0>",2,,ZGT + pop %eax + test %eax,%eax + setg %al + movzbl %al,%eax + pushl %eax + NEXT + + defcode "0<=",3,,ZLE + pop %eax + test %eax,%eax + setle %al + movzbl %al,%eax + pushl %eax + NEXT + + defcode "0>=",3,,ZGE + pop %eax + test %eax,%eax + setge %al + movzbl %al,%eax + pushl %eax + NEXT + + defcode "AND",3,,AND // bitwise AND + pop %eax + andl %eax,(%esp) + NEXT + + defcode "OR",2,,OR // bitwise OR + pop %eax + orl %eax,(%esp) + NEXT + + defcode "XOR",3,,XOR // bitwise XOR + pop %eax + xorl %eax,(%esp) + NEXT + + defcode "INVERT",6,,INVERT // this is the FORTH bitwise "NOT" function (cf. NEGATE and NOT) + notl (%esp) + NEXT + +/* + RETURNING FROM FORTH WORDS ---------------------------------------------------------------------- + + Time to talk about what happens when we EXIT a function. In this diagram QUADRUPLE has called + DOUBLE, and DOUBLE is about to exit (look at where %esi is pointing): + + QUADRUPLE + +------------------+ + | codeword | + +------------------+ DOUBLE + | addr of DOUBLE ---------------> +------------------+ + +------------------+ | codeword | + | addr of DOUBLE | +------------------+ + +------------------+ | addr of DUP | + | addr of EXIT | +------------------+ + +------------------+ | addr of + | + +------------------+ + %esi -> | addr of EXIT | + +------------------+ + + What happens when the + function does NEXT? Well, the following code is executed. +*/ + + defcode "EXIT",4,,EXIT + POPRSP %esi // pop return stack into %esi + NEXT + +/* + EXIT gets the old %esi which we saved from before on the return stack, and puts it in %esi. + So after this (but just before NEXT) we get: + + QUADRUPLE + +------------------+ + | codeword | + +------------------+ DOUBLE + | addr of DOUBLE ---------------> +------------------+ + +------------------+ | codeword | + %esi -> | addr of DOUBLE | +------------------+ + +------------------+ | addr of DUP | + | addr of EXIT | +------------------+ + +------------------+ | addr of + | + +------------------+ + | addr of EXIT | + +------------------+ + + And NEXT just completes the job by, well, in this case just by calling DOUBLE again :-) + + LITERALS ---------------------------------------------------------------------- + + The final point I "glossed over" before was how to deal with functions that do anything + apart from calling other functions. For example, suppose that DOUBLE was defined like this: + + : DOUBLE 2 * ; + + It does the same thing, but how do we compile it since it contains the literal 2? One way + would be to have a function called "2" (which you'd have to write in assembler), but you'd need + a function for every single literal that you wanted to use. + + FORTH solves this by compiling the function using a special word called LIT: + + +---------------------------+-------+-------+-------+-------+-------+ + | (usual header of DOUBLE) | DOCOL | LIT | 2 | * | EXIT | + +---------------------------+-------+-------+-------+-------+-------+ + + LIT is executed in the normal way, but what it does next is definitely not normal. It + looks at %esi (which now points to the number 2), grabs it, pushes it on the stack, then + manipulates %esi in order to skip the number as if it had never been there. + + What's neat is that the whole grab/manipulate can be done using a single byte single + i386 instruction, our old friend LODSL. Rather than me drawing more ASCII-art diagrams, + see if you can find out how LIT works: +*/ + + defcode "LIT",3,,LIT + // %esi points to the next command, but in this case it points to the next + // literal 32 bit integer. Get that literal into %eax and increment %esi. + // On x86, it's a convenient single byte instruction! (cf. NEXT macro) + lodsl + push %eax // push the literal number on to stack + NEXT + +/* + MEMORY ---------------------------------------------------------------------- + + An important point about FORTH is that it gives you direct access to the lowest levels + of the machine. Manipulating memory directly is done frequently in FORTH, and these are + the primitive words for doing it. +*/ + + defcode "!",1,,STORE + pop %ebx // address to store at + pop %eax // data to store there + mov %eax,(%ebx) // store it + NEXT + + defcode "@",1,,FETCH + pop %ebx // address to fetch + mov (%ebx),%eax // fetch it + push %eax // push value onto stack + NEXT + + defcode "+!",2,,ADDSTORE + pop %ebx // address + pop %eax // the amount to add + addl %eax,(%ebx) // add it + NEXT + + defcode "-!",2,,SUBSTORE + pop %ebx // address + pop %eax // the amount to subtract + subl %eax,(%ebx) // add it + NEXT + +/* + ! and @ (STORE and FETCH) store 32-bit words. It's also useful to be able to read and write bytes + so we also define standard words C@ and C!. + + Byte-oriented operations only work on architectures which permit them (i386 is one of those). + */ + + defcode "C!",2,,STOREBYTE + pop %ebx // address to store at + pop %eax // data to store there + movb %al,(%ebx) // store it + NEXT + + defcode "C@",2,,FETCHBYTE + pop %ebx // address to fetch + xor %eax,%eax + movb (%ebx),%al // fetch it + push %eax // push value onto stack + NEXT + +/* C@C! is a useful byte copy primitive. */ + defcode "C@C!",4,,CCOPY + movl 4(%esp),%ebx // source address + movb (%ebx),%al // get source character + pop %edi // destination address + stosb // copy to destination + push %edi // increment destination address + incl 4(%esp) // increment source address + NEXT + +/* and CMOVE is a block copy operation. */ + defcode "CMOVE",5,,CMOVE + mov %esi,%edx // preserve %esi + pop %ecx // length + pop %edi // destination address + pop %esi // source address + rep movsb // copy source to destination + mov %edx,%esi // restore %esi + NEXT + +/* + BUILT-IN VARIABLES ---------------------------------------------------------------------- + + These are some built-in variables and related standard FORTH words. Of these, the only one that we + have discussed so far was LATEST, which points to the last (most recently defined) word in the + FORTH dictionary. LATEST is also a FORTH word which pushes the address of LATEST (the variable) + on to the stack, so you can read or write it using @ and ! operators. For example, to print + the current value of LATEST (and this can apply to any FORTH variable) you would do: + + LATEST @ . CR + + To make defining variables shorter, I'm using a macro called defvar, similar to defword and + defcode above. (In fact the defvar macro uses defcode to do the dictionary header). +*/ + + .macro defvar name, namelen, flags=0, label, initial=0 + defcode \name,\namelen,\flags,\label + push $var_\name + NEXT + .data + .align 4 +var_\name : + .int \initial + .endm + +/* + The built-in variables are: + + STATE Is the interpreter executing code (0) or compiling a word (non-zero)? + LATEST Points to the latest (most recently defined) word in the dictionary. + HERE Points to the next free byte of memory. When compiling, compiled words go here. + S0 Stores the address of the top of the parameter stack. + BASE The current base for printing and reading numbers. + +*/ + defvar "STATE",5,,STATE + defvar "HERE",4,,HERE + defvar "LATEST",6,,LATEST,name_SYSCALL0 // SYSCALL0 must be last in built-in dictionary + defvar "S0",2,,SZ + defvar "BASE",4,,BASE,10 + +/* + BUILT-IN CONSTANTS ---------------------------------------------------------------------- + + It's also useful to expose a few constants to FORTH. When the word is executed it pushes a + constant value on the stack. + + The built-in constants are: + + VERSION Is the current version of this FORTH. + R0 The address of the top of the return stack. + DOCOL Pointer to DOCOL. + F_IMMED The IMMEDIATE flag's actual value. + F_HIDDEN The HIDDEN flag's actual value. + F_LENMASK The length mask in the flags/len byte. + + SYS_* and the numeric codes of various Linux syscalls (from ) +*/ + +//#include // you might need this instead +#include + + .macro defconst name, namelen, flags=0, label, value + defcode \name,\namelen,\flags,\label + push $\value + NEXT + .endm + + defconst "VERSION",7,,VERSION,JONES_VERSION + defconst "R0",2,,RZ,return_stack_top + defconst "DOCOL",5,,__DOCOL,DOCOL + defconst "F_IMMED",7,,__F_IMMED,F_IMMED + defconst "F_HIDDEN",8,,__F_HIDDEN,F_HIDDEN + defconst "F_LENMASK",9,,__F_LENMASK,F_LENMASK + + defconst "SYS_EXIT",8,,SYS_EXIT,__NR_exit + defconst "SYS_OPEN",8,,SYS_OPEN,__NR_open + defconst "SYS_CLOSE",9,,SYS_CLOSE,__NR_close + defconst "SYS_READ",8,,SYS_READ,__NR_read + defconst "SYS_WRITE",9,,SYS_WRITE,__NR_write + defconst "SYS_CREAT",9,,SYS_CREAT,__NR_creat + defconst "SYS_BRK",7,,SYS_BRK,__NR_brk + + defconst "O_RDONLY",8,,__O_RDONLY,0 + defconst "O_WRONLY",8,,__O_WRONLY,1 + defconst "O_RDWR",6,,__O_RDWR,2 + defconst "O_CREAT",7,,__O_CREAT,0100 + defconst "O_EXCL",6,,__O_EXCL,0200 + defconst "O_TRUNC",7,,__O_TRUNC,01000 + defconst "O_APPEND",8,,__O_APPEND,02000 + defconst "O_NONBLOCK",10,,__O_NONBLOCK,04000 + +/* + RETURN STACK ---------------------------------------------------------------------- + + These words allow you to access the return stack. Recall that the register %ebp always points to + the top of the return stack. +*/ + + defcode ">R",2,,TOR + pop %eax // pop parameter stack into %eax + PUSHRSP %eax // push it on to the return stack + NEXT + + defcode "R>",2,,FROMR + POPRSP %eax // pop return stack on to %eax + push %eax // and push on to parameter stack + NEXT + + defcode "RSP@",4,,RSPFETCH + push %ebp + NEXT + + defcode "RSP!",4,,RSPSTORE + pop %ebp + NEXT + + defcode "RDROP",5,,RDROP + addl $4,%ebp // pop return stack and throw away + NEXT + +/* + PARAMETER (DATA) STACK ---------------------------------------------------------------------- + + These functions allow you to manipulate the parameter stack. Recall that Linux sets up the parameter + stack for us, and it is accessed through %esp. +*/ + + defcode "DSP@",4,,DSPFETCH + mov %esp,%eax + push %eax + NEXT + + defcode "DSP!",4,,DSPSTORE + pop %esp + NEXT + +/* + INPUT AND OUTPUT ---------------------------------------------------------------------- + + These are our first really meaty/complicated FORTH primitives. I have chosen to write them in + assembler, but surprisingly in "real" FORTH implementations these are often written in terms + of more fundamental FORTH primitives. I chose to avoid that because I think that just obscures + the implementation. After all, you may not understand assembler but you can just think of it + as an opaque block of code that does what it says. + + Let's discuss input first. + + The FORTH word KEY reads the next byte from stdin (and pushes it on the parameter stack). + So if KEY is called and someone hits the space key, then the number 32 (ASCII code of space) + is pushed on the stack. + + In FORTH there is no distinction between reading code and reading input. We might be reading + and compiling code, we might be reading words to execute, we might be asking for the user + to type their name -- ultimately it all comes in through KEY. + + The implementation of KEY uses an input buffer of a certain size (defined at the end of this + file). It calls the Linux read(2) system call to fill this buffer and tracks its position + in the buffer using a couple of variables, and if it runs out of input buffer then it refills + it automatically. The other thing that KEY does is if it detects that stdin has closed, it + exits the program, which is why when you hit ^D the FORTH system cleanly exits. + + buffer bufftop + | | + V V + +-------------------------------+--------------------------------------+ + | INPUT READ FROM STDIN ....... | unused part of the buffer | + +-------------------------------+--------------------------------------+ + ^ + | + currkey (next character to read) + + <---------------------- BUFFER_SIZE (4096 bytes) ----------------------> +*/ + + defcode "KEY",3,,KEY + call _KEY + push %eax // push return value on stack + NEXT +_KEY: + mov (currkey),%ebx + cmp (bufftop),%ebx + jge 1f // exhausted the input buffer? + xor %eax,%eax + mov (%ebx),%al // get next key from input buffer + inc %ebx + mov %ebx,(currkey) // increment currkey + ret + +1: // Out of input; use read(2) to fetch more input from stdin. + xor %ebx,%ebx // 1st param: stdin + mov $buffer,%ecx // 2nd param: buffer + mov %ecx,currkey + mov $BUFFER_SIZE,%edx // 3rd param: max length + mov $__NR_read,%eax // syscall: read + int $0x80 + test %eax,%eax // If %eax <= 0, then exit. + jbe 2f + addl %eax,%ecx // buffer+%eax = bufftop + mov %ecx,bufftop + jmp _KEY + +2: // Error or end of input: exit the program. + xor %ebx,%ebx + mov $__NR_exit,%eax // syscall: exit + int $0x80 + + .data + .align 4 +currkey: + .int buffer // Current place in input buffer (next character to read). +bufftop: + .int buffer // Last valid data in input buffer + 1. + +/* + By contrast, output is much simpler. The FORTH word EMIT writes out a single byte to stdout. + This implementation just uses the write system call. No attempt is made to buffer output, but + it would be a good exercise to add it. +*/ + + defcode "EMIT",4,,EMIT + pop %eax + call _EMIT + NEXT +_EMIT: + mov $1,%ebx // 1st param: stdout + + // write needs the address of the byte to write + mov %al,emit_scratch + mov $emit_scratch,%ecx // 2nd param: address + + mov $1,%edx // 3rd param: nbytes = 1 + + mov $__NR_write,%eax // write syscall + int $0x80 + ret + + .data // NB: easier to fit in the .data section +emit_scratch: + .space 1 // scratch used by EMIT + +/* + Back to input, WORD is a FORTH word which reads the next full word of input. + + What it does in detail is that it first skips any blanks (spaces, tabs, newlines and so on). + Then it calls KEY to read characters into an internal buffer until it hits a blank. Then it + calculates the length of the word it read and returns the address and the length as + two words on the stack (with the length at the top of stack). + + Notice that WORD has a single internal buffer which it overwrites each time (rather like + a static C string). Also notice that WORD's internal buffer is just 32 bytes long and + there is NO checking for overflow. 31 bytes happens to be the maximum length of a + FORTH word that we support, and that is what WORD is used for: to read FORTH words when + we are compiling and executing code. The returned strings are not NUL-terminated. + + Start address+length is the normal way to represent strings in FORTH (not ending in an + ASCII NUL character as in C), and so FORTH strings can contain any character including NULs + and can be any length. + + WORD is not suitable for just reading strings (eg. user input) because of all the above + peculiarities and limitations. + + Note that when executing, you'll see: + WORD FOO + which puts "FOO" and length 3 on the stack, but when compiling: + : BAR WORD FOO ; + is an error (or at least it doesn't do what you might expect). Later we'll talk about compiling + and immediate mode, and you'll understand why. +*/ + + defcode "WORD",4,,WORD + call _WORD + push %edi // push base address + push %ecx // push length + NEXT + +_WORD: + /* Search for first non-blank character. Also skip \ comments. */ +1: + call _KEY // get next key, returned in %eax + cmpb $'\\',%al // start of a comment? + je 3f // if so, skip the comment + cmpb $' ',%al + jbe 1b // if so, keep looking + + /* Search for the end of the word, storing chars as we go. */ + mov $word_buffer,%edi // pointer to return buffer +2: + stosb // add character to return buffer + call _KEY // get next key, returned in %al + cmpb $' ',%al // is blank? + ja 2b // if not, keep looping + + /* Return the word (well, the static buffer) and length. */ + sub $word_buffer,%edi + mov %edi,%ecx // return length of the word + mov $word_buffer,%edi // return address of the word + ret + + /* Code to skip \ comments to end of the current line. */ +3: + call _KEY + cmpb $'\n',%al // end of line yet? + jne 3b + jmp 1b + + .data // NB: easier to fit in the .data section + // A static buffer where WORD returns. Subsequent calls + // overwrite this buffer. Maximum word length is 32 chars. +word_buffer: + .space 32 + +/* + As well as reading in words we'll need to read in numbers and for that we are using a function + called NUMBER. This parses a numeric string such as one returned by WORD and pushes the + number on the parameter stack. + + The function uses the variable BASE as the base (radix) for conversion, so for example if + BASE is 2 then we expect a binary number. Normally BASE is 10. + + If the word starts with a '-' character then the returned value is negative. + + If the string can't be parsed as a number (or contains characters outside the current BASE) + then we need to return an error indication. So NUMBER actually returns two items on the stack. + At the top of stack we return the number of unconverted characters (ie. if 0 then all characters + were converted, so there is no error). Second from top of stack is the parsed number or a + partial value if there was an error. +*/ + defcode "NUMBER",6,,NUMBER + pop %ecx // length of string + pop %edi // start address of string + call _NUMBER + push %eax // parsed number + push %ecx // number of unparsed characters (0 = no error) + NEXT + +_NUMBER: + xor %eax,%eax + xor %ebx,%ebx + + test %ecx,%ecx // trying to parse a zero-length string is an error, but will return 0. + jz 5f + + movl var_BASE,%edx // get BASE (in %dl) + + // Check if first character is '-'. + movb (%edi),%bl // %bl = first character in string + inc %edi + push %eax // push 0 on stack + cmpb $'-',%bl // negative number? + jnz 2f + pop %eax + push %ebx // push <> 0 on stack, indicating negative + dec %ecx + jnz 1f + pop %ebx // error: string is only '-'. + movl $1,%ecx + ret + + // Loop reading digits. +1: imull %edx,%eax // %eax *= BASE + movb (%edi),%bl // %bl = next character in string + inc %edi + + // Convert 0-9, A-Z to a number 0-35. +2: subb $'0',%bl // < '0'? + jb 4f + cmp $10,%bl // <= '9'? + jb 3f + subb $17,%bl // < 'A'? (17 is 'A'-'0') + jb 4f + addb $10,%bl + +3: cmp %dl,%bl // >= BASE? + jge 4f + + // OK, so add it to %eax and loop. + add %ebx,%eax + dec %ecx + jnz 1b + + // Negate the result if first character was '-' (saved on the stack). +4: pop %ebx + test %ebx,%ebx + jz 5f + neg %eax + +5: ret + +/* + DICTIONARY LOOK UPS ---------------------------------------------------------------------- + + We're building up to our prelude on how FORTH code is compiled, but first we need yet more infrastructure. + + The FORTH word FIND takes a string (a word as parsed by WORD -- see above) and looks it up in the + dictionary. What it actually returns is the address of the dictionary header, if it finds it, + or 0 if it didn't. + + So if DOUBLE is defined in the dictionary, then WORD DOUBLE FIND returns the following pointer: + + pointer to this + | + | + V + +---------+---+---+---+---+---+---+---+---+------------+------------+------------+------------+ + | LINK | 6 | D | O | U | B | L | E | 0 | DOCOL | DUP | + | EXIT | + +---------+---+---+---+---+---+---+---+---+------------+------------+------------+------------+ + + See also >CFA and >DFA. + + FIND doesn't find dictionary entries which are flagged as HIDDEN. See below for why. +*/ + + defcode "FIND",4,,FIND + pop %ecx // %ecx = length + pop %edi // %edi = address + call _FIND + push %eax // %eax = address of dictionary entry (or NULL) + NEXT + +_FIND: + push %esi // Save %esi so we can use it in string comparison. + + // Now we start searching backwards through the dictionary for this word. + mov var_LATEST,%edx // LATEST points to name header of the latest word in the dictionary +1: test %edx,%edx // NULL pointer? (end of the linked list) + je 4f + + // Compare the length expected and the length of the word. + // Note that if the F_HIDDEN flag is set on the word, then by a bit of trickery + // this won't pick the word (the length will appear to be wrong). + xor %eax,%eax + movb 4(%edx),%al // %al = flags+length field + andb $(F_HIDDEN|F_LENMASK),%al // %al = name length + cmpb %cl,%al // Length is the same? + jne 2f + + // Compare the strings in detail. + push %ecx // Save the length + push %edi // Save the address (repe cmpsb will move this pointer) + lea 5(%edx),%esi // Dictionary string we are checking against. + repe cmpsb // Compare the strings. + pop %edi + pop %ecx + jne 2f // Not the same. + + // The strings are the same - return the header pointer in %eax + pop %esi + mov %edx,%eax + ret + +2: mov (%edx),%edx // Move back through the link field to the previous word + jmp 1b // .. and loop. + +4: // Not found. + pop %esi + xor %eax,%eax // Return zero to indicate not found. + ret + +/* + FIND returns the dictionary pointer, but when compiling we need the codeword pointer (recall + that FORTH definitions are compiled into lists of codeword pointers). The standard FORTH + word >CFA turns a dictionary pointer into a codeword pointer. + + The example below shows the result of: + + WORD DOUBLE FIND >CFA + + FIND returns a pointer to this + | >CFA converts it to a pointer to this + | | + V V + +---------+---+---+---+---+---+---+---+---+------------+------------+------------+------------+ + | LINK | 6 | D | O | U | B | L | E | 0 | DOCOL | DUP | + | EXIT | + +---------+---+---+---+---+---+---+---+---+------------+------------+------------+------------+ + codeword + + Notes: + + Because names vary in length, this isn't just a simple increment. + + In this FORTH you cannot easily turn a codeword pointer back into a dictionary entry pointer, but + that is not true in most FORTH implementations where they store a back pointer in the definition + (with an obvious memory/complexity cost). The reason they do this is that it is useful to be + able to go backwards (codeword -> dictionary entry) in order to decompile FORTH definitions + quickly. + + What does CFA stand for? My best guess is "Code Field Address". +*/ + + defcode ">CFA",4,,TCFA + pop %edi + call _TCFA + push %edi + NEXT +_TCFA: + xor %eax,%eax + add $4,%edi // Skip link pointer. + movb (%edi),%al // Load flags+len into %al. + inc %edi // Skip flags+len byte. + andb $F_LENMASK,%al // Just the length, not the flags. + add %eax,%edi // Skip the name. + addl $3,%edi // The codeword is 4-byte aligned. + andl $~3,%edi + ret + +/* + Related to >CFA is >DFA which takes a dictionary entry address as returned by FIND and + returns a pointer to the first data field. + + FIND returns a pointer to this + | >CFA converts it to a pointer to this + | | + | | >DFA converts it to a pointer to this + | | | + V V V + +---------+---+---+---+---+---+---+---+---+------------+------------+------------+------------+ + | LINK | 6 | D | O | U | B | L | E | 0 | DOCOL | DUP | + | EXIT | + +---------+---+---+---+---+---+---+---+---+------------+------------+------------+------------+ + codeword + + (Note to those following the source of FIG-FORTH / ciforth: My >DFA definition is + different from theirs, because they have an extra indirection). + + You can see that >DFA is easily defined in FORTH just by adding 4 to the result of >CFA. +*/ + + defword ">DFA",4,,TDFA + .int TCFA // >CFA (get code field address) + .int INCR4 // 4+ (add 4 to it to get to next word) + .int EXIT // EXIT (return from FORTH word) + +/* + COMPILING ---------------------------------------------------------------------- + + Now we'll talk about how FORTH compiles words. Recall that a word definition looks like this: + + : DOUBLE DUP + ; + + and we have to turn this into: + + pointer to previous word + ^ + | + +--|------+---+---+---+---+---+---+---+---+------------+------------+------------+------------+ + | LINK | 6 | D | O | U | B | L | E | 0 | DOCOL | DUP | + | EXIT | + +---------+---+---+---+---+---+---+---+---+------------+--|---------+------------+------------+ + ^ len pad codeword | + | V + LATEST points here points to codeword of DUP + + There are several problems to solve. Where to put the new word? How do we read words? How + do we define the words : (COLON) and ; (SEMICOLON)? + + FORTH solves this rather elegantly and as you might expect in a very low-level way which + allows you to change how the compiler works on your own code. + + FORTH has an INTERPRET function (a true interpreter this time, not DOCOL) which runs in a + loop, reading words (using WORD), looking them up (using FIND), turning them into codeword + pointers (using >CFA) and deciding what to do with them. + + What it does depends on the mode of the interpreter (in variable STATE). + + When STATE is zero, the interpreter just runs each word as it looks them up. This is known as + immediate mode. + + The interesting stuff happens when STATE is non-zero -- compiling mode. In this mode the + interpreter appends the codeword pointer to user memory (the HERE variable points to the next + free byte of user memory -- see DATA SEGMENT section below). + + So you may be able to see how we could define : (COLON). The general plan is: + + (1) Use WORD to read the name of the function being defined. + + (2) Construct the dictionary entry -- just the header part -- in user memory: + + pointer to previous word (from LATEST) +-- Afterwards, HERE points here, where + ^ | the interpreter will start appending + | V codewords. + +--|------+---+---+---+---+---+---+---+---+------------+ + | LINK | 6 | D | O | U | B | L | E | 0 | DOCOL | + +---------+---+---+---+---+---+---+---+---+------------+ + len pad codeword + + (3) Set LATEST to point to the newly defined word, ... + + (4) .. and most importantly leave HERE pointing just after the new codeword. This is where + the interpreter will append codewords. + + (5) Set STATE to 1. This goes into compile mode so the interpreter starts appending codewords to + our partially-formed header. + + After : has run, our input is here: + + : DOUBLE DUP + ; + ^ + | + Next byte returned by KEY will be the 'D' character of DUP + + so the interpreter (now it's in compile mode, so I guess it's really the compiler) reads "DUP", + looks it up in the dictionary, gets its codeword pointer, and appends it: + + +-- HERE updated to point here. + | + V + +---------+---+---+---+---+---+---+---+---+------------+------------+ + | LINK | 6 | D | O | U | B | L | E | 0 | DOCOL | DUP | + +---------+---+---+---+---+---+---+---+---+------------+------------+ + len pad codeword + + Next we read +, get the codeword pointer, and append it: + + +-- HERE updated to point here. + | + V + +---------+---+---+---+---+---+---+---+---+------------+------------+------------+ + | LINK | 6 | D | O | U | B | L | E | 0 | DOCOL | DUP | + | + +---------+---+---+---+---+---+---+---+---+------------+------------+------------+ + len pad codeword + + The issue is what happens next. Obviously what we _don't_ want to happen is that we + read ";" and compile it and go on compiling everything afterwards. + + At this point, FORTH uses a trick. Remember the length byte in the dictionary definition + isn't just a plain length byte, but can also contain flags. One flag is called the + IMMEDIATE flag (F_IMMED in this code). If a word in the dictionary is flagged as + IMMEDIATE then the interpreter runs it immediately _even if it's in compile mode_. + + This is how the word ; (SEMICOLON) works -- as a word flagged in the dictionary as IMMEDIATE. + + And all it does is append the codeword for EXIT on to the current definition and switch + back to immediate mode (set STATE back to 0). Shortly we'll see the actual definition + of ; and we'll see that it's really a very simple definition, declared IMMEDIATE. + + After the interpreter reads ; and executes it 'immediately', we get this: + + +---------+---+---+---+---+---+---+---+---+------------+------------+------------+------------+ + | LINK | 6 | D | O | U | B | L | E | 0 | DOCOL | DUP | + | EXIT | + +---------+---+---+---+---+---+---+---+---+------------+------------+------------+------------+ + len pad codeword ^ + | + HERE + STATE is set to 0. + + And that's it, job done, our new definition is compiled, and we're back in immediate mode + just reading and executing words, perhaps including a call to test our new word DOUBLE. + + The only last wrinkle in this is that while our word was being compiled, it was in a + half-finished state. We certainly wouldn't want DOUBLE to be called somehow during + this time. There are several ways to stop this from happening, but in FORTH what we + do is flag the word with the HIDDEN flag (F_HIDDEN in this code) just while it is + being compiled. This prevents FIND from finding it, and thus in theory stops any + chance of it being called. + + The above explains how compiling, : (COLON) and ; (SEMICOLON) works and in a moment I'm + going to define them. The : (COLON) function can be made a little bit more general by writing + it in two parts. The first part, called CREATE, makes just the header: + + +-- Afterwards, HERE points here. + | + V + +---------+---+---+---+---+---+---+---+---+ + | LINK | 6 | D | O | U | B | L | E | 0 | + +---------+---+---+---+---+---+---+---+---+ + len pad + + and the second part, the actual definition of : (COLON), calls CREATE and appends the + DOCOL codeword, so leaving: + + +-- Afterwards, HERE points here. + | + V + +---------+---+---+---+---+---+---+---+---+------------+ + | LINK | 6 | D | O | U | B | L | E | 0 | DOCOL | + +---------+---+---+---+---+---+---+---+---+------------+ + len pad codeword + + CREATE is a standard FORTH word and the advantage of this split is that we can reuse it to + create other types of words (not just ones which contain code, but words which contain variables, + constants and other data). +*/ + + defcode "CREATE",6,,CREATE + + // Get the name length and address. + pop %ecx // %ecx = length + pop %ebx // %ebx = address of name + + // Link pointer. + movl var_HERE,%edi // %edi is the address of the header + movl var_LATEST,%eax // Get link pointer + stosl // and store it in the header. + + // Length byte and the word itself. + mov %cl,%al // Get the length. + stosb // Store the length/flags byte. + push %esi + mov %ebx,%esi // %esi = word + rep movsb // Copy the word + pop %esi + addl $3,%edi // Align to next 4 byte boundary. + andl $~3,%edi + + // Update LATEST and HERE. + movl var_HERE,%eax + movl %eax,var_LATEST + movl %edi,var_HERE + NEXT + +/* + Because I want to define : (COLON) in FORTH, not assembler, we need a few more FORTH words + to use. + + The first is , (COMMA) which is a standard FORTH word which appends a 32 bit integer to the user + memory pointed to by HERE, and adds 4 to HERE. So the action of , (COMMA) is: + + previous value of HERE + | + V + +---------+---+---+---+---+---+---+---+---+-- - - - - --+------------+ + | LINK | 6 | D | O | U | B | L | E | 0 | | | + +---------+---+---+---+---+---+---+---+---+-- - - - - --+------------+ + len pad ^ + | + new value of HERE + + and is whatever 32 bit integer was at the top of the stack. + + , (COMMA) is quite a fundamental operation when compiling. It is used to append codewords + to the current word that is being compiled. +*/ + + defcode ",",1,,COMMA + pop %eax // Code pointer to store. + call _COMMA + NEXT +_COMMA: + movl var_HERE,%edi // HERE + stosl // Store it. + movl %edi,var_HERE // Update HERE (incremented) + ret + +/* + Our definitions of : (COLON) and ; (SEMICOLON) will need to switch to and from compile mode. + + Immediate mode vs. compile mode is stored in the global variable STATE, and by updating this + variable we can switch between the two modes. + + For various reasons which may become apparent later, FORTH defines two standard words called + [ and ] (LBRAC and RBRAC) which switch between modes: + + Word Assembler Action Effect + [ LBRAC STATE := 0 Switch to immediate mode. + ] RBRAC STATE := 1 Switch to compile mode. + + [ (LBRAC) is an IMMEDIATE word. The reason is as follows: If we are in compile mode and the + interpreter saw [ then it would compile it rather than running it. We would never be able to + switch back to immediate mode! So we flag the word as IMMEDIATE so that even in compile mode + the word runs immediately, switching us back to immediate mode. +*/ + + defcode "[",1,F_IMMED,LBRAC + xor %eax,%eax + movl %eax,var_STATE // Set STATE to 0. + NEXT + + defcode "]",1,,RBRAC + movl $1,var_STATE // Set STATE to 1. + NEXT + +/* + Now we can define : (COLON) using CREATE. It just calls CREATE, appends DOCOL (the codeword), sets + the word HIDDEN and goes into compile mode. +*/ + + defword ":",1,,COLON + .int WORD // Get the name of the new word + .int CREATE // CREATE the dictionary entry / header + .int LIT, DOCOL, COMMA // Append DOCOL (the codeword). + .int LATEST, FETCH, HIDDEN // Make the word hidden (see below for definition). + .int RBRAC // Go into compile mode. + .int EXIT // Return from the function. + +/* + ; (SEMICOLON) is also elegantly simple. Notice the F_IMMED flag. +*/ + + defword ";",1,F_IMMED,SEMICOLON + .int LIT, EXIT, COMMA // Append EXIT (so the word will return). + .int LATEST, FETCH, HIDDEN // Toggle hidden flag -- unhide the word (see below for definition). + .int LBRAC // Go back to IMMEDIATE mode. + .int EXIT // Return from the function. + +/* + EXTENDING THE COMPILER ---------------------------------------------------------------------- + + Words flagged with IMMEDIATE (F_IMMED) aren't just for the FORTH compiler to use. You can define + your own IMMEDIATE words too, and this is a crucial aspect when extending basic FORTH, because + it allows you in effect to extend the compiler itself. Does gcc let you do that? + + Standard FORTH words like IF, WHILE, ." and so on are all written as extensions to the basic + compiler, and are all IMMEDIATE words. + + The IMMEDIATE word toggles the F_IMMED (IMMEDIATE flag) on the most recently defined word, + or on the current word if you call it in the middle of a definition. + + Typical usage is: + + : MYIMMEDWORD IMMEDIATE + ...definition... + ; + + but some FORTH programmers write this instead: + + : MYIMMEDWORD + ...definition... + ; IMMEDIATE + + The two usages are equivalent, to a first approximation. +*/ + + defcode "IMMEDIATE",9,F_IMMED,IMMEDIATE + movl var_LATEST,%edi // LATEST word. + addl $4,%edi // Point to name/flags byte. + xorb $F_IMMED,(%edi) // Toggle the IMMED bit. + NEXT + +/* + 'addr HIDDEN' toggles the hidden flag (F_HIDDEN) of the word defined at addr. To hide the + most recently defined word (used above in : and ; definitions) you would do: + + LATEST @ HIDDEN + + 'HIDE word' toggles the flag on a named 'word'. + + Setting this flag stops the word from being found by FIND, and so can be used to make 'private' + words. For example, to break up a large word into smaller parts you might do: + + : SUB1 ... subword ... ; + : SUB2 ... subword ... ; + : SUB3 ... subword ... ; + : MAIN ... defined in terms of SUB1, SUB2, SUB3 ... ; + HIDE SUB1 + HIDE SUB2 + HIDE SUB3 + + After this, only MAIN is 'exported' or seen by the rest of the program. +*/ + + defcode "HIDDEN",6,,HIDDEN + pop %edi // Dictionary entry. + addl $4,%edi // Point to name/flags byte. + xorb $F_HIDDEN,(%edi) // Toggle the HIDDEN bit. + NEXT + + defword "HIDE",4,,HIDE + .int WORD // Get the word (after HIDE). + .int FIND // Look up in the dictionary. + .int HIDDEN // Set F_HIDDEN flag. + .int EXIT // Return. + +/* + ' (TICK) is a standard FORTH word which returns the codeword pointer of the next word. + + The common usage is: + + ' FOO , + + which appends the codeword of FOO to the current word we are defining (this only works in compiled code). + + You tend to use ' in IMMEDIATE words. For example an alternate (and rather useless) way to define + a literal 2 might be: + + : LIT2 IMMEDIATE + ' LIT , \ Appends LIT to the currently-being-defined word + 2 , \ Appends the number 2 to the currently-being-defined word + ; + + So you could do: + + : DOUBLE LIT2 * ; + + (If you don't understand how LIT2 works, then you should review the material about compiling words + and immediate mode). + + This definition of ' uses a cheat which I copied from buzzard92. As a result it only works in + compiled code. It is possible to write a version of ' based on WORD, FIND, >CFA which works in + immediate mode too. +*/ + defcode "'",1,,TICK + lodsl // Get the address of the next word and skip it. + pushl %eax // Push it on the stack. + NEXT + +/* + BRANCHING ---------------------------------------------------------------------- + + It turns out that all you need in order to define looping constructs, IF-statements, etc. + are two primitives. + + BRANCH is an unconditional branch. 0BRANCH is a conditional branch (it only branches if the + top of stack is zero). + + The diagram below shows how BRANCH works in some imaginary compiled word. When BRANCH executes, + %esi starts by pointing to the offset field (compare to LIT above): + + +---------------------+-------+---- - - ---+------------+------------+---- - - - ----+------------+ + | (Dictionary header) | DOCOL | | BRANCH | offset | (skipped) | word | + +---------------------+-------+---- - - ---+------------+-----|------+---- - - - ----+------------+ + ^ | ^ + | | | + | +-----------------------+ + %esi added to offset + + The offset is added to %esi to make the new %esi, and the result is that when NEXT runs, execution + continues at the branch target. Negative offsets work as expected. + + 0BRANCH is the same except the branch happens conditionally. + + Now standard FORTH words such as IF, THEN, ELSE, WHILE, REPEAT, etc. can be implemented entirely + in FORTH. They are IMMEDIATE words which append various combinations of BRANCH or 0BRANCH + into the word currently being compiled. + + As an example, code written like this: + + condition-code IF true-part THEN rest-code + + compiles to: + + condition-code 0BRANCH OFFSET true-part rest-code + | ^ + | | + +-------------+ +*/ + + defcode "BRANCH",6,,BRANCH + add (%esi),%esi // add the offset to the instruction pointer + NEXT + + defcode "0BRANCH",7,,ZBRANCH + pop %eax + test %eax,%eax // top of stack is zero? + jz code_BRANCH // if so, jump back to the branch function above + lodsl // otherwise we need to skip the offset + NEXT + +/* + LITERAL STRINGS ---------------------------------------------------------------------- + + LITSTRING is a primitive used to implement the ." and S" operators (which are written in + FORTH). See the definition of those operators later. + + TELL just prints a string. It's more efficient to define this in assembly because we + can make it a single Linux syscall. +*/ + + defcode "LITSTRING",9,,LITSTRING + lodsl // get the length of the string + push %esi // push the address of the start of the string + push %eax // push it on the stack + addl %eax,%esi // skip past the string + addl $3,%esi // but round up to next 4 byte boundary + andl $~3,%esi + NEXT + + defcode "TELL",4,,TELL + mov $1,%ebx // 1st param: stdout + pop %edx // 3rd param: length of string + pop %ecx // 2nd param: address of string + mov $__NR_write,%eax // write syscall + int $0x80 + NEXT + +/* + QUIT AND INTERPRET ---------------------------------------------------------------------- + + QUIT is the first FORTH function called, almost immediately after the FORTH system "boots". + As explained before, QUIT doesn't "quit" anything. It does some initialisation (in particular + it clears the return stack) and it calls INTERPRET in a loop to interpret commands. The + reason it is called QUIT is because you can call it from your own FORTH words in order to + "quit" your program and start again at the user prompt. + + INTERPRET is the FORTH interpreter ("toploop", "toplevel" or "REPL" might be a more accurate + description -- see: http://en.wikipedia.org/wiki/REPL). +*/ + + // QUIT must not return (ie. must not call EXIT). + defword "QUIT",4,,QUIT + .int RZ,RSPSTORE // R0 RSP!, clear the return stack + .int INTERPRET // interpret the next word + .int BRANCH,-8 // and loop (indefinitely) + +/* + This interpreter is pretty simple, but remember that in FORTH you can always override + it later with a more powerful one! + */ + defcode "INTERPRET",9,,INTERPRET + call _WORD // Returns %ecx = length, %edi = pointer to word. + + // Is it in the dictionary? + xor %eax,%eax + movl %eax,interpret_is_lit // Not a literal number (not yet anyway ...) + call _FIND // Returns %eax = pointer to header or 0 if not found. + test %eax,%eax // Found? + jz 1f + + // In the dictionary. Is it an IMMEDIATE codeword? + mov %eax,%edi // %edi = dictionary entry + movb 4(%edi),%al // Get name+flags. + push %ax // Just save it for now. + call _TCFA // Convert dictionary entry (in %edi) to codeword pointer. + pop %ax + andb $F_IMMED,%al // Is IMMED flag set? + mov %edi,%eax + jnz 4f // If IMMED, jump straight to executing. + + jmp 2f + +1: // Not in the dictionary (not a word) so assume it's a literal number. + incl interpret_is_lit + call _NUMBER // Returns the parsed number in %eax, %ecx > 0 if error + test %ecx,%ecx + jnz 6f + mov %eax,%ebx + mov $LIT,%eax // The word is LIT + +2: // Are we compiling or executing? + movl var_STATE,%edx + test %edx,%edx + jz 4f // Jump if executing. + + // Compiling - just append the word to the current dictionary definition. + call _COMMA + mov interpret_is_lit,%ecx // Was it a literal? + test %ecx,%ecx + jz 3f + mov %ebx,%eax // Yes, so LIT is followed by a number. + call _COMMA +3: NEXT + +4: // Executing - run it! + mov interpret_is_lit,%ecx // Literal? + test %ecx,%ecx // Literal? + jnz 5f + + // Not a literal, execute it now. This never returns, but the codeword will + // eventually call NEXT which will reenter the loop in QUIT. + jmp *(%eax) + +5: // Executing a literal, which means push it on the stack. + push %ebx + NEXT + +6: // Parse error (not a known word or a number in the current BASE). + // Print an error message followed by up to 40 characters of context. + mov $2,%ebx // 1st param: stderr + mov $errmsg,%ecx // 2nd param: error message + mov $errmsgend-errmsg,%edx // 3rd param: length of string + mov $__NR_write,%eax // write syscall + int $0x80 + + mov (currkey),%ecx // the error occurred just before currkey position + mov %ecx,%edx + sub $buffer,%edx // %edx = currkey - buffer (length in buffer before currkey) + cmp $40,%edx // if > 40, then print only 40 characters + jle 7f + mov $40,%edx +7: sub %edx,%ecx // %ecx = start of area to print, %edx = length + mov $__NR_write,%eax // write syscall + int $0x80 + + mov $errmsgnl,%ecx // newline + mov $1,%edx + mov $__NR_write,%eax // write syscall + int $0x80 + + NEXT + + .section .rodata +errmsg: .ascii "PARSE ERROR: " +errmsgend: +errmsgnl: .ascii "\n" + + .data // NB: easier to fit in the .data section + .align 4 +interpret_is_lit: + .int 0 // Flag used to record if reading a literal + +/* + ODDS AND ENDS ---------------------------------------------------------------------- + + CHAR puts the ASCII code of the first character of the following word on the stack. For example + CHAR A puts 65 on the stack. + + EXECUTE is used to run execution tokens. See the discussion of execution tokens in the + FORTH code for more details. + + SYSCALL0, SYSCALL1, SYSCALL2, SYSCALL3 make a standard Linux system call. (See + for a list of system call numbers). As their name suggests these forms take between 0 and 3 + syscall parameters, plus the system call number. + + In this FORTH, SYSCALL0 must be the last word in the built-in (assembler) dictionary because we + initialise the LATEST variable to point to it. This means that if you want to extend the assembler + part, you must put new words before SYSCALL0, or else change how LATEST is initialised. +*/ + + defcode "CHAR",4,,CHAR + call _WORD // Returns %ecx = length, %edi = pointer to word. + xor %eax,%eax + movb (%edi),%al // Get the first character of the word. + push %eax // Push it onto the stack. + NEXT + + defcode "EXECUTE",7,,EXECUTE + pop %eax // Get xt into %eax + jmp *(%eax) // and jump to it. + // After xt runs its NEXT will continue executing the current word. + + defcode "SYSCALL3",8,,SYSCALL3 + pop %eax // System call number (see ) + pop %ebx // First parameter. + pop %ecx // Second parameter + pop %edx // Third parameter + int $0x80 + push %eax // Result (negative for -errno) + NEXT + + defcode "SYSCALL2",8,,SYSCALL2 + pop %eax // System call number (see ) + pop %ebx // First parameter. + pop %ecx // Second parameter + int $0x80 + push %eax // Result (negative for -errno) + NEXT + + defcode "SYSCALL1",8,,SYSCALL1 + pop %eax // System call number (see ) + pop %ebx // First parameter. + int $0x80 + push %eax // Result (negative for -errno) + NEXT + + defcode "SYSCALL0",8,,SYSCALL0 + pop %eax // System call number (see ) + int $0x80 + push %eax // Result (negative for -errno) + NEXT + +/* + DATA SEGMENT ---------------------------------------------------------------------- + + Here we set up the Linux data segment, used for user definitions and variously known as just + the 'data segment', 'user memory' or 'user definitions area'. It is an area of memory which + grows upwards and stores both newly-defined FORTH words and global variables of various + sorts. + + It is completely analogous to the C heap, except there is no generalised 'malloc' and 'free' + (but as with everything in FORTH, writing such functions would just be a Simple Matter + Of Programming). Instead in normal use the data segment just grows upwards as new FORTH + words are defined/appended to it. + + There are various "features" of the GNU toolchain which make setting up the data segment + more complicated than it really needs to be. One is the GNU linker which inserts a random + "build ID" segment. Another is Address Space Randomization which means we can't tell + where the kernel will choose to place the data segment (or the stack for that matter). + + Therefore writing this set_up_data_segment assembler routine is a little more complicated + than it really needs to be. We ask the Linux kernel where it thinks the data segment starts + using the brk(2) system call, then ask it to reserve some initial space (also using brk(2)). + + You don't need to worry about this code. +*/ + .text + .set INITIAL_DATA_SEGMENT_SIZE,65536 +set_up_data_segment: + xor %ebx,%ebx // Call brk(0) + movl $__NR_brk,%eax + int $0x80 + movl %eax,var_HERE // Initialise HERE to point at beginning of data segment. + addl $INITIAL_DATA_SEGMENT_SIZE,%eax // Reserve nn bytes of memory for initial data segment. + movl %eax,%ebx // Call brk(HERE+INITIAL_DATA_SEGMENT_SIZE) + movl $__NR_brk,%eax + int $0x80 + ret + +/* + We allocate static buffers for the return static and input buffer (used when + reading in files and text that the user types in). +*/ + .set RETURN_STACK_SIZE,8192 + .set BUFFER_SIZE,4096 + + .bss +/* FORTH return stack. */ + .align 4096 +return_stack: + .space RETURN_STACK_SIZE +return_stack_top: // Initial top of return stack. + +/* This is used as a temporary input buffer when reading from files or the terminal. */ + .align 4096 +buffer: + .space BUFFER_SIZE + +/* + START OF FORTH CODE ---------------------------------------------------------------------- + + We've now reached the stage where the FORTH system is running and self-hosting. All further + words can be written as FORTH itself, including words like IF, THEN, .", etc which in most + languages would be considered rather fundamental. + + I used to append this here in the assembly file, but I got sick of fighting against gas's + crack-smoking (lack of) multiline string syntax. So now that is in a separate file called + jonesforth.f + + If you don't already have that file, download it from http://annexia.org/forth in order + to continue the tutorial. +*/ + + +/* END OF jonesforth.S */ \ No newline at end of file