{"id":22261712,"url":"https://github.com/phillvancejr/x-forth","last_synced_at":"2026-04-13T21:31:31.705Z","repository":{"id":108705896,"uuid":"561359367","full_name":"phillvancejr/X-Forth","owner":"phillvancejr","description":"X-Forth is a small WIP specification for a Forth like language for fun and learning. Implementing a simple interpreter for beginners","archived":false,"fork":false,"pushed_at":"2022-11-10T16:24:43.000Z","size":110,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-08T13:04:35.183Z","etag":null,"topics":["compiler","compilers","concatenative","concatenative-language","dart","dartlang","forth","golang","interpreter","interpreter-forth","interpreter-language","interpreters","programming-language","python","stack-based","stack-based-language","stack-language"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/phillvancejr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-11-03T14:19:12.000Z","updated_at":"2023-04-26T12:38:29.000Z","dependencies_parsed_at":null,"dependency_job_id":"f6bbf3d4-a55a-4074-870c-382af7c2dfe3","html_url":"https://github.com/phillvancejr/X-Forth","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/phillvancejr/X-Forth","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phillvancejr%2FX-Forth","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phillvancejr%2FX-Forth/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phillvancejr%2FX-Forth/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phillvancejr%2FX-Forth/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/phillvancejr","download_url":"https://codeload.github.com/phillvancejr/X-Forth/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phillvancejr%2FX-Forth/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31771803,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-13T20:17:16.280Z","status":"ssl_error","status_checked_at":"2026-04-13T20:17:08.216Z","response_time":93,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["compiler","compilers","concatenative","concatenative-language","dart","dartlang","forth","golang","interpreter","interpreter-forth","interpreter-language","interpreters","programming-language","python","stack-based","stack-based-language","stack-language"],"created_at":"2024-12-03T09:13:52.856Z","updated_at":"2026-04-13T21:31:31.669Z","avatar_url":"https://github.com/phillvancejr.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!--reference\n Easy Forth: https://skilldrick.github.io/easyforth/#conditionals-and-loops\n Forth in y minutes: https://learnxinyminutes.com/docs/forth/\n--\u003e\n# X-Forth\nX-Forth is a small specification for a Forth like language meant to be used in compiler projects. You can likely implement the basic X-forth in a couple hours or less.\n```py\n2 3 + .s\n# \u003c2\u003e 2.0 3.0 ok\n```\nA more complex program:\n```py\na: 10 var\nb: 5  var\na @ b @ + . # 15.0\ndup * .     # 225.0\ndrop .s     # \u003c0\u003e ok\n5 6 + 3 4   # \u003c3\u003e 11.0 3.0 4.0 ok\n```\n## Tutorial\nThere are ongoing (WIP) tutorials that accompany the Python implementation [here](implementations/python/tutorial).\n\n\n## The Name\nX-Forth is so named because the X refers to a few aspects and goals of the project:\n- X-Forth - where X == implementation language, ex. Go-Forth, Dart-Forth, JS-Forth etc.\n- X for eXample - X-Forth is meant to be used as an example project to play with. The various extensions of X-Forth provide smaller sub projects to help you explore your language of choice as well as broader compiler/language features.\n- X for eXtended - X-Forth is intentionally designed as a series of extensions to a very primitive language\n\nSimilar to the Scheme language, X-forth specifies language add-ons which can be implemented to extend the language, designated as `X-\u003cnumber\u003e (description)`. The basic version of X-Forth is denoted as `X-B (Basic)` and contains a bare bones interpreter with very basic mathmatical and logical operators along with a few built in words for display and stack manipulation. The first few extensions are designed to provide easily manageable incremental projects.\n\n## Why A Forth?\n\nI believe concatenative stack based langauges are the most simple languages to write compilers for, even simpler than the more popular lisp, though they may be more unintuitive to program in than a traditional language. You can learn a lot and have fun focusing on features rather than parsing a complex langauge. If you're interested in something that is more similar to a traditional C like language, I'll be working on a sister project to this based on Basic called `X-Basic`.\n\nIt is very fast to write a Forth and it can even easily bootstrap itself from assembly as seen in [Jones Forth](https://github.com/nornagon/jonesforth/blob/master/jonesforth.S)\n\n\n## Current Extension Specs\n\n### X-B (Basic)\nThe most basic version of X-Forth. It contains only a few operators and functions, collectively known as `words`. The tokenizer is very primitive and effectively makes the language white space significant since all tokens are separated on white space.\n#### required types\n- Number - all numbers are treated as double precision floats. X-B does not have a boolean type and false is treated as 0.0 while true is 1.0\n#### words\n- +, -, *, / - The basic math operators\n- \u003c, \u003e, ==, != - The basic logic operators\n- . (dot) - print and consume the value on the top of the stack\n- .s - print the whole stack to the console without consuming it in the format: \\\u003ccount of values\u003e val1 val2 ... ok\n- drop - remove the top value from the stack\n- dup - duplicate the top value on the stack\n- show - print the value on the top of the stack without consuming it\n#### errors\n- Undefined token - present this error when we find an invalid token in the source code\n    - format `ERROR: Undefined token \u003ctoken\u003e`\n- Stack underflow - present this error when there aren't enough values on the stack for a word\n    - math and logic operators require 2 arguments\n    - . (dot) and dup require 1 argument\n    - format `ERROR: \u003cword name\u003e: Stack underflow`\n#### quirks\n- what happened!? - X-B contains virtually no error handling at the compiler level with the exception of throwing an error when encountering an Undefined token. There are no stack traces, line numbers in errors or other helpful bits of error context.\n- hardcoded source - X-B's source code is hardcoded in the program, see [X-1](#x-1-(external/variable-source-code)) (External Source Code) to get variable source code\n\n### X-1 (External/Variable Source Code)\nAcquire the source code from an external file. Receive an external file path on the command line, validate its existence and read its contents into a source string variable. \n\nX-Forth files use the `.xf` extension\n\n#### errors\n- Source file not found - The passed file path could not be found\n    - format: `ERROR: \u003csource path\u003e: Source File Not Found`\n#### spec\n* numbers - numbers are machine word/register sized floating point.\n* booleans - in X-Forth booleans are numeric values where 0 is true and anything else is false. This is odd compared to C languages, but it aligns with the design ofr errors wherein an error can be represented as an enum with the first value 0 representing no error, see [X-7 (errors)](#x-7-(errors)) for more. Instead of thinking in terms of true or false, we think in terms of \"did an error occur\" where `0` means no error occured and any other number denotes that some error occured and which one\n\n### X-2 (Symbols)\nSymbols are are words whose value equates to a hash value, they are similar to symbols found in Ruby. Syntactically a symbol is a word that ends with `:`, for example: `dup` is the word dup, and when this is encountered it be called immediately but, `dup:` is a symbol which instead of calling the `dup` word pushes a hash value to the stack. Symbols are important for things like variables, lookup tables and passing words around as values. Symbols can be converted to and from strings if you have implemented X-5 (String Support).\n#### spec\nSymbol is the type of symbols and their value should be a tuple (or equivalent) of the word as a string and its hash value. \n#### required overloads\n* X-5 (String support)\n    * to-string ( symbol -- string ) - converts a symbol into a string without the `:` suffix\n    * to-symbol ( string -- symbol ) - converts a string into a symbol\n#### required types\n* Symbol\n\n### X-3 (Bools)\nSupport for boolean types. This is mostly cosmetic as they should be treated as numbers under the hood. The words `True` and `False` should be aliases for `0` and `1` respectively, effectively making them constants. Though they are mostly aliases, it can be helpful to give them a dedicated boolean type even though they are stored numerically so you can differentiate them from numbers for printing. \n\nAs mentioned in the X-B section, the use of `0` for true and `1` for false differs from traditional C-like languages because it is designed with error handling in mind. Instead of thinking in terms of true or false we think in terms of asserting whether or not an error occured with `0` meaning no error occured and any other number not only denoting that an error occured, but which one. By convention, user defined errors should be `\u003e= 1 \u003c= MAX NUMBER`, while negative values are used for built in errors.\n#### required Types\n* Bool - can be either True (0) or False (1)\n#### required words\n* True `True: 0 con` - constant == `0`\n* False `False: 1 con` - constant == `1`\n#### required overloads\n* to-bool (number -- bool) - converts`0` to `True` and anything else to `False`\n    * to-bool (bool -- bool) - no op \n* to-number ( bool -- number ) - converts `True` to `0` and `False` to `1`\n    * to-number ( number -- number ) - no op\n* X-5 (String support)\n    * to-string ( bool -- string ) - converts a bool into either `\"True\"` or `\"False\"`\n\n### X-4 (Variables) requires X-2 (Symbols)\nImplements both variables and constants. X-Forth uses `var` and `con` for variables and constants respectively. As arguments var and con take a value and a symbol.\n```py\nnum: 10 var # store 10 into the variable num\nn2: 13 con # define n2 as the constant 13\n```\n\u003c!--`var` has a second verson wherein you can forward declare a variable with no value and then assign to it later. --\u003eIn order to assign a value to a variable/constant use the `!` (write) word:\n```py\nnum: var # num variable created with its value set to 'Undefined'\nnum 10 ! # write 10 to it\n```\nTo get the value of a variable use the `@` (read) word:\n```py\nnum @ # 10\n```\nLike a traditional Forth, the usage of the variable name pushes its address to the stack\u003c!--, however unlike a traditional Forth the `\u003cname\u003e: var` declaration also pushes the address to the stack, which allows assigning to a variable while only writing its name once: `` --\u003e. `con` is the same as `var` but internally it makes use of some sort of `is_set` flag denoting whether or not the constant has been set. It must be set before use and once set it cannot change.\n\nUnlike variables, constants do not push their address to the stack, and instead just directly push their value, thus you do not use `@` with constants.\n#### required words\n* Undefined - represents an undefined value, errors will occur if you try to use an undefined value. This is a built in value and must be given its own type which is also `Undefined`\n* var ( symbol any -- ) - If the top value is not a symbol, but the second value is, then the top value is assigned to the variable and the address is NOT pushed to the stack\n    * ( symbol -- address) - If the top value is a symbol, then variable's value will be set to `Undefined`.\u003c!-- and the address is pushed to the stack: `num: var # address of num variable is pushed to stack` --\u003e\n* con ( symbol any -- ) - con is exactly like the first overload of var except that its value cannot be changed and the words value rather than its address is pushed to the stack when the word is used \n* ! ( address any -- ) - writes the value on the top of the stack to the address\n* @ ( address -- any) - reads and pushes the value at the address\n```py\nvalue1: 15 var\nvalue2: 30 con\n```\n#### required types\n* Address - represents an address, it is similar to a pointer and is an index into the program's memory.\n* Undefined - the type of undefined variables\n\u003c!--\n#### spec\n* Memory - a contigous (optionally growable) block of memory should be allocated for each program. Variables should be names mapped to indices starting at `0` and this index should be used to index into the program's memory starting from the variable memory section. Python implementation example:\n```py\n# program memory\nMEMORY_CAPACITY = 1024\nmemory = [None] *  MEMORY_CAPACITY\n\n# variable lookup table\nvariables = {\n    'num': {'index': 0, 'constant': False, 'set': True }\n}\n\n# start of variable memory\nVAR_START = 500\n\n# accessing the num variable\nnum = memory[VAR_START + variables['num']['index']]\n```\n--\u003e\n### X-5 (String support)\nX-5 brings string support. Specifics about the string implementation like: immutability vs mutability, pascal style (length prefixed) vs c style (null terminated) are left to the implementation to decide.\n#### required words\n* length ( string -- number ) - gives count of characters in the string.\n* append ( string string -- string ) - string concatenation\n#### required overloads\n\u003c!--* append ( string string -- string ) - overload `+` operator to work with strings for concatenation--\u003e\n* to-string ( number -- string ) - converts a number into a string\n    * should be implemented for each primtive datatype you included in your Forth. So if you've implemented X-3 (Bool), you should also provide a bool conversion that returns `\"True\"` or `\"False\"`\n* X-2 (Symbols)\n    * symbol-from-string ( string -- symbol ) - convert a string into its symbol representation. Any string can be converted into a symbol even if the string does not end with ':'. So both `\"Pig\"` and `\"Pig:\"` convert to the symbol `Pig:`\n\u003c!--\nThese require error handling support because what do you do if the conversion was not successful?\n* to-number ( string -- number ) - convert a string into a number\n* to-bool ( string -- bool ) - convert a string into a bool\n--\u003e\n#### spec\nX-Forth strings are defined using double quotes `\"` which allows for the optional implementation of single char types.\n\n### X-6 (Includes) requires X-5 (String support)\nX-6 brings include support which allows including external Forth files. It works similarly to C's `include` and inserts the source code of another file at the location. `include` operates on a string path:\n```nim\n\"./files/some_file.xf\" include\n```\n`include` should by some means cache the file it includes so a file is only ever included once. Though it looks like a normal x-forth word it is more like a compiler command and should be executed (and removed from the token stream) before interpretation.\n#### required words\n* include (string -- ?) - extends the token stream with tokens from the passed file\n    * note that we have ? as the return value because the state of the stack depends on the file included. If that file pushed a value as the last statement then that would apply to the current program\n\n### X-7 (Blocks)\nBlocks are a unique construct in X-Forth and are similar to LISP lists. Blocks are denoted with square brackets `[]` and can contain any tokens: `[ 1 2 ]`, `[ 1 2 + ]`, `[ \"hello\" some-word ]`. Blocks are just lists of tokens which can be passed around and operated upon by words. Blocks serve as the basis for higher level constructs like custom words and control flow.\n\nBlocks have multiple uses and provide different functionality based on the words used to operate on them:\n* lists - blocks can be used as lists of data, similar to lists in Python or JavaScript, here is a block (list) of numbers : `[ 1 2 3 ]`\n* tables - blocks can be used as lookup tables as well: `[ 0 10 1 20 ] 0 get # 10`\n    * If you've implemented [X-2 (Symbols)](#x-2-(symbols)) you can get JavaScript like syntax: `[ a: 10 b: 20 ] a: get # 10`\n* custom words - blocks in combination with [X-4 (Variables)](#x-3-(variables)) for the basis for custom words (see [X-6](#x-6-(custom-words)))aka functions: `add-five: [ 5 + ] con`\n* anonymous functions - you can pass blocks around and execute them using the `call` and `apply` words:\n```py\n10 [ 5 + ] call # 15, call operates directly on the stack taking only a single block as an argument\n[ 5 + ] [ 10 ] apply # 15, apply takes a block of arguments which will be pushed to the stack first and a block of instructions \n```\n* named functions - If you define a block variable with `con` then the use of the constant name calls that block immediately:\n```py\nadd-five: [ + 5 ] con\n10 add-five . # 15.0\n```\nBlock variables act slightly differently depending on whether they are defined with `var` or `con`. If defined with `var` a variable holding a block just pushes the block to the stack like any other value, however if the block was defined with `con`, then in addition to pushing the block to the stack it is immediately called which is what allows user defined words to work. If you use a block which is a `var`, then you will need to also use `call` or `apply` to execute the block. \n#### required types\n* Block\n#### required words\n* call ( block-body -- ? ) - executes the tokens inside the passed block, applying its effect to the stack: `2 [ 3 + ] call # 5.0`\n* apply ( block-body block-args -- ?) - the same as call, except instead of getting its args directly from the stack, its top value is a block containing arguments that are pushed to the stack before the body is called: `[ 3 + ] [ 2 ] apply # 5.0`\n\u003c!--\nNow with variables and blocks you get custo words for free by assigning blocks to constants,\nhowever you should consider allowing stack effect comments such as (n -- n) be part of the arguments to var and con and actually be stored somewhere, perhaps in a separate lookup table. Consider expanding the stack effect comment syntax to include multiline strings or comments\n\n    add-five: [ 5 + ] ( n -- n\n        \"add-five adds five to its argument\") con\n\nI could parse out the stack effect into its args and its doc comment by simply splitting on \" and then on -- to get input and output. This extension can extend custom words with the stack effect and the doc/help/see words to get the info about a word\n\n### X-6 (Custom Words) requries X-4 (Variables), X-5 (Blocks)\n#### X-6.A (Constant Custom Word)\nImplements custom words that cannot be overriden. Attempting to redefine a word that already exists will result in a `Word redefinition` error \n\n#### errors\n- Word Refinition - you attempted to redefine an existing word\n    - format: `ERROR: \u003cword name\u003e : Word Redefinition`\n#### X-6.B (Redefinable Custom Words)\nImplements custom words that can be redefined. Defining a word that already exists will overwrite its entry in the global lookup table. This implementation aligns with more traditionals Forths wherein a dictionary of words is searched linearly from the end.\n--\u003e\n### X-8 (If) requires X-7 (Blocks)\nTODO\n### X-9 (Loop) requires X-7 (Blocks)\nTODO\n### X-10 (Word Documentation)\nX-10 brings the ability to add documentation to words with stack effect comments: `add-five: [ 5 + ] ( n -- n \"adds 5 to n\" ) con`. This stack comment is a special type of comment that it associated with the word and can be looked up with the words `help`, `sig`\n\u003c!-- 0 should be true and anything else false? This would integrate well with errors. Errors could similarly be aliases where 0 represents no error and positive numbers represent specific errors like an enum. This would allow things like:\n\n: work 1 ; # something went wrong\n\nwork if drop \"it worked!\" . else \"something went wrong, error # \" swap to-string concat .;\n\nMaybe I'm over thinking it. But errors should definitely be enums. I think this makes sense actually, 0 is true and anything else is error, that way the first value of an enum/error set is always no error\n--\u003e\n### X-11 (Errors)\nTODO\n### X-12 (REPL)\nAdd a Read Eval Print Loop. TODO\n### X-13 (Comments)\nX-Forth uses `#` for single line comments like Python. You can safely ignore any tokens beginning with `#`. \n### X-14 (Event Loop) requires X-4 (Variables)\nX-Forth uses a simple event loop in which the X-Forth interpreter runs two (or more) execution contexts (threads, coroutines or otherwise) with two (or more) interpreters, one for the main program denoted the `Main Context`, and another (or multiple) for the non bocking execution of asynchronous tasks, called the `Background Context`. The `Background Context` should have an event queue which the `Main Context` can push jobs to and which the `Background Context` will constantly poll\n### X-15 (Memory) requires X-4 (Variables)\nMemory is introduced in X-4 (Variables) to implement user defined variables, but it is also used heavily for the X-17 Graphics extension and potential others. The size of the memory (and graphics) are up to the user. The memory should be a contigous array or linked list of contiguous blocks with portions dedicated to variables (X-4), keyboard input (X-16), screen pixels (X-17), and a data section (X-18)\n### X-16 (Keyboard Input) requires X-14 (Event Loop), X-15 (Memory)\nAllows for Keyboard input, both block and non-blocking\n### X-17 (Graphics) requires X-16 (Keyboard Input)\nX-16 brings a simple pixel buffer based graphics API inspired by BASIC. The program memory array is used heavily for the graphics api and a portion of it is dedicated to the screen memory. The size of the screen is up to the implementation, recommended sizes are: 256x240\n### X-17 (Data section), X-14 (Memory)\nTODO\n### X-18 (With) requires X-4 (Variables)\nWith binds values on the stack to variable names temporarly for the lifetime of the top block passed to it: `10 5 [ a: b: ][ + ] with  # 15`. After execution of its block, the variables disappear and do not pollute the global scope.\n### X-19 (Builtin Words 1)\nThis extension adds more stack words that are normally seen in Forths.\n#### required words\n* over ( a b -- a b a ) - copies the second stack value to the top of the stack\n* swap ( a b -- b a ) - switch positions of the top two stack values\n* rot ( a b c -- c b a ) - swap the first and third values on the stack, rotating them around the second value. Note that this word behaves differently than the rot word seen in traditional Forths\n* grab ( a+ n -- a#n ) - given some values on the stack and a number at the top, copy value at index n (starting at 0) to the top.\n#### required words\n* with ( block block -- ? )\n### X-? (Bytecode)\nStores X-Forth into an efficient Bytecode format. Values should be Nan Boxed or Pointer Tagged. TODO\n### X-? (X-Forth Machine) requires X-? (Bytecode)\nThe X-Forth Machine is a virtual Forth machine, meant to be bootstrapped from native code such as Assembly, C for desktop or JavaScript or WASM in the browser. The XFVM (X-Forth Virtual Machine) posesses a fixed amount of memory used for variables, input/output, graphics and data storage. TODO \n\u003c!--The exact specs of the machine in regards to memory can vary depending on the host, however, you will find some recommended specs to get you started:\n#### Limited Hardware 1 (WIP)\nThis XFVM is modeled after the chip 8 virtual machine. TODO\n#### Limited Hardware 2 (WIP)\nThis XFVM is based on the specs of the Nintendo Entertainment System (NES):\n* 16 bit - machine words are 16 bits\n* numbers are 16 bit integers, no floats\n* 40 KB program data - This includes the Forth program itself, plus any data such as sprites or music and should be a `.xfb` X-Forth Binary file. Your Forth program must not exeed this size\n* 2KB Memory - \n    * 500 B stack\n    * 1590 B variable space\n    * 10 bytes read only memory for 10 keys, representing the 10 buttons on an NES controller\n        * up\n        * right\n        * down\n        * left\n        * select\n        * start\n        * A\n        * B\n        * L Button\n        * R Button\n* 56 colors available\n* 256x240 screen (61,440 bytes) each of which can hold a value of 0 to 55 used to index into the 56 color palette\n--\u003e\n\u003c!--\n## Suites\nSuites are collections of Extensions which represent packages of functionality and can be used to describe the feature level of an X-Forth implementation\n\n### S-1 (Turing)\nImplementing S-1 means you have implemented a completely turing complete implementation of X-Forth. TODO\n#### required extensions\n* X-B (Basic)\n* X-2 (Variables)\n* X-? (If Statements)\n* X-? (Loops)\n\n### S-? (Limited Hardware)\nTODO\n--\u003e\n## Implementations\nThere are several implementations of X-Forth created along with the project in varying stages of completion and extension implementation. All implementations listed implement at least X-B: \n### Dart\n* [phillvancejr / x-forth-dart](implementations/dart)\n    * [X] X-B (Basic)\n### Go\n* phillvancejr / x-forth-go TODO\n    * [ ] X-B (Basic)\n### Python\n* [phillvancejr / x-forth-py](implementations/python/tutorial)\n    * [X] X-B (Basic)\n    * [X] X-1 (External/Variable Source Code)\n    * [X] X-2 (Symbols)\n    * [X] X-3 (Bools)\n    * [X] X-4 (Variables)\n    * [X] X-5 (Strings)\n    * [X] X-6 (Includes)\n### Third Party\nIf you create an X-Forth please let me know, I'd love to link to it! Any language is great!\n\n## For Fun\nThis project was created to allow me to play with and compare different languages and to explore different aspects of programming languages and compilers like: interpreters, compiling to native code, assembly, virtual machines and more. Even if you're not interested in Forth, you might be interested in the ways similar things are implemented in the different languages used here. ","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphillvancejr%2Fx-forth","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fphillvancejr%2Fx-forth","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphillvancejr%2Fx-forth/lists"}