Added variable and constant to common.retro module
[retro.git] / toka / parser.c
blob7713822877da75e9b1d293601c2aa555a9cd7b43
1 /******************************************************
2 * Toka
4 *|F|
5 *|F| FILE: parser.c
6 *|F|
8 * Copyright (c) 2006, 2007 Charles R. Childers
10 * Permission to use, copy, modify, and distribute this
11 * software for any purpose with or without fee is hereby
12 * granted, provided that the above copyright notice and
13 * this permission notice appear in all copies.
15 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR
16 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18 * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE
19 * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
20 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
21 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
22 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
23 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
24 * OF THIS SOFTWARE.
25 ******************************************************/
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <ctype.h>
32 #include <memory.h>
34 #include "toka.h"
35 extern VM_STACK data, address, alternate;
40 /******************************************************
41 *|F| Variables:
42 *|F| FILE *input[]
43 *|F| Current file stream to parse from. Setup as
44 *|F| an array of 8 inputs.
45 *|F|
46 *|F| long isp
47 *|F| Pointer to the most recent input source in the array
48 *|F|
49 *|F| long base
50 *|F| Holds the current numeric base
51 *|F|
52 *|F| long parser
53 *|F| When ON (TRUE), system parsing words will parse. When
54 *|F| OFF (FALSE), they will take a string from the stack.
55 *|F|
56 *|F| long escapes
57 *|F| When ON (TRUE), escape sequences will be handled
58 *|F| by the parser. When OFF (FALSE), they will be ignored.
59 *|F|
61 *|G| base ( -a ) Variable containg the current
62 *|G| numeric base
63 *|G| parser ( -a ) Variable holding current parser
64 *|G| mode.
65 *|G| escape-sequences ( -a) Variable determining if
66 *|G| escape sequences are used.
67 ******************************************************/
68 FILE *input[8];
69 long base=10;
70 long isp=0;
71 long parser=TRUE;
72 long escapes=TRUE;
75 /******************************************************
76 *|G| >number ( a-nf ) Attempt to convert a string
77 *|G| to a number
79 *|F| to_number()
80 *|F| Attempt to convert a string (on TOS) to a number.
81 *|F| This accepts a format of:
82 *|F| [prefix][-]number
83 *|F| If successful, it leaves the number and a flag of
84 *|F| TRUE on the stack. Otherwise, it leaves the original
85 *|F| string, and a flag of FALSE.
86 *|F|
87 ******************************************************/
88 void to_number()
90 char *s, *t;
91 long flag, old_base;
93 s = (char *)TOS; DROP;
94 t = s;
95 flag = TRUE;
96 old_base = base;
98 if (*t == '%')
100 base = 2;
101 t++; s++;
103 if (*t == '&')
105 base = 8;
106 t++; s++;
108 if (*t == '#')
110 base = 10;
111 t++; s++;
113 if (*t == '$')
115 base = 16;
116 t++; s++;
119 if (*t == '-')
120 t++;
122 for (; *t; t++)
124 if (base <= 10)
126 if (!isdigit(*t))
128 flag = FALSE;
129 break;
132 else
134 if (!isxdigit(*t))
136 flag = FALSE;
137 break;
142 if (flag == TRUE)
143 vm_push(strtol(s, (char **)NULL, base));
144 else
145 vm_push((long)s);
147 vm_push(flag);
148 base = old_base;
153 /******************************************************
154 *|G| >string ( n-a ) Convert a number to a string
156 *|F| to_string()
157 *|F| Convert a number (on TOS) to a string.
158 *|F|
159 ******************************************************/
160 void to_string()
162 char *s;
163 s = gc_alloc(128, sizeof(char), GC_MEM);
164 switch (base)
166 case 8: snprintf(s, 128, "%lo", TOS); break;
167 case 16: snprintf(s, 128, "%lx", TOS); break;
168 default: snprintf(s, 128, "%li", TOS); break;
170 TOS = (long)s;
175 /******************************************************
176 *|G| parse ( d-a ) Parse until the character
177 *|G| represented by 'd' is found.
178 *|G| Return a pointer to the string
180 *|F| parse()
181 *|F| Parse the input buffer until the character passed
182 *|F| on TOS is found, or until the end of the line is
183 *|F| encountered. Return a pointer to the resulting
184 *|F| string on the stack.
185 *|F|
186 ******************************************************/
187 void parse()
189 long delim;
190 char *s;
192 delim = TOS; DROP;
193 s = gc_alloc(4096, sizeof(char), GC_MEM);
194 get_token(s, delim);
199 /******************************************************
200 *|F| get_token(char *s, long delim)
201 *|F| Return a string (in "s") up to the specified
202 *|F| delimiter. This also puts the resulting string
203 *|F| on the stack.
204 *|F|
205 ******************************************************/
206 void get_token(char *s, long delim)
208 char *t;
209 long c;
211 t = s;
213 while (1)
215 if ((c = getc(input[isp])) == EOF && input[isp] != stdin)
217 fclose(input[isp]);
218 isp--;
219 break;
221 if (c == EOF && input[isp] == stdin)
223 exit(0);
226 if (c == '\\' && escapes == TRUE)
228 c = getc(input[isp]);
229 if (c == 'n')
231 *t++ = 10;
232 c = 1;
234 if (c == 'r')
236 *t++ = 13;
237 c = 1;
239 if (c == '"')
241 *t++ = (char)c;
242 c = 1;
244 if (c == '^')
246 *t++ = 27;
247 c = 1;
251 if (delim == 10 || delim == 32)
253 if (c == 10 || c == 13)
255 break;
259 if (c == delim)
260 break;
261 if (c >= 32 || c == 10 || c == 13)
262 *t++ = (char)c;
264 *t++ = 0;
265 vm_push((long)s);
270 /******************************************************
271 *|F| long include_file(char *s)
272 *|F| Attempt to open a file ("s") and add it to the
273 *|F| top of the input stack.
274 *|F|
275 ******************************************************/
276 long include_file(char *s)
278 FILE *file;
279 long flag;
281 file = fopen(s, "r");
282 flag = FALSE;
284 if (file)
286 isp++;
287 input[isp] = file;
288 flag = TRUE;
291 return flag;
296 /******************************************************
297 *|G| include ( "- ) Attempt to open a file and
298 *|G| add it to the input stack.
299 *|G| ( $- ) Non-parsing form
301 *|F| include()
302 *|F| Take a filename off the stack, attempt to open
303 *|F| it and add it to the input stream if successful.
304 *|F|
305 ******************************************************/
306 void include()
308 char *s;
310 if (PARSING)
312 s = gc_alloc(256, sizeof(char), GC_TEMP);
313 get_token(s, 32); DROP;
315 else
317 s = (char *)TOS; DROP;
320 include_file(s);
325 /******************************************************
326 *|G| needs ( "- ) Attempt to include a file
327 *|G| from the library (normally
328 *|G| /usr/share/toka/library)
329 *|G| ( $- ) Non-parsing form
331 *|F| needs()
332 *|F| Take a filename off the stack. Attempt to open it
333 *|F| from the library, and add it to the input stream
334 *|F| if successful.
335 *|F|
336 ******************************************************/
337 void needs()
339 char *s;
340 char *d;
342 d = gc_alloc(384, sizeof(char), GC_TEMP);
343 strcpy(d, LIBRARY);
345 if (PARSING)
347 s = gc_alloc(256, sizeof(char), GC_TEMP);
348 get_token(s, 32); DROP;
350 else
352 s = (char *)TOS; DROP;
355 strcat(d, s);
356 include_file(d);
360 /******************************************************
361 *|G| end. ( - ) Remove the current file from
362 *|G| the input stack
364 *|F| force_eof()
365 *|F| Remove the current file from the input stack. This
366 *|F| can be used to abort an include.
367 *|F|
368 ******************************************************/
369 void force_eof()
371 if (isp > 0)
373 fclose(input[isp]);
374 isp--;
376 else
378 error(ERROR_CLOSE_STDIN);