996
|
1 /* -*- mode: C; coding: utf-8; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*-
|
|
2
|
|
3 cfunge - a conformant Befunge93/98/08 interpreter in C.
|
|
4 Copyright (C) 2008 Arvid Norlander <anmaster AT tele2 DOT se>
|
|
5 Copyright (C) 2008 Alex Smith
|
|
6
|
|
7 This program is free software; you can redistribute it and/or modify
|
|
8 it under the terms of the GNU General Public License as published by
|
|
9 the Free Software Foundation; either version 2 of the License, or
|
|
10 (at your option) any later version.
|
|
11
|
|
12 This program is distributed in the hope that it will be useful,
|
|
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
15 GNU General Public License for more details.
|
|
16
|
|
17 You should have received a copy of the GNU General Public License
|
|
18 along with this program; if not, write to the Free Software
|
|
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
20
|
|
21 Note that this code is designed to be linked against a GPLv3 library
|
|
22 (producing a GPLv3 output), and therefore it is recommended that
|
|
23 modifications to this code are compatible with GPLv3, although this
|
|
24 is not a legal requirement.
|
|
25 */
|
|
26
|
|
27 #include "IFFI.h"
|
|
28 #include "../../stack.h"
|
|
29 #include "../../settings.h"
|
|
30 #include "../../interpreter.h"
|
|
31
|
|
32 #ifdef HAVE_clock_gettime
|
|
33 # include <time.h>
|
|
34 #else
|
|
35 # include <sys/time.h>
|
|
36 #endif
|
|
37
|
|
38 static instructionPointer *iffiIP = NULL;
|
|
39
|
|
40 static bool firstload = true;
|
|
41
|
|
42 // Communication functions with the ecto_b98 expansion library
|
|
43 void ick_save_ip_pos_delta(struct ick_ipposdeltatype* ippd)
|
|
44 {
|
|
45 ippd->ix = iffiIP->position.x;
|
|
46 ippd->iy = iffiIP->position.y;
|
|
47 ippd->dx = iffiIP->delta.x;
|
|
48 ippd->dy = iffiIP->delta.y;
|
|
49 }
|
|
50
|
|
51 void ick_restore_ip_pos_delta(const struct ick_ipposdeltatype* ippd)
|
|
52 {
|
|
53 iffiIP->position.x = ippd->ix;
|
|
54 iffiIP->position.y = ippd->iy;
|
|
55 iffiIP->delta.x = ippd->dx;
|
|
56 iffiIP->delta.y = ippd->dy;
|
|
57 }
|
|
58
|
|
59 void ick_interpreter_run(void)
|
|
60 {
|
|
61 if (!fungespace_create()) {
|
|
62 perror("Couldn't create funge space!?");
|
|
63 exit(EXIT_FAILURE);
|
|
64 }
|
|
65 fungespace_load_string(ick_iffi_befungeString);
|
|
66 iffiIP = ip_create();
|
|
67 if (iffiIP == NULL) {
|
|
68 perror("Couldn't create instruction pointer!?");
|
|
69 exit(EXIT_FAILURE);
|
|
70 }
|
|
71 {
|
|
72 #ifdef HAVE_clock_gettime
|
|
73 struct timespec tv;
|
|
74 if (clock_gettime(CLOCK_REALTIME, &tv)) {
|
|
75 perror("Couldn't get time of day?!");
|
|
76 exit(EXIT_FAILURE);
|
|
77 }
|
|
78 // Set up randomness
|
|
79 srandom(tv.tv_nsec);
|
|
80 #else
|
|
81 struct timeval tv;
|
|
82 if (gettimeofday(&tv, NULL)) {
|
|
83 perror("Couldn't get time of day?!");
|
|
84 exit(EXIT_FAILURE);
|
|
85 }
|
|
86 // Set up randomness
|
|
87 srandom(tv.tv_usec);
|
|
88 #endif
|
|
89 }
|
|
90 if(ick_printflow) setting_trace_level=9;
|
|
91 ick_interpreter_main_loop();
|
|
92 }
|
|
93
|
|
94 void ick_iffi_interpreter_one_iteration(void)
|
|
95 {
|
|
96 funge_cell opcode;
|
|
97 opcode = fungespace_get(&iffiIP->position);
|
|
98
|
|
99 if (setting_trace_level > 8) {
|
|
100 fprintf(stderr, "x=%" FUNGECELLPRI " y=%" FUNGECELLPRI
|
|
101 ": %c (%" FUNGECELLPRI ")\n",
|
|
102 iffiIP->position.x, iffiIP->position.y, (char)opcode, opcode);
|
|
103 stack_print_top(iffiIP->stack);
|
|
104 } else if (setting_trace_level > 3) {
|
|
105 fprintf(stderr, "x=%" FUNGECELLPRI " y=%" FUNGECELLPRI
|
|
106 ": %c (%" FUNGECELLPRI ")\n",
|
|
107 iffiIP->position.x, iffiIP->position.y, (char)opcode, opcode);
|
|
108 } else if (setting_trace_level > 2)
|
|
109 fprintf(stderr, "%c", (char)opcode);
|
|
110
|
|
111 execute_instruction(opcode, iffiIP);
|
|
112 if (iffiIP->needMove)
|
|
113 ip_forward(iffiIP);
|
|
114 else
|
|
115 iffiIP->needMove = true;
|
|
116 }
|
|
117
|
|
118 // A - CREATE a new INTERCAL instruction
|
|
119 static void finger_IFFI_create(instructionPointer * ip)
|
|
120 {
|
|
121 // arguments: line number on TOS, signature as 0gnirts beneath it
|
|
122 funge_cell l = stack_pop(ip->stack);
|
|
123 unsigned char * restrict str = stack_pop_string(ip->stack, NULL);
|
|
124 ick_create((const char*)str, l);
|
|
125 }
|
|
126
|
|
127 // C - In markmode COME FROM the top of stack
|
|
128 static void finger_IFFI_come_from(instructionPointer * ip)
|
|
129 {
|
|
130 funge_cell l;
|
|
131
|
|
132 l = stack_pop(ip->stack);
|
|
133
|
|
134 if (ick_iffi_inmarkmode) {
|
|
135 ick_iffi_breakloop = 1;
|
|
136 ick_iffi_linelabel = l;
|
|
137 ick_iffi_comingfrom = 1;
|
|
138 }
|
|
139 }
|
|
140
|
|
141 // D - Push information about a CREATED instruction argument
|
|
142 static void finger_IFFI_create_data(instructionPointer * ip)
|
|
143 {
|
|
144 // Arguments: argument's index (0-based) on TOS
|
|
145 // Return: the following values (from bottom to top):
|
|
146 // The argument's data type, in bits
|
|
147 // Whether the argument is an array variable
|
|
148 // 0 if the argument is not a variable, or its number if it is
|
|
149 // The argument's value at the time the CREATED instruction was called
|
|
150 // The argument's value now (same as previous if -a was not used)
|
|
151 funge_cell i;
|
|
152
|
|
153 if (firstload) {
|
|
154 ip_reverse(ip);
|
|
155 return;
|
|
156 }
|
|
157
|
|
158 i = stack_pop(ip->stack);
|
|
159
|
|
160 stack_push(ip->stack, ick_c_i_width(i));
|
|
161 stack_push(ip->stack, ick_c_i_isarray(i));
|
|
162 stack_push(ip->stack, ick_c_i_varnumber(i));
|
|
163 stack_push(ip->stack, ick_c_i_value(i));
|
|
164 stack_push(ip->stack, ick_c_i_getvalue(i));
|
|
165 }
|
|
166
|
|
167 // F - FORGET NEXT stack entries equal to top of stack
|
|
168 static void finger_IFFI_forget(instructionPointer * ip)
|
|
169 {
|
|
170 funge_cell f;
|
|
171
|
|
172 if (firstload) {
|
|
173 ip_reverse(ip);
|
|
174 return;
|
|
175 }
|
|
176
|
|
177 if (ick_iffi_inmarkmode) { /* this is an error in the user's code */
|
|
178 ip_reverse(ip);
|
|
179 return;
|
|
180 }
|
|
181
|
|
182 f = stack_pop(ip->stack);
|
|
183
|
|
184 if (f > 81 || f < 0) f = 81;
|
|
185
|
|
186 ick_iffi_forgetcount = f;
|
|
187 }
|
|
188
|
|
189 // G - Get the value of an INTERCAL scalar variable
|
|
190 static void finger_IFFI_var_get(instructionPointer * ip)
|
|
191 {
|
|
192 // arguments: var number on TOS
|
|
193 // var numbers are positive for onespot, negative for twospot
|
|
194 // return: the value of the variable
|
|
195
|
|
196 funge_cell v;
|
|
197
|
|
198 if (firstload) {
|
|
199 ip_reverse(ip);
|
|
200 return;
|
|
201 }
|
|
202
|
|
203 v = stack_pop(ip->stack);
|
|
204
|
|
205 if (v == 0) {
|
|
206 ip_reverse(ip);
|
|
207 } else if (v > 0) {
|
|
208 stack_push(ip->stack, ick_getonespot(v));
|
|
209 } else {
|
|
210 stack_push(ip->stack, ick_gettwospot(-v));
|
|
211 }
|
|
212 }
|
|
213
|
|
214 // L - Use top of stack as a line label for this point
|
|
215 static void finger_IFFI_label(instructionPointer * ip)
|
|
216 {
|
|
217 funge_cell l;
|
|
218
|
|
219 if (firstload) {
|
|
220 ip_reverse(ip);
|
|
221 return;
|
|
222 }
|
|
223
|
|
224 l = stack_pop(ip->stack);
|
|
225
|
|
226 ick_iffi_breakloop = 1;
|
|
227 ick_iffi_linelabel = l;
|
|
228 ick_iffi_sucking = 1;
|
|
229 }
|
|
230
|
|
231 // M - Marks points where the code can be entered from outside
|
|
232 static void finger_IFFI_marker(instructionPointer * ip)
|
|
233 {
|
|
234 (void) ip;
|
|
235 ick_iffi_breakloop = ick_iffi_inmarkmode;
|
|
236 }
|
|
237
|
|
238 // N - Try to NEXT to the line labelled with the top of stack
|
|
239 static void finger_IFFI_next(instructionPointer * ip)
|
|
240 {
|
|
241 funge_cell l;
|
|
242
|
|
243 if (firstload) {
|
|
244 ip_reverse(ip);
|
|
245 return;
|
|
246 }
|
|
247
|
|
248 if (ick_iffi_inmarkmode) { /* this is an error in the user's code */
|
|
249 ip_reverse(ip);
|
|
250 return;
|
|
251 }
|
|
252
|
|
253 l = stack_pop(ip->stack);
|
|
254
|
|
255 ick_iffi_breakloop = 1;
|
|
256 ick_iffi_linelabel = l;
|
|
257 ick_iffi_nexting = 1;
|
|
258 }
|
|
259
|
|
260 // R - RESUME to the top-of-stackth NEXT stack entry
|
|
261 static void finger_IFFI_resume(instructionPointer * ip)
|
|
262 {
|
|
263 funge_cell f;
|
|
264
|
|
265 if (firstload) {
|
|
266 ip_reverse(ip);
|
|
267 return;
|
|
268 }
|
|
269
|
|
270 if (ick_iffi_inmarkmode) { /* this is an error in the user's code */
|
|
271 ip_reverse(ip);
|
|
272 return;
|
|
273 }
|
|
274
|
|
275 f = stack_pop(ip->stack);
|
|
276
|
|
277 if (f > 81 || f < 0) f = 81;
|
|
278
|
|
279 ick_iffi_forgetcount = f;
|
|
280
|
|
281 ick_iffi_resuming = 1;
|
|
282
|
|
283 ick_iffi_breakloop = 1;
|
|
284 }
|
|
285
|
|
286 // S - Set the value of an INTERCAL scalar variable
|
|
287 static void finger_IFFI_var_set(instructionPointer * ip)
|
|
288 {
|
|
289 // arguments: var number on TOS, new value beneath it
|
|
290 // var numbers are positive for onespot, negative for twospot
|
|
291 // return: the value of the variable
|
|
292
|
|
293 funge_cell v, d;
|
|
294
|
|
295 if (firstload) {
|
|
296 ip_reverse(ip);
|
|
297 return;
|
|
298 }
|
|
299
|
|
300 v = stack_pop(ip->stack);
|
|
301 d = stack_pop(ip->stack);
|
|
302
|
|
303 if (v == 0) {
|
|
304 ip_reverse(ip);
|
|
305 } else if (v > 0) {
|
|
306 ick_setonespot(v, d);
|
|
307 } else {
|
|
308 ick_settwospot(-v, d);
|
|
309 }
|
|
310 }
|
|
311
|
|
312 // V - Assign to a CREATEd instruction argument
|
|
313 static void finger_IFFI_arg_set(instructionPointer * ip)
|
|
314 {
|
|
315 // arguments: 0-based argument index on TOS, new value beneath it
|
|
316 // note that this is a NOP unless -a was used when compiling
|
|
317 funge_cell i, d;
|
|
318
|
|
319 if (firstload) {
|
|
320 ip_reverse(ip);
|
|
321 return;
|
|
322 }
|
|
323
|
|
324 i = stack_pop(ip->stack);
|
|
325 d = stack_pop(ip->stack);
|
|
326
|
|
327 ick_c_i_setvalue(i, d);
|
|
328 }
|
|
329
|
|
330 // X - In markmode NEXT FROM the top of stack
|
|
331 static void finger_IFFI_next_from(instructionPointer * ip)
|
|
332 {
|
|
333 funge_cell l;
|
|
334
|
|
335 l = stack_pop(ip->stack);
|
|
336
|
|
337 if (ick_iffi_inmarkmode) {
|
|
338 ick_iffi_breakloop = 1;
|
|
339 ick_iffi_linelabel = l;
|
|
340 ick_iffi_nextingfrom = 1;
|
|
341 }
|
|
342 }
|
|
343
|
|
344 // Y - Marks the end of initialisation
|
|
345 static void finger_IFFI_yield(instructionPointer * ip)
|
|
346 {
|
|
347 ick_iffi_breakloop = firstload;
|
|
348 if (! firstload)
|
|
349 ip_reverse(ip);
|
|
350 firstload = false;
|
|
351 }
|
|
352
|
|
353 bool finger_IFFI_load(instructionPointer * ip)
|
|
354 {
|
|
355 manager_add_opcode(IFFI, 'A', create)
|
|
356 manager_add_opcode(IFFI, 'C', come_from)
|
|
357 manager_add_opcode(IFFI, 'D', create_data)
|
|
358 manager_add_opcode(IFFI, 'F', forget)
|
|
359 manager_add_opcode(IFFI, 'G', var_get)
|
|
360 manager_add_opcode(IFFI, 'L', label)
|
|
361 manager_add_opcode(IFFI, 'M', marker)
|
|
362 manager_add_opcode(IFFI, 'N', next)
|
|
363 manager_add_opcode(IFFI, 'R', resume)
|
|
364 manager_add_opcode(IFFI, 'S', var_set)
|
|
365 manager_add_opcode(IFFI, 'V', arg_set)
|
|
366 manager_add_opcode(IFFI, 'X', next_from)
|
|
367 manager_add_opcode(IFFI, 'Y', yield)
|
|
368 return true;
|
|
369 }
|