-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathabout.html
More file actions
168 lines (168 loc) · 14.9 KB
/
about.html
File metadata and controls
168 lines (168 loc) · 14.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
<!DOCTYPE html>
<html lang="en-US">
<head>
<title>qrforth</title>
<link rel="icon" type="image/png" href="qrforth.png"/>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/yegor256/tacit@gh-pages/tacit-css-1.6.0.min.css"/>
<style>
small {
color: #4c4c4c;
}
</style>
</head>
<body>
<section>
<header>
<nav>
<ul>
<li><img src="qrforth.png" alt="qrforth logo" style="max-height: 150px;"/></li>
<li><a href="https://qrforth.com/#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
">Home</a></li>
<li><a href="about.html">About</a></li>
<li><a href="qrcode.html">QR Code</a></li>
<li><a href="examples.html">Examples</a></li>
</ul>
</nav>
</header>
<article>
<p>
<strong>qrforth</strong> is a tiny implementation of the <a href="https://en.wikipedia.org/wiki/Forth_(programming_language)">Forth</a> programming language that fits in a <a href="qrcode.html">QR code</a>. The heart of qrforth is a miniaturized <a href="https://www.rust-lang.org/">Rust</a> library compiled to <a href="https://webassembly.org/">WebAssembly</a> resulting in a ~1.3kB binary. The qrforth webassembly module is responsible for the Forth stack, primitive words, and functions that provide access to the stack and registers. Javascript is used to execute the webassembly, accept user input, and define new words. The size of all of this comes to ~2.8kB, just small enough to fit in a version 40 QR code (177x177) with the lowest level error correction. Visiting the Home page or scanning the QR code will run qrforth in your browser.
</p>
<h1>
How it Works
</h1>
<p>
The qrforth project consists of three main parts: the wasm module(lib.rs), the html/javascript code(qrforth.html), and the qrforth.com webpage(index.html). The wasm module is encoded in the qrforth.html page and the whole thing is encoded in the QR code. The url in the QR code needs to point to a resource on the web so the qrforth.com webpage is a simple static site hosted on <a href="https://pages.github.com/">GitHub Pages</a> that serves as a landing page and decodes the url contained in the QR Code.<br>
<br>
The url encoded in the QR code looks something like this <code>http://qrforth.com/#i9EKAICqqqrq/26XE5dDdph...</code> (truncated for readability, <a href="https://github.com/mattdeeds/qrforth/blob/main/url.txt">full URL here</a>). Using <a href="https://en.wikipedia.org/wiki/URI_fragment">URI fragments</a> the entire qrforth.html webpage is encoded in the URL itself. The qrforth.com webpage receives the URI fragment, decodes and decompresses it, and serves the resulting html as an iframe. All of this is done in the browser with no server side code. The following sections go into more detail on how each part of qrforth works.
<p>
To compile our rust library to webassembly we use the <code>--target=wasm32-unknown-unknown --release</code> cargo build flags. We need to keep the resulting wasm binary as small as possible so we need to: 1) use the <code>#![no_std]</code> attribute to disable the standard library, 2) define a custom panic handler with <code>#[panic_handler]</code>, 3) statically allocate our variables to avoid brining in dlmalloc, and 4) strip and optimize our binary with the strip and lto setting in our Cargo.toml file. All of this will keep the rust compiler from adding in typically useful but sizeable code to our wasm binary. I've linked some super helpful resources below that go into more detail on how to do this.
</p>
<ul>
<li><a href="https://surma.dev/things/rust-to-webassembly/">Rust to WebAssembly the hard way</a>, Surma</li>
<li><a href="https://nickb.dev/blog/avoiding-allocations-in-rust-to-shrink-wasm-modules/">Avoiding allocations in rust to shrink wasm modules</a>, nickb</li>
<li><a href="https://darkcoding.net/software/a-very-small-rust-binary-indeed/">A very small rust binary indeed</a>, Graham King</li>
</ul>
<p>
Now what we have our qrforth.wasm binary, we can encode it as a base64 string and put it in our qrforth.html page. The javascript in qrforth.html will decode the base64 string and initialize the wasm module when the browser loads the page. The qrforth.html page is now complete and the URI fragment can be created by compressing the html with <a href="https://github.com/google/brotli">brotli</a> and encoding the result as a base64 string. The URL fragment is then appended to the qrforth.com url and the resulting url is encoded as a <a href="/qrcode.html">QR code</a>.<br>
<br>
All of these steps are automated with a build script that makes rebuilding as easy as running <code>./build.sh</code>. qrforth can also be run locally with a simple python sever and running <code>./build.sh --local</code>. More info can be found in the <a href="https://github.com/mattdeeds/qrforth">GitHub repository</a>.
</p>
<h1>
Forth Implementation
</h1>
<p>
The qrforth implementation of Forth is designed to be very minimal and only includes a limited subset of the language. Using the words provided, more useful words can be written in qrforth. Some examples are provided <a href="/examples.html">here</a>here. Don't expect qrforth to be a perfect implementation of Forth or ANS Forth compliant, there are already plenty of well designed implementations out there. The goal of qrforth is mainly just to learn more about Forth, WebAssembly, and Rust.<br>
The memory for the system is arbitrarily laid out as an array of 32-bit signed integers, 8000 elements in length. The first 4000 elements reserved for the Forth stack and the second 4000 is general system memory. There is a 8-bit <code>FLAGS</code> register that is used communicating state from the wasm module to the qrforth html page. User input and output and the Forth dictionary are handled by the page's javascript. The following is a list of the words that make up qrforth:
<table>
<thead>
<tr>
<th>Word</th>
<th>Definition</th>
<th>Stack Effect</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>push</code></td>
<td>Push x onto the stack</td>
<td><i>( x -- )</i></td>
</tr>
<tr>
<td><code>+</code></td>
<td>Sum the two numbers at the top of the stack</td>
<td><i>( x y -- z )</i></td>
</tr>
<tr>
<td><code>nand</code></td>
<td>NAND the two numbers at the top of the stack</td>
<td><i>( x y -- z )</i></td>
</tr>
<tr>
<td><code>drop</code></td>
<td>Drop the number at the top of the stack</td>
<td><i>( x -- )</i></td>
</tr>
<tr>
<td><code>0=</code></td>
<td>If top of stack is 0, set to -1, otherwise set to 0</td>
<td><i>( x -- flag )</i></td>
</tr>
<tr>
<td><code>@</code></td>
<td>Fetch memory contents at addr</td>
<td><i>( addr -- x )</i></td>
</tr>
<tr>
<td><code>!</code></td>
<td>Store x at addr</td>
<td><i>( x addr -- )</i></td>
</tr>
<tr>
<td><code>sp@</code></td>
<td>Return stack top pointer to top of stack</td>
<td><i>( -- sp )</i></td>
</tr>
<tr>
<td><code>emit</code></td>
<td>Print x as an ASCII character</td>
<td><i>( x -- )</i></td>
</tr>
<tr>
<td><code>.</code></td>
<td>Print top of the stack</td>
<td><i>( x -- )</i></td>
</tr>
<tr>
<td><code>key</code></td>
<td>Read a character and push it onto the stack</td>
<td><i>( -- x )</i></td>
</tr>
<tr>
<td><code>begin</code></td>
<td>Marks the start of a <strong>begin until</strong> loop</td>
<td><i>( -- )</i></td>
</tr>
<tr>
<td><code>until</code></td>
<td>If x is zero, jumps to matching begin, if x is non-zero, continues execution </td>
<td><i>( x -- )</i></td>
</tr>
<tr>
<td><code>if</code></td>
<td>If x is -1, continue execution within <strong>if then</strong> block.</td>
<td><i>( x -- )</i></td>
</tr>
<tr>
<td><code>then</code></td>
<td>Marks the end of an <strong>if then</strong> block</td>
<td><i>( -- )</i></td>
</tr>
</tbody>
</table>
In typical Forth fashion, colon (<code>:</code>) and semicolon (<code>;</code>) words are available and are used to define new words in the dictionary. Commenting code is supported using parentheses. You can easily define a new word like <code>dup</code> to duplicate the top value on the stack:<br>
<code>: dup ( x -- x x ) sp@ @ ;</code><br>
</p>
<h2>Inspired by these cool projects:</h2>
<ul>
<li><a href="https://github.com/cesarblum/sectorforth">sectorforth</a></li>
<li><a href="https://github.com/skilldrick/easyforth">Easy Forth</a></li>
<li><a href="https://github.com/alcor/itty-bitty">itty.bitty</a></li>
</ul>
</article>
<footer>
<nav>
<ul>
<small>qrforth v0.1.0, 2023 Matthew Deeds,
<a href="https://opensource.org/license/mit/">MIT License</a>
<br>
<a href="https://github.com/mattdeeds/qrforth">GitHub</a>
</small>
</ul>
</nav>
</footer>
</section>
</body>
</html>