1 | /* ----------------------------------------------------------------------- * |
2 | * |
3 | * Copyright 1996-2018 The NASM Authors - All Rights Reserved |
4 | * See the file AUTHORS included with the NASM distribution for |
5 | * the specific copyright holders. |
6 | * |
7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following |
9 | * conditions are met: |
10 | * |
11 | * * Redistributions of source code must retain the above copyright |
12 | * notice, this list of conditions and the following disclaimer. |
13 | * * Redistributions in binary form must reproduce the above |
14 | * copyright notice, this list of conditions and the following |
15 | * disclaimer in the documentation and/or other materials provided |
16 | * with the distribution. |
17 | * |
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
19 | * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |
20 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
22 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
23 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
24 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
25 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
26 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
29 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, |
30 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
31 | * |
32 | * ----------------------------------------------------------------------- */ |
33 | |
34 | /* |
35 | * preproc.c macro preprocessor for the Netwide Assembler |
36 | */ |
37 | |
38 | /* Typical flow of text through preproc |
39 | * |
40 | * pp_getline gets tokenized lines, either |
41 | * |
42 | * from a macro expansion |
43 | * |
44 | * or |
45 | * { |
46 | * read_line gets raw text from stdmacpos, or predef, or current input file |
47 | * tokenize converts to tokens |
48 | * } |
49 | * |
50 | * expand_mmac_params is used to expand %1 etc., unless a macro is being |
51 | * defined or a false conditional is being processed |
52 | * (%0, %1, %+1, %-1, %%foo |
53 | * |
54 | * do_directive checks for directives |
55 | * |
56 | * expand_smacro is used to expand single line macros |
57 | * |
58 | * expand_mmacro is used to expand multi-line macros |
59 | * |
60 | * detoken is used to convert the line back to text |
61 | */ |
62 | |
63 | #include "compiler.h" |
64 | |
65 | #include <stdio.h> |
66 | #include <stdarg.h> |
67 | #include <stdlib.h> |
68 | #include <stddef.h> |
69 | #include <string.h> |
70 | #include <ctype.h> |
71 | #include <limits.h> |
72 | |
73 | #include "nasm.h" |
74 | #include "nasmlib.h" |
75 | #include "error.h" |
76 | #include "preproc.h" |
77 | #include "hashtbl.h" |
78 | #include "quote.h" |
79 | #include "stdscan.h" |
80 | #include "eval.h" |
81 | #include "tokens.h" |
82 | #include "tables.h" |
83 | #include "listing.h" |
84 | |
85 | typedef struct SMacro SMacro; |
86 | typedef struct MMacro MMacro; |
87 | typedef struct MMacroInvocation MMacroInvocation; |
88 | typedef struct Context Context; |
89 | typedef struct Token Token; |
90 | typedef struct Blocks Blocks; |
91 | typedef struct Line Line; |
92 | typedef struct Include Include; |
93 | typedef struct Cond Cond; |
94 | typedef struct IncPath IncPath; |
95 | |
96 | /* |
97 | * Note on the storage of both SMacro and MMacros: the hash table |
98 | * indexes them case-insensitively, and we then have to go through a |
99 | * linked list of potential case aliases (and, for MMacros, parameter |
100 | * ranges); this is to preserve the matching semantics of the earlier |
101 | * code. If the number of case aliases for a specific macro is a |
102 | * performance issue, you may want to reconsider your coding style. |
103 | */ |
104 | |
105 | /* |
106 | * Store the definition of a single-line macro. |
107 | */ |
108 | struct SMacro { |
109 | SMacro *next; |
110 | char *name; |
111 | bool casesense; |
112 | bool in_progress; |
113 | unsigned int nparam; |
114 | Token *expansion; |
115 | }; |
116 | |
117 | /* |
118 | * Store the definition of a multi-line macro. This is also used to |
119 | * store the interiors of `%rep...%endrep' blocks, which are |
120 | * effectively self-re-invoking multi-line macros which simply |
121 | * don't have a name or bother to appear in the hash tables. %rep |
122 | * blocks are signified by having a NULL `name' field. |
123 | * |
124 | * In a MMacro describing a `%rep' block, the `in_progress' field |
125 | * isn't merely boolean, but gives the number of repeats left to |
126 | * run. |
127 | * |
128 | * The `next' field is used for storing MMacros in hash tables; the |
129 | * `next_active' field is for stacking them on istk entries. |
130 | * |
131 | * When a MMacro is being expanded, `params', `iline', `nparam', |
132 | * `paramlen', `rotate' and `unique' are local to the invocation. |
133 | */ |
134 | struct MMacro { |
135 | MMacro *next; |
136 | MMacroInvocation *prev; /* previous invocation */ |
137 | char *name; |
138 | int nparam_min, nparam_max; |
139 | bool casesense; |
140 | bool plus; /* is the last parameter greedy? */ |
141 | bool nolist; /* is this macro listing-inhibited? */ |
142 | int64_t in_progress; /* is this macro currently being expanded? */ |
143 | int32_t max_depth; /* maximum number of recursive expansions allowed */ |
144 | Token *dlist; /* All defaults as one list */ |
145 | Token **defaults; /* Parameter default pointers */ |
146 | int ndefs; /* number of default parameters */ |
147 | Line *expansion; |
148 | |
149 | MMacro *next_active; |
150 | MMacro *rep_nest; /* used for nesting %rep */ |
151 | Token **params; /* actual parameters */ |
152 | Token *iline; /* invocation line */ |
153 | unsigned int nparam, rotate; |
154 | int *paramlen; |
155 | uint64_t unique; |
156 | int lineno; /* Current line number on expansion */ |
157 | uint64_t condcnt; /* number of if blocks... */ |
158 | |
159 | const char *fname; /* File where defined */ |
160 | int32_t xline; /* First line in macro */ |
161 | }; |
162 | |
163 | |
164 | /* Store the definition of a multi-line macro, as defined in a |
165 | * previous recursive macro expansion. |
166 | */ |
167 | struct MMacroInvocation { |
168 | MMacroInvocation *prev; /* previous invocation */ |
169 | Token **params; /* actual parameters */ |
170 | Token *iline; /* invocation line */ |
171 | unsigned int nparam, rotate; |
172 | int *paramlen; |
173 | uint64_t unique; |
174 | uint64_t condcnt; |
175 | }; |
176 | |
177 | |
178 | /* |
179 | * The context stack is composed of a linked list of these. |
180 | */ |
181 | struct Context { |
182 | Context *next; |
183 | char *name; |
184 | struct hash_table localmac; |
185 | uint32_t number; |
186 | }; |
187 | |
188 | /* |
189 | * This is the internal form which we break input lines up into. |
190 | * Typically stored in linked lists. |
191 | * |
192 | * Note that `type' serves a double meaning: TOK_SMAC_PARAM is not |
193 | * necessarily used as-is, but is intended to denote the number of |
194 | * the substituted parameter. So in the definition |
195 | * |
196 | * %define a(x,y) ( (x) & ~(y) ) |
197 | * |
198 | * the token representing `x' will have its type changed to |
199 | * TOK_SMAC_PARAM, but the one representing `y' will be |
200 | * TOK_SMAC_PARAM+1. |
201 | * |
202 | * TOK_INTERNAL_STRING is a dirty hack: it's a single string token |
203 | * which doesn't need quotes around it. Used in the pre-include |
204 | * mechanism as an alternative to trying to find a sensible type of |
205 | * quote to use on the filename we were passed. |
206 | */ |
207 | enum pp_token_type { |
208 | TOK_NONE = 0, TOK_WHITESPACE, , TOK_ID, |
209 | TOK_PREPROC_ID, TOK_STRING, |
210 | TOK_NUMBER, TOK_FLOAT, TOK_SMAC_END, TOK_OTHER, |
211 | TOK_INTERNAL_STRING, |
212 | TOK_PREPROC_Q, TOK_PREPROC_QQ, |
213 | TOK_PASTE, /* %+ */ |
214 | TOK_INDIRECT, /* %[...] */ |
215 | TOK_SMAC_PARAM, /* MUST BE LAST IN THE LIST!!! */ |
216 | TOK_MAX = INT_MAX /* Keep compiler from reducing the range */ |
217 | }; |
218 | |
219 | #define PP_CONCAT_MASK(x) (1 << (x)) |
220 | #define PP_CONCAT_MATCH(t, mask) (PP_CONCAT_MASK((t)->type) & mask) |
221 | |
222 | struct tokseq_match { |
223 | int mask_head; |
224 | int mask_tail; |
225 | }; |
226 | |
227 | struct Token { |
228 | Token *next; |
229 | char *text; |
230 | union { |
231 | SMacro *mac; /* associated macro for TOK_SMAC_END */ |
232 | size_t len; /* scratch length field */ |
233 | } a; /* Auxiliary data */ |
234 | enum pp_token_type type; |
235 | }; |
236 | |
237 | /* |
238 | * Multi-line macro definitions are stored as a linked list of |
239 | * these, which is essentially a container to allow several linked |
240 | * lists of Tokens. |
241 | * |
242 | * Note that in this module, linked lists are treated as stacks |
243 | * wherever possible. For this reason, Lines are _pushed_ on to the |
244 | * `expansion' field in MMacro structures, so that the linked list, |
245 | * if walked, would give the macro lines in reverse order; this |
246 | * means that we can walk the list when expanding a macro, and thus |
247 | * push the lines on to the `expansion' field in _istk_ in reverse |
248 | * order (so that when popped back off they are in the right |
249 | * order). It may seem cockeyed, and it relies on my design having |
250 | * an even number of steps in, but it works... |
251 | * |
252 | * Some of these structures, rather than being actual lines, are |
253 | * markers delimiting the end of the expansion of a given macro. |
254 | * This is for use in the cycle-tracking and %rep-handling code. |
255 | * Such structures have `finishes' non-NULL, and `first' NULL. All |
256 | * others have `finishes' NULL, but `first' may still be NULL if |
257 | * the line is blank. |
258 | */ |
259 | struct Line { |
260 | Line *next; |
261 | MMacro *finishes; |
262 | Token *first; |
263 | }; |
264 | |
265 | /* |
266 | * To handle an arbitrary level of file inclusion, we maintain a |
267 | * stack (ie linked list) of these things. |
268 | */ |
269 | struct Include { |
270 | Include *next; |
271 | FILE *fp; |
272 | Cond *conds; |
273 | Line *expansion; |
274 | const char *fname; |
275 | int lineno, lineinc; |
276 | MMacro *mstk; /* stack of active macros/reps */ |
277 | }; |
278 | |
279 | /* |
280 | * Include search path. This is simply a list of strings which get |
281 | * prepended, in turn, to the name of an include file, in an |
282 | * attempt to find the file if it's not in the current directory. |
283 | */ |
284 | struct IncPath { |
285 | IncPath *next; |
286 | char *path; |
287 | }; |
288 | |
289 | /* |
290 | * File real name hash, so we don't have to re-search the include |
291 | * path for every pass (and potentially more than that if a file |
292 | * is used more than once.) |
293 | */ |
294 | struct hash_table FileHash; |
295 | |
296 | /* |
297 | * Conditional assembly: we maintain a separate stack of these for |
298 | * each level of file inclusion. (The only reason we keep the |
299 | * stacks separate is to ensure that a stray `%endif' in a file |
300 | * included from within the true branch of a `%if' won't terminate |
301 | * it and cause confusion: instead, rightly, it'll cause an error.) |
302 | */ |
303 | struct Cond { |
304 | Cond *next; |
305 | int state; |
306 | }; |
307 | enum { |
308 | /* |
309 | * These states are for use just after %if or %elif: IF_TRUE |
310 | * means the condition has evaluated to truth so we are |
311 | * currently emitting, whereas IF_FALSE means we are not |
312 | * currently emitting but will start doing so if a %else comes |
313 | * up. In these states, all directives are admissible: %elif, |
314 | * %else and %endif. (And of course %if.) |
315 | */ |
316 | COND_IF_TRUE, COND_IF_FALSE, |
317 | /* |
318 | * These states come up after a %else: ELSE_TRUE means we're |
319 | * emitting, and ELSE_FALSE means we're not. In ELSE_* states, |
320 | * any %elif or %else will cause an error. |
321 | */ |
322 | COND_ELSE_TRUE, COND_ELSE_FALSE, |
323 | /* |
324 | * These states mean that we're not emitting now, and also that |
325 | * nothing until %endif will be emitted at all. COND_DONE is |
326 | * used when we've had our moment of emission |
327 | * and have now started seeing %elifs. COND_NEVER is used when |
328 | * the condition construct in question is contained within a |
329 | * non-emitting branch of a larger condition construct, |
330 | * or if there is an error. |
331 | */ |
332 | COND_DONE, COND_NEVER |
333 | }; |
334 | #define emitting(x) ( (x) == COND_IF_TRUE || (x) == COND_ELSE_TRUE ) |
335 | |
336 | /* |
337 | * These defines are used as the possible return values for do_directive |
338 | */ |
339 | #define NO_DIRECTIVE_FOUND 0 |
340 | #define DIRECTIVE_FOUND 1 |
341 | |
342 | /* max reps */ |
343 | #define REP_LIMIT ((INT64_C(1) << 62)) |
344 | |
345 | /* |
346 | * Condition codes. Note that we use c_ prefix not C_ because C_ is |
347 | * used in nasm.h for the "real" condition codes. At _this_ level, |
348 | * we treat CXZ and ECXZ as condition codes, albeit non-invertible |
349 | * ones, so we need a different enum... |
350 | */ |
351 | static const char * const conditions[] = { |
352 | "a" , "ae" , "b" , "be" , "c" , "cxz" , "e" , "ecxz" , "g" , "ge" , "l" , "le" , |
353 | "na" , "nae" , "nb" , "nbe" , "nc" , "ne" , "ng" , "nge" , "nl" , "nle" , "no" , |
354 | "np" , "ns" , "nz" , "o" , "p" , "pe" , "po" , "rcxz" , "s" , "z" |
355 | }; |
356 | enum pp_conds { |
357 | c_A, c_AE, c_B, c_BE, c_C, c_CXZ, c_E, c_ECXZ, c_G, c_GE, c_L, c_LE, |
358 | c_NA, c_NAE, c_NB, c_NBE, c_NC, c_NE, c_NG, c_NGE, c_NL, c_NLE, c_NO, |
359 | c_NP, c_NS, c_NZ, c_O, c_P, c_PE, c_PO, c_RCXZ, c_S, c_Z, |
360 | c_none = -1 |
361 | }; |
362 | static const enum pp_conds inverse_ccs[] = { |
363 | c_NA, c_NAE, c_NB, c_NBE, c_NC, -1, c_NE, -1, c_NG, c_NGE, c_NL, c_NLE, |
364 | c_A, c_AE, c_B, c_BE, c_C, c_E, c_G, c_GE, c_L, c_LE, c_O, c_P, c_S, |
365 | c_Z, c_NO, c_NP, c_PO, c_PE, -1, c_NS, c_NZ |
366 | }; |
367 | |
368 | /* |
369 | * Directive names. |
370 | */ |
371 | /* If this is a an IF, ELIF, ELSE or ENDIF keyword */ |
372 | static int is_condition(enum preproc_token arg) |
373 | { |
374 | return PP_IS_COND(arg) || (arg == PP_ELSE) || (arg == PP_ENDIF); |
375 | } |
376 | |
377 | /* For TASM compatibility we need to be able to recognise TASM compatible |
378 | * conditional compilation directives. Using the NASM pre-processor does |
379 | * not work, so we look for them specifically from the following list and |
380 | * then jam in the equivalent NASM directive into the input stream. |
381 | */ |
382 | |
383 | enum { |
384 | TM_ARG, TM_ELIF, TM_ELSE, TM_ENDIF, TM_IF, TM_IFDEF, TM_IFDIFI, |
385 | TM_IFNDEF, TM_INCLUDE, TM_LOCAL |
386 | }; |
387 | |
388 | static const char * const tasm_directives[] = { |
389 | "arg" , "elif" , "else" , "endif" , "if" , "ifdef" , "ifdifi" , |
390 | "ifndef" , "include" , "local" |
391 | }; |
392 | |
393 | static int StackSize = 4; |
394 | static const char *StackPointer = "ebp" ; |
395 | static int ArgOffset = 8; |
396 | static int LocalOffset = 0; |
397 | |
398 | static Context *cstk; |
399 | static Include *istk; |
400 | static IncPath *ipath = NULL; |
401 | |
402 | static int pass; /* HACK: pass 0 = generate dependencies only */ |
403 | static StrList **dephead; |
404 | |
405 | static uint64_t unique; /* unique identifier numbers */ |
406 | |
407 | static Line *predef = NULL; |
408 | static bool do_predef; |
409 | |
410 | /* |
411 | * The current set of multi-line macros we have defined. |
412 | */ |
413 | static struct hash_table mmacros; |
414 | |
415 | /* |
416 | * The current set of single-line macros we have defined. |
417 | */ |
418 | static struct hash_table smacros; |
419 | |
420 | /* |
421 | * The multi-line macro we are currently defining, or the %rep |
422 | * block we are currently reading, if any. |
423 | */ |
424 | static MMacro *defining; |
425 | |
426 | static uint64_t nested_mac_count; |
427 | static uint64_t nested_rep_count; |
428 | |
429 | /* |
430 | * The number of macro parameters to allocate space for at a time. |
431 | */ |
432 | #define PARAM_DELTA 16 |
433 | |
434 | /* |
435 | * The standard macro set: defined in macros.c in a set of arrays. |
436 | * This gives our position in any macro set, while we are processing it. |
437 | * The stdmacset is an array of such macro sets. |
438 | */ |
439 | static macros_t *stdmacpos; |
440 | static macros_t **stdmacnext; |
441 | static macros_t *stdmacros[8]; |
442 | static macros_t *; |
443 | |
444 | /* |
445 | * Tokens are allocated in blocks to improve speed |
446 | */ |
447 | #define TOKEN_BLOCKSIZE 4096 |
448 | static Token *freeTokens = NULL; |
449 | struct Blocks { |
450 | Blocks *next; |
451 | void *chunk; |
452 | }; |
453 | |
454 | static Blocks blocks = { NULL, NULL }; |
455 | |
456 | /* |
457 | * Forward declarations. |
458 | */ |
459 | static void pp_add_stdmac(macros_t *macros); |
460 | static Token *expand_mmac_params(Token * tline); |
461 | static Token *expand_smacro(Token * tline); |
462 | static Token *expand_id(Token * tline); |
463 | static Context *get_ctx(const char *name, const char **namep); |
464 | static void make_tok_num(Token * tok, int64_t val); |
465 | static void pp_verror(int severity, const char *fmt, va_list ap); |
466 | static vefunc real_verror; |
467 | static void *new_Block(size_t size); |
468 | static void delete_Blocks(void); |
469 | static Token *new_Token(Token * next, enum pp_token_type type, |
470 | const char *text, int txtlen); |
471 | static Token *delete_Token(Token * t); |
472 | |
473 | /* |
474 | * Macros for safe checking of token pointers, avoid *(NULL) |
475 | */ |
476 | #define tok_type_(x,t) ((x) && (x)->type == (t)) |
477 | #define skip_white_(x) if (tok_type_((x), TOK_WHITESPACE)) (x)=(x)->next |
478 | #define tok_is_(x,v) (tok_type_((x), TOK_OTHER) && !strcmp((x)->text,(v))) |
479 | #define tok_isnt_(x,v) ((x) && ((x)->type!=TOK_OTHER || strcmp((x)->text,(v)))) |
480 | |
481 | /* |
482 | * nasm_unquote with error if the string contains NUL characters. |
483 | * If the string contains NUL characters, issue an error and return |
484 | * the C len, i.e. truncate at the NUL. |
485 | */ |
486 | static size_t nasm_unquote_cstr(char *qstr, enum preproc_token directive) |
487 | { |
488 | size_t len = nasm_unquote(qstr, NULL); |
489 | size_t clen = strlen(qstr); |
490 | |
491 | if (len != clen) |
492 | nasm_error(ERR_NONFATAL, "NUL character in `%s' directive" , |
493 | pp_directives[directive]); |
494 | |
495 | return clen; |
496 | } |
497 | |
498 | /* |
499 | * In-place reverse a list of tokens. |
500 | */ |
501 | static Token *reverse_tokens(Token *t) |
502 | { |
503 | Token *prev = NULL; |
504 | Token *next; |
505 | |
506 | while (t) { |
507 | next = t->next; |
508 | t->next = prev; |
509 | prev = t; |
510 | t = next; |
511 | } |
512 | |
513 | return prev; |
514 | } |
515 | |
516 | /* |
517 | * Handle TASM specific directives, which do not contain a % in |
518 | * front of them. We do it here because I could not find any other |
519 | * place to do it for the moment, and it is a hack (ideally it would |
520 | * be nice to be able to use the NASM pre-processor to do it). |
521 | */ |
522 | static char *check_tasm_directive(char *line) |
523 | { |
524 | int32_t i, j, k, m, len; |
525 | char *p, *q, *oldline, oldchar; |
526 | |
527 | p = nasm_skip_spaces(line); |
528 | |
529 | /* Binary search for the directive name */ |
530 | i = -1; |
531 | j = ARRAY_SIZE(tasm_directives); |
532 | q = nasm_skip_word(p); |
533 | len = q - p; |
534 | if (len) { |
535 | oldchar = p[len]; |
536 | p[len] = 0; |
537 | while (j - i > 1) { |
538 | k = (j + i) / 2; |
539 | m = nasm_stricmp(p, tasm_directives[k]); |
540 | if (m == 0) { |
541 | /* We have found a directive, so jam a % in front of it |
542 | * so that NASM will then recognise it as one if it's own. |
543 | */ |
544 | p[len] = oldchar; |
545 | len = strlen(p); |
546 | oldline = line; |
547 | line = nasm_malloc(len + 2); |
548 | line[0] = '%'; |
549 | if (k == TM_IFDIFI) { |
550 | /* |
551 | * NASM does not recognise IFDIFI, so we convert |
552 | * it to %if 0. This is not used in NASM |
553 | * compatible code, but does need to parse for the |
554 | * TASM macro package. |
555 | */ |
556 | strcpy(line + 1, "if 0" ); |
557 | } else { |
558 | memcpy(line + 1, p, len + 1); |
559 | } |
560 | nasm_free(oldline); |
561 | return line; |
562 | } else if (m < 0) { |
563 | j = k; |
564 | } else |
565 | i = k; |
566 | } |
567 | p[len] = oldchar; |
568 | } |
569 | return line; |
570 | } |
571 | |
572 | /* |
573 | * The pre-preprocessing stage... This function translates line |
574 | * number indications as they emerge from GNU cpp (`# lineno "file" |
575 | * flags') into NASM preprocessor line number indications (`%line |
576 | * lineno file'). |
577 | */ |
578 | static char *prepreproc(char *line) |
579 | { |
580 | int lineno, fnlen; |
581 | char *fname, *oldline; |
582 | |
583 | if (line[0] == '#' && line[1] == ' ') { |
584 | oldline = line; |
585 | fname = oldline + 2; |
586 | lineno = atoi(fname); |
587 | fname += strspn(fname, "0123456789 " ); |
588 | if (*fname == '"') |
589 | fname++; |
590 | fnlen = strcspn(fname, "\"" ); |
591 | line = nasm_malloc(20 + fnlen); |
592 | snprintf(line, 20 + fnlen, "%%line %d %.*s" , lineno, fnlen, fname); |
593 | nasm_free(oldline); |
594 | } |
595 | if (tasm_compatible_mode) |
596 | return check_tasm_directive(line); |
597 | return line; |
598 | } |
599 | |
600 | /* |
601 | * Free a linked list of tokens. |
602 | */ |
603 | static void free_tlist(Token * list) |
604 | { |
605 | while (list) |
606 | list = delete_Token(list); |
607 | } |
608 | |
609 | /* |
610 | * Free a linked list of lines. |
611 | */ |
612 | static void free_llist(Line * list) |
613 | { |
614 | Line *l, *tmp; |
615 | list_for_each_safe(l, tmp, list) { |
616 | free_tlist(l->first); |
617 | nasm_free(l); |
618 | } |
619 | } |
620 | |
621 | /* |
622 | * Free an MMacro |
623 | */ |
624 | static void free_mmacro(MMacro * m) |
625 | { |
626 | nasm_free(m->name); |
627 | free_tlist(m->dlist); |
628 | nasm_free(m->defaults); |
629 | free_llist(m->expansion); |
630 | nasm_free(m); |
631 | } |
632 | |
633 | /* |
634 | * Free all currently defined macros, and free the hash tables |
635 | */ |
636 | static void free_smacro_table(struct hash_table *smt) |
637 | { |
638 | SMacro *s, *tmp; |
639 | const char *key; |
640 | struct hash_tbl_node *it = NULL; |
641 | |
642 | while ((s = hash_iterate(smt, &it, &key)) != NULL) { |
643 | nasm_free((void *)key); |
644 | list_for_each_safe(s, tmp, s) { |
645 | nasm_free(s->name); |
646 | free_tlist(s->expansion); |
647 | nasm_free(s); |
648 | } |
649 | } |
650 | hash_free(smt); |
651 | } |
652 | |
653 | static void free_mmacro_table(struct hash_table *mmt) |
654 | { |
655 | MMacro *m, *tmp; |
656 | const char *key; |
657 | struct hash_tbl_node *it = NULL; |
658 | |
659 | it = NULL; |
660 | while ((m = hash_iterate(mmt, &it, &key)) != NULL) { |
661 | nasm_free((void *)key); |
662 | list_for_each_safe(m ,tmp, m) |
663 | free_mmacro(m); |
664 | } |
665 | hash_free(mmt); |
666 | } |
667 | |
668 | static void free_macros(void) |
669 | { |
670 | free_smacro_table(&smacros); |
671 | free_mmacro_table(&mmacros); |
672 | } |
673 | |
674 | /* |
675 | * Initialize the hash tables |
676 | */ |
677 | static void init_macros(void) |
678 | { |
679 | hash_init(&smacros, HASH_LARGE); |
680 | hash_init(&mmacros, HASH_LARGE); |
681 | } |
682 | |
683 | /* |
684 | * Pop the context stack. |
685 | */ |
686 | static void ctx_pop(void) |
687 | { |
688 | Context *c = cstk; |
689 | |
690 | cstk = cstk->next; |
691 | free_smacro_table(&c->localmac); |
692 | nasm_free(c->name); |
693 | nasm_free(c); |
694 | } |
695 | |
696 | /* |
697 | * Search for a key in the hash index; adding it if necessary |
698 | * (in which case we initialize the data pointer to NULL.) |
699 | */ |
700 | static void ** |
701 | hash_findi_add(struct hash_table *hash, const char *str) |
702 | { |
703 | struct hash_insert hi; |
704 | void **r; |
705 | char *strx; |
706 | |
707 | r = hash_findi(hash, str, &hi); |
708 | if (r) |
709 | return r; |
710 | |
711 | strx = nasm_strdup(str); /* Use a more efficient allocator here? */ |
712 | return hash_add(&hi, strx, NULL); |
713 | } |
714 | |
715 | /* |
716 | * Like hash_findi, but returns the data element rather than a pointer |
717 | * to it. Used only when not adding a new element, hence no third |
718 | * argument. |
719 | */ |
720 | static void * |
721 | hash_findix(struct hash_table *hash, const char *str) |
722 | { |
723 | void **p; |
724 | |
725 | p = hash_findi(hash, str, NULL); |
726 | return p ? *p : NULL; |
727 | } |
728 | |
729 | /* |
730 | * read line from standart macros set, |
731 | * if there no more left -- return NULL |
732 | */ |
733 | static char *line_from_stdmac(void) |
734 | { |
735 | unsigned char c; |
736 | const unsigned char *p = stdmacpos; |
737 | char *line, *q; |
738 | size_t len = 0; |
739 | |
740 | if (!stdmacpos) |
741 | return NULL; |
742 | |
743 | while ((c = *p++)) { |
744 | if (c >= 0x80) |
745 | len += pp_directives_len[c - 0x80] + 1; |
746 | else |
747 | len++; |
748 | } |
749 | |
750 | line = nasm_malloc(len + 1); |
751 | q = line; |
752 | while ((c = *stdmacpos++)) { |
753 | if (c >= 0x80) { |
754 | memcpy(q, pp_directives[c - 0x80], pp_directives_len[c - 0x80]); |
755 | q += pp_directives_len[c - 0x80]; |
756 | *q++ = ' '; |
757 | } else { |
758 | *q++ = c; |
759 | } |
760 | } |
761 | stdmacpos = p; |
762 | *q = '\0'; |
763 | |
764 | if (!*stdmacpos) { |
765 | /* This was the last of this particular macro set */ |
766 | stdmacpos = NULL; |
767 | if (*stdmacnext) { |
768 | stdmacpos = *stdmacnext++; |
769 | } else if (do_predef) { |
770 | Line *pd, *l; |
771 | Token *head, **tail, *t; |
772 | |
773 | /* |
774 | * Nasty hack: here we push the contents of |
775 | * `predef' on to the top-level expansion stack, |
776 | * since this is the most convenient way to |
777 | * implement the pre-include and pre-define |
778 | * features. |
779 | */ |
780 | list_for_each(pd, predef) { |
781 | head = NULL; |
782 | tail = &head; |
783 | list_for_each(t, pd->first) { |
784 | *tail = new_Token(NULL, t->type, t->text, 0); |
785 | tail = &(*tail)->next; |
786 | } |
787 | |
788 | l = nasm_malloc(sizeof(Line)); |
789 | l->next = istk->expansion; |
790 | l->first = head; |
791 | l->finishes = NULL; |
792 | |
793 | istk->expansion = l; |
794 | } |
795 | do_predef = false; |
796 | } |
797 | } |
798 | |
799 | return line; |
800 | } |
801 | |
802 | static char *read_line(void) |
803 | { |
804 | unsigned int size, c, next; |
805 | const unsigned int delta = 512; |
806 | const unsigned int pad = 8; |
807 | unsigned int nr_cont = 0; |
808 | bool cont = false; |
809 | char *buffer, *p; |
810 | |
811 | /* Standart macros set (predefined) goes first */ |
812 | p = line_from_stdmac(); |
813 | if (p) |
814 | return p; |
815 | |
816 | size = delta; |
817 | p = buffer = nasm_malloc(size); |
818 | |
819 | for (;;) { |
820 | c = fgetc(istk->fp); |
821 | if ((int)(c) == EOF) { |
822 | p[0] = 0; |
823 | break; |
824 | } |
825 | |
826 | switch (c) { |
827 | case '\r': |
828 | next = fgetc(istk->fp); |
829 | if (next != '\n') |
830 | ungetc(next, istk->fp); |
831 | if (cont) { |
832 | cont = false; |
833 | continue; |
834 | } |
835 | break; |
836 | |
837 | case '\n': |
838 | if (cont) { |
839 | cont = false; |
840 | continue; |
841 | } |
842 | break; |
843 | |
844 | case '\\': |
845 | next = fgetc(istk->fp); |
846 | ungetc(next, istk->fp); |
847 | if (next == '\r' || next == '\n') { |
848 | cont = true; |
849 | nr_cont++; |
850 | continue; |
851 | } |
852 | break; |
853 | } |
854 | |
855 | if (c == '\r' || c == '\n') { |
856 | *p++ = 0; |
857 | break; |
858 | } |
859 | |
860 | if (p >= (buffer + size - pad)) { |
861 | buffer = nasm_realloc(buffer, size + delta); |
862 | p = buffer + size - pad; |
863 | size += delta; |
864 | } |
865 | |
866 | *p++ = (unsigned char)c; |
867 | } |
868 | |
869 | if (p == buffer) { |
870 | nasm_free(buffer); |
871 | return NULL; |
872 | } |
873 | |
874 | src_set_linnum(src_get_linnum() + istk->lineinc + |
875 | (nr_cont * istk->lineinc)); |
876 | |
877 | /* |
878 | * Handle spurious ^Z, which may be inserted into source files |
879 | * by some file transfer utilities. |
880 | */ |
881 | buffer[strcspn(buffer, "\032" )] = '\0'; |
882 | |
883 | lfmt->line(LIST_READ, buffer); |
884 | |
885 | return buffer; |
886 | } |
887 | |
888 | /* |
889 | * Tokenize a line of text. This is a very simple process since we |
890 | * don't need to parse the value out of e.g. numeric tokens: we |
891 | * simply split one string into many. |
892 | */ |
893 | static Token *tokenize(char *line) |
894 | { |
895 | char c, *p = line; |
896 | enum pp_token_type type; |
897 | Token *list = NULL; |
898 | Token *t, **tail = &list; |
899 | |
900 | while (*line) { |
901 | p = line; |
902 | if (*p == '%') { |
903 | p++; |
904 | if (*p == '+' && !nasm_isdigit(p[1])) { |
905 | p++; |
906 | type = TOK_PASTE; |
907 | } else if (nasm_isdigit(*p) || |
908 | ((*p == '-' || *p == '+') && nasm_isdigit(p[1]))) { |
909 | do { |
910 | p++; |
911 | } |
912 | while (nasm_isdigit(*p)); |
913 | type = TOK_PREPROC_ID; |
914 | } else if (*p == '{') { |
915 | p++; |
916 | while (*p) { |
917 | if (*p == '}') |
918 | break; |
919 | p[-1] = *p; |
920 | p++; |
921 | } |
922 | if (*p != '}') |
923 | nasm_error(ERR_WARNING | ERR_PASS1, |
924 | "unterminated %%{ construct" ); |
925 | p[-1] = '\0'; |
926 | if (*p) |
927 | p++; |
928 | type = TOK_PREPROC_ID; |
929 | } else if (*p == '[') { |
930 | int lvl = 1; |
931 | line += 2; /* Skip the leading %[ */ |
932 | p++; |
933 | while (lvl && (c = *p++)) { |
934 | switch (c) { |
935 | case ']': |
936 | lvl--; |
937 | break; |
938 | case '%': |
939 | if (*p == '[') |
940 | lvl++; |
941 | break; |
942 | case '\'': |
943 | case '\"': |
944 | case '`': |
945 | p = nasm_skip_string(p - 1); |
946 | if (*p) |
947 | p++; |
948 | break; |
949 | default: |
950 | break; |
951 | } |
952 | } |
953 | p--; |
954 | if (*p) |
955 | *p++ = '\0'; |
956 | if (lvl) |
957 | nasm_error(ERR_NONFATAL|ERR_PASS1, |
958 | "unterminated %%[ construct" ); |
959 | type = TOK_INDIRECT; |
960 | } else if (*p == '?') { |
961 | type = TOK_PREPROC_Q; /* %? */ |
962 | p++; |
963 | if (*p == '?') { |
964 | type = TOK_PREPROC_QQ; /* %?? */ |
965 | p++; |
966 | } |
967 | } else if (*p == '!') { |
968 | type = TOK_PREPROC_ID; |
969 | p++; |
970 | if (isidchar(*p)) { |
971 | do { |
972 | p++; |
973 | } |
974 | while (isidchar(*p)); |
975 | } else if (*p == '\'' || *p == '\"' || *p == '`') { |
976 | p = nasm_skip_string(p); |
977 | if (*p) |
978 | p++; |
979 | else |
980 | nasm_error(ERR_NONFATAL|ERR_PASS1, |
981 | "unterminated %%! string" ); |
982 | } else { |
983 | /* %! without string or identifier */ |
984 | type = TOK_OTHER; /* Legacy behavior... */ |
985 | } |
986 | } else if (isidchar(*p) || |
987 | ((*p == '!' || *p == '%' || *p == '$') && |
988 | isidchar(p[1]))) { |
989 | do { |
990 | p++; |
991 | } |
992 | while (isidchar(*p)); |
993 | type = TOK_PREPROC_ID; |
994 | } else { |
995 | type = TOK_OTHER; |
996 | if (*p == '%') |
997 | p++; |
998 | } |
999 | } else if (isidstart(*p) || (*p == '$' && isidstart(p[1]))) { |
1000 | type = TOK_ID; |
1001 | p++; |
1002 | while (*p && isidchar(*p)) |
1003 | p++; |
1004 | } else if (*p == '\'' || *p == '"' || *p == '`') { |
1005 | /* |
1006 | * A string token. |
1007 | */ |
1008 | type = TOK_STRING; |
1009 | p = nasm_skip_string(p); |
1010 | |
1011 | if (*p) { |
1012 | p++; |
1013 | } else { |
1014 | nasm_error(ERR_WARNING|ERR_PASS1, "unterminated string" ); |
1015 | /* Handling unterminated strings by UNV */ |
1016 | /* type = -1; */ |
1017 | } |
1018 | } else if (p[0] == '$' && p[1] == '$') { |
1019 | type = TOK_OTHER; /* TOKEN_BASE */ |
1020 | p += 2; |
1021 | } else if (isnumstart(*p)) { |
1022 | bool is_hex = false; |
1023 | bool is_float = false; |
1024 | bool has_e = false; |
1025 | char c, *r; |
1026 | |
1027 | /* |
1028 | * A numeric token. |
1029 | */ |
1030 | |
1031 | if (*p == '$') { |
1032 | p++; |
1033 | is_hex = true; |
1034 | } |
1035 | |
1036 | for (;;) { |
1037 | c = *p++; |
1038 | |
1039 | if (!is_hex && (c == 'e' || c == 'E')) { |
1040 | has_e = true; |
1041 | if (*p == '+' || *p == '-') { |
1042 | /* |
1043 | * e can only be followed by +/- if it is either a |
1044 | * prefixed hex number or a floating-point number |
1045 | */ |
1046 | p++; |
1047 | is_float = true; |
1048 | } |
1049 | } else if (c == 'H' || c == 'h' || c == 'X' || c == 'x') { |
1050 | is_hex = true; |
1051 | } else if (c == 'P' || c == 'p') { |
1052 | is_float = true; |
1053 | if (*p == '+' || *p == '-') |
1054 | p++; |
1055 | } else if (isnumchar(c)) |
1056 | ; /* just advance */ |
1057 | else if (c == '.') { |
1058 | /* |
1059 | * we need to deal with consequences of the legacy |
1060 | * parser, like "1.nolist" being two tokens |
1061 | * (TOK_NUMBER, TOK_ID) here; at least give it |
1062 | * a shot for now. In the future, we probably need |
1063 | * a flex-based scanner with proper pattern matching |
1064 | * to do it as well as it can be done. Nothing in |
1065 | * the world is going to help the person who wants |
1066 | * 0x123.p16 interpreted as two tokens, though. |
1067 | */ |
1068 | r = p; |
1069 | while (*r == '_') |
1070 | r++; |
1071 | |
1072 | if (nasm_isdigit(*r) || (is_hex && nasm_isxdigit(*r)) || |
1073 | (!is_hex && (*r == 'e' || *r == 'E')) || |
1074 | (*r == 'p' || *r == 'P')) { |
1075 | p = r; |
1076 | is_float = true; |
1077 | } else |
1078 | break; /* Terminate the token */ |
1079 | } else |
1080 | break; |
1081 | } |
1082 | p--; /* Point to first character beyond number */ |
1083 | |
1084 | if (p == line+1 && *line == '$') { |
1085 | type = TOK_OTHER; /* TOKEN_HERE */ |
1086 | } else { |
1087 | if (has_e && !is_hex) { |
1088 | /* 1e13 is floating-point, but 1e13h is not */ |
1089 | is_float = true; |
1090 | } |
1091 | |
1092 | type = is_float ? TOK_FLOAT : TOK_NUMBER; |
1093 | } |
1094 | } else if (nasm_isspace(*p)) { |
1095 | type = TOK_WHITESPACE; |
1096 | p = nasm_skip_spaces(p); |
1097 | /* |
1098 | * Whitespace just before end-of-line is discarded by |
1099 | * pretending it's a comment; whitespace just before a |
1100 | * comment gets lumped into the comment. |
1101 | */ |
1102 | if (!*p || *p == ';') { |
1103 | type = TOK_COMMENT; |
1104 | while (*p) |
1105 | p++; |
1106 | } |
1107 | } else if (*p == ';') { |
1108 | type = TOK_COMMENT; |
1109 | while (*p) |
1110 | p++; |
1111 | } else { |
1112 | /* |
1113 | * Anything else is an operator of some kind. We check |
1114 | * for all the double-character operators (>>, <<, //, |
1115 | * %%, <=, >=, ==, !=, <>, &&, ||, ^^), but anything |
1116 | * else is a single-character operator. |
1117 | */ |
1118 | type = TOK_OTHER; |
1119 | if ((p[0] == '>' && p[1] == '>') || |
1120 | (p[0] == '<' && p[1] == '<') || |
1121 | (p[0] == '/' && p[1] == '/') || |
1122 | (p[0] == '<' && p[1] == '=') || |
1123 | (p[0] == '>' && p[1] == '=') || |
1124 | (p[0] == '=' && p[1] == '=') || |
1125 | (p[0] == '!' && p[1] == '=') || |
1126 | (p[0] == '<' && p[1] == '>') || |
1127 | (p[0] == '&' && p[1] == '&') || |
1128 | (p[0] == '|' && p[1] == '|') || |
1129 | (p[0] == '^' && p[1] == '^')) { |
1130 | p++; |
1131 | } |
1132 | p++; |
1133 | } |
1134 | |
1135 | /* Handling unterminated string by UNV */ |
1136 | /*if (type == -1) |
1137 | { |
1138 | *tail = t = new_Token(NULL, TOK_STRING, line, p-line+1); |
1139 | t->text[p-line] = *line; |
1140 | tail = &t->next; |
1141 | } |
1142 | else */ |
1143 | if (type != TOK_COMMENT) { |
1144 | *tail = t = new_Token(NULL, type, line, p - line); |
1145 | tail = &t->next; |
1146 | } |
1147 | line = p; |
1148 | } |
1149 | return list; |
1150 | } |
1151 | |
1152 | /* |
1153 | * this function allocates a new managed block of memory and |
1154 | * returns a pointer to the block. The managed blocks are |
1155 | * deleted only all at once by the delete_Blocks function. |
1156 | */ |
1157 | static void *new_Block(size_t size) |
1158 | { |
1159 | Blocks *b = &blocks; |
1160 | |
1161 | /* first, get to the end of the linked list */ |
1162 | while (b->next) |
1163 | b = b->next; |
1164 | /* now allocate the requested chunk */ |
1165 | b->chunk = nasm_malloc(size); |
1166 | |
1167 | /* now allocate a new block for the next request */ |
1168 | b->next = nasm_zalloc(sizeof(Blocks)); |
1169 | return b->chunk; |
1170 | } |
1171 | |
1172 | /* |
1173 | * this function deletes all managed blocks of memory |
1174 | */ |
1175 | static void delete_Blocks(void) |
1176 | { |
1177 | Blocks *a, *b = &blocks; |
1178 | |
1179 | /* |
1180 | * keep in mind that the first block, pointed to by blocks |
1181 | * is a static and not dynamically allocated, so we don't |
1182 | * free it. |
1183 | */ |
1184 | while (b) { |
1185 | if (b->chunk) |
1186 | nasm_free(b->chunk); |
1187 | a = b; |
1188 | b = b->next; |
1189 | if (a != &blocks) |
1190 | nasm_free(a); |
1191 | } |
1192 | memset(&blocks, 0, sizeof(blocks)); |
1193 | } |
1194 | |
1195 | /* |
1196 | * this function creates a new Token and passes a pointer to it |
1197 | * back to the caller. It sets the type and text elements, and |
1198 | * also the a.mac and next elements to NULL. |
1199 | */ |
1200 | static Token *new_Token(Token * next, enum pp_token_type type, |
1201 | const char *text, int txtlen) |
1202 | { |
1203 | Token *t; |
1204 | int i; |
1205 | |
1206 | if (!freeTokens) { |
1207 | freeTokens = (Token *) new_Block(TOKEN_BLOCKSIZE * sizeof(Token)); |
1208 | for (i = 0; i < TOKEN_BLOCKSIZE - 1; i++) |
1209 | freeTokens[i].next = &freeTokens[i + 1]; |
1210 | freeTokens[i].next = NULL; |
1211 | } |
1212 | t = freeTokens; |
1213 | freeTokens = t->next; |
1214 | t->next = next; |
1215 | t->a.mac = NULL; |
1216 | t->type = type; |
1217 | if (type == TOK_WHITESPACE || !text) { |
1218 | t->text = NULL; |
1219 | } else { |
1220 | if (txtlen == 0) |
1221 | txtlen = strlen(text); |
1222 | t->text = nasm_malloc(txtlen+1); |
1223 | memcpy(t->text, text, txtlen); |
1224 | t->text[txtlen] = '\0'; |
1225 | } |
1226 | return t; |
1227 | } |
1228 | |
1229 | static Token *delete_Token(Token * t) |
1230 | { |
1231 | Token *next = t->next; |
1232 | nasm_free(t->text); |
1233 | t->next = freeTokens; |
1234 | freeTokens = t; |
1235 | return next; |
1236 | } |
1237 | |
1238 | /* |
1239 | * Convert a line of tokens back into text. |
1240 | * If expand_locals is not zero, identifiers of the form "%$*xxx" |
1241 | * will be transformed into [email protected] |
1242 | */ |
1243 | static char *detoken(Token * tlist, bool expand_locals) |
1244 | { |
1245 | Token *t; |
1246 | char *line, *p; |
1247 | const char *q; |
1248 | int len = 0; |
1249 | |
1250 | list_for_each(t, tlist) { |
1251 | if (t->type == TOK_PREPROC_ID && t->text && |
1252 | t->text[0] && t->text[1] == '!') { |
1253 | char *v; |
1254 | char *q = t->text; |
1255 | |
1256 | v = t->text + 2; |
1257 | if (*v == '\'' || *v == '\"' || *v == '`') { |
1258 | size_t len = nasm_unquote(v, NULL); |
1259 | size_t clen = strlen(v); |
1260 | |
1261 | if (len != clen) { |
1262 | nasm_error(ERR_NONFATAL | ERR_PASS1, |
1263 | "NUL character in %%! string" ); |
1264 | v = NULL; |
1265 | } |
1266 | } |
1267 | |
1268 | if (v) { |
1269 | char *p = getenv(v); |
1270 | if (!p) { |
1271 | nasm_error(ERR_NONFATAL | ERR_PASS1, |
1272 | "nonexistent environment variable `%s'" , v); |
1273 | /* |
1274 | * FIXME We better should investigate if accessing |
1275 | * ->text[1] without ->text[0] is safe enough. |
1276 | */ |
1277 | t->text = nasm_zalloc(2); |
1278 | } else |
1279 | t->text = nasm_strdup(p); |
1280 | nasm_free(q); |
1281 | } |
1282 | } |
1283 | |
1284 | /* Expand local macros here and not during preprocessing */ |
1285 | if (expand_locals && |
1286 | t->type == TOK_PREPROC_ID && t->text && |
1287 | t->text[0] == '%' && t->text[1] == '$') { |
1288 | const char *q; |
1289 | char *p; |
1290 | Context *ctx = get_ctx(t->text, &q); |
1291 | if (ctx) { |
1292 | char buffer[40]; |
1293 | snprintf(buffer, sizeof(buffer), "..@%" PRIu32"." , ctx->number); |
1294 | p = nasm_strcat(buffer, q); |
1295 | nasm_free(t->text); |
1296 | t->text = p; |
1297 | } |
1298 | } |
1299 | if (t->type == TOK_WHITESPACE) |
1300 | len++; |
1301 | else if (t->text) |
1302 | len += strlen(t->text); |
1303 | } |
1304 | |
1305 | p = line = nasm_malloc(len + 1); |
1306 | |
1307 | list_for_each(t, tlist) { |
1308 | if (t->type == TOK_WHITESPACE) { |
1309 | *p++ = ' '; |
1310 | } else if (t->text) { |
1311 | q = t->text; |
1312 | while (*q) |
1313 | *p++ = *q++; |
1314 | } |
1315 | } |
1316 | *p = '\0'; |
1317 | |
1318 | return line; |
1319 | } |
1320 | |
1321 | /* |
1322 | * A scanner, suitable for use by the expression evaluator, which |
1323 | * operates on a line of Tokens. Expects a pointer to a pointer to |
1324 | * the first token in the line to be passed in as its private_data |
1325 | * field. |
1326 | * |
1327 | * FIX: This really needs to be unified with stdscan. |
1328 | */ |
1329 | static int ppscan(void *private_data, struct tokenval *tokval) |
1330 | { |
1331 | Token **tlineptr = private_data; |
1332 | Token *tline; |
1333 | char ourcopy[MAX_KEYWORD+1], *p, *r, *s; |
1334 | |
1335 | do { |
1336 | tline = *tlineptr; |
1337 | *tlineptr = tline ? tline->next : NULL; |
1338 | } while (tline && (tline->type == TOK_WHITESPACE || |
1339 | tline->type == TOK_COMMENT)); |
1340 | |
1341 | if (!tline) |
1342 | return tokval->t_type = TOKEN_EOS; |
1343 | |
1344 | tokval->t_charptr = tline->text; |
1345 | |
1346 | if (tline->text[0] == '$' && !tline->text[1]) |
1347 | return tokval->t_type = TOKEN_HERE; |
1348 | if (tline->text[0] == '$' && tline->text[1] == '$' && !tline->text[2]) |
1349 | return tokval->t_type = TOKEN_BASE; |
1350 | |
1351 | if (tline->type == TOK_ID) { |
1352 | p = tokval->t_charptr = tline->text; |
1353 | if (p[0] == '$') { |
1354 | tokval->t_charptr++; |
1355 | return tokval->t_type = TOKEN_ID; |
1356 | } |
1357 | |
1358 | for (r = p, s = ourcopy; *r; r++) { |
1359 | if (r >= p+MAX_KEYWORD) |
1360 | return tokval->t_type = TOKEN_ID; /* Not a keyword */ |
1361 | *s++ = nasm_tolower(*r); |
1362 | } |
1363 | *s = '\0'; |
1364 | /* right, so we have an identifier sitting in temp storage. now, |
1365 | * is it actually a register or instruction name, or what? */ |
1366 | return nasm_token_hash(ourcopy, tokval); |
1367 | } |
1368 | |
1369 | if (tline->type == TOK_NUMBER) { |
1370 | bool rn_error; |
1371 | tokval->t_integer = readnum(tline->text, &rn_error); |
1372 | tokval->t_charptr = tline->text; |
1373 | if (rn_error) |
1374 | return tokval->t_type = TOKEN_ERRNUM; |
1375 | else |
1376 | return tokval->t_type = TOKEN_NUM; |
1377 | } |
1378 | |
1379 | if (tline->type == TOK_FLOAT) { |
1380 | return tokval->t_type = TOKEN_FLOAT; |
1381 | } |
1382 | |
1383 | if (tline->type == TOK_STRING) { |
1384 | char bq, *ep; |
1385 | |
1386 | bq = tline->text[0]; |
1387 | tokval->t_charptr = tline->text; |
1388 | tokval->t_inttwo = nasm_unquote(tline->text, &ep); |
1389 | |
1390 | if (ep[0] != bq || ep[1] != '\0') |
1391 | return tokval->t_type = TOKEN_ERRSTR; |
1392 | else |
1393 | return tokval->t_type = TOKEN_STR; |
1394 | } |
1395 | |
1396 | if (tline->type == TOK_OTHER) { |
1397 | if (!strcmp(tline->text, "<<" )) |
1398 | return tokval->t_type = TOKEN_SHL; |
1399 | if (!strcmp(tline->text, ">>" )) |
1400 | return tokval->t_type = TOKEN_SHR; |
1401 | if (!strcmp(tline->text, "//" )) |
1402 | return tokval->t_type = TOKEN_SDIV; |
1403 | if (!strcmp(tline->text, "%%" )) |
1404 | return tokval->t_type = TOKEN_SMOD; |
1405 | if (!strcmp(tline->text, "==" )) |
1406 | return tokval->t_type = TOKEN_EQ; |
1407 | if (!strcmp(tline->text, "<>" )) |
1408 | return tokval->t_type = TOKEN_NE; |
1409 | if (!strcmp(tline->text, "!=" )) |
1410 | return tokval->t_type = TOKEN_NE; |
1411 | if (!strcmp(tline->text, "<=" )) |
1412 | return tokval->t_type = TOKEN_LE; |
1413 | if (!strcmp(tline->text, ">=" )) |
1414 | return tokval->t_type = TOKEN_GE; |
1415 | if (!strcmp(tline->text, "&&" )) |
1416 | return tokval->t_type = TOKEN_DBL_AND; |
1417 | if (!strcmp(tline->text, "^^" )) |
1418 | return tokval->t_type = TOKEN_DBL_XOR; |
1419 | if (!strcmp(tline->text, "||" )) |
1420 | return tokval->t_type = TOKEN_DBL_OR; |
1421 | } |
1422 | |
1423 | /* |
1424 | * We have no other options: just return the first character of |
1425 | * the token text. |
1426 | */ |
1427 | return tokval->t_type = tline->text[0]; |
1428 | } |
1429 | |
1430 | /* |
1431 | * Compare a string to the name of an existing macro; this is a |
1432 | * simple wrapper which calls either strcmp or nasm_stricmp |
1433 | * depending on the value of the `casesense' parameter. |
1434 | */ |
1435 | static int mstrcmp(const char *p, const char *q, bool casesense) |
1436 | { |
1437 | return casesense ? strcmp(p, q) : nasm_stricmp(p, q); |
1438 | } |
1439 | |
1440 | /* |
1441 | * Compare a string to the name of an existing macro; this is a |
1442 | * simple wrapper which calls either strcmp or nasm_stricmp |
1443 | * depending on the value of the `casesense' parameter. |
1444 | */ |
1445 | static int mmemcmp(const char *p, const char *q, size_t l, bool casesense) |
1446 | { |
1447 | return casesense ? memcmp(p, q, l) : nasm_memicmp(p, q, l); |
1448 | } |
1449 | |
1450 | /* |
1451 | * Return the Context structure associated with a %$ token. Return |
1452 | * NULL, having _already_ reported an error condition, if the |
1453 | * context stack isn't deep enough for the supplied number of $ |
1454 | * signs. |
1455 | * |
1456 | * If "namep" is non-NULL, set it to the pointer to the macro name |
1457 | * tail, i.e. the part beyond %$... |
1458 | */ |
1459 | static Context *get_ctx(const char *name, const char **namep) |
1460 | { |
1461 | Context *ctx; |
1462 | int i; |
1463 | |
1464 | if (namep) |
1465 | *namep = name; |
1466 | |
1467 | if (!name || name[0] != '%' || name[1] != '$') |
1468 | return NULL; |
1469 | |
1470 | if (!cstk) { |
1471 | nasm_error(ERR_NONFATAL, "`%s': context stack is empty" , name); |
1472 | return NULL; |
1473 | } |
1474 | |
1475 | name += 2; |
1476 | ctx = cstk; |
1477 | i = 0; |
1478 | while (ctx && *name == '$') { |
1479 | name++; |
1480 | i++; |
1481 | ctx = ctx->next; |
1482 | } |
1483 | if (!ctx) { |
1484 | nasm_error(ERR_NONFATAL, "`%s': context stack is only" |
1485 | " %d level%s deep" , name, i, (i == 1 ? "" : "s" )); |
1486 | return NULL; |
1487 | } |
1488 | |
1489 | if (namep) |
1490 | *namep = name; |
1491 | |
1492 | return ctx; |
1493 | } |
1494 | |
1495 | /* |
1496 | * Open an include file. This routine must always return a valid |
1497 | * file pointer if it returns - it's responsible for throwing an |
1498 | * ERR_FATAL and bombing out completely if not. It should also try |
1499 | * the include path one by one until it finds the file or reaches |
1500 | * the end of the path. |
1501 | * |
1502 | * Note: for INC_PROBE the function returns NULL at all times; |
1503 | * instead look for the |
1504 | */ |
1505 | enum incopen_mode { |
1506 | INC_NEEDED, /* File must exist */ |
1507 | INC_OPTIONAL, /* Missing is OK */ |
1508 | INC_PROBE /* Only an existence probe */ |
1509 | }; |
1510 | |
1511 | /* This is conducts a full pathname search */ |
1512 | static FILE *inc_fopen_search(const char *file, StrList **slpath, |
1513 | enum incopen_mode omode, enum file_flags fmode) |
1514 | { |
1515 | FILE *fp; |
1516 | char *prefix = "" ; |
1517 | const IncPath *ip = ipath; |
1518 | int len; |
1519 | StrList *sl; |
1520 | char *sp; |
1521 | bool found; |
1522 | |
1523 | while (1) { |
1524 | sp = nasm_catfile(prefix, file); |
1525 | len = strlen(sp) + 1; |
1526 | sl = nasm_malloc(len + sizeof sl->next); |
1527 | memcpy(sl->str, sp, len); |
1528 | sl->next = NULL; |
1529 | nasm_free(sp); |
1530 | |
1531 | if (omode == INC_PROBE) { |
1532 | fp = NULL; |
1533 | found = nasm_file_exists(sl->str); |
1534 | } else { |
1535 | fp = nasm_open_read(sl->str, fmode); |
1536 | found = (fp != NULL); |
1537 | } |
1538 | if (found) { |
1539 | *slpath = sl; |
1540 | return fp; |
1541 | } |
1542 | |
1543 | nasm_free(sl); |
1544 | |
1545 | if (!ip) |
1546 | return NULL; |
1547 | |
1548 | prefix = ip->path; |
1549 | ip = ip->next; |
1550 | } |
1551 | } |
1552 | |
1553 | /* |
1554 | * Open a file, or test for the presence of one (depending on omode), |
1555 | * considering the include path. |
1556 | */ |
1557 | static FILE *inc_fopen(const char *file, |
1558 | StrList **dhead, |
1559 | const char **found_path, |
1560 | enum incopen_mode omode, |
1561 | enum file_flags fmode) |
1562 | { |
1563 | StrList *sl; |
1564 | struct hash_insert hi; |
1565 | void **hp; |
1566 | char *path; |
1567 | FILE *fp = NULL; |
1568 | |
1569 | hp = hash_find(&FileHash, file, &hi); |
1570 | if (hp) { |
1571 | path = *hp; |
1572 | if (path || omode != INC_NEEDED) { |
1573 | nasm_add_string_to_strlist(dhead, path ? path : file); |
1574 | } |
1575 | } else { |
1576 | /* Need to do the actual path search */ |
1577 | size_t file_len; |
1578 | |
1579 | sl = NULL; |
1580 | fp = inc_fopen_search(file, &sl, omode, fmode); |
1581 | |
1582 | file_len = strlen(file); |
1583 | |
1584 | if (!sl) { |
1585 | /* Store negative result for this file */ |
1586 | sl = nasm_malloc(file_len + 1 + sizeof sl->next); |
1587 | memcpy(sl->str, file, file_len+1); |
1588 | sl->next = NULL; |
1589 | file = sl->str; |
1590 | path = NULL; |
1591 | } else { |
1592 | path = sl->str; |
1593 | file = strchr(path, '\0') - file_len; |
1594 | } |
1595 | |
1596 | hash_add(&hi, file, path); /* Positive or negative result */ |
1597 | |
1598 | /* |
1599 | * Add file to dependency path. The in_list() is needed |
1600 | * in case the file was already added with %depend. |
1601 | */ |
1602 | if (path || omode != INC_NEEDED) |
1603 | nasm_add_to_strlist(dhead, sl); |
1604 | } |
1605 | |
1606 | if (!path) { |
1607 | if (omode == INC_NEEDED) |
1608 | nasm_fatal(0, "unable to open include file `%s'" , file); |
1609 | |
1610 | if (found_path) |
1611 | *found_path = NULL; |
1612 | |
1613 | return NULL; |
1614 | } |
1615 | |
1616 | if (!fp && omode != INC_PROBE) |
1617 | fp = nasm_open_read(path, fmode); |
1618 | |
1619 | if (found_path) |
1620 | *found_path = path; |
1621 | |
1622 | return fp; |
1623 | } |
1624 | |
1625 | /* |
1626 | * Opens an include or input file. Public version, for use by modules |
1627 | * that get a file:lineno pair and need to look at the file again |
1628 | * (e.g. the CodeView debug backend). Returns NULL on failure. |
1629 | */ |
1630 | FILE *pp_input_fopen(const char *filename, enum file_flags mode) |
1631 | { |
1632 | return inc_fopen(filename, NULL, NULL, INC_OPTIONAL, mode); |
1633 | } |
1634 | |
1635 | /* |
1636 | * Determine if we should warn on defining a single-line macro of |
1637 | * name `name', with `nparam' parameters. If nparam is 0 or -1, will |
1638 | * return true if _any_ single-line macro of that name is defined. |
1639 | * Otherwise, will return true if a single-line macro with either |
1640 | * `nparam' or no parameters is defined. |
1641 | * |
1642 | * If a macro with precisely the right number of parameters is |
1643 | * defined, or nparam is -1, the address of the definition structure |
1644 | * will be returned in `defn'; otherwise NULL will be returned. If `defn' |
1645 | * is NULL, no action will be taken regarding its contents, and no |
1646 | * error will occur. |
1647 | * |
1648 | * Note that this is also called with nparam zero to resolve |
1649 | * `ifdef'. |
1650 | * |
1651 | * If you already know which context macro belongs to, you can pass |
1652 | * the context pointer as first parameter; if you won't but name begins |
1653 | * with %$ the context will be automatically computed. If all_contexts |
1654 | * is true, macro will be searched in outer contexts as well. |
1655 | */ |
1656 | static bool |
1657 | smacro_defined(Context * ctx, const char *name, int nparam, SMacro ** defn, |
1658 | bool nocase) |
1659 | { |
1660 | struct hash_table *smtbl; |
1661 | SMacro *m; |
1662 | |
1663 | if (ctx) { |
1664 | smtbl = &ctx->localmac; |
1665 | } else if (name[0] == '%' && name[1] == '$') { |
1666 | if (cstk) |
1667 | ctx = get_ctx(name, &name); |
1668 | if (!ctx) |
1669 | return false; /* got to return _something_ */ |
1670 | smtbl = &ctx->localmac; |
1671 | } else { |
1672 | smtbl = &smacros; |
1673 | } |
1674 | m = (SMacro *) hash_findix(smtbl, name); |
1675 | |
1676 | while (m) { |
1677 | if (!mstrcmp(m->name, name, m->casesense && nocase) && |
1678 | (nparam <= 0 || m->nparam == 0 || nparam == (int) m->nparam)) { |
1679 | if (defn) { |
1680 | if (nparam == (int) m->nparam || nparam == -1) |
1681 | *defn = m; |
1682 | else |
1683 | *defn = NULL; |
1684 | } |
1685 | return true; |
1686 | } |
1687 | m = m->next; |
1688 | } |
1689 | |
1690 | return false; |
1691 | } |
1692 | |
1693 | /* |
1694 | * Count and mark off the parameters in a multi-line macro call. |
1695 | * This is called both from within the multi-line macro expansion |
1696 | * code, and also to mark off the default parameters when provided |
1697 | * in a %macro definition line. |
1698 | */ |
1699 | static void count_mmac_params(Token * t, int *nparam, Token *** params) |
1700 | { |
1701 | int paramsize, brace; |
1702 | |
1703 | *nparam = paramsize = 0; |
1704 | *params = NULL; |
1705 | while (t) { |
1706 | /* +1: we need space for the final NULL */ |
1707 | if (*nparam+1 >= paramsize) { |
1708 | paramsize += PARAM_DELTA; |
1709 | *params = nasm_realloc(*params, sizeof(**params) * paramsize); |
1710 | } |
1711 | skip_white_(t); |
1712 | brace = 0; |
1713 | if (tok_is_(t, "{" )) |
1714 | brace++; |
1715 | (*params)[(*nparam)++] = t; |
1716 | if (brace) { |
1717 | while (brace && (t = t->next) != NULL) { |
1718 | if (tok_is_(t, "{" )) |
1719 | brace++; |
1720 | else if (tok_is_(t, "}" )) |
1721 | brace--; |
1722 | } |
1723 | |
1724 | if (t) { |
1725 | /* |
1726 | * Now we've found the closing brace, look further |
1727 | * for the comma. |
1728 | */ |
1729 | t = t->next; |
1730 | skip_white_(t); |
1731 | if (tok_isnt_(t, "," )) { |
1732 | nasm_error(ERR_NONFATAL, |
1733 | "braces do not enclose all of macro parameter" ); |
1734 | while (tok_isnt_(t, "," )) |
1735 | t = t->next; |
1736 | } |
1737 | } |
1738 | } else { |
1739 | while (tok_isnt_(t, "," )) |
1740 | t = t->next; |
1741 | } |
1742 | if (t) { /* got a comma/brace */ |
1743 | t = t->next; /* eat the comma */ |
1744 | } |
1745 | } |
1746 | } |
1747 | |
1748 | /* |
1749 | * Determine whether one of the various `if' conditions is true or |
1750 | * not. |
1751 | * |
1752 | * We must free the tline we get passed. |
1753 | */ |
1754 | static bool if_condition(Token * tline, enum preproc_token ct) |
1755 | { |
1756 | enum pp_conditional i = PP_COND(ct); |
1757 | bool j; |
1758 | Token *t, *tt, **tptr, *origline; |
1759 | struct tokenval tokval; |
1760 | expr *evalresult; |
1761 | enum pp_token_type needtype; |
1762 | char *p; |
1763 | |
1764 | origline = tline; |
1765 | |
1766 | switch (i) { |
1767 | case PPC_IFCTX: |
1768 | j = false; /* have we matched yet? */ |
1769 | while (true) { |
1770 | skip_white_(tline); |
1771 | if (!tline) |
1772 | break; |
1773 | if (tline->type != TOK_ID) { |
1774 | nasm_error(ERR_NONFATAL, |
1775 | "`%s' expects context identifiers" , pp_directives[ct]); |
1776 | free_tlist(origline); |
1777 | return -1; |
1778 | } |
1779 | if (cstk && cstk->name && !nasm_stricmp(tline->text, cstk->name)) |
1780 | j = true; |
1781 | tline = tline->next; |
1782 | } |
1783 | break; |
1784 | |
1785 | case PPC_IFDEF: |
1786 | j = false; /* have we matched yet? */ |
1787 | while (tline) { |
1788 | skip_white_(tline); |
1789 | if (!tline || (tline->type != TOK_ID && |
1790 | (tline->type != TOK_PREPROC_ID || |
1791 | tline->text[1] != '$'))) { |
1792 | nasm_error(ERR_NONFATAL, |
1793 | "`%s' expects macro identifiers" , pp_directives[ct]); |
1794 | goto fail; |
1795 | } |
1796 | if (smacro_defined(NULL, tline->text, 0, NULL, true)) |
1797 | j = true; |
1798 | tline = tline->next; |
1799 | } |
1800 | break; |
1801 | |
1802 | case PPC_IFENV: |
1803 | tline = expand_smacro(tline); |
1804 | j = false; /* have we matched yet? */ |
1805 | while (tline) { |
1806 | skip_white_(tline); |
1807 | if (!tline || (tline->type != TOK_ID && |
1808 | tline->type != TOK_STRING && |
1809 | (tline->type != TOK_PREPROC_ID || |
1810 | tline->text[1] != '!'))) { |
1811 | nasm_error(ERR_NONFATAL, |
1812 | "`%s' expects environment variable names" , |
1813 | pp_directives[ct]); |
1814 | goto fail; |
1815 | } |
1816 | p = tline->text; |
1817 | if (tline->type == TOK_PREPROC_ID) |
1818 | p += 2; /* Skip leading %! */ |
1819 | if (*p == '\'' || *p == '\"' || *p == '`') |
1820 | nasm_unquote_cstr(p, ct); |
1821 | if (getenv(p)) |
1822 | j = true; |
1823 | tline = tline->next; |
1824 | } |
1825 | break; |
1826 | |
1827 | case PPC_IFIDN: |
1828 | case PPC_IFIDNI: |
1829 | tline = expand_smacro(tline); |
1830 | t = tt = tline; |
1831 | while (tok_isnt_(tt, "," )) |
1832 | tt = tt->next; |
1833 | if (!tt) { |
1834 | nasm_error(ERR_NONFATAL, |
1835 | "`%s' expects two comma-separated arguments" , |
1836 | pp_directives[ct]); |
1837 | goto fail; |
1838 | } |
1839 | tt = tt->next; |
1840 | j = true; /* assume equality unless proved not */ |
1841 | while ((t->type != TOK_OTHER || strcmp(t->text, "," )) && tt) { |
1842 | if (tt->type == TOK_OTHER && !strcmp(tt->text, "," )) { |
1843 | nasm_error(ERR_NONFATAL, "`%s': more than one comma on line" , |
1844 | pp_directives[ct]); |
1845 | goto fail; |
1846 | } |
1847 | if (t->type == TOK_WHITESPACE) { |
1848 | t = t->next; |
1849 | continue; |
1850 | } |
1851 | if (tt->type == TOK_WHITESPACE) { |
1852 | tt = tt->next; |
1853 | continue; |
1854 | } |
1855 | if (tt->type != t->type) { |
1856 | j = false; /* found mismatching tokens */ |
1857 | break; |
1858 | } |
1859 | /* When comparing strings, need to unquote them first */ |
1860 | if (t->type == TOK_STRING) { |
1861 | size_t l1 = nasm_unquote(t->text, NULL); |
1862 | size_t l2 = nasm_unquote(tt->text, NULL); |
1863 | |
1864 | if (l1 != l2) { |
1865 | j = false; |
1866 | break; |
1867 | } |
1868 | if (mmemcmp(t->text, tt->text, l1, i == PPC_IFIDN)) { |
1869 | j = false; |
1870 | break; |
1871 | } |
1872 | } else if (mstrcmp(tt->text, t->text, i == PPC_IFIDN) != 0) { |
1873 | j = false; /* found mismatching tokens */ |
1874 | break; |
1875 | } |
1876 | |
1877 | t = t->next; |
1878 | tt = tt->next; |
1879 | } |
1880 | if ((t->type != TOK_OTHER || strcmp(t->text, "," )) || tt) |
1881 | j = false; /* trailing gunk on one end or other */ |
1882 | break; |
1883 | |
1884 | case PPC_IFMACRO: |
1885 | { |
1886 | bool found = false; |
1887 | MMacro searching, *mmac; |
1888 | |
1889 | skip_white_(tline); |
1890 | tline = expand_id(tline); |
1891 | if (!tok_type_(tline, TOK_ID)) { |
1892 | nasm_error(ERR_NONFATAL, |
1893 | "`%s' expects a macro name" , pp_directives[ct]); |
1894 | goto fail; |
1895 | } |
1896 | searching.name = nasm_strdup(tline->text); |
1897 | searching.casesense = true; |
1898 | searching.plus = false; |
1899 | searching.nolist = false; |
1900 | searching.in_progress = 0; |
1901 | searching.max_depth = 0; |
1902 | searching.rep_nest = NULL; |
1903 | searching.nparam_min = 0; |
1904 | searching.nparam_max = INT_MAX; |
1905 | tline = expand_smacro(tline->next); |
1906 | skip_white_(tline); |
1907 | if (!tline) { |
1908 | } else if (!tok_type_(tline, TOK_NUMBER)) { |
1909 | nasm_error(ERR_NONFATAL, |
1910 | "`%s' expects a parameter count or nothing" , |
1911 | pp_directives[ct]); |
1912 | } else { |
1913 | searching.nparam_min = searching.nparam_max = |
1914 | readnum(tline->text, &j); |
1915 | if (j) |
1916 | nasm_error(ERR_NONFATAL, |
1917 | "unable to parse parameter count `%s'" , |
1918 | tline->text); |
1919 | } |
1920 | if (tline && tok_is_(tline->next, "-" )) { |
1921 | tline = tline->next->next; |
1922 | if (tok_is_(tline, "*" )) |
1923 | searching.nparam_max = INT_MAX; |
1924 | else if (!tok_type_(tline, TOK_NUMBER)) |
1925 | nasm_error(ERR_NONFATAL, |
1926 | "`%s' expects a parameter count after `-'" , |
1927 | pp_directives[ct]); |
1928 | else { |
1929 | searching.nparam_max = readnum(tline->text, &j); |
1930 | if (j) |
1931 | nasm_error(ERR_NONFATAL, |
1932 | "unable to parse parameter count `%s'" , |
1933 | tline->text); |
1934 | if (searching.nparam_min > searching.nparam_max) { |
1935 | nasm_error(ERR_NONFATAL, |
1936 | "minimum parameter count exceeds maximum" ); |
1937 | searching.nparam_max = searching.nparam_min; |
1938 | } |
1939 | } |
1940 | } |
1941 | if (tline && tok_is_(tline->next, "+" )) { |
1942 | tline = tline->next; |
1943 | searching.plus = true; |
1944 | } |
1945 | mmac = (MMacro *) hash_findix(&mmacros, searching.name); |
1946 | while (mmac) { |
1947 | if (!strcmp(mmac->name, searching.name) && |
1948 | (mmac->nparam_min <= searching.nparam_max |
1949 | || searching.plus) |
1950 | && (searching.nparam_min <= mmac->nparam_max |
1951 | || mmac->plus)) { |
1952 | found = true; |
1953 | break; |
1954 | } |
1955 | mmac = mmac->next; |
1956 | } |
1957 | if (tline && tline->next) |
1958 | nasm_error(ERR_WARNING|ERR_PASS1, |
1959 | "trailing garbage after %%ifmacro ignored" ); |
1960 | nasm_free(searching.name); |
1961 | j = found; |
1962 | break; |
1963 | } |
1964 | |
1965 | case PPC_IFID: |
1966 | needtype = TOK_ID; |
1967 | goto iftype; |
1968 | case PPC_IFNUM: |
1969 | needtype = TOK_NUMBER; |
1970 | goto iftype; |
1971 | case PPC_IFSTR: |
1972 | needtype = TOK_STRING; |
1973 | goto iftype; |
1974 | |
1975 | iftype: |
1976 | t = tline = expand_smacro(tline); |
1977 | |
1978 | while (tok_type_(t, TOK_WHITESPACE) || |
1979 | (needtype == TOK_NUMBER && |
1980 | tok_type_(t, TOK_OTHER) && |
1981 | (t->text[0] == '-' || t->text[0] == '+') && |
1982 | !t->text[1])) |
1983 | t = t->next; |
1984 | |
1985 | j = tok_type_(t, needtype); |
1986 | break; |
1987 | |
1988 | case PPC_IFTOKEN: |
1989 | t = tline = expand_smacro(tline); |
1990 | while (tok_type_(t, TOK_WHITESPACE)) |
1991 | t = t->next; |
1992 | |
1993 | j = false; |
1994 | if (t) { |
1995 | t = t->next; /* Skip the actual token */ |
1996 | while (tok_type_(t, TOK_WHITESPACE)) |
1997 | t = t->next; |
1998 | j = !t; /* Should be nothing left */ |
1999 | } |
2000 | break; |
2001 | |
2002 | case PPC_IFEMPTY: |
2003 | t = tline = expand_smacro(tline); |
2004 | while (tok_type_(t, TOK_WHITESPACE)) |
2005 | t = t->next; |
2006 | |
2007 | j = !t; /* Should be empty */ |
2008 | break; |
2009 | |
2010 | case PPC_IF: |
2011 | t = tline = expand_smacro(tline); |
2012 | tptr = &t; |
2013 | tokval.t_type = TOKEN_INVALID; |
2014 | evalresult = evaluate(ppscan, tptr, &tokval, |
2015 | NULL, pass | CRITICAL, NULL); |
2016 | if (!evalresult) |
2017 | return -1; |
2018 | if (tokval.t_type) |
2019 | nasm_error(ERR_WARNING|ERR_PASS1, |
2020 | "trailing garbage after expression ignored" ); |
2021 | if (!is_simple(evalresult)) { |
2022 | nasm_error(ERR_NONFATAL, |
2023 | "non-constant value given to `%s'" , pp_directives[ct]); |
2024 | goto fail; |
2025 | } |
2026 | j = reloc_value(evalresult) != 0; |
2027 | break; |
2028 | |
2029 | default: |
2030 | nasm_error(ERR_FATAL, |
2031 | "preprocessor directive `%s' not yet implemented" , |
2032 | pp_directives[ct]); |
2033 | goto fail; |
2034 | } |
2035 | |
2036 | free_tlist(origline); |
2037 | return j ^ PP_NEGATIVE(ct); |
2038 | |
2039 | fail: |
2040 | free_tlist(origline); |
2041 | return -1; |
2042 | } |
2043 | |
2044 | /* |
2045 | * Common code for defining an smacro |
2046 | */ |
2047 | static bool define_smacro(Context *ctx, const char *mname, bool casesense, |
2048 | int nparam, Token *expansion) |
2049 | { |
2050 | SMacro *smac, **smhead; |
2051 | struct hash_table *smtbl; |
2052 | |
2053 | if (smacro_defined(ctx, mname, nparam, &smac, casesense)) { |
2054 | if (!smac) { |
2055 | nasm_error(ERR_WARNING|ERR_PASS1, |
2056 | "single-line macro `%s' defined both with and" |
2057 | " without parameters" , mname); |
2058 | /* |
2059 | * Some instances of the old code considered this a failure, |
2060 | * some others didn't. What is the right thing to do here? |
2061 | */ |
2062 | free_tlist(expansion); |
2063 | return false; /* Failure */ |
2064 | } else { |
2065 | /* |
2066 | * We're redefining, so we have to take over an |
2067 | * existing SMacro structure. This means freeing |
2068 | * what was already in it. |
2069 | */ |
2070 | nasm_free(smac->name); |
2071 | free_tlist(smac->expansion); |
2072 | } |
2073 | } else { |
2074 | smtbl = ctx ? &ctx->localmac : &smacros; |
2075 | smhead = (SMacro **) hash_findi_add(smtbl, mname); |
2076 | smac = nasm_malloc(sizeof(SMacro)); |
2077 | smac->next = *smhead; |
2078 | *smhead = smac; |
2079 | } |
2080 | smac->name = nasm_strdup(mname); |
2081 | smac->casesense = casesense; |
2082 | smac->nparam = nparam; |
2083 | smac->expansion = expansion; |
2084 | smac->in_progress = false; |
2085 | return true; /* Success */ |
2086 | } |
2087 | |
2088 | /* |
2089 | * Undefine an smacro |
2090 | */ |
2091 | static void undef_smacro(Context *ctx, const char *mname) |
2092 | { |
2093 | SMacro **smhead, *s, **sp; |
2094 | struct hash_table *smtbl; |
2095 | |
2096 | smtbl = ctx ? &ctx->localmac : &smacros; |
2097 | smhead = (SMacro **)hash_findi(smtbl, mname, NULL); |
2098 | |
2099 | if (smhead) { |
2100 | /* |
2101 | * We now have a macro name... go hunt for it. |
2102 | */ |
2103 | sp = smhead; |
2104 | while ((s = *sp) != NULL) { |
2105 | if (!mstrcmp(s->name, mname, s->casesense)) { |
2106 | *sp = s->next; |
2107 | nasm_free(s->name); |
2108 | free_tlist(s->expansion); |
2109 | nasm_free(s); |
2110 | } else { |
2111 | sp = &s->next; |
2112 | } |
2113 | } |
2114 | } |
2115 | } |
2116 | |
2117 | /* |
2118 | * Parse a mmacro specification. |
2119 | */ |
2120 | static bool parse_mmacro_spec(Token *tline, MMacro *def, const char *directive) |
2121 | { |
2122 | bool err; |
2123 | |
2124 | tline = tline->next; |
2125 | skip_white_(tline); |
2126 | tline = expand_id(tline); |
2127 | if (!tok_type_(tline, TOK_ID)) { |
2128 | nasm_error(ERR_NONFATAL, "`%s' expects a macro name" , directive); |
2129 | return false; |
2130 | } |
2131 | |
2132 | def->prev = NULL; |
2133 | def->name = nasm_strdup(tline->text); |
2134 | def->plus = false; |
2135 | def->nolist = false; |
2136 | def->in_progress = 0; |
2137 | def->rep_nest = NULL; |
2138 | def->nparam_min = 0; |
2139 | def->nparam_max = 0; |
2140 | |
2141 | tline = expand_smacro(tline->next); |
2142 | skip_white_(tline); |
2143 | if (!tok_type_(tline, TOK_NUMBER)) { |
2144 | nasm_error(ERR_NONFATAL, "`%s' expects a parameter count" , directive); |
2145 | } else { |
2146 | def->nparam_min = def->nparam_max = |
2147 | readnum(tline->text, &err); |
2148 | if (err) |
2149 | nasm_error(ERR_NONFATAL, |
2150 | "unable to parse parameter count `%s'" , tline->text); |
2151 | } |
2152 | if (tline && tok_is_(tline->next, "-" )) { |
2153 | tline = tline->next->next; |
2154 | if (tok_is_(tline, "*" )) { |
2155 | def->nparam_max = INT_MAX; |
2156 | } else if (!tok_type_(tline, TOK_NUMBER)) { |
2157 | nasm_error(ERR_NONFATAL, |
2158 | "`%s' expects a parameter count after `-'" , directive); |
2159 | } else { |
2160 | def->nparam_max = readnum(tline->text, &err); |
2161 | if (err) { |
2162 | nasm_error(ERR_NONFATAL, "unable to parse parameter count `%s'" , |
2163 | tline->text); |
2164 | } |
2165 | if (def->nparam_min > def->nparam_max) { |
2166 | nasm_error(ERR_NONFATAL, "minimum parameter count exceeds maximum" ); |
2167 | def->nparam_max = def->nparam_min; |
2168 | } |
2169 | } |
2170 | } |
2171 | if (tline && tok_is_(tline->next, "+" )) { |
2172 | tline = tline->next; |
2173 | def->plus = true; |
2174 | } |
2175 | if (tline && tok_type_(tline->next, TOK_ID) && |
2176 | !nasm_stricmp(tline->next->text, ".nolist" )) { |
2177 | tline = tline->next; |
2178 | def->nolist = true; |
2179 | } |
2180 | |
2181 | /* |
2182 | * Handle default parameters. |
2183 | */ |
2184 | if (tline && tline->next) { |
2185 | def->dlist = tline->next; |
2186 | tline->next = NULL; |
2187 | count_mmac_params(def->dlist, &def->ndefs, &def->defaults); |
2188 | } else { |
2189 | def->dlist = NULL; |
2190 | def->defaults = NULL; |
2191 | } |
2192 | def->expansion = NULL; |
2193 | |
2194 | if (def->defaults && def->ndefs > def->nparam_max - def->nparam_min && |
2195 | !def->plus) |
2196 | nasm_error(ERR_WARNING|ERR_PASS1|WARN_MDP, |
2197 | "too many default macro parameters" ); |
2198 | |
2199 | return true; |
2200 | } |
2201 | |
2202 | |
2203 | /* |
2204 | * Decode a size directive |
2205 | */ |
2206 | static int parse_size(const char *str) { |
2207 | static const char *size_names[] = |
2208 | { "byte" , "dword" , "oword" , "qword" , "tword" , "word" , "yword" }; |
2209 | static const int sizes[] = |
2210 | { 0, 1, 4, 16, 8, 10, 2, 32 }; |
2211 | return str ? sizes[bsii(str, size_names, ARRAY_SIZE(size_names))+1] : 0; |
2212 | } |
2213 | |
2214 | /* |
2215 | * Process a preprocessor %pragma directive. Currently there are none. |
2216 | * Gets passed the token list starting with the "preproc" token from |
2217 | * "%pragma preproc". |
2218 | */ |
2219 | static void do_pragma_preproc(Token *tline) |
2220 | { |
2221 | /* Skip to the real stuff */ |
2222 | tline = tline->next; |
2223 | skip_white_(tline); |
2224 | if (!tline) |
2225 | return; |
2226 | |
2227 | (void)tline; /* Nothing else to do at present */ |
2228 | } |
2229 | |
2230 | /** |
2231 | * find and process preprocessor directive in passed line |
2232 | * Find out if a line contains a preprocessor directive, and deal |
2233 | * with it if so. |
2234 | * |
2235 | * If a directive _is_ found, it is the responsibility of this routine |
2236 | * (and not the caller) to free_tlist() the line. |
2237 | * |
2238 | * @param tline a pointer to the current tokeninzed line linked list |
2239 | * @param output if this directive generated output |
2240 | * @return DIRECTIVE_FOUND or NO_DIRECTIVE_FOUND |
2241 | * |
2242 | */ |
2243 | static int do_directive(Token *tline, char **output) |
2244 | { |
2245 | enum preproc_token i; |
2246 | int j; |
2247 | bool err; |
2248 | int nparam; |
2249 | bool nolist; |
2250 | bool casesense; |
2251 | int k, m; |
2252 | int offset; |
2253 | char *p, *pp; |
2254 | const char *found_path; |
2255 | const char *mname; |
2256 | Include *inc; |
2257 | Context *ctx; |
2258 | Cond *cond; |
2259 | MMacro *mmac, **mmhead; |
2260 | Token *t = NULL, *tt, *param_start, *macro_start, *last, **tptr, *origline; |
2261 | Line *l; |
2262 | struct tokenval tokval; |
2263 | expr *evalresult; |
2264 | MMacro *tmp_defining; /* Used when manipulating rep_nest */ |
2265 | int64_t count; |
2266 | size_t len; |
2267 | int severity; |
2268 | |
2269 | *output = NULL; /* No output generated */ |
2270 | origline = tline; |
2271 | |
2272 | skip_white_(tline); |
2273 | if (!tline || !tok_type_(tline, TOK_PREPROC_ID) || |
2274 | (tline->text[0] && (tline->text[1] == '%' || |
2275 | tline->text[1] == '$' || |
2276 | tline->text[1] == '!'))) |
2277 | return NO_DIRECTIVE_FOUND; |
2278 | |
2279 | i = pp_token_hash(tline->text); |
2280 | |
2281 | /* |
2282 | * FIXME: We zap execution of PP_RMACRO, PP_IRMACRO, PP_EXITMACRO |
2283 | * since they are known to be buggy at moment, we need to fix them |
2284 | * in future release (2.09-2.10) |
2285 | */ |
2286 | if (i == PP_RMACRO || i == PP_IRMACRO || i == PP_EXITMACRO) { |
2287 | nasm_error(ERR_NONFATAL, "unknown preprocessor directive `%s'" , |
2288 | tline->text); |
2289 | return NO_DIRECTIVE_FOUND; |
2290 | } |
2291 | |
2292 | /* |
2293 | * If we're in a non-emitting branch of a condition construct, |
2294 | * or walking to the end of an already terminated %rep block, |
2295 | * we should ignore all directives except for condition |
2296 | * directives. |
2297 | */ |
2298 | if (((istk->conds && !emitting(istk->conds->state)) || |
2299 | (istk->mstk && !istk->mstk->in_progress)) && !is_condition(i)) { |
2300 | return NO_DIRECTIVE_FOUND; |
2301 | } |
2302 | |
2303 | /* |
2304 | * If we're defining a macro or reading a %rep block, we should |
2305 | * ignore all directives except for %macro/%imacro (which nest), |
2306 | * %endm/%endmacro, and (only if we're in a %rep block) %endrep. |
2307 | * If we're in a %rep block, another %rep nests, so should be let through. |
2308 | */ |
2309 | if (defining && i != PP_MACRO && i != PP_IMACRO && |
2310 | i != PP_RMACRO && i != PP_IRMACRO && |
2311 | i != PP_ENDMACRO && i != PP_ENDM && |
2312 | (defining->name || (i != PP_ENDREP && i != PP_REP))) { |
2313 | return NO_DIRECTIVE_FOUND; |
2314 | } |
2315 | |
2316 | if (defining) { |
2317 | if (i == PP_MACRO || i == PP_IMACRO || |
2318 | i == PP_RMACRO || i == PP_IRMACRO) { |
2319 | nested_mac_count++; |
2320 | return NO_DIRECTIVE_FOUND; |
2321 | } else if (nested_mac_count > 0) { |
2322 | if (i == PP_ENDMACRO) { |
2323 | nested_mac_count--; |
2324 | return NO_DIRECTIVE_FOUND; |
2325 | } |
2326 | } |
2327 | if (!defining->name) { |
2328 | if (i == PP_REP) { |
2329 | nested_rep_count++; |
2330 | return NO_DIRECTIVE_FOUND; |
2331 | } else if (nested_rep_count > 0) { |
2332 | if (i == PP_ENDREP) { |
2333 | nested_rep_count--; |
2334 | return NO_DIRECTIVE_FOUND; |
2335 | } |
2336 | } |
2337 | } |
2338 | } |
2339 | |
2340 | switch (i) { |
2341 | case PP_INVALID: |
2342 | nasm_error(ERR_NONFATAL, "unknown preprocessor directive `%s'" , |
2343 | tline->text); |
2344 | return NO_DIRECTIVE_FOUND; /* didn't get it */ |
2345 | |
2346 | case PP_PRAGMA: |
2347 | /* |
2348 | * %pragma namespace options... |
2349 | * |
2350 | * The namespace "preproc" is reserved for the preprocessor; |
2351 | * all other namespaces generate a [pragma] assembly directive. |
2352 | * |
2353 | * Invalid %pragmas are ignored and may have different |
2354 | * meaning in future versions of NASM. |
2355 | */ |
2356 | tline = tline->next; |
2357 | skip_white_(tline); |
2358 | tline = expand_smacro(tline); |
2359 | if (tok_type_(tline, TOK_ID)) { |
2360 | if (!nasm_stricmp(tline->text, "preproc" )) { |
2361 | /* Preprocessor pragma */ |
2362 | do_pragma_preproc(tline); |
2363 | } else { |
2364 | /* Build the assembler directive */ |
2365 | t = new_Token(NULL, TOK_OTHER, "[" , 1); |
2366 | t->next = new_Token(NULL, TOK_ID, "pragma" , 6); |
2367 | t->next->next = new_Token(tline, TOK_WHITESPACE, NULL, 0); |
2368 | tline = t; |
2369 | for (t = tline; t->next; t = t->next) |
2370 | ; |
2371 | t->next = new_Token(NULL, TOK_OTHER, "]" , 1); |
2372 | /* true here can be revisited in the future */ |
2373 | *output = detoken(tline, true); |
2374 | } |
2375 | } |
2376 | free_tlist(origline); |
2377 | return DIRECTIVE_FOUND; |
2378 | |
2379 | case PP_STACKSIZE: |
2380 | /* Directive to tell NASM what the default stack size is. The |
2381 | * default is for a 16-bit stack, and this can be overriden with |
2382 | * %stacksize large. |
2383 | */ |
2384 | tline = tline->next; |
2385 | if (tline && tline->type == TOK_WHITESPACE) |
2386 | tline = tline->next; |
2387 | if (!tline || tline->type != TOK_ID) { |
2388 | nasm_error(ERR_NONFATAL, "`%%stacksize' missing size parameter" ); |
2389 | free_tlist(origline); |
2390 | return DIRECTIVE_FOUND; |
2391 | } |
2392 | if (nasm_stricmp(tline->text, "flat" ) == 0) { |
2393 | /* All subsequent ARG directives are for a 32-bit stack */ |
2394 | StackSize = 4; |
2395 | StackPointer = "ebp" ; |
2396 | ArgOffset = 8; |
2397 | LocalOffset = 0; |
2398 | } else if (nasm_stricmp(tline->text, "flat64" ) == 0) { |
2399 | /* All subsequent ARG directives are for a 64-bit stack */ |
2400 | StackSize = 8; |
2401 | StackPointer = "rbp" ; |
2402 | ArgOffset = 16; |
2403 | LocalOffset = 0; |
2404 | } else if (nasm_stricmp(tline->text, "large" ) == 0) { |
2405 | /* All subsequent ARG directives are for a 16-bit stack, |
2406 | * far function call. |
2407 | */ |
2408 | StackSize = 2; |
2409 | StackPointer = "bp" ; |
2410 | ArgOffset = 4; |
2411 | LocalOffset = 0; |
2412 | } else if (nasm_stricmp(tline->text, "small" ) == 0) { |
2413 | /* All subsequent ARG directives are for a 16-bit stack, |
2414 | * far function call. We don't support near functions. |
2415 | */ |
2416 | StackSize = 2; |
2417 | StackPointer = "bp" ; |
2418 | ArgOffset = 6; |
2419 | LocalOffset = 0; |
2420 | } else { |
2421 | nasm_error(ERR_NONFATAL, "`%%stacksize' invalid size type" ); |
2422 | free_tlist(origline); |
2423 | return DIRECTIVE_FOUND; |
2424 | } |
2425 | free_tlist(origline); |
2426 | return DIRECTIVE_FOUND; |
2427 | |
2428 | case PP_ARG: |
2429 | /* TASM like ARG directive to define arguments to functions, in |
2430 | * the following form: |
2431 | * |
2432 | * ARG arg1:WORD, arg2:DWORD, arg4:QWORD |
2433 | */ |
2434 | offset = ArgOffset; |
2435 | do { |
2436 | char *arg, directive[256]; |
2437 | int size = StackSize; |
2438 | |
2439 | /* Find the argument name */ |
2440 | tline = tline->next; |
2441 | if (tline && tline->type == TOK_WHITESPACE) |
2442 | tline = tline->next; |
2443 | if (!tline || tline->type != TOK_ID) { |
2444 | nasm_error(ERR_NONFATAL, "`%%arg' missing argument parameter" ); |
2445 | free_tlist(origline); |
2446 | return DIRECTIVE_FOUND; |
2447 | } |
2448 | arg = tline->text; |
2449 | |
2450 | /* Find the argument size type */ |
2451 | tline = tline->next; |
2452 | if (!tline || tline->type != TOK_OTHER |
2453 | || tline->text[0] != ':') { |
2454 | nasm_error(ERR_NONFATAL, |
2455 | "Syntax error processing `%%arg' directive" ); |
2456 | free_tlist(origline); |
2457 | return DIRECTIVE_FOUND; |
2458 | } |
2459 | tline = tline->next; |
2460 | if (!tline || tline->type != TOK_ID) { |
2461 | nasm_error(ERR_NONFATAL, "`%%arg' missing size type parameter" ); |
2462 | free_tlist(origline); |
2463 | return DIRECTIVE_FOUND; |
2464 | } |
2465 | |
2466 | /* Allow macro expansion of type parameter */ |
2467 | tt = tokenize(tline->text); |
2468 | tt = expand_smacro(tt); |
2469 | size = parse_size(tt->text); |
2470 | if (!size) { |
2471 | nasm_error(ERR_NONFATAL, |
2472 | "Invalid size type for `%%arg' missing directive" ); |
2473 | free_tlist(tt); |
2474 | free_tlist(origline); |
2475 | return DIRECTIVE_FOUND; |
2476 | } |
2477 | free_tlist(tt); |
2478 | |
2479 | /* Round up to even stack slots */ |
2480 | size = ALIGN(size, StackSize); |
2481 | |
2482 | /* Now define the macro for the argument */ |
2483 | snprintf(directive, sizeof(directive), "%%define %s (%s+%d)" , |
2484 | arg, StackPointer, offset); |
2485 | do_directive(tokenize(directive), output); |
2486 | offset += size; |
2487 | |
2488 | /* Move to the next argument in the list */ |
2489 | tline = tline->next; |
2490 | if (tline && tline->type == TOK_WHITESPACE) |
2491 | tline = tline->next; |
2492 | } while (tline && tline->type == TOK_OTHER && tline->text[0] == ','); |
2493 | ArgOffset = offset; |
2494 | free_tlist(origline); |
2495 | return DIRECTIVE_FOUND; |
2496 | |
2497 | case PP_LOCAL: |
2498 | /* TASM like LOCAL directive to define local variables for a |
2499 | * function, in the following form: |
2500 | * |
2501 | * LOCAL local1:WORD, local2:DWORD, local4:QWORD = LocalSize |
2502 | * |
2503 | * The '= LocalSize' at the end is ignored by NASM, but is |
2504 | * required by TASM to define the local parameter size (and used |
2505 | * by the TASM macro package). |
2506 | */ |
2507 | offset = LocalOffset; |
2508 | do { |
2509 | char *local, directive[256]; |
2510 | int size = StackSize; |
2511 | |
2512 | /* Find the argument name */ |
2513 | tline = tline->next; |
2514 | if (tline && tline->type == TOK_WHITESPACE) |
2515 | tline = tline->next; |
2516 | if (!tline || tline->type != TOK_ID) { |
2517 | nasm_error(ERR_NONFATAL, |
2518 | "`%%local' missing argument parameter" ); |
2519 | free_tlist(origline); |
2520 | return DIRECTIVE_FOUND; |
2521 | } |
2522 | local = tline->text; |
2523 | |
2524 | /* Find the argument size type */ |
2525 | tline = tline->next; |
2526 | if (!tline || tline->type != TOK_OTHER |
2527 | || tline->text[0] != ':') { |
2528 | nasm_error(ERR_NONFATAL, |
2529 | "Syntax error processing `%%local' directive" ); |
2530 | free_tlist(origline); |
2531 | return DIRECTIVE_FOUND; |
2532 | } |
2533 | tline = tline->next; |
2534 | if (!tline || tline->type != TOK_ID) { |
2535 | nasm_error(ERR_NONFATAL, |
2536 | "`%%local' missing size type parameter" ); |
2537 | free_tlist(origline); |
2538 | return DIRECTIVE_FOUND; |
2539 | } |
2540 | |
2541 | /* Allow macro expansion of type parameter */ |
2542 | tt = tokenize(tline->text); |
2543 | tt = expand_smacro(tt); |
2544 | size = parse_size(tt->text); |
2545 | if (!size) { |
2546 | nasm_error(ERR_NONFATAL, |
2547 | "Invalid size type for `%%local' missing directive" ); |
2548 | free_tlist(tt); |
2549 | free_tlist(origline); |
2550 | return DIRECTIVE_FOUND; |
2551 | } |
2552 | free_tlist(tt); |
2553 | |
2554 | /* Round up to even stack slots */ |
2555 | size = ALIGN(size, StackSize); |
2556 | |
2557 | offset += size; /* Negative offset, increment before */ |
2558 | |
2559 | /* Now define the macro for the argument */ |
2560 | snprintf(directive, sizeof(directive), "%%define %s (%s-%d)" , |
2561 | local, StackPointer, offset); |
2562 | do_directive(tokenize(directive), output); |
2563 | |
2564 | /* Now define the assign to setup the enter_c macro correctly */ |
2565 | snprintf(directive, sizeof(directive), |
2566 | "%%assign %%$localsize %%$localsize+%d" , size); |
2567 | do_directive(tokenize(directive), output); |
2568 | |
2569 | /* Move to the next argument in the list */ |
2570 | tline = tline->next; |
2571 | if (tline && tline->type == TOK_WHITESPACE) |
2572 | tline = tline->next; |
2573 | } while (tline && tline->type == TOK_OTHER && tline->text[0] == ','); |
2574 | LocalOffset = offset; |
2575 | free_tlist(origline); |
2576 | return DIRECTIVE_FOUND; |
2577 | |
2578 | case PP_CLEAR: |
2579 | if (tline->next) |
2580 | nasm_error(ERR_WARNING|ERR_PASS1, |
2581 | "trailing garbage after `%%clear' ignored" ); |
2582 | free_macros(); |
2583 | init_macros(); |
2584 | free_tlist(origline); |
2585 | return DIRECTIVE_FOUND; |
2586 | |
2587 | case PP_DEPEND: |
2588 | t = tline->next = expand_smacro(tline->next); |
2589 | skip_white_(t); |
2590 | if (!t || (t->type != TOK_STRING && |
2591 | t->type != TOK_INTERNAL_STRING)) { |
2592 | nasm_error(ERR_NONFATAL, "`%%depend' expects a file name" ); |
2593 | free_tlist(origline); |
2594 | return DIRECTIVE_FOUND; /* but we did _something_ */ |
2595 | } |
2596 | if (t->next) |
2597 | nasm_error(ERR_WARNING|ERR_PASS1, |
2598 | "trailing garbage after `%%depend' ignored" ); |
2599 | p = t->text; |
2600 | if (t->type != TOK_INTERNAL_STRING) |
2601 | nasm_unquote_cstr(p, i); |
2602 | nasm_add_string_to_strlist(dephead, p); |
2603 | free_tlist(origline); |
2604 | return DIRECTIVE_FOUND; |
2605 | |
2606 | case PP_INCLUDE: |
2607 | t = tline->next = expand_smacro(tline->next); |
2608 | skip_white_(t); |
2609 | |
2610 | if (!t || (t->type != TOK_STRING && |
2611 | t->type != TOK_INTERNAL_STRING)) { |
2612 | nasm_error(ERR_NONFATAL, "`%%include' expects a file name" ); |
2613 | free_tlist(origline); |
2614 | return DIRECTIVE_FOUND; /* but we did _something_ */ |
2615 | } |
2616 | if (t->next) |
2617 | nasm_error(ERR_WARNING|ERR_PASS1, |
2618 | "trailing garbage after `%%include' ignored" ); |
2619 | p = t->text; |
2620 | if (t->type != TOK_INTERNAL_STRING) |
2621 | nasm_unquote_cstr(p, i); |
2622 | inc = nasm_malloc(sizeof(Include)); |
2623 | inc->next = istk; |
2624 | inc->conds = NULL; |
2625 | found_path = NULL; |
2626 | inc->fp = inc_fopen(p, dephead, &found_path, |
2627 | pass == 0 ? INC_OPTIONAL : INC_NEEDED, NF_TEXT); |
2628 | if (!inc->fp) { |
2629 | /* -MG given but file not found */ |
2630 | nasm_free(inc); |
2631 | } else { |
2632 | inc->fname = src_set_fname(found_path ? found_path : p); |
2633 | inc->lineno = src_set_linnum(0); |
2634 | inc->lineinc = 1; |
2635 | inc->expansion = NULL; |
2636 | inc->mstk = NULL; |
2637 | istk = inc; |
2638 | lfmt->uplevel(LIST_INCLUDE); |
2639 | } |
2640 | free_tlist(origline); |
2641 | return DIRECTIVE_FOUND; |
2642 | |
2643 | case PP_USE: |
2644 | { |
2645 | static macros_t *use_pkg; |
2646 | const char *pkg_macro = NULL; |
2647 | |
2648 | tline = tline->next; |
2649 | skip_white_(tline); |
2650 | tline = expand_id(tline); |
2651 | |
2652 | if (!tline || (tline->type != TOK_STRING && |
2653 | tline->type != TOK_INTERNAL_STRING && |
2654 | tline->type != TOK_ID)) { |
2655 | nasm_error(ERR_NONFATAL, "`%%use' expects a package name" ); |
2656 | free_tlist(origline); |
2657 | return DIRECTIVE_FOUND; /* but we did _something_ */ |
2658 | } |
2659 | if (tline->next) |
2660 | nasm_error(ERR_WARNING|ERR_PASS1, |
2661 | "trailing garbage after `%%use' ignored" ); |
2662 | if (tline->type == TOK_STRING) |
2663 | nasm_unquote_cstr(tline->text, i); |
2664 | use_pkg = nasm_stdmac_find_package(tline->text); |
2665 | if (!use_pkg) |
2666 | nasm_error(ERR_NONFATAL, "unknown `%%use' package: %s" , tline->text); |
2667 | else |
2668 | pkg_macro = (char *)use_pkg + 1; /* The first string will be <%define>__USE_*__ */ |
2669 | if (use_pkg && ! smacro_defined(NULL, pkg_macro, 0, NULL, true)) { |
2670 | /* Not already included, go ahead and include it */ |
2671 | stdmacpos = use_pkg; |
2672 | } |
2673 | free_tlist(origline); |
2674 | return DIRECTIVE_FOUND; |
2675 | } |
2676 | case PP_PUSH: |
2677 | case PP_REPL: |
2678 | case PP_POP: |
2679 | tline = tline->next; |
2680 | skip_white_(tline); |
2681 | tline = expand_id(tline); |
2682 | if (tline) { |
2683 | if (!tok_type_(tline, TOK_ID)) { |
2684 | nasm_error(ERR_NONFATAL, "`%s' expects a context identifier" , |
2685 | pp_directives[i]); |
2686 | free_tlist(origline); |
2687 | return DIRECTIVE_FOUND; /* but we did _something_ */ |
2688 | } |
2689 | if (tline->next) |
2690 | nasm_error(ERR_WARNING|ERR_PASS1, |
2691 | "trailing garbage after `%s' ignored" , |
2692 | pp_directives[i]); |
2693 | p = nasm_strdup(tline->text); |
2694 | } else { |
2695 | p = NULL; /* Anonymous */ |
2696 | } |
2697 | |
2698 | if (i == PP_PUSH) { |
2699 | ctx = nasm_malloc(sizeof(Context)); |
2700 | ctx->next = cstk; |
2701 | hash_init(&ctx->localmac, HASH_SMALL); |
2702 | ctx->name = p; |
2703 | ctx->number = unique++; |
2704 | cstk = ctx; |
2705 | } else { |
2706 | /* %pop or %repl */ |
2707 | if (!cstk) { |
2708 | nasm_error(ERR_NONFATAL, "`%s': context stack is empty" , |
2709 | pp_directives[i]); |
2710 | } else if (i == PP_POP) { |
2711 | if (p && (!cstk->name || nasm_stricmp(p, cstk->name))) |
2712 | nasm_error(ERR_NONFATAL, "`%%pop' in wrong context: %s, " |
2713 | "expected %s" , |
2714 | cstk->name ? cstk->name : "anonymous" , p); |
2715 | else |
2716 | ctx_pop(); |
2717 | } else { |
2718 | /* i == PP_REPL */ |
2719 | nasm_free(cstk->name); |
2720 | cstk->name = p; |
2721 | p = NULL; |
2722 | } |
2723 | nasm_free(p); |
2724 | } |
2725 | free_tlist(origline); |
2726 | return DIRECTIVE_FOUND; |
2727 | case PP_FATAL: |
2728 | severity = ERR_FATAL; |
2729 | goto issue_error; |
2730 | case PP_ERROR: |
2731 | severity = ERR_NONFATAL; |
2732 | goto issue_error; |
2733 | case PP_WARNING: |
2734 | severity = ERR_WARNING|WARN_USER; |
2735 | goto issue_error; |
2736 | |
2737 | issue_error: |
2738 | { |
2739 | /* Only error out if this is the final pass */ |
2740 | if (pass != 2 && i != PP_FATAL) |
2741 | return DIRECTIVE_FOUND; |
2742 | |
2743 | tline->next = expand_smacro(tline->next); |
2744 | tline = tline->next; |
2745 | skip_white_(tline); |
2746 | t = tline ? tline->next : NULL; |
2747 | skip_white_(t); |
2748 | if (tok_type_(tline, TOK_STRING) && !t) { |
2749 | /* The line contains only a quoted string */ |
2750 | p = tline->text; |
2751 | nasm_unquote(p, NULL); /* Ignore NUL character truncation */ |
2752 | nasm_error(severity, "%s" , p); |
2753 | } else { |
2754 | /* Not a quoted string, or more than a quoted string */ |
2755 | p = detoken(tline, false); |
2756 | nasm_error(severity, "%s" , p); |
2757 | nasm_free(p); |
2758 | } |
2759 | free_tlist(origline); |
2760 | return DIRECTIVE_FOUND; |
2761 | } |
2762 | |
2763 | CASE_PP_IF: |
2764 | if (istk->conds && !emitting(istk->conds->state)) |
2765 | j = COND_NEVER; |
2766 | else { |
2767 | j = if_condition(tline->next, i); |
2768 | tline->next = NULL; /* it got freed */ |
2769 | j = j < 0 ? COND_NEVER : j ? COND_IF_TRUE : COND_IF_FALSE; |
2770 | } |
2771 | cond = nasm_malloc(sizeof(Cond)); |
2772 | cond->next = istk->conds; |
2773 | cond->state = j; |
2774 | istk->conds = cond; |
2775 | if(istk->mstk) |
2776 | istk->mstk->condcnt ++; |
2777 | free_tlist(origline); |
2778 | return DIRECTIVE_FOUND; |
2779 | |
2780 | CASE_PP_ELIF: |
2781 | if (!istk->conds) |
2782 | nasm_error(ERR_FATAL, "`%s': no matching `%%if'" , pp_directives[i]); |
2783 | switch(istk->conds->state) { |
2784 | case COND_IF_TRUE: |
2785 | istk->conds->state = COND_DONE; |
2786 | break; |
2787 | |
2788 | case COND_DONE: |
2789 | case COND_NEVER: |
2790 | break; |
2791 | |
2792 | case COND_ELSE_TRUE: |
2793 | case COND_ELSE_FALSE: |
2794 | nasm_error(ERR_WARNING|ERR_PASS1|ERR_PP_PRECOND, |
2795 | "`%%elif' after `%%else' ignored" ); |
2796 | istk->conds->state = COND_NEVER; |
2797 | break; |
2798 | |
2799 | case COND_IF_FALSE: |
2800 | /* |
2801 | * IMPORTANT: In the case of %if, we will already have |
2802 | * called expand_mmac_params(); however, if we're |
2803 | * processing an %elif we must have been in a |
2804 | * non-emitting mode, which would have inhibited |
2805 | * the normal invocation of expand_mmac_params(). |
2806 | * Therefore, we have to do it explicitly here. |
2807 | */ |
2808 | j = if_condition(expand_mmac_params(tline->next), i); |
2809 | tline->next = NULL; /* it got freed */ |
2810 | istk->conds->state = |
2811 | j < 0 ? COND_NEVER : j ? COND_IF_TRUE : COND_IF_FALSE; |
2812 | break; |
2813 | } |
2814 | free_tlist(origline); |
2815 | return DIRECTIVE_FOUND; |
2816 | |
2817 | case PP_ELSE: |
2818 | if (tline->next) |
2819 | nasm_error(ERR_WARNING|ERR_PASS1|ERR_PP_PRECOND, |
2820 | "trailing garbage after `%%else' ignored" ); |
2821 | if (!istk->conds) |
2822 | nasm_fatal(0, "`%%else: no matching `%%if'" ); |
2823 | switch(istk->conds->state) { |
2824 | case COND_IF_TRUE: |
2825 | case COND_DONE: |
2826 | istk->conds->state = COND_ELSE_FALSE; |
2827 | break; |
2828 | |
2829 | case COND_NEVER: |
2830 | break; |
2831 | |
2832 | case COND_IF_FALSE: |
2833 | istk->conds->state = COND_ELSE_TRUE; |
2834 | break; |
2835 | |
2836 | case COND_ELSE_TRUE: |
2837 | case COND_ELSE_FALSE: |
2838 | nasm_error(ERR_WARNING|ERR_PASS1|ERR_PP_PRECOND, |
2839 | "`%%else' after `%%else' ignored." ); |
2840 | istk->conds->state = COND_NEVER; |
2841 | break; |
2842 | } |
2843 | free_tlist(origline); |
2844 | return DIRECTIVE_FOUND; |
2845 | |
2846 | case PP_ENDIF: |
2847 | if (tline->next) |
2848 | nasm_error(ERR_WARNING|ERR_PASS1|ERR_PP_PRECOND, |
2849 | "trailing garbage after `%%endif' ignored" ); |
2850 | if (!istk->conds) |
2851 | nasm_error(ERR_FATAL, "`%%endif': no matching `%%if'" ); |
2852 | cond = istk->conds; |
2853 | istk->conds = cond->next; |
2854 | nasm_free(cond); |
2855 | if(istk->mstk) |
2856 | istk->mstk->condcnt --; |
2857 | free_tlist(origline); |
2858 | return DIRECTIVE_FOUND; |
2859 | |
2860 | case PP_RMACRO: |
2861 | case PP_IRMACRO: |
2862 | case PP_MACRO: |
2863 | case PP_IMACRO: |
2864 | if (defining) { |
2865 | nasm_error(ERR_FATAL, "`%s': already defining a macro" , |
2866 | pp_directives[i]); |
2867 | return DIRECTIVE_FOUND; |
2868 | } |
2869 | defining = nasm_zalloc(sizeof(MMacro)); |
2870 | defining->max_depth = ((i == PP_RMACRO) || (i == PP_IRMACRO)) |
2871 | ? nasm_limit[LIMIT_MACROS] : 0; |
2872 | defining->casesense = (i == PP_MACRO) || (i == PP_RMACRO); |
2873 | if (!parse_mmacro_spec(tline, defining, pp_directives[i])) { |
2874 | nasm_free(defining); |
2875 | defining = NULL; |
2876 | return DIRECTIVE_FOUND; |
2877 | } |
2878 | |
2879 | src_get(&defining->xline, &defining->fname); |
2880 | |
2881 | mmac = (MMacro *) hash_findix(&mmacros, defining->name); |
2882 | while (mmac) { |
2883 | if (!strcmp(mmac->name, defining->name) && |
2884 | (mmac->nparam_min <= defining->nparam_max |
2885 | || defining->plus) |
2886 | && (defining->nparam_min <= mmac->nparam_max |
2887 | || mmac->plus)) { |
2888 | nasm_error(ERR_WARNING|ERR_PASS1, |
2889 | "redefining multi-line macro `%s'" , defining->name); |
2890 | return DIRECTIVE_FOUND; |
2891 | } |
2892 | mmac = mmac->next; |
2893 | } |
2894 | free_tlist(origline); |
2895 | return DIRECTIVE_FOUND; |
2896 | |
2897 | case PP_ENDM: |
2898 | case PP_ENDMACRO: |
2899 | if (! (defining && defining->name)) { |
2900 | nasm_error(ERR_NONFATAL, "`%s': not defining a macro" , tline->text); |
2901 | return DIRECTIVE_FOUND; |
2902 | } |
2903 | mmhead = (MMacro **) hash_findi_add(&mmacros, defining->name); |
2904 | defining->next = *mmhead; |
2905 | *mmhead = defining; |
2906 | defining = NULL; |
2907 | free_tlist(origline); |
2908 | return DIRECTIVE_FOUND; |
2909 | |
2910 | case PP_EXITMACRO: |
2911 | /* |
2912 | * We must search along istk->expansion until we hit a |
2913 | * macro-end marker for a macro with a name. Then we |
2914 | * bypass all lines between exitmacro and endmacro. |
2915 | */ |
2916 | list_for_each(l, istk->expansion) |
2917 | if (l->finishes && l->finishes->name) |
2918 | break; |
2919 | |
2920 | if (l) { |
2921 | /* |
2922 | * Remove all conditional entries relative to this |
2923 | * macro invocation. (safe to do in this context) |
2924 | */ |
2925 | for ( ; l->finishes->condcnt > 0; l->finishes->condcnt --) { |
2926 | cond = istk->conds; |
2927 | istk->conds = cond->next; |
2928 | nasm_free(cond); |
2929 | } |
2930 | istk->expansion = l; |
2931 | } else { |
2932 | nasm_error(ERR_NONFATAL, "`%%exitmacro' not within `%%macro' block" ); |
2933 | } |
2934 | free_tlist(origline); |
2935 | return DIRECTIVE_FOUND; |
2936 | |
2937 | case PP_UNMACRO: |
2938 | case PP_UNIMACRO: |
2939 | { |
2940 | MMacro **mmac_p; |
2941 | MMacro spec; |
2942 | |
2943 | spec.casesense = (i == PP_UNMACRO); |
2944 | if (!parse_mmacro_spec(tline, &spec, pp_directives[i])) { |
2945 | return DIRECTIVE_FOUND; |
2946 | } |
2947 | mmac_p = (MMacro **) hash_findi(&mmacros, spec.name, NULL); |
2948 | while (mmac_p && *mmac_p) { |
2949 | mmac = *mmac_p; |
2950 | if (mmac->casesense == spec.casesense && |
2951 | !mstrcmp(mmac->name, spec.name, spec.casesense) && |
2952 | mmac->nparam_min == spec.nparam_min && |
2953 | mmac->nparam_max == spec.nparam_max && |
2954 | mmac->plus == spec.plus) { |
2955 | *mmac_p = mmac->next; |
2956 | free_mmacro(mmac); |
2957 | } else { |
2958 | mmac_p = &mmac->next; |
2959 | } |
2960 | } |
2961 | free_tlist(origline); |
2962 | free_tlist(spec.dlist); |
2963 | return DIRECTIVE_FOUND; |
2964 | } |
2965 | |
2966 | case PP_ROTATE: |
2967 | if (tline->next && tline->next->type == TOK_WHITESPACE) |
2968 | tline = tline->next; |
2969 | if (!tline->next) { |
2970 | free_tlist(origline); |
2971 | nasm_error(ERR_NONFATAL, "`%%rotate' missing rotate count" ); |
2972 | return DIRECTIVE_FOUND; |
2973 | } |
2974 | t = expand_smacro(tline->next); |
2975 | tline->next = NULL; |
2976 | free_tlist(origline); |
2977 | tline = t; |
2978 | tptr = &t; |
2979 | tokval.t_type = TOKEN_INVALID; |
2980 | evalresult = |
2981 | evaluate(ppscan, tptr, &tokval, NULL, pass, NULL); |
2982 | free_tlist(tline); |
2983 | if (!evalresult) |
2984 | return DIRECTIVE_FOUND; |
2985 | if (tokval.t_type) |
2986 | nasm_error(ERR_WARNING|ERR_PASS1, |
2987 | "trailing garbage after expression ignored" ); |
2988 | if (!is_simple(evalresult)) { |
2989 | nasm_error(ERR_NONFATAL, "non-constant value given to `%%rotate'" ); |
2990 | return DIRECTIVE_FOUND; |
2991 | } |
2992 | mmac = istk->mstk; |
2993 | while (mmac && !mmac->name) /* avoid mistaking %reps for macros */ |
2994 | mmac = mmac->next_active; |
2995 | if (!mmac) { |
2996 | nasm_error(ERR_NONFATAL, "`%%rotate' invoked outside a macro call" ); |
2997 | } else if (mmac->nparam == 0) { |
2998 | nasm_error(ERR_NONFATAL, |
2999 | "`%%rotate' invoked within macro without parameters" ); |
3000 | } else { |
3001 | int rotate = mmac->rotate + reloc_value(evalresult); |
3002 | |
3003 | rotate %= (int)mmac->nparam; |
3004 | if (rotate < 0) |
3005 | rotate += mmac->nparam; |
3006 | |
3007 | mmac->rotate = rotate; |
3008 | } |
3009 | return DIRECTIVE_FOUND; |
3010 | |
3011 | case PP_REP: |
3012 | nolist = false; |
3013 | do { |
3014 | tline = tline->next; |
3015 | } while (tok_type_(tline, TOK_WHITESPACE)); |
3016 | |
3017 | if (tok_type_(tline, TOK_ID) && |
3018 | nasm_stricmp(tline->text, ".nolist" ) == 0) { |
3019 | nolist = true; |
3020 | do { |
3021 | tline = tline->next; |
3022 | } while (tok_type_(tline, TOK_WHITESPACE)); |
3023 | } |
3024 | |
3025 | if (tline) { |
3026 | t = expand_smacro(tline); |
3027 | tptr = &t; |
3028 | tokval.t_type = TOKEN_INVALID; |
3029 | evalresult = |
3030 | evaluate(ppscan, tptr, &tokval, NULL, pass, NULL); |
3031 | if (!evalresult) { |
3032 | free_tlist(origline); |
3033 | return DIRECTIVE_FOUND; |
3034 | } |
3035 | if (tokval.t_type) |
3036 | nasm_error(ERR_WARNING|ERR_PASS1, |
3037 | "trailing garbage after expression ignored" ); |
3038 | if (!is_simple(evalresult)) { |
3039 | nasm_error(ERR_NONFATAL, "non-constant value given to `%%rep'" ); |
3040 | return DIRECTIVE_FOUND; |
3041 | } |
3042 | count = reloc_value(evalresult); |
3043 | if (count > nasm_limit[LIMIT_REP]) { |
3044 | nasm_error(ERR_NONFATAL, |
3045 | "`%%rep' count %" PRId64" exceeds limit (currently %" PRId64")" , |
3046 | count, nasm_limit[LIMIT_REP]); |
3047 | count = 0; |
3048 | } else if (count < 0) { |
3049 | nasm_error(ERR_WARNING|ERR_PASS2|WARN_NEG_REP, |
3050 | "negative `%%rep' count: %" PRId64, count); |
3051 | count = 0; |
3052 | } else { |
3053 | count++; |
3054 | } |
3055 | } else { |
3056 | nasm_error(ERR_NONFATAL, "`%%rep' expects a repeat count" ); |
3057 | count = 0; |
3058 | } |
3059 | free_tlist(origline); |
3060 | |
3061 | tmp_defining = defining; |
3062 | defining = nasm_malloc(sizeof(MMacro)); |
3063 | defining->prev = NULL; |
3064 | defining->name = NULL; /* flags this macro as a %rep block */ |
3065 | defining->casesense = false; |
3066 | defining->plus = false; |
3067 | defining->nolist = nolist; |
3068 | defining->in_progress = count; |
3069 | defining->max_depth = 0; |
3070 | defining->nparam_min = defining->nparam_max = 0; |
3071 | defining->defaults = NULL; |
3072 | defining->dlist = NULL; |
3073 | defining->expansion = NULL; |
3074 | defining->next_active = istk->mstk; |
3075 | defining->rep_nest = tmp_defining; |
3076 | return DIRECTIVE_FOUND; |
3077 | |
3078 | case PP_ENDREP: |
3079 | if (!defining || defining->name) { |
3080 | nasm_error(ERR_NONFATAL, "`%%endrep': no matching `%%rep'" ); |
3081 | return DIRECTIVE_FOUND; |
3082 | } |
3083 | |
3084 | /* |
3085 | * Now we have a "macro" defined - although it has no name |
3086 | * and we won't be entering it in the hash tables - we must |
3087 | * push a macro-end marker for it on to istk->expansion. |
3088 | * After that, it will take care of propagating itself (a |
3089 | * macro-end marker line for a macro which is really a %rep |
3090 | * block will cause the macro to be re-expanded, complete |
3091 | * with another macro-end marker to ensure the process |
3092 | * continues) until the whole expansion is forcibly removed |
3093 | * from istk->expansion by a %exitrep. |
3094 | */ |
3095 | l = nasm_malloc(sizeof(Line)); |
3096 | l->next = istk->expansion; |
3097 | l->finishes = defining; |
3098 | l->first = NULL; |
3099 | istk->expansion = l; |
3100 | |
3101 | istk->mstk = defining; |
3102 | |
3103 | lfmt->uplevel(defining->nolist ? LIST_MACRO_NOLIST : LIST_MACRO); |
3104 | tmp_defining = defining; |
3105 | defining = defining->rep_nest; |
3106 | free_tlist(origline); |
3107 | return DIRECTIVE_FOUND; |
3108 | |
3109 | case PP_EXITREP: |
3110 | /* |
3111 | * We must search along istk->expansion until we hit a |
3112 | * macro-end marker for a macro with no name. Then we set |
3113 | * its `in_progress' flag to 0. |
3114 | */ |
3115 | list_for_each(l, istk->expansion) |
3116 | if (l->finishes && !l->finishes->name) |
3117 | break; |
3118 | |
3119 | if (l) |
3120 | l->finishes->in_progress = 1; |
3121 | else |
3122 | nasm_error(ERR_NONFATAL, "`%%exitrep' not within `%%rep' block" ); |
3123 | free_tlist(origline); |
3124 | return DIRECTIVE_FOUND; |
3125 | |
3126 | case PP_XDEFINE: |
3127 | case PP_IXDEFINE: |
3128 | case PP_DEFINE: |
3129 | case PP_IDEFINE: |
3130 | casesense = (i == PP_DEFINE || i == PP_XDEFINE); |
3131 | |
3132 | tline = tline->next; |
3133 | skip_white_(tline); |
3134 | tline = expand_id(tline); |
3135 | if (!tline || (tline->type != TOK_ID && |
3136 | (tline->type != TOK_PREPROC_ID || |
3137 | tline->text[1] != '$'))) { |
3138 | nasm_error(ERR_NONFATAL, "`%s' expects a macro identifier" , |
3139 | pp_directives[i]); |
3140 | free_tlist(origline); |
3141 | return DIRECTIVE_FOUND; |
3142 | } |
3143 | |
3144 | ctx = get_ctx(tline->text, &mname); |
3145 | last = tline; |
3146 | param_start = tline = tline->next; |
3147 | nparam = 0; |
3148 | |
3149 | /* Expand the macro definition now for %xdefine and %ixdefine */ |
3150 | if ((i == PP_XDEFINE) || (i == PP_IXDEFINE)) |
3151 | tline = expand_smacro(tline); |
3152 | |
3153 | if (tok_is_(tline, "(" )) { |
3154 | /* |
3155 | * This macro has parameters. |
3156 | */ |
3157 | |
3158 | tline = tline->next; |
3159 | while (1) { |
3160 | skip_white_(tline); |
3161 | if (!tline) { |
3162 | nasm_error(ERR_NONFATAL, "parameter identifier expected" ); |
3163 | free_tlist(origline); |
3164 | return DIRECTIVE_FOUND; |
3165 | } |
3166 | if (tline->type != TOK_ID) { |
3167 | nasm_error(ERR_NONFATAL, |
3168 | "`%s': parameter identifier expected" , |
3169 | tline->text); |
3170 | free_tlist(origline); |
3171 | return DIRECTIVE_FOUND; |
3172 | } |
3173 | tline->type = TOK_SMAC_PARAM + nparam++; |
3174 | tline = tline->next; |
3175 | skip_white_(tline); |
3176 | if (tok_is_(tline, "," )) { |
3177 | tline = tline->next; |
3178 | } else { |
3179 | if (!tok_is_(tline, ")" )) { |
3180 | nasm_error(ERR_NONFATAL, |
3181 | "`)' expected to terminate macro template" ); |
3182 | free_tlist(origline); |
3183 | return DIRECTIVE_FOUND; |
3184 | } |
3185 | break; |
3186 | } |
3187 | } |
3188 | last = tline; |
3189 | tline = tline->next; |
3190 | } |
3191 | if (tok_type_(tline, TOK_WHITESPACE)) |
3192 | last = tline, tline = tline->next; |
3193 | macro_start = NULL; |
3194 | last->next = NULL; |
3195 | t = tline; |
3196 | while (t) { |
3197 | if (t->type == TOK_ID) { |
3198 | list_for_each(tt, param_start) |
3199 | if (tt->type >= TOK_SMAC_PARAM && |
3200 | !strcmp(tt->text, t->text)) |
3201 | t->type = tt->type; |
3202 | } |
3203 | tt = t->next; |
3204 | t->next = macro_start; |
3205 | macro_start = t; |
3206 | t = tt; |
3207 | } |
3208 | /* |
3209 | * Good. We now have a macro name, a parameter count, and a |
3210 | * token list (in reverse order) for an expansion. We ought |
3211 | * to be OK just to create an SMacro, store it, and let |
3212 | * free_tlist have the rest of the line (which we have |
3213 | * carefully re-terminated after chopping off the expansion |
3214 | * from the end). |
3215 | */ |
3216 | define_smacro(ctx, mname, casesense, nparam, macro_start); |
3217 | free_tlist(origline); |
3218 | return DIRECTIVE_FOUND; |
3219 | |
3220 | case PP_UNDEF: |
3221 | tline = tline->next; |
3222 | skip_white_(tline); |
3223 | tline = expand_id(tline); |
3224 | if (!tline || (tline->type != TOK_ID && |
3225 | (tline->type != TOK_PREPROC_ID || |
3226 | tline->text[1] != '$'))) { |
3227 | nasm_error(ERR_NONFATAL, "`%%undef' expects a macro identifier" ); |
3228 | free_tlist(origline); |
3229 | return DIRECTIVE_FOUND; |
3230 | } |
3231 | if (tline->next) { |
3232 | nasm_error(ERR_WARNING|ERR_PASS1, |
3233 | "trailing garbage after macro name ignored" ); |
3234 | } |
3235 | |
3236 | /* Find the context that symbol belongs to */ |
3237 | ctx = get_ctx(tline->text, &mname); |
3238 | undef_smacro(ctx, mname); |
3239 | free_tlist(origline); |
3240 | return DIRECTIVE_FOUND; |
3241 | |
3242 | case PP_DEFSTR: |
3243 | case PP_IDEFSTR: |
3244 | casesense = (i == PP_DEFSTR); |
3245 | |
3246 | tline = tline->next; |
3247 | skip_white_(tline); |
3248 | tline = expand_id(tline); |
3249 | if (!tline || (tline->type != TOK_ID && |
3250 | (tline->type != TOK_PREPROC_ID || |
3251 | tline->text[1] != '$'))) { |
3252 | nasm_error(ERR_NONFATAL, "`%s' expects a macro identifier" , |
3253 | pp_directives[i]); |
3254 | free_tlist(origline); |
3255 | return DIRECTIVE_FOUND; |
3256 | } |
3257 | |
3258 | ctx = get_ctx(tline->text, &mname); |
3259 | last = tline; |
3260 | tline = expand_smacro(tline->next); |
3261 | last->next = NULL; |
3262 | |
3263 | while (tok_type_(tline, TOK_WHITESPACE)) |
3264 | tline = delete_Token(tline); |
3265 | |
3266 | p = detoken(tline, false); |
3267 | macro_start = nasm_malloc(sizeof(*macro_start)); |
3268 | macro_start->next = NULL; |
3269 | macro_start->text = nasm_quote(p, strlen(p)); |
3270 | macro_start->type = TOK_STRING; |
3271 | macro_start->a.mac = NULL; |
3272 | nasm_free(p); |
3273 | |
3274 | /* |
3275 | * We now have a macro name, an implicit parameter count of |
3276 | * zero, and a string token to use as an expansion. Create |
3277 | * and store an SMacro. |
3278 | */ |
3279 | define_smacro(ctx, mname, casesense, 0, macro_start); |
3280 | free_tlist(origline); |
3281 | return DIRECTIVE_FOUND; |
3282 | |
3283 | case PP_DEFTOK: |
3284 | case PP_IDEFTOK: |
3285 | casesense = (i == PP_DEFTOK); |
3286 | |
3287 | tline = tline->next; |
3288 | skip_white_(tline); |
3289 | tline = expand_id(tline); |
3290 | if (!tline || (tline->type != TOK_ID && |
3291 | (tline->type != TOK_PREPROC_ID || |
3292 | tline->text[1] != '$'))) { |
3293 | nasm_error(ERR_NONFATAL, |
3294 | "`%s' expects a macro identifier as first parameter" , |
3295 | pp_directives[i]); |
3296 | free_tlist(origline); |
3297 | return DIRECTIVE_FOUND; |
3298 | } |
3299 | ctx = get_ctx(tline->text, &mname); |
3300 | last = tline; |
3301 | tline = expand_smacro(tline->next); |
3302 | last->next = NULL; |
3303 | |
3304 | t = tline; |
3305 | while (tok_type_(t, TOK_WHITESPACE)) |
3306 | t = t->next; |
3307 | /* t should now point to the string */ |
3308 | if (!tok_type_(t, TOK_STRING)) { |
3309 | nasm_error(ERR_NONFATAL, |
3310 | "`%s` requires string as second parameter" , |
3311 | pp_directives[i]); |
3312 | free_tlist(tline); |
3313 | free_tlist(origline); |
3314 | return DIRECTIVE_FOUND; |
3315 | } |
3316 | |
3317 | /* |
3318 | * Convert the string to a token stream. Note that smacros |
3319 | * are stored with the token stream reversed, so we have to |
3320 | * reverse the output of tokenize(). |
3321 | */ |
3322 | nasm_unquote_cstr(t->text, i); |
3323 | macro_start = reverse_tokens(tokenize(t->text)); |
3324 | |
3325 | /* |
3326 | * We now have a macro name, an implicit parameter count of |
3327 | * zero, and a numeric token to use as an expansion. Create |
3328 | * and store an SMacro. |
3329 | */ |
3330 | define_smacro(ctx, mname, casesense, 0, macro_start); |
3331 | free_tlist(tline); |
3332 | free_tlist(origline); |
3333 | return DIRECTIVE_FOUND; |
3334 | |
3335 | case PP_PATHSEARCH: |
3336 | { |
3337 | const char *found_path; |
3338 | |
3339 | casesense = true; |
3340 | |
3341 | tline = tline->next; |
3342 | skip_white_(tline); |
3343 | tline = expand_id(tline); |
3344 | if (!tline || (tline->type != TOK_ID && |
3345 | (tline->type != TOK_PREPROC_ID || |
3346 | tline->text[1] != '$'))) { |
3347 | nasm_error(ERR_NONFATAL, |
3348 | "`%%pathsearch' expects a macro identifier as first parameter" ); |
3349 | free_tlist(origline); |
3350 | return DIRECTIVE_FOUND; |
3351 | } |
3352 | ctx = get_ctx(tline->text, &mname); |
3353 | last = tline; |
3354 | tline = expand_smacro(tline->next); |
3355 | last->next = NULL; |
3356 | |
3357 | t = tline; |
3358 | while (tok_type_(t, TOK_WHITESPACE)) |
3359 | t = t->next; |
3360 | |
3361 | if (!t || (t->type != TOK_STRING && |
3362 | t->type != TOK_INTERNAL_STRING)) { |
3363 | nasm_error(ERR_NONFATAL, "`%%pathsearch' expects a file name" ); |
3364 | free_tlist(tline); |
3365 | free_tlist(origline); |
3366 | return DIRECTIVE_FOUND; /* but we did _something_ */ |
3367 | } |
3368 | if (t->next) |
3369 | nasm_error(ERR_WARNING|ERR_PASS1, |
3370 | "trailing garbage after `%%pathsearch' ignored" ); |
3371 | p = t->text; |
3372 | if (t->type != TOK_INTERNAL_STRING) |
3373 | nasm_unquote(p, NULL); |
3374 | |
3375 | inc_fopen(p, NULL, &found_path, INC_PROBE, NF_BINARY); |
3376 | if (!found_path) |
3377 | found_path = p; |
3378 | macro_start = nasm_malloc(sizeof(*macro_start)); |
3379 | macro_start->next = NULL; |
3380 | macro_start->text = nasm_quote(found_path, strlen(found_path)); |
3381 | macro_start->type = TOK_STRING; |
3382 | macro_start->a.mac = NULL; |
3383 | |
3384 | /* |
3385 | * We now have a macro name, an implicit parameter count of |
3386 | * zero, and a string token to use as an expansion. Create |
3387 | * and store an SMacro. |
3388 | */ |
3389 | define_smacro(ctx, mname, casesense, 0, macro_start); |
3390 | free_tlist(tline); |
3391 | free_tlist(origline); |
3392 | return DIRECTIVE_FOUND; |
3393 | } |
3394 | |
3395 | case PP_STRLEN: |
3396 | casesense = true; |
3397 | |
3398 | tline = tline->next; |
3399 | skip_white_(tline); |
3400 | tline = expand_id(tline); |
3401 | if (!tline || (tline->type != TOK_ID && |
3402 | (tline->type != TOK_PREPROC_ID || |
3403 | tline->text[1] != '$'))) { |
3404 | nasm_error(ERR_NONFATAL, |
3405 | "`%%strlen' expects a macro identifier as first parameter" ); |
3406 | free_tlist(origline); |
3407 | return DIRECTIVE_FOUND; |
3408 | } |
3409 | ctx = get_ctx(tline->text, &mname); |
3410 | last = tline; |
3411 | tline = expand_smacro(tline->next); |
3412 | last->next = NULL; |
3413 | |
3414 | t = tline; |
3415 | while (tok_type_(t, TOK_WHITESPACE)) |
3416 | t = t->next; |
3417 | /* t should now point to the string */ |
3418 | if (!tok_type_(t, TOK_STRING)) { |
3419 | nasm_error(ERR_NONFATAL, |
3420 | "`%%strlen` requires string as second parameter" ); |
3421 | free_tlist(tline); |
3422 | free_tlist(origline); |
3423 | return DIRECTIVE_FOUND; |
3424 | } |
3425 | |
3426 | macro_start = nasm_malloc(sizeof(*macro_start)); |
3427 | macro_start->next = NULL; |
3428 | make_tok_num(macro_start, nasm_unquote(t->text, NULL)); |
3429 | macro_start->a.mac = NULL; |
3430 | |
3431 | /* |
3432 | * We now have a macro name, an implicit parameter count of |
3433 | * zero, and a numeric token to use as an expansion. Create |
3434 | * and store an SMacro. |
3435 | */ |
3436 | define_smacro(ctx, mname, casesense, 0, macro_start); |
3437 | free_tlist(tline); |
3438 | free_tlist(origline); |
3439 | return DIRECTIVE_FOUND; |
3440 | |
3441 | case PP_STRCAT: |
3442 | casesense = true; |
3443 | |
3444 | tline = tline->next; |
3445 | skip_white_(tline); |
3446 | tline = expand_id(tline); |
3447 | if (!tline || (tline->type != TOK_ID && |
3448 | (tline->type != TOK_PREPROC_ID || |
3449 | tline->text[1] != '$'))) { |
3450 | nasm_error(ERR_NONFATAL, |
3451 | "`%%strcat' expects a macro identifier as first parameter" ); |
3452 | free_tlist(origline); |
3453 | return DIRECTIVE_FOUND; |
3454 | } |
3455 | ctx = get_ctx(tline->text, &mname); |
3456 | last = tline; |
3457 | tline = expand_smacro(tline->next); |
3458 | last->next = NULL; |
3459 | |
3460 | len = 0; |
3461 | list_for_each(t, tline) { |
3462 | switch (t->type) { |
3463 | case TOK_WHITESPACE: |
3464 | break; |
3465 | case TOK_STRING: |
3466 | len += t->a.len = nasm_unquote(t->text, NULL); |
3467 | break; |
3468 | case TOK_OTHER: |
3469 | if (!strcmp(t->text, "," )) /* permit comma separators */ |
3470 | break; |
3471 | /* else fall through */ |
3472 | default: |
3473 | nasm_error(ERR_NONFATAL, |
3474 | "non-string passed to `%%strcat' (%d)" , t->type); |
3475 | free_tlist(tline); |
3476 | free_tlist(origline); |
3477 | return DIRECTIVE_FOUND; |
3478 | } |
3479 | } |
3480 | |
3481 | p = pp = nasm_malloc(len); |
3482 | list_for_each(t, tline) { |
3483 | if (t->type == TOK_STRING) { |
3484 | memcpy(p, t->text, t->a.len); |
3485 | p += t->a.len; |
3486 | } |
3487 | } |
3488 | |
3489 | /* |
3490 | * We now have a macro name, an implicit parameter count of |
3491 | * zero, and a numeric token to use as an expansion. Create |
3492 | * and store an SMacro. |
3493 | */ |
3494 | macro_start = new_Token(NULL, TOK_STRING, NULL, 0); |
3495 | macro_start->text = nasm_quote(pp, len); |
3496 | nasm_free(pp); |
3497 | define_smacro(ctx, mname, casesense, 0, macro_start); |
3498 | free_tlist(tline); |
3499 | free_tlist(origline); |
3500 | return DIRECTIVE_FOUND; |
3501 | |
3502 | case PP_SUBSTR: |
3503 | { |
3504 | int64_t start, count; |
3505 | size_t len; |
3506 | |
3507 | casesense = true; |
3508 | |
3509 | tline = tline->next; |
3510 | skip_white_(tline); |
3511 | tline = expand_id(tline); |
3512 | if (!tline || (tline->type != TOK_ID && |
3513 | (tline->type != TOK_PREPROC_ID || |
3514 | tline->text[1] != '$'))) { |
3515 | nasm_error(ERR_NONFATAL, |
3516 | "`%%substr' expects a macro identifier as first parameter" ); |
3517 | free_tlist(origline); |
3518 | return DIRECTIVE_FOUND; |
3519 | } |
3520 | ctx = get_ctx(tline->text, &mname); |
3521 | last = tline; |
3522 | tline = expand_smacro(tline->next); |
3523 | last->next = NULL; |
3524 | |
3525 | if (tline) /* skip expanded id */ |
3526 | t = tline->next; |
3527 | while (tok_type_(t, TOK_WHITESPACE)) |
3528 | t = t->next; |
3529 | |
3530 | /* t should now point to the string */ |
3531 | if (!tok_type_(t, TOK_STRING)) { |
3532 | nasm_error(ERR_NONFATAL, |
3533 | "`%%substr` requires string as second parameter" ); |
3534 | free_tlist(tline); |
3535 | free_tlist(origline); |
3536 | return DIRECTIVE_FOUND; |
3537 | } |
3538 | |
3539 | tt = t->next; |
3540 | tptr = &tt; |
3541 | tokval.t_type = TOKEN_INVALID; |
3542 | evalresult = evaluate(ppscan, tptr, &tokval, NULL, pass, NULL); |
3543 | if (!evalresult) { |
3544 | free_tlist(tline); |
3545 | free_tlist(origline); |
3546 | return DIRECTIVE_FOUND; |
3547 | } else if (!is_simple(evalresult)) { |
3548 | nasm_error(ERR_NONFATAL, "non-constant value given to `%%substr`" ); |
3549 | free_tlist(tline); |
3550 | free_tlist(origline); |
3551 | return DIRECTIVE_FOUND; |
3552 | } |
3553 | start = evalresult->value - 1; |
3554 | |
3555 | while (tok_type_(tt, TOK_WHITESPACE)) |
3556 | tt = tt->next; |
3557 | if (!tt) { |
3558 | count = 1; /* Backwards compatibility: one character */ |
3559 | } else { |
3560 | tokval.t_type = TOKEN_INVALID; |
3561 | evalresult = evaluate(ppscan, tptr, &tokval, NULL, pass, NULL); |
3562 | if (!evalresult) { |
3563 | free_tlist(tline); |
3564 | free_tlist(origline); |
3565 | return DIRECTIVE_FOUND; |
3566 | } else if (!is_simple(evalresult)) { |
3567 | nasm_error(ERR_NONFATAL, "non-constant value given to `%%substr`" ); |
3568 | free_tlist(tline); |
3569 | free_tlist(origline); |
3570 | return DIRECTIVE_FOUND; |
3571 | } |
3572 | count = evalresult->value; |
3573 | } |
3574 | |
3575 | len = nasm_unquote(t->text, NULL); |
3576 | |
3577 | /* make start and count being in range */ |
3578 | if (start < 0) |
3579 | start = 0; |
3580 | if (count < 0) |
3581 | count = len + count + 1 - start; |
3582 | if (start + count > (int64_t)len) |
3583 | count = len - start; |
3584 | if (!len || count < 0 || start >=(int64_t)len) |
3585 | start = -1, count = 0; /* empty string */ |
3586 | |
3587 | macro_start = nasm_malloc(sizeof(*macro_start)); |
3588 | macro_start->next = NULL; |
3589 | macro_start->text = nasm_quote((start < 0) ? "" : t->text + start, count); |
3590 | macro_start->type = TOK_STRING; |
3591 | macro_start->a.mac = NULL; |
3592 | |
3593 | /* |
3594 | * We now have a macro name, an implicit parameter count of |
3595 | * zero, and a numeric token to use as an expansion. Create |
3596 | * and store an SMacro. |
3597 | */ |
3598 | define_smacro(ctx, mname, casesense, 0, macro_start); |
3599 | free_tlist(tline); |
3600 | free_tlist(origline); |
3601 | return DIRECTIVE_FOUND; |
3602 | } |
3603 | |
3604 | case PP_ASSIGN: |
3605 | case PP_IASSIGN: |
3606 | casesense = (i == PP_ASSIGN); |
3607 | |
3608 | tline = tline->next; |
3609 | skip_white_(tline); |
3610 | tline = expand_id(tline); |
3611 | if (!tline || (tline->type != TOK_ID && |
3612 | (tline->type != TOK_PREPROC_ID || |
3613 | tline->text[1] != '$'))) { |
3614 | nasm_error(ERR_NONFATAL, |
3615 | "`%%%sassign' expects a macro identifier" , |
3616 | (i == PP_IASSIGN ? "i" : "" )); |
3617 | free_tlist(origline); |
3618 | return DIRECTIVE_FOUND; |
3619 | } |
3620 | ctx = get_ctx(tline->text, &mname); |
3621 | last = tline; |
3622 | tline = expand_smacro(tline->next); |
3623 | last->next = NULL; |
3624 | |
3625 | t = tline; |
3626 | tptr = &t; |
3627 | tokval.t_type = TOKEN_INVALID; |
3628 | evalresult = evaluate(ppscan, tptr, &tokval, NULL, pass, NULL); |
3629 | free_tlist(tline); |
3630 | if (!evalresult) { |
3631 | free_tlist(origline); |
3632 | return DIRECTIVE_FOUND; |
3633 | } |
3634 | |
3635 | if (tokval.t_type) |
3636 | nasm_error(ERR_WARNING|ERR_PASS1, |
3637 | "trailing garbage after expression ignored" ); |
3638 | |
3639 | if (!is_simple(evalresult)) { |
3640 | nasm_error(ERR_NONFATAL, |
3641 | "non-constant value given to `%%%sassign'" , |
3642 | (i == PP_IASSIGN ? "i" : "" )); |
3643 | free_tlist(origline); |
3644 | return DIRECTIVE_FOUND; |
3645 | } |
3646 | |
3647 | macro_start = nasm_malloc(sizeof(*macro_start)); |
3648 | macro_start->next = NULL; |
3649 | make_tok_num(macro_start, reloc_value(evalresult)); |
3650 | macro_start->a.mac = NULL; |
3651 | |
3652 | /* |
3653 | * We now have a macro name, an implicit parameter count of |
3654 | * zero, and a numeric token to use as an expansion. Create |
3655 | * and store an SMacro. |
3656 | */ |
3657 | define_smacro(ctx, mname, casesense, 0, macro_start); |
3658 | free_tlist(origline); |
3659 | return DIRECTIVE_FOUND; |
3660 | |
3661 | case PP_LINE: |
3662 | /* |
3663 | * Syntax is `%line nnn[+mmm] [filename]' |
3664 | */ |
3665 | if (unlikely(pp_noline)) { |
3666 | free_tlist(origline); |
3667 | return DIRECTIVE_FOUND; |
3668 | } |
3669 | tline = tline->next; |
3670 | skip_white_(tline); |
3671 | if (!tok_type_(tline, TOK_NUMBER)) { |
3672 | nasm_error(ERR_NONFATAL, "`%%line' expects line number" ); |
3673 | free_tlist(origline); |
3674 | return DIRECTIVE_FOUND; |
3675 | } |
3676 | k = readnum(tline->text, &err); |
3677 | m = 1; |
3678 | tline = tline->next; |
3679 | if (tok_is_(tline, "+" )) { |
3680 | tline = tline->next; |
3681 | if (!tok_type_(tline, TOK_NUMBER)) { |
3682 | nasm_error(ERR_NONFATAL, "`%%line' expects line increment" ); |
3683 | free_tlist(origline); |
3684 | return DIRECTIVE_FOUND; |
3685 | } |
3686 | m = readnum(tline->text, &err); |
3687 | tline = tline->next; |
3688 | } |
3689 | skip_white_(tline); |
3690 | src_set_linnum(k); |
3691 | istk->lineinc = m; |
3692 | if (tline) { |
3693 | char *fname = detoken(tline, false); |
3694 | src_set_fname(fname); |
3695 | nasm_free(fname); |
3696 | } |
3697 | free_tlist(origline); |
3698 | return DIRECTIVE_FOUND; |
3699 | |
3700 | default: |
3701 | nasm_error(ERR_FATAL, |
3702 | "preprocessor directive `%s' not yet implemented" , |
3703 | pp_directives[i]); |
3704 | return DIRECTIVE_FOUND; |
3705 | } |
3706 | } |
3707 | |
3708 | /* |
3709 | * Ensure that a macro parameter contains a condition code and |
3710 | * nothing else. Return the condition code index if so, or -1 |
3711 | * otherwise. |
3712 | */ |
3713 | static int find_cc(Token * t) |
3714 | { |
3715 | Token *tt; |
3716 | |
3717 | if (!t) |
3718 | return -1; /* Probably a %+ without a space */ |
3719 | |
3720 | skip_white_(t); |
3721 | if (!t) |
3722 | return -1; |
3723 | if (t->type != TOK_ID) |
3724 | return -1; |
3725 | tt = t->next; |
3726 | skip_white_(tt); |
3727 | if (tt && (tt->type != TOK_OTHER || strcmp(tt->text, "," ))) |
3728 | return -1; |
3729 | |
3730 | return bsii(t->text, (const char **)conditions, ARRAY_SIZE(conditions)); |
3731 | } |
3732 | |
3733 | /* |
3734 | * This routines walks over tokens strem and hadnles tokens |
3735 | * pasting, if @handle_explicit passed then explicit pasting |
3736 | * term is handled, otherwise -- implicit pastings only. |
3737 | */ |
3738 | static bool paste_tokens(Token **head, const struct tokseq_match *m, |
3739 | size_t mnum, bool handle_explicit) |
3740 | { |
3741 | Token *tok, *next, **prev_next, **prev_nonspace; |
3742 | bool pasted = false; |
3743 | char *buf, *p; |
3744 | size_t len, i; |
3745 | |
3746 | /* |
3747 | * The last token before pasting. We need it |
3748 | * to be able to connect new handled tokens. |
3749 | * In other words if there were a tokens stream |
3750 | * |
3751 | * A -> B -> C -> D |
3752 | * |
3753 | * and we've joined tokens B and C, the resulting |
3754 | * stream should be |
3755 | * |
3756 | * A -> BC -> D |
3757 | */ |
3758 | tok = *head; |
3759 | prev_next = NULL; |
3760 | |
3761 | if (!tok_type_(tok, TOK_WHITESPACE) && !tok_type_(tok, TOK_PASTE)) |
3762 | prev_nonspace = head; |
3763 | else |
3764 | prev_nonspace = NULL; |
3765 | |
3766 | while (tok && (next = tok->next)) { |
3767 | |
3768 | switch (tok->type) { |
3769 | case TOK_WHITESPACE: |
3770 | /* Zap redundant whitespaces */ |
3771 | while (tok_type_(next, TOK_WHITESPACE)) |
3772 | next = delete_Token(next); |
3773 | tok->next = next; |
3774 | break; |
3775 | |
3776 | case TOK_PASTE: |
3777 | /* Explicit pasting */ |
3778 | if (!handle_explicit) |
3779 | break; |
3780 | next = delete_Token(tok); |
3781 | |
3782 | while (tok_type_(next, TOK_WHITESPACE)) |
3783 | next = delete_Token(next); |
3784 | |
3785 | if (!pasted) |
3786 | pasted = true; |
3787 | |
3788 | /* Left pasting token is start of line */ |
3789 | if (!prev_nonspace) |
3790 | nasm_error(ERR_FATAL, "No lvalue found on pasting" ); |
3791 | |
3792 | /* |
3793 | * No ending token, this might happen in two |
3794 | * cases |
3795 | * |
3796 | * 1) There indeed no right token at all |
3797 | * 2) There is a bare "%define ID" statement, |
3798 | * and @ID does expand to whitespace. |
3799 | * |
3800 | * So technically we need to do a grammar analysis |
3801 | * in another stage of parsing, but for now lets don't |
3802 | * change the behaviour people used to. Simply allow |
3803 | * whitespace after paste token. |
3804 | */ |
3805 | if (!next) { |
3806 | /* |
3807 | * Zap ending space tokens and that's all. |
3808 | */ |
3809 | tok = (*prev_nonspace)->next; |
3810 | while (tok_type_(tok, TOK_WHITESPACE)) |
3811 | tok = delete_Token(tok); |
3812 | tok = *prev_nonspace; |
3813 | tok->next = NULL; |
3814 | break; |
3815 | } |
3816 | |
3817 | tok = *prev_nonspace; |
3818 | while (tok_type_(tok, TOK_WHITESPACE)) |
3819 | tok = delete_Token(tok); |
3820 | len = strlen(tok->text); |
3821 | len += strlen(next->text); |
3822 | |
3823 | p = buf = nasm_malloc(len + 1); |
3824 | strcpy(p, tok->text); |
3825 | p = strchr(p, '\0'); |
3826 | strcpy(p, next->text); |
3827 | |
3828 | delete_Token(tok); |
3829 | |
3830 | tok = tokenize(buf); |
3831 | nasm_free(buf); |
3832 | |
3833 | *prev_nonspace = tok; |
3834 | while (tok && tok->next) |
3835 | tok = tok->next; |
3836 | |
3837 | tok->next = delete_Token(next); |
3838 | |
3839 | /* Restart from pasted tokens head */ |
3840 | tok = *prev_nonspace; |
3841 | break; |
3842 | |
3843 | default: |
3844 | /* implicit pasting */ |
3845 | for (i = 0; i < mnum; i++) { |
3846 | if (!(PP_CONCAT_MATCH(tok, m[i].mask_head))) |
3847 | continue; |
3848 | |
3849 | len = 0; |
3850 | while (next && PP_CONCAT_MATCH(next, m[i].mask_tail)) { |
3851 | len += strlen(next->text); |
3852 | next = next->next; |
3853 | } |
3854 | |
3855 | /* No match or no text to process */ |
3856 | if (tok == next || len == 0) |
3857 | break; |
3858 | |
3859 | len += strlen(tok->text); |
3860 | p = buf = nasm_malloc(len + 1); |
3861 | |
3862 | strcpy(p, tok->text); |
3863 | p = strchr(p, '\0'); |
3864 | tok = delete_Token(tok); |
3865 | |
3866 | while (tok != next) { |
3867 | if (PP_CONCAT_MATCH(tok, m[i].mask_tail)) { |
3868 | strcpy(p, tok->text); |
3869 | p = strchr(p, '\0'); |
3870 | } |
3871 | tok = delete_Token(tok); |
3872 | } |
3873 | |
3874 | tok = tokenize(buf); |
3875 | nasm_free(buf); |
3876 | |
3877 | if (prev_next) |
3878 | *prev_next = tok; |
3879 | else |
3880 | *head = tok; |
3881 | |
3882 | /* |
3883 | * Connect pasted into original stream, |
3884 | * ie A -> new-tokens -> B |
3885 | */ |
3886 | while (tok && tok->next) |
3887 | tok = tok->next; |
3888 | tok->next = next; |
3889 | |
3890 | if (!pasted) |
3891 | pasted = true; |
3892 | |
3893 | /* Restart from pasted tokens head */ |
3894 | tok = prev_next ? *prev_next : *head; |
3895 | } |
3896 | |
3897 | break; |
3898 | } |
3899 | |
3900 | prev_next = &tok->next; |
3901 | |
3902 | if (tok->next && |
3903 | !tok_type_(tok->next, TOK_WHITESPACE) && |
3904 | !tok_type_(tok->next, TOK_PASTE)) |
3905 | prev_nonspace = prev_next; |
3906 | |
3907 | tok = tok->next; |
3908 | } |
3909 | |
3910 | return pasted; |
3911 | } |
3912 | |
3913 | /* |
3914 | * expands to a list of tokens from %{x:y} |
3915 | */ |
3916 | static Token *expand_mmac_params_range(MMacro *mac, Token *tline, Token ***last) |
3917 | { |
3918 | Token *t = tline, **tt, *tm, *head; |
3919 | char *pos; |
3920 | int fst, lst, j, i; |
3921 | |
3922 | pos = strchr(tline->text, ':'); |
3923 | nasm_assert(pos); |
3924 | |
3925 | lst = atoi(pos + 1); |
3926 | fst = atoi(tline->text + 1); |
3927 | |
3928 | /* |
3929 | * only macros params are accounted so |
3930 | * if someone passes %0 -- we reject such |
3931 | * value(s) |
3932 | */ |
3933 | if (lst == 0 || fst == 0) |
3934 | goto err; |
3935 | |
3936 | /* the values should be sane */ |
3937 | if ((fst > (int)mac->nparam || fst < (-(int)mac->nparam)) || |
3938 | (lst > (int)mac->nparam || lst < (-(int)mac->nparam))) |
3939 | goto err; |
3940 | |
3941 | fst = fst < 0 ? fst + (int)mac->nparam + 1: fst; |
3942 | lst = lst < 0 ? lst + (int)mac->nparam + 1: lst; |
3943 | |
3944 | /* counted from zero */ |
3945 | fst--, lst--; |
3946 | |
3947 | /* |
3948 | * It will be at least one token. Note we |
3949 | * need to scan params until separator, otherwise |
3950 | * only first token will be passed. |
3951 | */ |
3952 | tm = mac->params[(fst + mac->rotate) % mac->nparam]; |
3953 | if (!tm) |
3954 | goto err; |
3955 | head = new_Token(NULL, tm->type, tm->text, 0); |
3956 | tt = &head->next, tm = tm->next; |
3957 | while (tok_isnt_(tm, "," )) { |
3958 | t = new_Token(NULL, tm->type, tm->text, 0); |
3959 | *tt = t, tt = &t->next, tm = tm->next; |
3960 | } |
3961 | |
3962 | if (fst < lst) { |
3963 | for (i = fst + 1; i <= lst; i++) { |
3964 | t = new_Token(NULL, TOK_OTHER, "," , 0); |
3965 | *tt = t, tt = &t->next; |
3966 | j = (i + mac->rotate) % mac->nparam; |
3967 | tm = mac->params[j]; |
3968 | while (tok_isnt_(tm, "," )) { |
3969 | t = new_Token(NULL, tm->type, tm->text, 0); |
3970 | *tt = t, tt = &t->next, tm = tm->next; |
3971 | } |
3972 | } |
3973 | } else { |
3974 | for (i = fst - 1; i >= lst; i--) { |
3975 | t = new_Token(NULL, TOK_OTHER, "," , 0); |
3976 | *tt = t, tt = &t->next; |
3977 | j = (i + mac->rotate) % mac->nparam; |
3978 | tm = mac->params[j]; |
3979 | while (tok_isnt_(tm, "," )) { |
3980 | t = new_Token(NULL, tm->type, tm->text, 0); |
3981 | *tt = t, tt = &t->next, tm = tm->next; |
3982 | } |
3983 | } |
3984 | } |
3985 | |
3986 | *last = tt; |
3987 | return head; |
3988 | |
3989 | err: |
3990 | nasm_error(ERR_NONFATAL, "`%%{%s}': macro parameters out of range" , |
3991 | &tline->text[1]); |
3992 | return tline; |
3993 | } |
3994 | |
3995 | /* |
3996 | * Expand MMacro-local things: parameter references (%0, %n, %+n, |
3997 | * %-n) and MMacro-local identifiers (%%foo) as well as |
3998 | * macro indirection (%[...]) and range (%{..:..}). |
3999 | */ |
4000 | static Token *expand_mmac_params(Token * tline) |
4001 | { |
4002 | Token *t, *tt, **tail, *thead; |
4003 | bool changed = false; |
4004 | char *pos; |
4005 | |
4006 | tail = &thead; |
4007 | thead = NULL; |
4008 | |
4009 | while (tline) { |
4010 | if (tline->type == TOK_PREPROC_ID && tline->text && tline->text[0] && |
4011 | (((tline->text[1] == '+' || tline->text[1] == '-') && tline->text[2]) || |
4012 | (tline->text[1] >= '0' && tline->text[1] <= '9') || |
4013 | tline->text[1] == '%')) { |
4014 | char *text = NULL; |
4015 | int type = 0, cc; /* type = 0 to placate optimisers */ |
4016 | char tmpbuf[30]; |
4017 | unsigned int n; |
4018 | int i; |
4019 | MMacro *mac; |
4020 | |
4021 | t = tline; |
4022 | tline = tline->next; |
4023 | |
4024 | mac = istk->mstk; |
4025 | while (mac && !mac->name) /* avoid mistaking %reps for macros */ |
4026 | mac = mac->next_active; |
4027 | if (!mac) { |
4028 | nasm_error(ERR_NONFATAL, "`%s': not in a macro call" , t->text); |
4029 | } else { |
4030 | pos = strchr(t->text, ':'); |
4031 | if (!pos) { |
4032 | switch (t->text[1]) { |
4033 | /* |
4034 | * We have to make a substitution of one of the |
4035 | * forms %1, %-1, %+1, %%foo, %0. |
4036 | */ |
4037 | case '0': |
4038 | type = TOK_NUMBER; |
4039 | snprintf(tmpbuf, sizeof(tmpbuf), "%d" , mac->nparam); |
4040 | text = nasm_strdup(tmpbuf); |
4041 | break; |
4042 | case '%': |
4043 | type = TOK_ID; |
4044 | snprintf(tmpbuf, sizeof(tmpbuf), "..@%" PRIu64"." , |
4045 | mac->unique); |
4046 | text = nasm_strcat(tmpbuf, t->text + 2); |
4047 | break; |
4048 | case '-': |
4049 | n = atoi(t->text + 2) - 1; |
4050 | if (n >= mac->nparam) |
4051 | tt = NULL; |
4052 | else { |
4053 | if (mac->nparam > 1) |
4054 | n = (n + mac->rotate) % mac->nparam; |
4055 | tt = mac->params[n]; |
4056 | } |
4057 | cc = find_cc(tt); |
4058 | if (cc == -1) { |
4059 | nasm_error(ERR_NONFATAL, |
4060 | "macro parameter %d is not a condition code" , |
4061 | n + 1); |
4062 | text = NULL; |
4063 | } else { |
4064 | type = TOK_ID; |
4065 | if (inverse_ccs[cc] == -1) { |
4066 | nasm_error(ERR_NONFATAL, |
4067 | "condition code `%s' is not invertible" , |
4068 | conditions[cc]); |
4069 | text = NULL; |
4070 | } else |
4071 | text = nasm_strdup(conditions[inverse_ccs[cc]]); |
4072 | } |
4073 | break; |
4074 | case '+': |
4075 | n = atoi(t->text + 2) - 1; |
4076 | if (n >= mac->nparam) |
4077 | tt = NULL; |
4078 | else { |
4079 | if (mac->nparam > 1) |
4080 | n = (n + mac->rotate) % mac->nparam; |
4081 | tt = mac->params[n]; |
4082 | } |
4083 | cc = find_cc(tt); |
4084 | if (cc == -1) { |
4085 | nasm_error(ERR_NONFATAL, |
4086 | "macro parameter %d is not a condition code" , |
4087 | n + 1); |
4088 | text = NULL; |
4089 | } else { |
4090 | type = TOK_ID; |
4091 | text = nasm_strdup(conditions[cc]); |
4092 | } |
4093 | break; |
4094 | default: |
4095 | n = atoi(t->text + 1) - 1; |
4096 | if (n >= mac->nparam) |
4097 | tt = NULL; |
4098 | else { |
4099 | if (mac->nparam > 1) |
4100 | n = (n + mac->rotate) % mac->nparam; |
4101 | tt = mac->params[n]; |
4102 | } |
4103 | if (tt) { |
4104 | for (i = 0; i < mac->paramlen[n]; i++) { |
4105 | *tail = new_Token(NULL, tt->type, tt->text, 0); |
4106 | tail = &(*tail)->next; |
4107 | tt = tt->next; |
4108 | } |
4109 | } |
4110 | text = NULL; /* we've done it here */ |
4111 | break; |
4112 | } |
4113 | } else { |
4114 | /* |
4115 | * seems we have a parameters range here |
4116 | */ |
4117 | Token *head, **last; |
4118 | head = expand_mmac_params_range(mac, t, &last); |
4119 | if (head != t) { |
4120 | *tail = head; |
4121 | *last = tline; |
4122 | tline = head; |
4123 | text = NULL; |
4124 | } |
4125 | } |
4126 | } |
4127 | if (!text) { |
4128 | delete_Token(t); |
4129 | } else { |
4130 | *tail = t; |
4131 | tail = &t->next; |
4132 | t->type = type; |
4133 | nasm_free(t->text); |
4134 | t->text = text; |
4135 | t->a.mac = NULL; |
4136 | } |
4137 | changed = true; |
4138 | continue; |
4139 | } else if (tline->type == TOK_INDIRECT) { |
4140 | t = tline; |
4141 | tline = tline->next; |
4142 | tt = tokenize(t->text); |
4143 | tt = expand_mmac_params(tt); |
4144 | tt = expand_smacro(tt); |
4145 | *tail = tt; |
4146 | while (tt) { |
4147 | tt->a.mac = NULL; /* Necessary? */ |
4148 | tail = &tt->next; |
4149 | tt = tt->next; |
4150 | } |
4151 | delete_Token(t); |
4152 | changed = true; |
4153 | } else { |
4154 | t = *tail = tline; |
4155 | tline = tline->next; |
4156 | t->a.mac = NULL; |
4157 | tail = &t->next; |
4158 | } |
4159 | } |
4160 | *tail = NULL; |
4161 | |
4162 | if (changed) { |
4163 | const struct tokseq_match t[] = { |
4164 | { |
4165 | PP_CONCAT_MASK(TOK_ID) | |
4166 | PP_CONCAT_MASK(TOK_FLOAT), /* head */ |
4167 | PP_CONCAT_MASK(TOK_ID) | |
4168 | PP_CONCAT_MASK(TOK_NUMBER) | |
4169 | PP_CONCAT_MASK(TOK_FLOAT) | |
4170 | PP_CONCAT_MASK(TOK_OTHER) /* tail */ |
4171 | }, |
4172 | { |
4173 | PP_CONCAT_MASK(TOK_NUMBER), /* head */ |
4174 | PP_CONCAT_MASK(TOK_NUMBER) /* tail */ |
4175 | } |
4176 | }; |
4177 | paste_tokens(&thead, t, ARRAY_SIZE(t), false); |
4178 | } |
4179 | |
4180 | return thead; |
4181 | } |
4182 | |
4183 | /* |
4184 | * Expand all single-line macro calls made in the given line. |
4185 | * Return the expanded version of the line. The original is deemed |
4186 | * to be destroyed in the process. (In reality we'll just move |
4187 | * Tokens from input to output a lot of the time, rather than |
4188 | * actually bothering to destroy and replicate.) |
4189 | */ |
4190 | |
4191 | static Token *expand_smacro(Token * tline) |
4192 | { |
4193 | Token *t, *tt, *mstart, **tail, *thead; |
4194 | SMacro *head = NULL, *m; |
4195 | Token **params; |
4196 | int *paramsize; |
4197 | unsigned int nparam, sparam; |
4198 | int brackets; |
4199 | Token *org_tline = tline; |
4200 | Context *ctx; |
4201 | const char *mname; |
4202 | int64_t deadman = nasm_limit[LIMIT_MACROS]; |
4203 | bool expanded; |
4204 | |
4205 | /* |
4206 | * Trick: we should avoid changing the start token pointer since it can |
4207 | * be contained in "next" field of other token. Because of this |
4208 | * we allocate a copy of first token and work with it; at the end of |
4209 | * routine we copy it back |
4210 | */ |
4211 | if (org_tline) { |
4212 | tline = new_Token(org_tline->next, org_tline->type, |
4213 | org_tline->text, 0); |
4214 | tline->a.mac = org_tline->a.mac; |
4215 | nasm_free(org_tline->text); |
4216 | org_tline->text = NULL; |
4217 | } |
4218 | |
4219 | expanded = true; /* Always expand %+ at least once */ |
4220 | |
4221 | again: |
4222 | thead = NULL; |
4223 | tail = &thead; |
4224 | |
4225 | while (tline) { /* main token loop */ |
4226 | if (!--deadman) { |
4227 | nasm_error(ERR_NONFATAL, "interminable macro recursion" ); |
4228 | goto err; |
4229 | } |
4230 | |
4231 | if ((mname = tline->text)) { |
4232 | /* if this token is a local macro, look in local context */ |
4233 | if (tline->type == TOK_ID) { |
4234 | head = (SMacro *)hash_findix(&smacros, mname); |
4235 | } else if (tline->type == TOK_PREPROC_ID) { |
4236 | ctx = get_ctx(mname, &mname); |
4237 | head = ctx ? (SMacro *)hash_findix(&ctx->localmac, mname) : NULL; |
4238 | } else |
4239 | head = NULL; |
4240 | |
4241 | /* |
4242 | * We've hit an identifier. As in is_mmacro below, we first |
4243 | * check whether the identifier is a single-line macro at |
4244 | * all, then think about checking for parameters if |
4245 | * necessary. |
4246 | */ |
4247 | list_for_each(m, head) |
4248 | if (!mstrcmp(m->name, mname, m->casesense)) |
4249 | break; |
4250 | if (m) { |
4251 | mstart = tline; |
4252 | params = NULL; |
4253 | paramsize = NULL; |
4254 | if (m->nparam == 0) { |
4255 | /* |
4256 | * Simple case: the macro is parameterless. Discard the |
4257 | * one token that the macro call took, and push the |
4258 | * expansion back on the to-do stack. |
4259 | */ |
4260 | if (!m->expansion) { |
4261 | if (!strcmp("__FILE__" , m->name)) { |
4262 | const char *file = src_get_fname(); |
4263 | /* nasm_free(tline->text); here? */ |
4264 | tline->text = nasm_quote(file, strlen(file)); |
4265 | tline->type = TOK_STRING; |
4266 | continue; |
4267 | } |
4268 | if (!strcmp("__LINE__" , m->name)) { |
4269 | nasm_free(tline->text); |
4270 | make_tok_num(tline, src_get_linnum()); |
4271 | continue; |
4272 | } |
4273 | if (!strcmp("__BITS__" , m->name)) { |
4274 | nasm_free(tline->text); |
4275 | make_tok_num(tline, globalbits); |
4276 | continue; |
4277 | } |
4278 | tline = delete_Token(tline); |
4279 | continue; |
4280 | } |
4281 | } else { |
4282 | /* |
4283 | * Complicated case: at least one macro with this name |
4284 | * exists and takes parameters. We must find the |
4285 | * parameters in the call, count them, find the SMacro |
4286 | * that corresponds to that form of the macro call, and |
4287 | * substitute for the parameters when we expand. What a |
4288 | * pain. |
4289 | */ |
4290 | /*tline = tline->next; |
4291 | skip_white_(tline); */ |
4292 | do { |
4293 | t = tline->next; |
4294 | while (tok_type_(t, TOK_SMAC_END)) { |
4295 | t->a.mac->in_progress = false; |
4296 | t->text = NULL; |
4297 | t = tline->next = delete_Token(t); |
4298 | } |
4299 | tline = t; |
4300 | } while (tok_type_(tline, TOK_WHITESPACE)); |
4301 | if (!tok_is_(tline, "(" )) { |
4302 | /* |
4303 | * This macro wasn't called with parameters: ignore |
4304 | * the call. (Behaviour borrowed from gnu cpp.) |
4305 | */ |
4306 | tline = mstart; |
4307 | m = NULL; |
4308 | } else { |
4309 | int paren = 0; |
4310 | int white = 0; |
4311 | brackets = 0; |
4312 | nparam = 0; |
4313 | sparam = PARAM_DELTA; |
4314 | params = nasm_malloc(sparam * sizeof(Token *)); |
4315 | params[0] = tline->next; |
4316 | paramsize = nasm_malloc(sparam * sizeof(int)); |
4317 | paramsize[0] = 0; |
4318 | while (true) { /* parameter loop */ |
4319 | /* |
4320 | * For some unusual expansions |
4321 | * which concatenates function call |
4322 | */ |
4323 | t = tline->next; |
4324 | while (tok_type_(t, TOK_SMAC_END)) { |
4325 | t->a.mac->in_progress = false; |
4326 | t->text = NULL; |
4327 | t = tline->next = delete_Token(t); |
4328 | } |
4329 | tline = t; |
4330 | |
4331 | if (!tline) { |
4332 | nasm_error(ERR_NONFATAL, |
4333 | "macro call expects terminating `)'" ); |
4334 | break; |
4335 | } |
4336 | if (tline->type == TOK_WHITESPACE |
4337 | && brackets <= 0) { |
4338 | if (paramsize[nparam]) |
4339 | white++; |
4340 | else |
4341 | params[nparam] = tline->next; |
4342 | continue; /* parameter loop */ |
4343 | } |
4344 | if (tline->type == TOK_OTHER |
4345 | && tline->text[1] == 0) { |
4346 | char ch = tline->text[0]; |
4347 | if (ch == ',' && !paren && brackets <= 0) { |
4348 | if (++nparam >= sparam) { |
4349 | sparam += PARAM_DELTA; |
4350 | params = nasm_realloc(params, |
4351 | sparam * sizeof(Token *)); |
4352 | paramsize = nasm_realloc(paramsize, |
4353 | sparam * sizeof(int)); |
4354 | } |
4355 | params[nparam] = tline->next; |
4356 | paramsize[nparam] = 0; |
4357 | white = 0; |
4358 | continue; /* parameter loop */ |
4359 | } |
4360 | if (ch == '{' && |
4361 | (brackets > 0 || (brackets == 0 && |
4362 | !paramsize[nparam]))) |
4363 | { |
4364 | if (!(brackets++)) { |
4365 | params[nparam] = tline->next; |
4366 | continue; /* parameter loop */ |
4367 | } |
4368 | } |
4369 | if (ch == '}' && brackets > 0) |
4370 | if (--brackets == 0) { |
4371 | brackets = -1; |
4372 | continue; /* parameter loop */ |
4373 | } |
4374 | if (ch == '(' && !brackets) |
4375 | paren++; |
4376 | if (ch == ')' && brackets <= 0) |
4377 | if (--paren < 0) |
4378 | break; |
4379 | } |
4380 | if (brackets < 0) { |
4381 | brackets = 0; |
4382 | nasm_error(ERR_NONFATAL, "braces do not " |
4383 | "enclose all of macro parameter" ); |
4384 | } |
4385 | paramsize[nparam] += white + 1; |
4386 | white = 0; |
4387 | } /* parameter loop */ |
4388 | nparam++; |
4389 | while (m && (m->nparam != nparam || |
4390 | mstrcmp(m->name, mname, |
4391 | m->casesense))) |
4392 | m = m->next; |
4393 | if (!m) |
4394 | nasm_error(ERR_WARNING|ERR_PASS1|WARN_MNP, |
4395 | "macro `%s' exists, " |
4396 | "but not taking %d parameters" , |
4397 | mstart->text, nparam); |
4398 | } |
4399 | } |
4400 | if (m && m->in_progress) |
4401 | m = NULL; |
4402 | if (!m) { /* in progess or didn't find '(' or wrong nparam */ |
4403 | /* |
4404 | * Design question: should we handle !tline, which |
4405 | * indicates missing ')' here, or expand those |
4406 | * macros anyway, which requires the (t) test a few |
4407 | * lines down? |
4408 | */ |
4409 | nasm_free(params); |
4410 | nasm_free(paramsize); |
4411 | tline = mstart; |
4412 | } else { |
4413 | /* |
4414 | * Expand the macro: we are placed on the last token of the |
4415 | * call, so that we can easily split the call from the |
4416 | * following tokens. We also start by pushing an SMAC_END |
4417 | * token for the cycle removal. |
4418 | */ |
4419 | t = tline; |
4420 | if (t) { |
4421 | tline = t->next; |
4422 | t->next = NULL; |
4423 | } |
4424 | tt = new_Token(tline, TOK_SMAC_END, NULL, 0); |
4425 | tt->a.mac = m; |
4426 | m->in_progress = true; |
4427 | tline = tt; |
4428 | list_for_each(t, m->expansion) { |
4429 | if (t->type >= TOK_SMAC_PARAM) { |
4430 | Token *pcopy = tline, **ptail = &pcopy; |
4431 | Token *ttt, *pt; |
4432 | int i; |
4433 | |
4434 | ttt = params[t->type - TOK_SMAC_PARAM]; |
4435 | i = paramsize[t->type - TOK_SMAC_PARAM]; |
4436 | while (--i >= 0) { |
4437 | pt = *ptail = new_Token(tline, ttt->type, |
4438 | ttt->text, 0); |
4439 | ptail = &pt->next; |
4440 | ttt = ttt->next; |
4441 | if (!ttt && i > 0) { |
4442 | /* |
4443 | * FIXME: Need to handle more gracefully, |
4444 | * exiting early on agruments analysis. |
4445 | */ |
4446 | nasm_error(ERR_FATAL, |
4447 | "macro `%s' expects %d args" , |
4448 | mstart->text, |
4449 | (int)paramsize[t->type - TOK_SMAC_PARAM]); |
4450 | } |
4451 | } |
4452 | tline = pcopy; |
4453 | } else if (t->type == TOK_PREPROC_Q) { |
4454 | tt = new_Token(tline, TOK_ID, mname, 0); |
4455 | tline = tt; |
4456 | } else if (t->type == TOK_PREPROC_QQ) { |
4457 | tt = new_Token(tline, TOK_ID, m->name, 0); |
4458 | tline = tt; |
4459 | } else { |
4460 | tt = new_Token(tline, t->type, t->text, 0); |
4461 | tline = tt; |
4462 | } |
4463 | } |
4464 | |
4465 | /* |
4466 | * Having done that, get rid of the macro call, and clean |
4467 | * up the parameters. |
4468 | */ |
4469 | nasm_free(params); |
4470 | nasm_free(paramsize); |
4471 | free_tlist(mstart); |
4472 | expanded = true; |
4473 | continue; /* main token loop */ |
4474 | } |
4475 | } |
4476 | } |
4477 | |
4478 | if (tline->type == TOK_SMAC_END) { |
4479 | /* On error path it might already be dropped */ |
4480 | if (tline->a.mac) |
4481 | tline->a.mac->in_progress = false; |
4482 | tline = delete_Token(tline); |
4483 | } else { |
4484 | t = *tail = tline; |
4485 | tline = tline->next; |
4486 | t->a.mac = NULL; |
4487 | t->next = NULL; |
4488 | tail = &t->next; |
4489 | } |
4490 | } |
4491 | |
4492 | /* |
4493 | * Now scan the entire line and look for successive TOK_IDs that resulted |
4494 | * after expansion (they can't be produced by tokenize()). The successive |
4495 | * TOK_IDs should be concatenated. |
4496 | * Also we look for %+ tokens and concatenate the tokens before and after |
4497 | * them (without white spaces in between). |
4498 | */ |
4499 | if (expanded) { |
4500 | const struct tokseq_match t[] = { |
4501 | { |
4502 | PP_CONCAT_MASK(TOK_ID) | |
4503 | PP_CONCAT_MASK(TOK_PREPROC_ID), /* head */ |
4504 | PP_CONCAT_MASK(TOK_ID) | |
4505 | PP_CONCAT_MASK(TOK_PREPROC_ID) | |
4506 | PP_CONCAT_MASK(TOK_NUMBER) /* tail */ |
4507 | } |
4508 | }; |
4509 | if (paste_tokens(&thead, t, ARRAY_SIZE(t), true)) { |
4510 | /* |
4511 | * If we concatenated something, *and* we had previously expanded |
4512 | * an actual macro, scan the lines again for macros... |
4513 | */ |
4514 | tline = thead; |
4515 | expanded = false; |
4516 | goto again; |
4517 | } |
4518 | } |
4519 | |
4520 | err: |
4521 | if (org_tline) { |
4522 | if (thead) { |
4523 | *org_tline = *thead; |
4524 | /* since we just gave text to org_line, don't free it */ |
4525 | thead->text = NULL; |
4526 | delete_Token(thead); |
4527 | } else { |
4528 | /* the expression expanded to empty line; |
4529 | we can't return NULL for some reasons |
4530 | we just set the line to a single WHITESPACE token. */ |
4531 | memset(org_tline, 0, sizeof(*org_tline)); |
4532 | org_tline->text = NULL; |
4533 | org_tline->type = TOK_WHITESPACE; |
4534 | } |
4535 | thead = org_tline; |
4536 | } |
4537 | |
4538 | return thead; |
4539 | } |
4540 | |
4541 | /* |
4542 | * Similar to expand_smacro but used exclusively with macro identifiers |
4543 | * right before they are fetched in. The reason is that there can be |
4544 | * identifiers consisting of several subparts. We consider that if there |
4545 | * are more than one element forming the name, user wants a expansion, |
4546 | * otherwise it will be left as-is. Example: |
4547 | * |
4548 | * %define %$abc cde |
4549 | * |
4550 | * the identifier %$abc will be left as-is so that the handler for %define |
4551 | * will suck it and define the corresponding value. Other case: |
4552 | * |
4553 | * %define _%$abc cde |
4554 | * |
4555 | * In this case user wants name to be expanded *before* %define starts |
4556 | * working, so we'll expand %$abc into something (if it has a value; |
4557 | * otherwise it will be left as-is) then concatenate all successive |
4558 | * PP_IDs into one. |
4559 | */ |
4560 | static Token *expand_id(Token * tline) |
4561 | { |
4562 | Token *cur, *oldnext = NULL; |
4563 | |
4564 | if (!tline || !tline->next) |
4565 | return tline; |
4566 | |
4567 | cur = tline; |
4568 | while (cur->next && |
4569 | (cur->next->type == TOK_ID || |
4570 | cur->next->type == TOK_PREPROC_ID |
4571 | || cur->next->type == TOK_NUMBER)) |
4572 | cur = cur->next; |
4573 | |
4574 | /* If identifier consists of just one token, don't expand */ |
4575 | if (cur == tline) |
4576 | return tline; |
4577 | |
4578 | if (cur) { |
4579 | oldnext = cur->next; /* Detach the tail past identifier */ |
4580 | cur->next = NULL; /* so that expand_smacro stops here */ |
4581 | } |
4582 | |
4583 | tline = expand_smacro(tline); |
4584 | |
4585 | if (cur) { |
4586 | /* expand_smacro possibly changhed tline; re-scan for EOL */ |
4587 | cur = tline; |
4588 | while (cur && cur->next) |
4589 | cur = cur->next; |
4590 | if (cur) |
4591 | cur->next = oldnext; |
4592 | } |
4593 | |
4594 | return tline; |
4595 | } |
4596 | |
4597 | /* |
4598 | * Determine whether the given line constitutes a multi-line macro |
4599 | * call, and return the MMacro structure called if so. Doesn't have |
4600 | * to check for an initial label - that's taken care of in |
4601 | * expand_mmacro - but must check numbers of parameters. Guaranteed |
4602 | * to be called with tline->type == TOK_ID, so the putative macro |
4603 | * name is easy to find. |
4604 | */ |
4605 | static MMacro *is_mmacro(Token * tline, Token *** params_array) |
4606 | { |
4607 | MMacro *head, *m; |
4608 | Token **params; |
4609 | int nparam; |
4610 | |
4611 | head = (MMacro *) hash_findix(&mmacros, tline->text); |
4612 | |
4613 | /* |
4614 | * Efficiency: first we see if any macro exists with the given |
4615 | * name. If not, we can return NULL immediately. _Then_ we |
4616 | * count the parameters, and then we look further along the |
4617 | * list if necessary to find the proper MMacro. |
4618 | */ |
4619 | list_for_each(m, head) |
4620 | if (!mstrcmp(m->name, tline->text, m->casesense)) |
4621 | break; |
4622 | if (!m) |
4623 | return NULL; |
4624 | |
4625 | /* |
4626 | * OK, we have a potential macro. Count and demarcate the |
4627 | * parameters. |
4628 | */ |
4629 | count_mmac_params(tline->next, &nparam, ¶ms); |
4630 | |
4631 | /* |
4632 | * So we know how many parameters we've got. Find the MMacro |
4633 | * structure that handles this number. |
4634 | */ |
4635 | while (m) { |
4636 | if (m->nparam_min <= nparam |
4637 | && (m->plus || nparam <= m->nparam_max)) { |
4638 | /* |
4639 | * This one is right. Just check if cycle removal |
4640 | * prohibits us using it before we actually celebrate... |
4641 | */ |
4642 | if (m->in_progress > m->max_depth) { |
4643 | if (m->max_depth > 0) { |
4644 | nasm_error(ERR_WARNING, |
4645 | "reached maximum recursion depth of %i" , |
4646 | m->max_depth); |
4647 | } |
4648 | nasm_free(params); |
4649 | return NULL; |
4650 | } |
4651 | /* |
4652 | * It's right, and we can use it. Add its default |
4653 | * parameters to the end of our list if necessary. |
4654 | */ |
4655 | if (m->defaults && nparam < m->nparam_min + m->ndefs) { |
4656 | params = |
4657 | nasm_realloc(params, |
4658 | ((m->nparam_min + m->ndefs + |
4659 | 1) * sizeof(*params))); |
4660 | while (nparam < m->nparam_min + m->ndefs) { |
4661 | params[nparam] = m->defaults[nparam - m->nparam_min]; |
4662 | nparam++; |
4663 | } |
4664 | } |
4665 | /* |
4666 | * If we've gone over the maximum parameter count (and |
4667 | * we're in Plus mode), ignore parameters beyond |
4668 | * nparam_max. |
4669 | */ |
4670 | if (m->plus && nparam > m->nparam_max) |
4671 | nparam = m->nparam_max; |
4672 | /* |
4673 | * Then terminate the parameter list, and leave. |
4674 | */ |
4675 | if (!params) { /* need this special case */ |
4676 | params = nasm_malloc(sizeof(*params)); |
4677 | nparam = 0; |
4678 | } |
4679 | params[nparam] = NULL; |
4680 | *params_array = params; |
4681 | return m; |
4682 | } |
4683 | /* |
4684 | * This one wasn't right: look for the next one with the |
4685 | * same name. |
4686 | */ |
4687 | list_for_each(m, m->next) |
4688 | if (!mstrcmp(m->name, tline->text, m->casesense)) |
4689 | break; |
4690 | } |
4691 | |
4692 | /* |
4693 | * After all that, we didn't find one with the right number of |
4694 | * parameters. Issue a warning, and fail to expand the macro. |
4695 | */ |
4696 | nasm_error(ERR_WARNING|ERR_PASS1|WARN_MNP, |
4697 | "macro `%s' exists, but not taking %d parameters" , |
4698 | tline->text, nparam); |
4699 | nasm_free(params); |
4700 | return NULL; |
4701 | } |
4702 | |
4703 | |
4704 | /* |
4705 | * Save MMacro invocation specific fields in |
4706 | * preparation for a recursive macro expansion |
4707 | */ |
4708 | static void push_mmacro(MMacro *m) |
4709 | { |
4710 | MMacroInvocation *i; |
4711 | |
4712 | i = nasm_malloc(sizeof(MMacroInvocation)); |
4713 | i->prev = m->prev; |
4714 | i->params = m->params; |
4715 | i->iline = m->iline; |
4716 | i->nparam = m->nparam; |
4717 | i->rotate = m->rotate; |
4718 | i->paramlen = m->paramlen; |
4719 | i->unique = m->unique; |
4720 | i->condcnt = m->condcnt; |
4721 | m->prev = i; |
4722 | } |
4723 | |
4724 | |
4725 | /* |
4726 | * Restore MMacro invocation specific fields that were |
4727 | * saved during a previous recursive macro expansion |
4728 | */ |
4729 | static void pop_mmacro(MMacro *m) |
4730 | { |
4731 | MMacroInvocation *i; |
4732 | |
4733 | if (m->prev) { |
4734 | i = m->prev; |
4735 | m->prev = i->prev; |
4736 | m->params = i->params; |
4737 | m->iline = i->iline; |
4738 | m->nparam = i->nparam; |
4739 | m->rotate = i->rotate; |
4740 | m->paramlen = i->paramlen; |
4741 | m->unique = i->unique; |
4742 | m->condcnt = i->condcnt; |
4743 | nasm_free(i); |
4744 | } |
4745 | } |
4746 | |
4747 | |
4748 | /* |
4749 | * Expand the multi-line macro call made by the given line, if |
4750 | * there is one to be expanded. If there is, push the expansion on |
4751 | * istk->expansion and return 1. Otherwise return 0. |
4752 | */ |
4753 | static int expand_mmacro(Token * tline) |
4754 | { |
4755 | Token *startline = tline; |
4756 | Token *label = NULL; |
4757 | int dont_prepend = 0; |
4758 | Token **params, *t, *tt; |
4759 | MMacro *m; |
4760 | Line *l, *ll; |
4761 | int i, nparam, *paramlen; |
4762 | const char *mname; |
4763 | |
4764 | t = tline; |
4765 | skip_white_(t); |
4766 | /* if (!tok_type_(t, TOK_ID)) Lino 02/25/02 */ |
4767 | if (!tok_type_(t, TOK_ID) && !tok_type_(t, TOK_PREPROC_ID)) |
4768 | return 0; |
4769 | m = is_mmacro(t, ¶ms); |
4770 | if (m) { |
4771 | mname = t->text; |
4772 | } else { |
4773 | Token *last; |
4774 | /* |
4775 | * We have an id which isn't a macro call. We'll assume |
4776 | * it might be a label; we'll also check to see if a |
4777 | * colon follows it. Then, if there's another id after |
4778 | * that lot, we'll check it again for macro-hood. |
4779 | */ |
4780 | label = last = t; |
4781 | t = t->next; |
4782 | if (tok_type_(t, TOK_WHITESPACE)) |
4783 | last = t, t = t->next; |
4784 | if (tok_is_(t, ":" )) { |
4785 | dont_prepend = 1; |
4786 | last = t, t = t->next; |
4787 | if (tok_type_(t, TOK_WHITESPACE)) |
4788 | last = t, t = t->next; |
4789 | } |
4790 | if (!tok_type_(t, TOK_ID) || !(m = is_mmacro(t, ¶ms))) |
4791 | return 0; |
4792 | last->next = NULL; |
4793 | mname = t->text; |
4794 | tline = t; |
4795 | } |
4796 | |
4797 | /* |
4798 | * Fix up the parameters: this involves stripping leading and |
4799 | * trailing whitespace, then stripping braces if they are |
4800 | * present. |
4801 | */ |
4802 | for (nparam = 0; params[nparam]; nparam++) ; |
4803 | paramlen = nparam ? nasm_malloc(nparam * sizeof(*paramlen)) : NULL; |
4804 | |
4805 | for (i = 0; params[i]; i++) { |
4806 | int brace = 0; |
4807 | int comma = (!m->plus || i < nparam - 1); |
4808 | |
4809 | t = params[i]; |
4810 | skip_white_(t); |
4811 | if (tok_is_(t, "{" )) |
4812 | t = t->next, brace++, comma = false; |
4813 | params[i] = t; |
4814 | paramlen[i] = 0; |
4815 | while (t) { |
4816 | if (comma && t->type == TOK_OTHER && !strcmp(t->text, "," )) |
4817 | break; /* ... because we have hit a comma */ |
4818 | if (comma && t->type == TOK_WHITESPACE |
4819 | && tok_is_(t->next, "," )) |
4820 | break; /* ... or a space then a comma */ |
4821 | if (brace && t->type == TOK_OTHER) { |
4822 | if (t->text[0] == '{') |
4823 | brace++; /* ... or a nested opening brace */ |
4824 | else if (t->text[0] == '}') |
4825 | if (!--brace) |
4826 | break; /* ... or a brace */ |
4827 | } |
4828 | t = t->next; |
4829 | paramlen[i]++; |
4830 | } |
4831 | if (brace) |
4832 | nasm_error(ERR_NONFATAL, "macro params should be enclosed in braces" ); |
4833 | } |
4834 | |
4835 | /* |
4836 | * OK, we have a MMacro structure together with a set of |
4837 | * parameters. We must now go through the expansion and push |
4838 | * copies of each Line on to istk->expansion. Substitution of |
4839 | * parameter tokens and macro-local tokens doesn't get done |
4840 | * until the single-line macro substitution process; this is |
4841 | * because delaying them allows us to change the semantics |
4842 | * later through %rotate. |
4843 | * |
4844 | * First, push an end marker on to istk->expansion, mark this |
4845 | * macro as in progress, and set up its invocation-specific |
4846 | * variables. |
4847 | */ |
4848 | ll = nasm_malloc(sizeof(Line)); |
4849 | ll->next = istk->expansion; |
4850 | ll->finishes = m; |
4851 | ll->first = NULL; |
4852 | istk->expansion = ll; |
4853 | |
4854 | /* |
4855 | * Save the previous MMacro expansion in the case of |
4856 | * macro recursion |
4857 | */ |
4858 | if (m->max_depth && m->in_progress) |
4859 | push_mmacro(m); |
4860 | |
4861 | m->in_progress ++; |
4862 | m->params = params; |
4863 | m->iline = tline; |
4864 | m->nparam = nparam; |
4865 | m->rotate = 0; |
4866 | m->paramlen = paramlen; |
4867 | m->unique = unique++; |
4868 | m->lineno = 0; |
4869 | m->condcnt = 0; |
4870 | |
4871 | m->next_active = istk->mstk; |
4872 | istk->mstk = m; |
4873 | |
4874 | list_for_each(l, m->expansion) { |
4875 | Token **tail; |
4876 | |
4877 | ll = nasm_malloc(sizeof(Line)); |
4878 | ll->finishes = NULL; |
4879 | ll->next = istk->expansion; |
4880 | istk->expansion = ll; |
4881 | tail = &ll->first; |
4882 | |
4883 | list_for_each(t, l->first) { |
4884 | Token *x = t; |
4885 | switch (t->type) { |
4886 | case TOK_PREPROC_Q: |
4887 | tt = *tail = new_Token(NULL, TOK_ID, mname, 0); |
4888 | break; |
4889 | case TOK_PREPROC_QQ: |
4890 | tt = *tail = new_Token(NULL, TOK_ID, m->name, 0); |
4891 | break; |
4892 | case TOK_PREPROC_ID: |
4893 | if (t->text[1] == '0' && t->text[2] == '0') { |
4894 | dont_prepend = -1; |
4895 | x = label; |
4896 | if (!x) |
4897 | continue; |
4898 | } |
4899 | /* fall through */ |
4900 | default: |
4901 | tt = *tail = new_Token(NULL, x->type, x->text, 0); |
4902 | break; |
4903 | } |
4904 | tail = &tt->next; |
4905 | } |
4906 | *tail = NULL; |
4907 | } |
4908 | |
4909 | /* |
4910 | * If we had a label, push it on as the first line of |
4911 | * the macro expansion. |
4912 | */ |
4913 | if (label) { |
4914 | if (dont_prepend < 0) |
4915 | free_tlist(startline); |
4916 | else { |
4917 | ll = nasm_malloc(sizeof(Line)); |
4918 | ll->finishes = NULL; |
4919 | ll->next = istk->expansion; |
4920 | istk->expansion = ll; |
4921 | ll->first = startline; |
4922 | if (!dont_prepend) { |
4923 | while (label->next) |
4924 | label = label->next; |
4925 | label->next = tt = new_Token(NULL, TOK_OTHER, ":" , 0); |
4926 | } |
4927 | } |
4928 | } |
4929 | |
4930 | lfmt->uplevel(m->nolist ? LIST_MACRO_NOLIST : LIST_MACRO); |
4931 | |
4932 | return 1; |
4933 | } |
4934 | |
4935 | /* |
4936 | * This function adds macro names to error messages, and suppresses |
4937 | * them if necessary. |
4938 | */ |
4939 | static void pp_verror(int severity, const char *fmt, va_list arg) |
4940 | { |
4941 | char buff[BUFSIZ]; |
4942 | MMacro *mmac = NULL; |
4943 | int delta = 0; |
4944 | |
4945 | /* |
4946 | * If we're in a dead branch of IF or something like it, ignore the error. |
4947 | * However, because %else etc are evaluated in the state context |
4948 | * of the previous branch, errors might get lost: |
4949 | * %if 0 ... %else trailing garbage ... %endif |
4950 | * So %else etc should set the ERR_PP_PRECOND flag. |
4951 | */ |
4952 | if ((severity & ERR_MASK) < ERR_FATAL && |
4953 | istk && istk->conds && |
4954 | ((severity & ERR_PP_PRECOND) ? |
4955 | istk->conds->state == COND_NEVER : |
4956 | !emitting(istk->conds->state))) |
4957 | return; |
4958 | |
4959 | /* get %macro name */ |
4960 | if (!(severity & ERR_NOFILE) && istk && istk->mstk) { |
4961 | mmac = istk->mstk; |
4962 | /* but %rep blocks should be skipped */ |
4963 | while (mmac && !mmac->name) |
4964 | mmac = mmac->next_active, delta++; |
4965 | } |
4966 | |
4967 | if (mmac) { |
4968 | vsnprintf(buff, sizeof(buff), fmt, arg); |
4969 | |
4970 | nasm_set_verror(real_verror); |
4971 | nasm_error(severity, "(%s:%d) %s" , |
4972 | mmac->name, mmac->lineno - delta, buff); |
4973 | nasm_set_verror(pp_verror); |
4974 | } else { |
4975 | real_verror(severity, fmt, arg); |
4976 | } |
4977 | } |
4978 | |
4979 | static void |
4980 | pp_reset(const char *file, int apass, StrList **deplist) |
4981 | { |
4982 | Token *t; |
4983 | |
4984 | cstk = NULL; |
4985 | istk = nasm_malloc(sizeof(Include)); |
4986 | istk->next = NULL; |
4987 | istk->conds = NULL; |
4988 | istk->expansion = NULL; |
4989 | istk->mstk = NULL; |
4990 | istk->fp = nasm_open_read(file, NF_TEXT); |
4991 | istk->fname = NULL; |
4992 | src_set(0, file); |
4993 | istk->lineinc = 1; |
4994 | if (!istk->fp) |
4995 | nasm_fatal(ERR_NOFILE, "unable to open input file `%s'" , file); |
4996 | defining = NULL; |
4997 | nested_mac_count = 0; |
4998 | nested_rep_count = 0; |
4999 | init_macros(); |
5000 | unique = 0; |
5001 | |
5002 | if (tasm_compatible_mode) |
5003 | pp_add_stdmac(nasm_stdmac_tasm); |
5004 | |
5005 | pp_add_stdmac(nasm_stdmac_nasm); |
5006 | pp_add_stdmac(nasm_stdmac_version); |
5007 | |
5008 | if (extrastdmac) |
5009 | pp_add_stdmac(extrastdmac); |
5010 | |
5011 | stdmacpos = stdmacros[0]; |
5012 | stdmacnext = &stdmacros[1]; |
5013 | |
5014 | do_predef = true; |
5015 | |
5016 | /* |
5017 | * 0 for dependencies, 1 for preparatory passes, 2 for final pass. |
5018 | * The caller, however, will also pass in 3 for preprocess-only so |
5019 | * we can set __PASS__ accordingly. |
5020 | */ |
5021 | pass = apass > 2 ? 2 : apass; |
5022 | |
5023 | dephead = deplist; |
5024 | nasm_add_string_to_strlist(dephead, file); |
5025 | |
5026 | /* |
5027 | * Define the __PASS__ macro. This is defined here unlike |
5028 | * all the other builtins, because it is special -- it varies between |
5029 | * passes. |
5030 | */ |
5031 | t = nasm_malloc(sizeof(*t)); |
5032 | t->next = NULL; |
5033 | make_tok_num(t, apass); |
5034 | t->a.mac = NULL; |
5035 | define_smacro(NULL, "__PASS__" , true, 0, t); |
5036 | } |
5037 | |
5038 | static void pp_init(void) |
5039 | { |
5040 | hash_init(&FileHash, HASH_MEDIUM); |
5041 | } |
5042 | |
5043 | static char *pp_getline(void) |
5044 | { |
5045 | char *line; |
5046 | Token *tline; |
5047 | |
5048 | real_verror = nasm_set_verror(pp_verror); |
5049 | |
5050 | while (1) { |
5051 | /* |
5052 | * Fetch a tokenized line, either from the macro-expansion |
5053 | * buffer or from the input file. |
5054 | */ |
5055 | tline = NULL; |
5056 | while (istk->expansion && istk->expansion->finishes) { |
5057 | Line *l = istk->expansion; |
5058 | if (!l->finishes->name && l->finishes->in_progress > 1) { |
5059 | Line *ll; |
5060 | |
5061 | /* |
5062 | * This is a macro-end marker for a macro with no |
5063 | * name, which means it's not really a macro at all |
5064 | * but a %rep block, and the `in_progress' field is |
5065 | * more than 1, meaning that we still need to |
5066 | * repeat. (1 means the natural last repetition; 0 |
5067 | * means termination by %exitrep.) We have |
5068 | * therefore expanded up to the %endrep, and must |
5069 | * push the whole block on to the expansion buffer |
5070 | * again. We don't bother to remove the macro-end |
5071 | * marker: we'd only have to generate another one |
5072 | * if we did. |
5073 | */ |
5074 | l->finishes->in_progress--; |
5075 | list_for_each(l, l->finishes->expansion) { |
5076 | Token *t, *tt, **tail; |
5077 | |
5078 | ll = nasm_malloc(sizeof(Line)); |
5079 | ll->next = istk->expansion; |
5080 | ll->finishes = NULL; |
5081 | ll->first = NULL; |
5082 | tail = &ll->first; |
5083 | |
5084 | list_for_each(t, l->first) { |
5085 | if (t->text || t->type == TOK_WHITESPACE) { |
5086 | tt = *tail = new_Token(NULL, t->type, t->text, 0); |
5087 | tail = &tt->next; |
5088 | } |
5089 | } |
5090 | |
5091 | istk->expansion = ll; |
5092 | } |
5093 | } else { |
5094 | /* |
5095 | * Check whether a `%rep' was started and not ended |
5096 | * within this macro expansion. This can happen and |
5097 | * should be detected. It's a fatal error because |
5098 | * I'm too confused to work out how to recover |
5099 | * sensibly from it. |
5100 | */ |
5101 | if (defining) { |
5102 | if (defining->name) |
5103 | nasm_panic(0, "defining with name in expansion" ); |
5104 | else if (istk->mstk->name) |
5105 | nasm_fatal(0, "`%%rep' without `%%endrep' within" |
5106 | " expansion of macro `%s'" , |
5107 | istk->mstk->name); |
5108 | } |
5109 | |
5110 | /* |
5111 | * FIXME: investigate the relationship at this point between |
5112 | * istk->mstk and l->finishes |
5113 | */ |
5114 | { |
5115 | MMacro *m = istk->mstk; |
5116 | istk->mstk = m->next_active; |
5117 | if (m->name) { |
5118 | /* |
5119 | * This was a real macro call, not a %rep, and |
5120 | * therefore the parameter information needs to |
5121 | * be freed. |
5122 | */ |
5123 | if (m->prev) { |
5124 | pop_mmacro(m); |
5125 | l->finishes->in_progress --; |
5126 | } else { |
5127 | nasm_free(m->params); |
5128 | free_tlist(m->iline); |
5129 | nasm_free(m->paramlen); |
5130 | l->finishes->in_progress = 0; |
5131 | } |
5132 | } |
5133 | |
5134 | /* |
5135 | * FIXME It is incorrect to always free_mmacro here. |
5136 | * It leads to usage-after-free. |
5137 | * |
5138 | * https://bugzilla.nasm.us/show_bug.cgi?id=3392414 |
5139 | */ |
5140 | #if 0 |
5141 | else |
5142 | free_mmacro(m); |
5143 | #endif |
5144 | } |
5145 | istk->expansion = l->next; |
5146 | nasm_free(l); |
5147 | lfmt->downlevel(LIST_MACRO); |
5148 | } |
5149 | } |
5150 | while (1) { /* until we get a line we can use */ |
5151 | |
5152 | if (istk->expansion) { /* from a macro expansion */ |
5153 | char *p; |
5154 | Line *l = istk->expansion; |
5155 | if (istk->mstk) |
5156 | istk->mstk->lineno++; |
5157 | tline = l->first; |
5158 | istk->expansion = l->next; |
5159 | nasm_free(l); |
5160 | p = detoken(tline, false); |
5161 | lfmt->line(LIST_MACRO, p); |
5162 | nasm_free(p); |
5163 | break; |
5164 | } |
5165 | line = read_line(); |
5166 | if (line) { /* from the current input file */ |
5167 | line = prepreproc(line); |
5168 | tline = tokenize(line); |
5169 | nasm_free(line); |
5170 | break; |
5171 | } |
5172 | /* |
5173 | * The current file has ended; work down the istk |
5174 | */ |
5175 | { |
5176 | Include *i = istk; |
5177 | fclose(i->fp); |
5178 | if (i->conds) { |
5179 | /* nasm_error can't be conditionally suppressed */ |
5180 | nasm_fatal(0, |
5181 | "expected `%%endif' before end of file" ); |
5182 | } |
5183 | /* only set line and file name if there's a next node */ |
5184 | if (i->next) |
5185 | src_set(i->lineno, i->fname); |
5186 | istk = i->next; |
5187 | lfmt->downlevel(LIST_INCLUDE); |
5188 | nasm_free(i); |
5189 | if (!istk) { |
5190 | line = NULL; |
5191 | goto done; |
5192 | } |
5193 | if (istk->expansion && istk->expansion->finishes) |
5194 | break; |
5195 | } |
5196 | } |
5197 | |
5198 | /* |
5199 | * We must expand MMacro parameters and MMacro-local labels |
5200 | * _before_ we plunge into directive processing, to cope |
5201 | * with things like `%define something %1' such as STRUC |
5202 | * uses. Unless we're _defining_ a MMacro, in which case |
5203 | * those tokens should be left alone to go into the |
5204 | * definition; and unless we're in a non-emitting |
5205 | * condition, in which case we don't want to meddle with |
5206 | * anything. |
5207 | */ |
5208 | if (!defining && !(istk->conds && !emitting(istk->conds->state)) |
5209 | && !(istk->mstk && !istk->mstk->in_progress)) { |
5210 | tline = expand_mmac_params(tline); |
5211 | } |
5212 | |
5213 | /* |
5214 | * Check the line to see if it's a preprocessor directive. |
5215 | */ |
5216 | if (do_directive(tline, &line) == DIRECTIVE_FOUND) { |
5217 | if (line) |
5218 | break; /* Directive generated output */ |
5219 | else |
5220 | continue; |
5221 | } else if (defining) { |
5222 | /* |
5223 | * We're defining a multi-line macro. We emit nothing |
5224 | * at all, and just |
5225 | * shove the tokenized line on to the macro definition. |
5226 | */ |
5227 | Line *l = nasm_malloc(sizeof(Line)); |
5228 | l->next = defining->expansion; |
5229 | l->first = tline; |
5230 | l->finishes = NULL; |
5231 | defining->expansion = l; |
5232 | continue; |
5233 | } else if (istk->conds && !emitting(istk->conds->state)) { |
5234 | /* |
5235 | * We're in a non-emitting branch of a condition block. |
5236 | * Emit nothing at all, not even a blank line: when we |
5237 | * emerge from the condition we'll give a line-number |
5238 | * directive so we keep our place correctly. |
5239 | */ |
5240 | free_tlist(tline); |
5241 | continue; |
5242 | } else if (istk->mstk && !istk->mstk->in_progress) { |
5243 | /* |
5244 | * We're in a %rep block which has been terminated, so |
5245 | * we're walking through to the %endrep without |
5246 | * emitting anything. Emit nothing at all, not even a |
5247 | * blank line: when we emerge from the %rep block we'll |
5248 | * give a line-number directive so we keep our place |
5249 | * correctly. |
5250 | */ |
5251 | free_tlist(tline); |
5252 | continue; |
5253 | } else { |
5254 | tline = expand_smacro(tline); |
5255 | if (!expand_mmacro(tline)) { |
5256 | /* |
5257 | * De-tokenize the line again, and emit it. |
5258 | */ |
5259 | line = detoken(tline, true); |
5260 | free_tlist(tline); |
5261 | break; |
5262 | } else { |
5263 | continue; /* expand_mmacro calls free_tlist */ |
5264 | } |
5265 | } |
5266 | } |
5267 | |
5268 | done: |
5269 | nasm_set_verror(real_verror); |
5270 | return line; |
5271 | } |
5272 | |
5273 | static void pp_cleanup(int pass) |
5274 | { |
5275 | real_verror = nasm_set_verror(pp_verror); |
5276 | |
5277 | if (defining) { |
5278 | if (defining->name) { |
5279 | nasm_error(ERR_NONFATAL, |
5280 | "end of file while still defining macro `%s'" , |
5281 | defining->name); |
5282 | } else { |
5283 | nasm_error(ERR_NONFATAL, "end of file while still in %%rep" ); |
5284 | } |
5285 | |
5286 | free_mmacro(defining); |
5287 | defining = NULL; |
5288 | } |
5289 | |
5290 | nasm_set_verror(real_verror); |
5291 | |
5292 | while (cstk) |
5293 | ctx_pop(); |
5294 | free_macros(); |
5295 | while (istk) { |
5296 | Include *i = istk; |
5297 | istk = istk->next; |
5298 | fclose(i->fp); |
5299 | nasm_free(i); |
5300 | } |
5301 | while (cstk) |
5302 | ctx_pop(); |
5303 | src_set_fname(NULL); |
5304 | if (pass == 0) { |
5305 | IncPath *i; |
5306 | free_llist(predef); |
5307 | predef = NULL; |
5308 | delete_Blocks(); |
5309 | freeTokens = NULL; |
5310 | while ((i = ipath)) { |
5311 | ipath = i->next; |
5312 | if (i->path) |
5313 | nasm_free(i->path); |
5314 | nasm_free(i); |
5315 | } |
5316 | } |
5317 | } |
5318 | |
5319 | static void pp_include_path(char *path) |
5320 | { |
5321 | IncPath *i; |
5322 | |
5323 | i = nasm_malloc(sizeof(IncPath)); |
5324 | i->path = path ? nasm_strdup(path) : NULL; |
5325 | i->next = NULL; |
5326 | |
5327 | if (ipath) { |
5328 | IncPath *j = ipath; |
5329 | while (j->next) |
5330 | j = j->next; |
5331 | j->next = i; |
5332 | } else { |
5333 | ipath = i; |
5334 | } |
5335 | } |
5336 | |
5337 | static void pp_pre_include(char *fname) |
5338 | { |
5339 | Token *inc, *space, *name; |
5340 | Line *l; |
5341 | |
5342 | name = new_Token(NULL, TOK_INTERNAL_STRING, fname, 0); |
5343 | space = new_Token(name, TOK_WHITESPACE, NULL, 0); |
5344 | inc = new_Token(space, TOK_PREPROC_ID, "%include" , 0); |
5345 | |
5346 | l = nasm_malloc(sizeof(Line)); |
5347 | l->next = predef; |
5348 | l->first = inc; |
5349 | l->finishes = NULL; |
5350 | predef = l; |
5351 | } |
5352 | |
5353 | static void pp_pre_define(char *definition) |
5354 | { |
5355 | Token *def, *space; |
5356 | Line *l; |
5357 | char *equals; |
5358 | |
5359 | real_verror = nasm_set_verror(pp_verror); |
5360 | |
5361 | equals = strchr(definition, '='); |
5362 | space = new_Token(NULL, TOK_WHITESPACE, NULL, 0); |
5363 | def = new_Token(space, TOK_PREPROC_ID, "%define" , 0); |
5364 | if (equals) |
5365 | *equals = ' '; |
5366 | space->next = tokenize(definition); |
5367 | if (equals) |
5368 | *equals = '='; |
5369 | |
5370 | if (space->next->type != TOK_PREPROC_ID && |
5371 | space->next->type != TOK_ID) |
5372 | nasm_error(ERR_WARNING, "pre-defining non ID `%s\'\n" , definition); |
5373 | |
5374 | l = nasm_malloc(sizeof(Line)); |
5375 | l->next = predef; |
5376 | l->first = def; |
5377 | l->finishes = NULL; |
5378 | predef = l; |
5379 | |
5380 | nasm_set_verror(real_verror); |
5381 | } |
5382 | |
5383 | static void pp_pre_undefine(char *definition) |
5384 | { |
5385 | Token *def, *space; |
5386 | Line *l; |
5387 | |
5388 | space = new_Token(NULL, TOK_WHITESPACE, NULL, 0); |
5389 | def = new_Token(space, TOK_PREPROC_ID, "%undef" , 0); |
5390 | space->next = tokenize(definition); |
5391 | |
5392 | l = nasm_malloc(sizeof(Line)); |
5393 | l->next = predef; |
5394 | l->first = def; |
5395 | l->finishes = NULL; |
5396 | predef = l; |
5397 | } |
5398 | |
5399 | /* Insert an early preprocessor command that doesn't need special handling */ |
5400 | static void pp_pre_command(const char *what, char *string) |
5401 | { |
5402 | char *cmd; |
5403 | Token *def, *space; |
5404 | Line *l; |
5405 | |
5406 | def = tokenize(string); |
5407 | if (what) { |
5408 | cmd = nasm_strcat(what[0] == '%' ? "" : "%" , what); |
5409 | space = new_Token(def, TOK_WHITESPACE, NULL, 0); |
5410 | def = new_Token(space, TOK_PREPROC_ID, cmd, 0); |
5411 | } |
5412 | |
5413 | l = nasm_malloc(sizeof(Line)); |
5414 | l->next = predef; |
5415 | l->first = def; |
5416 | l->finishes = NULL; |
5417 | predef = l; |
5418 | } |
5419 | |
5420 | static void pp_add_stdmac(macros_t *macros) |
5421 | { |
5422 | macros_t **mp; |
5423 | |
5424 | /* Find the end of the list and avoid duplicates */ |
5425 | for (mp = stdmacros; *mp; mp++) { |
5426 | if (*mp == macros) |
5427 | return; /* Nothing to do */ |
5428 | } |
5429 | |
5430 | nasm_assert(mp < &stdmacros[ARRAY_SIZE(stdmacros)-1]); |
5431 | |
5432 | *mp = macros; |
5433 | } |
5434 | |
5435 | static void (macros_t *macros) |
5436 | { |
5437 | extrastdmac = macros; |
5438 | } |
5439 | |
5440 | static void make_tok_num(Token * tok, int64_t val) |
5441 | { |
5442 | char numbuf[32]; |
5443 | snprintf(numbuf, sizeof(numbuf), "%" PRId64"" , val); |
5444 | tok->text = nasm_strdup(numbuf); |
5445 | tok->type = TOK_NUMBER; |
5446 | } |
5447 | |
5448 | static void pp_list_one_macro(MMacro *m, int severity) |
5449 | { |
5450 | if (!m) |
5451 | return; |
5452 | |
5453 | /* We need to print the next_active list in reverse order */ |
5454 | pp_list_one_macro(m->next_active, severity); |
5455 | |
5456 | if (m->name && !m->nolist) { |
5457 | src_set(m->xline + m->lineno, m->fname); |
5458 | nasm_error(severity, "... from macro `%s' defined" , m->name); |
5459 | } |
5460 | } |
5461 | |
5462 | static void pp_error_list_macros(int severity) |
5463 | { |
5464 | int32_t saved_line; |
5465 | const char *saved_fname = NULL; |
5466 | |
5467 | severity |= ERR_PP_LISTMACRO | ERR_NO_SEVERITY | ERR_HERE; |
5468 | src_get(&saved_line, &saved_fname); |
5469 | |
5470 | if (istk) |
5471 | pp_list_one_macro(istk->mstk, severity); |
5472 | |
5473 | src_set(saved_line, saved_fname); |
5474 | } |
5475 | |
5476 | const struct preproc_ops nasmpp = { |
5477 | pp_init, |
5478 | pp_reset, |
5479 | pp_getline, |
5480 | pp_cleanup, |
5481 | pp_extra_stdmac, |
5482 | pp_pre_define, |
5483 | pp_pre_undefine, |
5484 | pp_pre_include, |
5485 | pp_pre_command, |
5486 | pp_include_path, |
5487 | pp_error_list_macros, |
5488 | }; |
5489 | |