-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathexample_hello_world.hell
More file actions
361 lines (304 loc) · 8.46 KB
/
example_hello_world.hell
File metadata and controls
361 lines (304 loc) · 8.46 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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
/*
* This file is part of LMAO (Low-level Malbolge Assembler, Ooh!), an
* assembler for Malbolge.
* Copyright (C) 2013-2017 Matthias Lutter
*
* LMAO is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LMAO is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* E-Mail: matthias@lutter.cc
*
*
* Example in HeLL: Printing out a string using loops.
*
* This HeLL program prints out a String by reading it character by character
* from an array. This consumes much more memory of the virtual Malbolge
* machine than other well known methods for printing out a string in Malbolge.
* But it demonstrates how to use conditional branches and loops. Thus, this
* program could be extended to something like the 99 bottles of beer program.
*
* The main techniques used by the code below came from reverse engineering
* of the 99 bottles of beer program by Hisashi Iizawa et al.
* http://www.99-bottles-of-beer.net/language-malbolge-995.html
*/
.DATA
// The string that will be printed out. Each character must be followed by
// data_read, but the last character must be followed by last_data_read.
// Notice that "abc",D is equvalent to 'a' D 'b' D 'c'
STRING:
"Hello, World!\n", data_read
last_data_read
.CODE
FLAG1:
Nop/MovD
Jmp
FLAG2:
Nop/MovD
Jmp
FLAG3:
Nop/MovD
Jmp
MOVED:
MovD/Nop
Jmp
LOOP2:
MovD/Nop
Jmp
LOOP2_2:
Nop/MovD
Jmp
LOOP2_3:
Nop/MovD
Jmp
LOOP5:
Nop/Nop/Nop/Nop/MovD
Jmp
LOOP4:
Nop/Nop/Nop/MovD
Jmp
NO_MORE_CARRY_FLAG:
Nop/MovD
Jmp
NO_MORE_DATA_FLAG:
Nop/MovD
Jmp
NOP:
Jmp
CRAZY:
Opr/Nop
Jmp
ROT:
Rot/Nop
Jmp
HALT:
Hlt
OUT:
Out/Nop
Jmp
LOAD_CHARACTER:
; Move D register to the address the string pointer points to.
MovD/Nop/Nop/Nop/Nop/Nop/Nop/Nop/Nop
RNop
RNop
; Load the current character of the string with the Opr instruction.
Opr/Nop/Nop/Nop/Nop/Rot/Nop/Nop/Nop
; label for xlat2 restoring the above Opr-command.
PARTIAL_R_LOAD_CHARACTER:
; Move D register to data_read or last_data_read (see STRING)
MovD/Nop/Nop/Nop/Nop/Nop/Nop/Nop/Nop
Jmp
@C21 CARRY:
; The carry variable may be C20 or C21. By executing the code at the
; carry address the increment of the D register until reaching the
; Jmp instruction differs. This is used for conditional branching
; dependent on the value of the carry.
; RNop at C21
RNop
; RNop at C2
RNop
; Jmp at C0
Jmp
.DATA
// ******************** \\
// Variable definitions \\
// ******************** \\
// var string_ptr
// string ptr: points to the character of the string that should be printed out
// the next time
crazy_string_ptr:
U_CRAZY string_ptr
load_character_string_ptr:
U_LOAD_CHARACTER string_ptr
rot_string_ptr:
U_ROT string_ptr
string_ptr:
STRING-2
FLAG1 return_from_string_ptr_1 R_FLAG1
FLAG2 return_from_string_ptr_2 R_FLAG2
// var carry
// carry: stores while incrementing the string_ptr whether the next trit has
// to be incremented also or not.
crazy_carry:
U_CRAZY carry
carry:
CARRY
U_NOP execution_not_jumped_to_carry
U_NOP carry_was_not_set
U_NOP carry_was_set
carry_was_set:
R_MOVED
MOVED return_carry_was_set
carry_was_not_set:
R_MOVED
MOVED return_carry_was_not_set
execution_not_jumped_to_carry:
FLAG1 return_from_carry_1 R_FLAG1
// var tmp
// tmp: used during increment
crazy_tmp:
U_CRAZY tmp
tmp:
C0 // must not contain any trit that is 2.
FLAG1 return_from_tmp_1 R_FLAG1
FLAG2 return_from_tmp_2 R_FLAG2
// ******************** \\
// Program code \\
// ******************** \\
// Increment string_ptr twice to point to the next character
// Code sequence to increment the last trit of the memory cell "value":
//
// SET tmp = C0
// SET carry = C20 or C21
// ROT C2
// OPR value
// OPR tmp
// OPR carry
// OPR value
// OPR tmp
// OPR carry
// if (carry == C20){
// // carry is set
// }else if (carry == C21){
// // no carry
// }
//
// After the lowest trit has been incremented, the variable has to be rotated.
// Depending on the carry, the increment has to be done again or not.
// After 10 rotates the variable is incremented.
;
// To increment string_ptr by 2, these steps will be executed twice.
increment_string_ptr:
R_MOVED
// We have to set tmp to C0. It won't contain any trit that is 2,
// so we can just crazy C1 into tmp.
set_tmp_to_C0:
ROT C1 R_ROT
R_FLAG1 // set return flag
MOVED crazy_tmp // crazy C1 into tmp variable to set it to C0
return_from_tmp_1:
R_CRAZY R_MOVED
ROT C2 R_ROT // load C2 to A register
// now we have to execute the command sequence
// OPR value
// OPR tmp
// OPR carry
// twice.
crazy_loop_increment_string_ptr:
//the following sequence must be executed twice;
//label for loop
R_FLAG1 // set return flag
MOVED crazy_string_ptr // crazy A register into tmp variable
return_from_string_ptr_1:
R_MOVED R_CRAZY
R_FLAG2 // set return flag
MOVED crazy_tmp // crazy into tmp variable
return_from_tmp_2:
R_CRAZY R_MOVED
R_FLAG1 // set return flag
MOVED crazy_carry // crazy into carry variable
{
return_from_carry_1:
R_CRAZY R_MOVED
// check loop condition
LOOP2 crazy_loop_increment_string_ptr
MOVED carry
return_carry_was_not_set:
R_NO_MORE_CARRY_FLAG
return_carry_was_set:
R_MOVED
// rotate string_ptr until it has been rotated 10 times.
// after rotating go to increment or rotate again corresponding to
// the NO_MORE_CARRY_FLAG
R_FLAG2 // set return flag
MOVED rot_string_ptr // rot string_ptr
}
return_from_string_ptr_2:
R_MOVED R_ROT
// exit loop after 5 times
LOOP5 exit_inner_increment_loop
NO_MORE_CARRY_FLAG restore_no_more_carry_flag_and_rotate_string_ptr
R_NO_MORE_CARRY_FLAG
MOVED increment_string_ptr
exit_inner_increment_loop:
// exit loop after 2 times
LOOP2_2 exit_increment_loop
NO_MORE_CARRY_FLAG restore_no_more_carry_flag_and_rotate_string_ptr
R_NO_MORE_CARRY_FLAG
MOVED increment_string_ptr
restore_no_more_carry_flag_and_rotate_string_ptr:
R_NO_MORE_CARRY_FLAG
MOVED carry_was_set
exit_increment_loop:
NO_MORE_CARRY_FLAG nomorecarrykilled
R_NO_MORE_CARRY_FLAG
nomorecarrykilled:
LOOP2_3 ENTRY
MOVED increment_string_ptr
// read character at string_ptr and print it out
ENTRY:
// load character at string_ptr
ROT C2 R_ROT
MOVED load_character_string_ptr
{
// return labels for load_character_string_ptr-function
// (see definition of STRING)
last_data_read:
// force NO_MORE_DATA_FLAG to be set
NO_MORE_DATA_FLAG last_data_read
// after the flag is set, the last character is read in as any other
// character
data_read: restore_load_character:
R_MOVED
restore_load_character_no_r_moved:
// restore LOAD_CHARACTER code. This is a bit tricky and requires
// 2 loops.
// 9-cycles in LOAD_CHARACTER;
// containing evil cycle Opr/Nop/Nop/Nop/Nop/Rot/Nop/Nop/Nop
// the Rot operation MUST NOT BE executed during restoring,
// because this would override the character we read into the
// A register
// the PARTIAL_R_LOAD_CHARACTER-restore-opration prevents executing
// the Rot command, but the full command has to be restored 9 times,
// too.
PARTIAL_R_LOAD_CHARACTER ?-
R_LOAD_CHARACTER ?- ?- ?- ?-
LOOP4 half_of_restore_load_character_done
// continue restoring
MOVED restore_load_character
}
half_of_restore_load_character_done:
// quit at second call
LOOP2_2 restore_load_character_done
// destroy PARTIAL restored LOAD_CHARACTER, so the LOOP4-loop
// can restore the whole command sequence
PARTIAL_R_LOAD_CHARACTER
// render meanwhile restored MovD command harmless
// continue restoring
restore_load_character_no_r_moved
{
restore_load_character_done:
// we crazied C2 into a character at position (string_ptr+2).
// we must do this twice to read the original character.
LOOP2 ENTRY
// we copied the character at position (string_ptr+2) into the
// A register. Now we will print it out.
OUT ?- R_OUT
// if it was the last character of the string, we will go to the
// label whole_string_printed and terminate the program
NO_MORE_DATA_FLAG whole_string_printed R_NO_MORE_DATA_FLAG
// if it was not the last character, we have to increment
// string_ptr (twice) to point to the next character
MOVED increment_string_ptr
}
whole_string_printed:
HALT