1 /*
2 Z88-DK Z80ASM - Z80 Assembler
3
4 Copyright (C) Gunther Strube, InterLogic 1993-99
5 Copyright (C) Paulo Custodio, 2011-2020
6 License: The Artistic License 2.0, http://www.perlfoundation.org/artistic_license_2_0
7 Repository: https://github.com/z88dk/z88dk
8
9 Scanner. Scanning engine is built by ragel from scan_rules.rl.
10 */
11
12 #include "alloc.h"
13 #include "errors.h"
14 #include "init.h"
15 #include "list.h"
16 #include "model.h"
17 #include "options.h"
18 #include "scan.h"
19 #include "str.h"
20 #include "utarray.h"
21 #include "die.h"
22 #include "zutils.h"
23
24 #include <ctype.h>
25
26 /*-----------------------------------------------------------------------------
27 * Globals
28 *----------------------------------------------------------------------------*/
29 Sym sym;
30 bool EOL;
31
32 /*-----------------------------------------------------------------------------
33 * Static - current scan context
34 *----------------------------------------------------------------------------*/
35 static Str *input_buf; /* current input buffer */
36 static List *input_stack; /* stack of previous contexts */
37
38 static bool at_bol; /* true if at beginning of line */
39
40 static int cs, act; /* Ragel state variables */
41 static char *p, *pe, *eof_, *ts, *te; /* Ragel state variables */
42
43 /* static DEFINE_STR(sym_string, STR_SIZE); */
44
45 static bool expect_opcode; /* true to return opcodes as tokens,
46 * false to return as names */
47
48 /* save scan status */
49 typedef struct scan_state_t
50 {
51 Sym sym;
52 char *input_buf;
53 bool at_bol;
54 bool EOL;
55 int cs, act;
56 int p, pe, eof_, ts, te;
57 // char *sym_string;
58 bool expect_opcode;
59 } ScanState;
60
ut_scan_state_dtor(void * elt)61 static void ut_scan_state_dtor(void *elt)
62 {
63 ScanState *state = elt;
64 m_free(state->input_buf);
65 // m_free(state->sym_string);
66 }
67 static UT_array *scan_state;
68 static UT_icd ut_scan_state_icd = { sizeof(ScanState), NULL, NULL, ut_scan_state_dtor };
69
70 /*-----------------------------------------------------------------------------
71 * Init, save and restore current sym
72 *----------------------------------------------------------------------------*/
init_sym(void)73 static void init_sym(void)
74 {
75 sym.tok = sym.tok_opcode = TK_END;
76 sym.tstart = "";
77 sym.tlen = 0;
78 #if 0
79 sym.text = "";
80 sym.string = NULL;
81 sym.filename = NULL;
82 sym.line_nr = 0;
83 #endif
84 sym.number = 0;
85 }
86
87 /*-----------------------------------------------------------------------------
88 * Init functions
89 *----------------------------------------------------------------------------*/
DEFINE_init_module()90 DEFINE_init_module()
91 {
92 input_buf = Str_new(STR_SIZE);
93 p = Str_data(input_buf);
94
95 input_stack = OBJ_NEW(List);
96 input_stack->free_data = m_free_compat;
97
98 init_sym();
99 utarray_new(scan_state, &ut_scan_state_icd);
100 }
101
DEFINE_dtor_module()102 DEFINE_dtor_module()
103 {
104 Str_delete(input_buf);
105 OBJ_DELETE(input_stack);
106 utarray_free(scan_state);
107 }
108
109 /*-----------------------------------------------------------------------------
110 * Save and restore current state
111 *----------------------------------------------------------------------------*/
save_scan_state(void)112 void save_scan_state(void)
113 {
114 ScanState save;
115
116 init_module();
117
118 save.sym = sym;
119 save.input_buf = m_strdup(Str_data(input_buf));
120 save.at_bol = at_bol;
121 save.EOL = EOL;
122 save.cs = cs;
123 save.act = act;
124 save.p = p ? p - Str_data(input_buf) : -1;
125 save.pe = pe ? pe - Str_data(input_buf) : -1;
126 save.eof_ = eof_ ? eof_ - Str_data(input_buf) : -1;
127 save.ts = ts ? ts - Str_data(input_buf) : -1;
128 save.te = te ? te - Str_data(input_buf) : -1;
129 // save.sym_string = m_strdup(sym_string->str);
130 save.expect_opcode = expect_opcode;
131
132 utarray_push_back(scan_state, &save);
133 }
134
restore_scan_state(void)135 void restore_scan_state(void)
136 {
137 ScanState *save;
138
139 init_module();
140
141 save = (ScanState *)utarray_back(scan_state);
142 sym = save->sym;
143 Str_set(input_buf, save->input_buf);
144 at_bol = save->at_bol;
145 EOL = save->EOL;
146 cs = save->cs;
147 act = save->act;
148 p = save->p >= 0 ? Str_data(input_buf) + save->p : NULL;
149 pe = save->pe >= 0 ? Str_data(input_buf) + save->pe : NULL;
150 eof_ = save->eof_ >= 0 ? Str_data(input_buf) + save->eof_ : NULL;
151 ts = save->ts >= 0 ? Str_data(input_buf) + save->ts : NULL;
152 te = save->te >= 0 ? Str_data(input_buf) + save->te : NULL;
153 // Str_set(sym_string, save->sym_string);
154 expect_opcode = save->expect_opcode;
155
156 utarray_pop_back(scan_state);
157 }
158
drop_scan_state(void)159 void drop_scan_state(void)
160 {
161 init_module();
162
163 utarray_pop_back(scan_state);
164 }
165
scan_expect_opcode(void)166 void scan_expect_opcode(void)
167 {
168 init_module();
169
170 expect_opcode = true;
171
172 /* convert current symbol */
173 if (sym.tok_opcode)
174 sym.tok = sym.tok_opcode;
175 }
176
scan_expect_operands(void)177 void scan_expect_operands(void)
178 {
179 init_module();
180
181 expect_opcode = false;
182
183 /* convert current symbol */
184 if (sym.tok_opcode)
185 sym.tok = TK_NAME;
186 }
187
188
189 /*-----------------------------------------------------------------------------
190 * convert number to int, range warning if greater than INT_MAX
191 *----------------------------------------------------------------------------*/
scan_num(char * text,int length,int base)192 static long scan_num ( char *text, int length, int base )
193 {
194 long value;
195 int digit = 0;
196 char c;
197 int i;
198
199 value = 0;
200 for ( i = 0 ; i < length ; i++ )
201 {
202 c = *text++; /* read each digit */
203 if ( isdigit(c) )
204 {
205 digit = c - '0';
206 }
207 else if ( isalpha(c) )
208 {
209 digit = toupper(c) - 'A' + 10;
210 }
211 else if ( base == 2 && (c == '-' || c == '#') )
212 {
213 digit = (c == '#') ? 1 : 0;
214 }
215 else
216 {
217 xassert(0); /* invalid digit - should not be reached */
218 }
219
220 if (digit >= base)
221 {
222 xassert(0); /* digit out of range - should not be reached */
223 }
224
225 value = value * base + digit;
226 }
227
228 return value;
229 }
230
231 /*-----------------------------------------------------------------------------
232 * copy tok_string, start with p pointing at the start quote (' or "),
233 * end with p pointing at the end quote, copy characters to tok_string
234 * handling C escape sequences. Return false if string not terminated.
235 *----------------------------------------------------------------------------*/
get_sym_string(void)236 static bool get_sym_string( void )
237 {
238 char quote;
239
240 /* mark token start */
241 quote = *p++;
242 xassert( quote == '"' || quote == '\'' );
243 ts = p;
244
245 /* search for end quote or end of string */
246 while (true)
247 {
248 if (*p == '\\' && p[1] != '\0')
249 p++; /* skip char after backslash, may be a quote */
250 else if (*p == quote)
251 {
252 te = p;
253 return true;
254 }
255 else if (*p == '\n' || *p == '\0')
256 {
257 te = ts;
258 p--; /* point to before separator */
259 return false;
260 }
261
262 /* advance to next */
263 p++;
264 }
265 }
266
267 /*-----------------------------------------------------------------------------
268 * skip up to and not including newline
269 *----------------------------------------------------------------------------*/
skip_to_newline(void)270 static void skip_to_newline( void )
271 {
272 char *newline = strchr( p, '\n' );
273 if ( newline != NULL && newline > p )
274 p = newline - 1;
275 }
276
277 /*-----------------------------------------------------------------------------
278 * Skip line past the newline, set EOL
279 *----------------------------------------------------------------------------*/
Skipline(void)280 void Skipline( void )
281 {
282 init_module();
283
284 if ( ! EOL )
285 {
286 char *newline = strchr( p, '\n' );
287 if ( newline == NULL )
288 p += strlen(p);
289 else
290 p = newline + 1;
291
292 EOL = true;
293 }
294 }
295
296
297 /*-----------------------------------------------------------------------------
298 * Import scanner generated by ragel
299 *----------------------------------------------------------------------------*/
300 #include "scan_rules.h"
301
302 /*-----------------------------------------------------------------------------
303 * Fill scan buffer if needed, return false on end of file
304 *----------------------------------------------------------------------------*/
fill_buffer(void)305 static bool fill_buffer( void )
306 {
307 char *line;
308
309 while ( *p == '\0' )
310 {
311 /* get last buffer from stack, if any */
312 line = List_pop( input_stack );
313 if ( line != NULL )
314 {
315 set_scan_buf( line, false ); /* read from stack - assume not at BOL */
316 m_free( line );
317 }
318 else
319 {
320 /* get next line from input source file */
321 line = src_getline();
322 if ( line == NULL )
323 return false;
324
325 /* got new line */
326 set_scan_buf( line, true ); /* read from file - at BOL */
327 }
328 }
329
330 return true;
331 }
332
333 /*-----------------------------------------------------------------------------
334 * Get the next token, fill the corresponding tok* variables
335 *----------------------------------------------------------------------------*/
GetSym(void)336 tokid_t GetSym( void )
337 {
338 init_module();
339
340 init_sym();
341
342 /* keep returning TK_NEWLINE until EOL is cleared
343 * NOTE: HACK for inconsistent parser in handling newlines, should be removed */
344 if ( EOL )
345 {
346 at_bol = true;
347 sym.tstart = "\n"; sym.tlen = 1;
348 return (sym.tok = TK_NEWLINE); /* assign and return */
349 }
350
351 /* loop filling buffer when needed */
352 do
353 {
354 /* refill buffer if needed, check for end of file */
355 if ( ! fill_buffer() )
356 {
357 sym.tok = TK_END;
358 ts = te = p;
359 break;
360 }
361
362 /* run the state machine */
363 sym.tok = _scan_get();
364
365 } while ( sym.tok == TK_END );
366
367 sym.tstart = ts; sym.tlen = te - ts; /* remember token position */
368
369 at_bol = EOL = (sym.tok == TK_NEWLINE) ? true : false;
370 return sym.tok;
371 }
372
373
374 /* get the next token, error if not the expected one */
GetSymExpect(tokid_t expected_tok)375 void GetSymExpect(tokid_t expected_tok)
376 {
377 init_module();
378
379 GetSym();
380 CurSymExpect(expected_tok);
381 }
382
383
384 /* check the current token, error if not the expected one */
CurSymExpect(tokid_t expected_tok)385 void CurSymExpect(tokid_t expected_tok)
386 {
387 init_module();
388
389 if (sym.tok != expected_tok)
390 error_syntax();
391 }
392
393
394 /*-----------------------------------------------------------------------------
395 * Insert the given text at the current scan position
396 *----------------------------------------------------------------------------*/
SetTemporaryLine(const char * line)397 void SetTemporaryLine(const char *line )
398 {
399 init_module();
400
401 #if 0
402 if (*p != '\0')
403 List_push(&input_stack, m_strdup(p)); /* save current input */
404 #endif
405 set_scan_buf( line, false ); /* assume not at BOL */
406 }
407
408 /*-----------------------------------------------------------------------------
409 * return static string with current token text
410 * non-reentrant, string needs to be saved by caller
411 *----------------------------------------------------------------------------*/
sym_text(Sym * sym)412 char *sym_text(Sym *sym)
413 {
414 static STR_DEFINE(text, STR_SIZE);
415
416 Str_set_bytes(text, sym->tstart, sym->tlen);
417 return Str_data(text);
418 }
419