1 # Meow5: "Meow. Meow. Meow. Meow. Meow."
2
3 <img src="raw/meow5cat.svg" alt="SVG meow5 kitty cat logo" align="right">
4
5 **Update 2023-11-21** Meow5 is done!
6 <a href="https://www.ratfactor.com/meow5/done">Read my conclusion here!</a>
7
8 Meow5 is a stack-based pure inlining concatenative programming language.
9
10 Running Meow5 interactively looks like this:
11
12 5 5 +
13 "The answer is $." print$
14 The answer is 10.
15
16 In the above example, the first line puts two fives on the
17 stack and adds them.
18
19 The second line prints the answer. (The "$" character pops a number from the stack and includes it in the printed string.)
20
21 Now we can see that 5 + 5 is 10.
22
23 A block of code can be given a name and is called a "def"
24 (short for definition). Here's one:
25
26 def meow
27 "Meow!" print
28 ;
29
30 meow
31 Meow!
32
33 Defs can include other defs. Here's a silly example:
34
35 def five 5 ;
36 def plus + ;
37 def ten five five plus ;
38
39 ten "Ten is $" print$
40 Ten is 10
41
42 Meow5 can write *any* def as a stand-alone 32-bit Linux ELF
43 executable. (But not all defs are position-independent at
44 this time, so some executables will segfault!) Here's an
45 example session:
46
47 $ ./meow5
48
49 def forty-two
50 42 exit
51 ;
52
53 elf forty-two
54 Wrote to "forty-two".
55
56 $ ./forty-two
57 $ echo $?
58 42
59
60 Note that `$?` contains the exit code of the previous command.
61
62 The file `forty-two` is a 97-byte program that will run on
63 any Linux system!
64
65 The canonical Meow5 program writes five meows. Here is a
66 self-contained meow file:
67
68 $ cat 5.meow
69 def meow
70 "Meow!\n" print
71 ;
72
73 def five-meows
74 meow
75 meow
76 meow
77 meow
78 meow
79 exit
80 ;
81
82 elf five-meows
83
84 That last line tells the interpreter to write out the
85 five-meows def as a stand-alone executable. Let's see what
86 happens when we redirect this file to the interpreter:
87
88 $ ./meow5 < 5.meow
89 Wrote to "five-meows".
90
91 It wrote a 317 byte executable named `five-meows`. Let's run it:
92
93 $ ./five-meows
94 Meow!
95 Meow!
96 Meow!
97 Meow!
98 Meow!
99
100 Now I can have meowing in my terminal any time I want!
101
102 ### Now with loops!
103
104 Ah, but now it gets better! I've added ifs and loops.
105 A looped version of the five-meows program is much
106 more efficient with space. Here's `five-loop.meow`:
107
108 def meow
109 "Meow!\n" print
110
111 # decrement the stack each time or
112 # we'll end up with an infinite loop!
113 dec
114 ;
115
116 # Another def that loops!
117 def five-meows-loop
118 5 loop? meow
119 exit
120 ;
121
122 # Write an executable :-)
123 elf five-meows-loop
124
125 It works exactly like the five copy inline version:
126
127 $ ./meow5 <five-loop.meow
128 Wrote to "five-meows-loop".
129
130 $ ./five-meows-loop
131 Meow!
132 Meow!
133 Meow!
134 Meow!
135 Meow!
136
137 Except this executable is a mere **160 bytes**. Cool!
138
139
140 ## What is Meow5? (and what is "pure inlining"?)
141
142 A Forth-like language that is conCATenative in two ways:
143
144 1. Concatenative data flow (traditional)
145 2. Concatenated machine code (weird)
146
147 There's a lot of information on the Web about concatenative
148 programming in the first, traditional sense. But that second
149 part is what's unique about Meow5.
150
151 Luckily, really easy to explain how this works, thanks to
152 Meow5's introspection abilities:
153
154 Using `inspect`, we can view the machine code of any def:
155
156 inspect +
157 +: 5 bytes IMMEDIATE COMPILE
158 58 5b 1 d8 50
159
160 We can see that the `+` def contains five bytes of machine
161 code.
162
163 By the way, that machine code disassembles into this assembly
164 language:
165
166 pop eax
167 pop ebx
168 add eax, ebx
169 push eax
170
171 If we define a new def that uses an existing def, the
172 machine code simply gets concatenated together:
173
174 def ++
175 +
176 +
177 ;
178
179 Let's use this new def to see that it adds three numbers
180 together:
181
182 10 10 10 ++ printnum
183 30
184
185 And since we can see that the contents of our new def is,
186 indeed, the simple concatenation of its constituents (two
187 copies of the 5 byte `+`):
188
189 inspect ++
190 ++: 10 bytes IMMEDIATE COMPILE
191 58 5b 1 d8 50 58 5b 1 d8 50
192
193 The consequence of this is that any def in Meow5 is a
194 _complete, stand-alone sequence of instructions_. That's why
195 writing an executable for any def is as simple as writing
196 its contents to disk! (Plus the ELF header to make it valid,
197 of course.)
198
199 Q: Is this wasteful? Doesn't this cause a lot of redundant
200 copies of code?
201
202 A: Yes.
203
204 But it's interesting because we're also avoiding a lot of
205 branching - most Meow5 code is a continuous stream of
206 actions with very tiny relative local jumps. I think it
207 produces unusual code.
208
209 See also:
210
211 <a href="http://ratfactor.com/assembly-nights2">Assembly Nights 2</a> - This actually part of a series, a personal exploration of the joy of computing.
212
213 <a href="http://ratfactor.com/meow5/">ratfactor.com/meow5/</a> - Meow5's page on the World Wide Web (though this README is more up to date).
214
215
216 ## Why?
217
218 My idea came about while studying Forth. A traditional
219 "threaded interpreted" Forth goes to some pretty extreme
220 lengths to conserve memory. The execution model is not only
221 complicated, but seems also likely to not be all that great
222 for efficiency on modern machines where memory is much more
223 abundant and the bottleneck oftenseems to be getting data
224 into the CPU fast enough.
225
226 In particular, the old Forth literature I have been reading
227 is full of statements about needing to conserve the **few
228 kilobytes of core memory** on a late 1960s machine. But
229 even my most modest low-powered Celeron and Atom-based
230 computers have **L1 CPU caches** that dwarf those
231 quantities!
232
233 So, given the tiny size of the programs I was writing with
234 my JONESFORTH port, I kept thinking, "how far could I get if
235 I just inlined _everything_?" As in, actually made a copy of
236 every word's machine instructions every time it is
237 "compiled".
238
239 I expect this will be silly but fun and educational.