NASM 2.10.rc7
[nasm/sigaren-mirror.git] / preproc.c
blob835ad3e68298967af5e1ace1830ddd50b9d752c7
1 /* ----------------------------------------------------------------------- *
3 * Copyright 1996-2011 The NASM Authors - All Rights Reserved
4 * See the file AUTHORS included with the NASM distribution for
5 * the specific copyright holders.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following
9 * conditions are met:
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.
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.
32 * ----------------------------------------------------------------------- */
35 * preproc.c macro preprocessor for the Netwide Assembler
38 /* Typical flow of text through preproc
40 * pp_getline gets tokenized lines, either
42 * from a macro expansion
44 * or
45 * {
46 * read_line gets raw text from stdmacpos, or predef, or current input file
47 * tokenize converts to tokens
48 * }
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
54 * do_directive checks for directives
56 * expand_smacro is used to expand single line macros
58 * expand_mmacro is used to expand multi-line macros
60 * detoken is used to convert the line back to text
63 #include "compiler.h"
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 #include <inttypes.h>
74 #include "nasm.h"
75 #include "nasmlib.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"
84 typedef struct SMacro SMacro;
85 typedef struct ExpDef ExpDef;
86 typedef struct ExpInv ExpInv;
87 typedef struct Context Context;
88 typedef struct Token Token;
89 typedef struct Blocks Blocks;
90 typedef struct Line Line;
91 typedef struct Include Include;
92 typedef struct Cond Cond;
93 typedef struct IncPath IncPath;
96 * Note on the storage of both SMacro and MMacros: the hash table
97 * indexes them case-insensitively, and we then have to go through a
98 * linked list of potential case aliases (and, for MMacros, parameter
99 * ranges); this is to preserve the matching semantics of the earlier
100 * code. If the number of case aliases for a specific macro is a
101 * performance issue, you may want to reconsider your coding style.
105 * Store the definition of a single-line macro.
107 struct SMacro {
108 SMacro *next;
109 char *name;
110 Token *expansion;
111 unsigned int nparam;
112 bool casesense;
113 bool in_progress;
117 * The context stack is composed of a linked list of these.
119 struct Context {
120 Context *next;
121 char *name;
122 struct hash_table localmac;
123 uint32_t number;
127 * This is the internal form which we break input lines up into.
128 * Typically stored in linked lists.
130 * Note that `type' serves a double meaning: TOK_SMAC_PARAM is not
131 * necessarily used as-is, but is intended to denote the number of
132 * the substituted parameter. So in the definition
134 * %define a(x,y) ( (x) & ~(y) )
136 * the token representing `x' will have its type changed to
137 * TOK_SMAC_PARAM, but the one representing `y' will be
138 * TOK_SMAC_PARAM+1.
140 * TOK_INTERNAL_STRING is a dirty hack: it's a single string token
141 * which doesn't need quotes around it. Used in the pre-include
142 * mechanism as an alternative to trying to find a sensible type of
143 * quote to use on the filename we were passed.
145 enum pp_token_type {
146 TOK_NONE = 0, TOK_WHITESPACE, TOK_COMMENT, TOK_ID,
147 TOK_PREPROC_ID, TOK_STRING,
148 TOK_NUMBER, TOK_FLOAT, TOK_SMAC_END, TOK_OTHER,
149 TOK_INTERNAL_STRING,
150 TOK_PREPROC_Q, TOK_PREPROC_QQ,
151 TOK_PASTE, /* %+ */
152 TOK_INDIRECT, /* %[...] */
153 TOK_SMAC_PARAM, /* MUST BE LAST IN THE LIST!!! */
154 TOK_MAX = INT_MAX /* Keep compiler from reducing the range */
157 #define PP_CONCAT_MASK(x) (1 << (x))
159 struct tokseq_match {
160 int mask_head;
161 int mask_tail;
164 struct Token {
165 Token *next;
166 char *text;
167 union {
168 SMacro *mac; /* associated macro for TOK_SMAC_END */
169 size_t len; /* scratch length field */
170 } a; /* Auxiliary data */
171 enum pp_token_type type;
175 * Expansion definitions are stored as a linked list of
176 * these, which is essentially a container to allow several linked
177 * lists of Tokens.
179 * Note that in this module, linked lists are treated as stacks
180 * wherever possible. For this reason, Lines are _pushed_ on to the
181 * `last' field in ExpDef structures, so that the linked list,
182 * if walked, would emit the expansion lines in the proper order.
184 struct Line {
185 Line *next;
186 Token *first;
190 * Expansion Types
192 enum pp_exp_type {
193 EXP_NONE = 0, EXP_PREDEF,
194 EXP_MMACRO, EXP_REP,
195 EXP_IF, EXP_WHILE,
196 EXP_COMMENT, EXP_FINAL,
197 EXP_MAX = INT_MAX /* Keep compiler from reducing the range */
201 * Store the definition of an expansion, in which is any
202 * preprocessor directive that has an ending pair.
204 * This design allows for arbitrary expansion/recursion depth,
205 * upto the DEADMAN_LIMIT.
207 * The `next' field is used for storing ExpDef in hash tables; the
208 * `prev' field is for the global `expansions` linked-list.
210 struct ExpDef {
211 ExpDef *prev; /* previous definition */
212 ExpDef *next; /* next in hash table */
213 enum pp_exp_type type; /* expansion type */
214 char *name; /* definition name */
215 int nparam_min;
216 int nparam_max;
217 bool casesense;
218 bool plus; /* is the last parameter greedy? */
219 bool nolist; /* is this expansion listing-inhibited? */
220 Token *dlist; /* all defaults as one list */
221 Token **defaults; /* parameter default pointers */
222 int ndefs; /* number of default parameters */
224 int prepend; /* label prepend state */
225 Line *label;
226 Line *line;
227 Line *last;
228 int linecount; /* number of lines within expansion */
230 int64_t def_depth; /* current number of definition pairs deep */
231 int64_t cur_depth; /* current number of expansions */
232 int64_t max_depth; /* maximum number of expansions allowed */
234 int state; /* condition state */
235 bool ignoring; /* ignoring definition lines */
239 * Store the invocation of an expansion.
241 * The `prev' field is for the `istk->expansion` linked-list.
243 * When an expansion is being expanded, `params', `iline', `nparam',
244 * `paramlen', `rotate' and `unique' are local to the invocation.
246 struct ExpInv {
247 ExpInv *prev; /* previous invocation */
248 ExpDef *def; /* pointer to expansion definition */
249 char *name; /* invocation name */
250 Line *label; /* pointer to label */
251 char *label_text; /* pointer to label text */
252 Line *current; /* pointer to current line in invocation */
254 Token **params; /* actual parameters */
255 Token *iline; /* invocation line */
256 int *paramlen;
257 unsigned int nparam;
258 unsigned int rotate;
260 uint64_t unique;
261 int lineno; /* current line number in expansion */
262 int linnum; /* line number at invocation */
263 int relno; /* relative line number at invocation */
264 enum pp_exp_type type; /* expansion type */
265 bool emitting;
269 * To handle an arbitrary level of file inclusion, we maintain a
270 * stack (ie linked list) of these things.
272 struct Include {
273 Include *next;
274 FILE *fp;
275 Cond *conds;
276 ExpInv *expansion;
277 char *fname;
278 int lineno;
279 int lineinc;
280 int mmac_depth;
284 * Include search path. This is simply a list of strings which get
285 * prepended, in turn, to the name of an include file, in an
286 * attempt to find the file if it's not in the current directory.
288 struct IncPath {
289 IncPath *next;
290 char *path;
294 * Conditional assembly: we maintain a separate stack of these for
295 * each level of file inclusion. (The only reason we keep the
296 * stacks separate is to ensure that a stray `%endif' in a file
297 * included from within the true branch of a `%if' won't terminate
298 * it and cause confusion: instead, rightly, it'll cause an error.)
300 enum {
302 * These states are for use just after %if or %elif: IF_TRUE
303 * means the condition has evaluated to truth so we are
304 * currently emitting, whereas IF_FALSE means we are not
305 * currently emitting but will start doing so if a %else comes
306 * up. In these states, all directives are admissible: %elif,
307 * %else and %endif. (And of course %if.)
309 COND_IF_TRUE, COND_IF_FALSE,
311 * These states come up after a %else: ELSE_TRUE means we're
312 * emitting, and ELSE_FALSE means we're not. In ELSE_* states,
313 * any %elif or %else will cause an error.
315 COND_ELSE_TRUE, COND_ELSE_FALSE,
317 * These states mean that we're not emitting now, and also that
318 * nothing until %endif will be emitted at all. COND_DONE is
319 * used when we've had our moment of emission
320 * and have now started seeing %elifs. COND_NEVER is used when
321 * the condition construct in question is contained within a
322 * non-emitting branch of a larger condition construct,
323 * or if there is an error.
325 COND_DONE, COND_NEVER
327 #define emitting(x) ( (x) == COND_IF_TRUE || (x) == COND_ELSE_TRUE )
330 * These defines are used as the possible return values for do_directive
332 #define NO_DIRECTIVE_FOUND 0
333 #define DIRECTIVE_FOUND 1
336 * This define sets the upper limit for smacro and expansions
338 #define DEADMAN_LIMIT (1 << 20)
340 /* max reps */
341 #define REP_LIMIT ((INT64_C(1) << 62))
344 * Condition codes. Note that we use c_ prefix not C_ because C_ is
345 * used in nasm.h for the "real" condition codes. At _this_ level,
346 * we treat CXZ and ECXZ as condition codes, albeit non-invertible
347 * ones, so we need a different enum...
349 static const char * const conditions[] = {
350 "a", "ae", "b", "be", "c", "cxz", "e", "ecxz", "g", "ge", "l", "le",
351 "na", "nae", "nb", "nbe", "nc", "ne", "ng", "nge", "nl", "nle", "no",
352 "np", "ns", "nz", "o", "p", "pe", "po", "rcxz", "s", "z"
354 enum pp_conds {
355 c_A, c_AE, c_B, c_BE, c_C, c_CXZ, c_E, c_ECXZ, c_G, c_GE, c_L, c_LE,
356 c_NA, c_NAE, c_NB, c_NBE, c_NC, c_NE, c_NG, c_NGE, c_NL, c_NLE, c_NO,
357 c_NP, c_NS, c_NZ, c_O, c_P, c_PE, c_PO, c_RCXZ, c_S, c_Z,
358 c_none = -1
360 static const enum pp_conds inverse_ccs[] = {
361 c_NA, c_NAE, c_NB, c_NBE, c_NC, -1, c_NE, -1, c_NG, c_NGE, c_NL, c_NLE,
362 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,
363 c_Z, c_NO, c_NP, c_PO, c_PE, -1, c_NS, c_NZ
366 /* For TASM compatibility we need to be able to recognise TASM compatible
367 * conditional compilation directives. Using the NASM pre-processor does
368 * not work, so we look for them specifically from the following list and
369 * then jam in the equivalent NASM directive into the input stream.
372 enum {
373 TM_ARG, TM_ELIF, TM_ELSE, TM_ENDIF, TM_IF, TM_IFDEF, TM_IFDIFI,
374 TM_IFNDEF, TM_INCLUDE, TM_LOCAL
377 static const char * const tasm_directives[] = {
378 "arg", "elif", "else", "endif", "if", "ifdef", "ifdifi",
379 "ifndef", "include", "local"
382 static int StackSize = 4;
383 static char *StackPointer = "ebp";
384 static int ArgOffset = 8;
385 static int LocalOffset = 0;
387 static Context *cstk;
388 static Include *istk;
389 static IncPath *ipath = NULL;
391 static int pass; /* HACK: pass 0 = generate dependencies only */
392 static StrList **dephead, **deptail; /* Dependency list */
394 static uint64_t unique; /* unique identifier numbers */
396 static Line *predef = NULL;
397 static bool do_predef;
399 static ListGen *list;
402 * The current set of expansion definitions we have defined.
404 static struct hash_table expdefs;
407 * The current set of single-line macros we have defined.
409 static struct hash_table smacros;
412 * Linked List of all active expansion definitions
414 struct ExpDef *expansions = NULL;
417 * The expansion we are currently defining
419 static ExpDef *defining = NULL;
421 static uint64_t nested_mac_count;
422 static uint64_t nested_rep_count;
425 * Linked-list of lines to preprocess, prior to cleanup
427 static Line *finals = NULL;
428 static bool in_final = false;
431 * The number of macro parameters to allocate space for at a time.
433 #define PARAM_DELTA 16
436 * The standard macro set: defined in macros.c in the array nasm_stdmac.
437 * This gives our position in the macro set, when we're processing it.
439 static macros_t *stdmacpos;
442 * The extra standard macros that come from the object format, if
443 * any.
445 static macros_t *extrastdmac = NULL;
446 static bool any_extrastdmac;
449 * Tokens are allocated in blocks to improve speed
451 #define TOKEN_BLOCKSIZE 4096
452 static Token *freeTokens = NULL;
453 struct Blocks {
454 Blocks *next;
455 void *chunk;
458 static Blocks blocks = { NULL, NULL };
461 * Forward declarations.
463 static Token *expand_mmac_params(Token * tline);
464 static Token *expand_smacro(Token * tline);
465 static Token *expand_id(Token * tline);
466 static Context *get_ctx(const char *name, const char **namep);
467 static void make_tok_num(Token * tok, int64_t val);
468 static void error(int severity, const char *fmt, ...);
469 static void error_precond(int severity, const char *fmt, ...);
470 static void *new_Block(size_t size);
471 static void delete_Blocks(void);
472 static Token *new_Token(Token * next, enum pp_token_type type,
473 const char *text, int txtlen);
474 static Token *copy_Token(Token * tline);
475 static Token *delete_Token(Token * t);
476 static Line *new_Line(void);
477 static ExpDef *new_ExpDef(int exp_type);
478 static ExpInv *new_ExpInv(int exp_type, ExpDef *ed);
481 * Macros for safe checking of token pointers, avoid *(NULL)
483 #define tok_type_(x,t) ((x) && (x)->type == (t))
484 #define skip_white_(x) if (tok_type_((x), TOK_WHITESPACE)) (x)=(x)->next
485 #define tok_is_(x,v) (tok_type_((x), TOK_OTHER) && !strcmp((x)->text,(v)))
486 #define tok_isnt_(x,v) ((x) && ((x)->type!=TOK_OTHER || strcmp((x)->text,(v))))
489 * A few helpers for single macros
492 /* We might be not smacro parameter at all */
493 static bool is_smacro_param(Token *t)
495 return t->type >= TOK_SMAC_PARAM;
498 /* smacro parameters are counted in a special way */
499 static int smacro_get_param_idx(Token *t)
501 return t->type - TOK_SMAC_PARAM;
504 /* encode smacro parameter index */
505 static int smacro_set_param_idx(Token *t, unsigned int index)
507 return t->type = TOK_SMAC_PARAM + index;
510 #ifdef NASM_TRACE
512 #define stringify(x) #x
514 #define nasm_trace(msg, ...) printf("(%s:%d): " msg "\n", __func__, __LINE__, ##__VA_ARGS__)
515 #define nasm_dump_token(t) nasm_raw_dump_token(t, __FILE__, __LINE__, __func__);
516 #define nasm_dump_stream(t) nasm_raw_dump_stream(t, __FILE__, __LINE__, __func__);
518 /* FIXME: we really need some compound type here instead of inplace code */
519 static const char *nasm_get_tok_type_str(enum pp_token_type type)
521 #define SWITCH_TOK_NAME(type) \
522 case (type): \
523 return stringify(type)
525 switch (type) {
526 SWITCH_TOK_NAME(TOK_NONE);
527 SWITCH_TOK_NAME(TOK_WHITESPACE);
528 SWITCH_TOK_NAME(TOK_COMMENT);
529 SWITCH_TOK_NAME(TOK_ID);
530 SWITCH_TOK_NAME(TOK_PREPROC_ID);
531 SWITCH_TOK_NAME(TOK_STRING);
532 SWITCH_TOK_NAME(TOK_NUMBER);
533 SWITCH_TOK_NAME(TOK_FLOAT);
534 SWITCH_TOK_NAME(TOK_SMAC_END);
535 SWITCH_TOK_NAME(TOK_OTHER);
536 SWITCH_TOK_NAME(TOK_INTERNAL_STRING);
537 SWITCH_TOK_NAME(TOK_PREPROC_Q);
538 SWITCH_TOK_NAME(TOK_PREPROC_QQ);
539 SWITCH_TOK_NAME(TOK_PASTE);
540 SWITCH_TOK_NAME(TOK_INDIRECT);
541 SWITCH_TOK_NAME(TOK_SMAC_PARAM);
542 SWITCH_TOK_NAME(TOK_MAX);
545 return NULL;
548 static void nasm_raw_dump_token(Token *token, const char *file, int line, const char *func)
550 printf("---[%s (%s:%d): %p]---\n", func, file, line, (void *)token);
551 if (token) {
552 Token *t;
553 list_for_each(t, token) {
554 if (t->text)
555 printf("'%s'(%s) ", t->text,
556 nasm_get_tok_type_str(t->type));
558 printf("\n\n");
562 static void nasm_raw_dump_stream(Token *token, const char *file, int line, const char *func)
564 printf("---[%s (%s:%d): %p]---\n", func, file, line, (void *)token);
565 if (token) {
566 Token *t;
567 list_for_each(t, token)
568 printf("%s", t->text ? t->text : " ");
569 printf("\n\n");
573 #else
574 #define nasm_trace(msg, ...)
575 #define nasm_dump_token(t)
576 #define nasm_dump_stream(t)
577 #endif
580 * nasm_unquote with error if the string contains NUL characters.
581 * If the string contains NUL characters, issue an error and return
582 * the C len, i.e. truncate at the NUL.
584 static size_t nasm_unquote_cstr(char *qstr, enum preproc_token directive)
586 size_t len = nasm_unquote(qstr, NULL);
587 size_t clen = strlen(qstr);
589 if (len != clen)
590 error(ERR_NONFATAL, "NUL character in `%s' directive",
591 pp_directives[directive]);
593 return clen;
597 * In-place reverse a list of tokens.
599 static Token *reverse_tokens(Token *t)
601 Token *prev, *next;
603 list_reverse(t, prev, next);
605 return t;
609 * Handle TASM specific directives, which do not contain a % in
610 * front of them. We do it here because I could not find any other
611 * place to do it for the moment, and it is a hack (ideally it would
612 * be nice to be able to use the NASM pre-processor to do it).
614 static char *check_tasm_directive(char *line)
616 int32_t i, j, k, m, len;
617 char *p, *q, *oldline, oldchar;
619 p = nasm_skip_spaces(line);
621 /* Binary search for the directive name */
622 i = -1;
623 j = ARRAY_SIZE(tasm_directives);
624 q = nasm_skip_word(p);
625 len = q - p;
626 if (len) {
627 oldchar = p[len];
628 p[len] = 0;
629 while (j - i > 1) {
630 k = (j + i) / 2;
631 m = nasm_stricmp(p, tasm_directives[k]);
632 if (m == 0) {
633 /* We have found a directive, so jam a % in front of it
634 * so that NASM will then recognise it as one if it's own.
636 p[len] = oldchar;
637 len = strlen(p);
638 oldline = line;
639 line = nasm_malloc(len + 2);
640 line[0] = '%';
641 if (k == TM_IFDIFI) {
643 * NASM does not recognise IFDIFI, so we convert
644 * it to %if 0. This is not used in NASM
645 * compatible code, but does need to parse for the
646 * TASM macro package.
648 strcpy(line + 1, "if 0");
649 } else {
650 memcpy(line + 1, p, len + 1);
652 nasm_free(oldline);
653 return line;
654 } else if (m < 0) {
655 j = k;
656 } else
657 i = k;
659 p[len] = oldchar;
661 return line;
665 * The pre-preprocessing stage... This function translates line
666 * number indications as they emerge from GNU cpp (`# lineno "file"
667 * flags') into NASM preprocessor line number indications (`%line
668 * lineno file').
670 static char *prepreproc(char *line)
672 int lineno, fnlen;
673 char *fname, *oldline;
675 if (line[0] == '#' && line[1] == ' ') {
676 oldline = line;
677 fname = oldline + 2;
678 lineno = atoi(fname);
679 fname += strspn(fname, "0123456789 ");
680 if (*fname == '"')
681 fname++;
682 fnlen = strcspn(fname, "\"");
683 line = nasm_malloc(20 + fnlen);
684 snprintf(line, 20 + fnlen, "%%line %d %.*s", lineno, fnlen, fname);
685 nasm_free(oldline);
687 if (tasm_compatible_mode)
688 return check_tasm_directive(line);
689 return line;
693 * Free a linked list of tokens.
695 static void free_tlist(Token * list)
697 while (list)
698 list = delete_Token(list);
702 * Free a linked list of lines.
704 static void free_llist(Line * list)
706 Line *l, *tmp;
707 list_for_each_safe(l, tmp, list) {
708 free_tlist(l->first);
709 nasm_free(l);
714 * Free an ExpDef
716 static void free_expdef(ExpDef * ed)
718 nasm_free(ed->name);
719 free_tlist(ed->dlist);
720 nasm_free(ed->defaults);
721 free_llist(ed->line);
722 nasm_free(ed);
726 * Free an ExpInv
728 static void free_expinv(ExpInv * ei)
730 nasm_free(ei->name);
731 nasm_free(ei->label_text);
732 nasm_free(ei);
736 * Free all currently defined macros, and free the hash tables
738 static void free_smacro_table(struct hash_table *smt)
740 SMacro *s, *tmp;
741 const char *key;
742 struct hash_tbl_node *it = NULL;
744 while ((s = hash_iterate(smt, &it, &key)) != NULL) {
745 nasm_free((void *)key);
746 list_for_each_safe(s, tmp, s) {
747 nasm_free(s->name);
748 free_tlist(s->expansion);
749 nasm_free(s);
752 hash_free(smt);
755 static void free_expdef_table(struct hash_table *edt)
757 ExpDef *ed, *tmp;
758 const char *key;
759 struct hash_tbl_node *it = NULL;
761 it = NULL;
762 while ((ed = hash_iterate(edt, &it, &key)) != NULL) {
763 nasm_free((void *)key);
764 list_for_each_safe(ed ,tmp, ed)
765 free_expdef(ed);
767 hash_free(edt);
770 static void free_macros(void)
772 free_smacro_table(&smacros);
773 free_expdef_table(&expdefs);
777 * Initialize the hash tables
779 static void init_macros(void)
781 hash_init(&smacros, HASH_LARGE);
782 hash_init(&expdefs, HASH_LARGE);
786 * Pop the context stack.
788 static void ctx_pop(void)
790 Context *c = cstk;
792 cstk = cstk->next;
793 free_smacro_table(&c->localmac);
794 nasm_free(c->name);
795 nasm_free(c);
799 * Search for a key in the hash index; adding it if necessary
800 * (in which case we initialize the data pointer to NULL.)
802 static void **
803 hash_findi_add(struct hash_table *hash, const char *str)
805 struct hash_insert hi;
806 void **r;
807 char *strx;
809 r = hash_findi(hash, str, &hi);
810 if (r)
811 return r;
813 strx = nasm_strdup(str); /* Use a more efficient allocator here? */
814 return hash_add(&hi, strx, NULL);
818 * Like hash_findi, but returns the data element rather than a pointer
819 * to it. Used only when not adding a new element, hence no third
820 * argument.
822 static void *
823 hash_findix(struct hash_table *hash, const char *str)
825 void **p;
827 p = hash_findi(hash, str, NULL);
828 return p ? *p : NULL;
832 * read line from standard macros set,
833 * if there no more left -- return NULL
835 static char *line_from_stdmac(void)
837 unsigned char c;
838 const unsigned char *p = stdmacpos;
839 char *line, *q;
840 size_t len = 0;
842 if (!stdmacpos)
843 return NULL;
845 while ((c = *p++)) {
846 if (c >= 0x80)
847 len += pp_directives_len[c - 0x80] + 1;
848 else
849 len++;
852 line = nasm_malloc(len + 1);
853 q = line;
854 while ((c = *stdmacpos++)) {
855 if (c >= 0x80) {
856 memcpy(q, pp_directives[c - 0x80], pp_directives_len[c - 0x80]);
857 q += pp_directives_len[c - 0x80];
858 *q++ = ' ';
859 } else {
860 *q++ = c;
863 stdmacpos = p;
864 *q = '\0';
866 if (!*stdmacpos) {
867 /* This was the last of the standard macro chain... */
868 stdmacpos = NULL;
869 if (any_extrastdmac) {
870 stdmacpos = extrastdmac;
871 any_extrastdmac = false;
872 } else if (do_predef) {
873 ExpInv *ei;
874 Line *pd, *l;
875 Token *head, **tail, *t;
878 * Nasty hack: here we push the contents of
879 * `predef' on to the top-level expansion stack,
880 * since this is the most convenient way to
881 * implement the pre-include and pre-define
882 * features.
884 list_for_each(pd, predef) {
885 head = NULL;
886 tail = &head;
887 list_for_each(t, pd->first) {
888 *tail = new_Token(NULL, t->type, t->text, 0);
889 tail = &(*tail)->next;
892 l = new_Line();
893 l->first = head;
894 ei = new_ExpInv(EXP_PREDEF, NULL);
895 ei->current = l;
896 ei->emitting = true;
897 ei->prev = istk->expansion;
898 istk->expansion = ei;
900 do_predef = false;
904 return line;
907 #define BUF_DELTA 512
909 * Read a line from the top file in istk, handling multiple CR/LFs
910 * at the end of the line read, and handling spurious ^Zs. Will
911 * return lines from the standard macro set if this has not already
912 * been done.
914 static char *read_line(void)
916 char *buffer, *p, *q;
917 int bufsize, continued_count;
920 * standart macros set (predefined) goes first
922 p = line_from_stdmac();
923 if (p)
924 return p;
927 * regular read from a file
929 bufsize = BUF_DELTA;
930 buffer = nasm_malloc(BUF_DELTA);
931 p = buffer;
932 continued_count = 0;
933 while (1) {
934 q = fgets(p, bufsize - (p - buffer), istk->fp);
935 if (!q)
936 break;
937 p += strlen(p);
938 if (p > buffer && p[-1] == '\n') {
940 * Convert backslash-CRLF line continuation sequences into
941 * nothing at all (for DOS and Windows)
943 if (((p - 2) > buffer) && (p[-3] == '\\') && (p[-2] == '\r')) {
944 p -= 3;
945 *p = 0;
946 continued_count++;
949 * Also convert backslash-LF line continuation sequences into
950 * nothing at all (for Unix)
952 else if (((p - 1) > buffer) && (p[-2] == '\\')) {
953 p -= 2;
954 *p = 0;
955 continued_count++;
956 } else {
957 break;
960 if (p - buffer > bufsize - 10) {
961 int32_t offset = p - buffer;
962 bufsize += BUF_DELTA;
963 buffer = nasm_realloc(buffer, bufsize);
964 p = buffer + offset; /* prevent stale-pointer problems */
968 if (!q && p == buffer) {
969 nasm_free(buffer);
970 return NULL;
973 src_set_linnum(src_get_linnum() + istk->lineinc +
974 (continued_count * istk->lineinc));
977 * Play safe: remove CRs as well as LFs, if any of either are
978 * present at the end of the line.
980 while (--p >= buffer && (*p == '\n' || *p == '\r'))
981 *p = '\0';
984 * Handle spurious ^Z, which may be inserted into source files
985 * by some file transfer utilities.
987 buffer[strcspn(buffer, "\032")] = '\0';
989 list->line(LIST_READ, buffer);
991 return buffer;
995 * Tokenize a line of text. This is a very simple process since we
996 * don't need to parse the value out of e.g. numeric tokens: we
997 * simply split one string into many.
999 static Token *tokenize(char *line)
1001 char c, *p = line;
1002 enum pp_token_type type;
1003 Token *list = NULL;
1004 Token *t, **tail = &list;
1005 bool verbose = true;
1007 nasm_trace("Tokenize for '%s'", line);
1009 if ((defining != NULL) && (defining->ignoring == true)) {
1010 verbose = false;
1013 while (*line) {
1014 p = line;
1015 if (*p == '%') {
1016 p++;
1017 if (*p == '+' && !nasm_isdigit(p[1])) {
1018 p++;
1019 type = TOK_PASTE;
1020 } else if (nasm_isdigit(*p) ||
1021 ((*p == '-' || *p == '+') && nasm_isdigit(p[1]))) {
1022 do {
1023 p++;
1025 while (nasm_isdigit(*p));
1026 type = TOK_PREPROC_ID;
1027 } else if (*p == '{') {
1028 p++;
1029 while (*p && *p != '}') {
1030 p[-1] = *p;
1031 p++;
1033 p[-1] = '\0';
1034 if (*p)
1035 p++;
1036 type = TOK_PREPROC_ID;
1037 } else if (*p == '[') {
1038 int lvl = 1;
1039 line += 2; /* Skip the leading %[ */
1040 p++;
1041 while (lvl && (c = *p++)) {
1042 switch (c) {
1043 case ']':
1044 lvl--;
1045 break;
1046 case '%':
1047 if (*p == '[')
1048 lvl++;
1049 break;
1050 case '\'':
1051 case '\"':
1052 case '`':
1053 p = nasm_skip_string(p - 1) + 1;
1054 break;
1055 default:
1056 break;
1059 p--;
1060 if (*p)
1061 *p++ = '\0';
1062 if (lvl && verbose)
1063 error(ERR_NONFATAL, "unterminated %[ construct");
1064 type = TOK_INDIRECT;
1065 } else if (*p == '?') {
1066 type = TOK_PREPROC_Q; /* %? */
1067 p++;
1068 if (*p == '?') {
1069 type = TOK_PREPROC_QQ; /* %?? */
1070 p++;
1072 } else if (*p == '!') {
1073 type = TOK_PREPROC_ID;
1074 p++;
1075 if (isidchar(*p)) {
1076 do {
1077 p++;
1078 } while (isidchar(*p));
1079 } else if (*p == '\'' || *p == '\"' || *p == '`') {
1080 p = nasm_skip_string(p);
1081 if (*p)
1082 p++;
1083 else if(verbose)
1084 error(ERR_NONFATAL|ERR_PASS1, "unterminated %! string");
1085 } else {
1086 /* %! without string or identifier */
1087 type = TOK_OTHER; /* Legacy behavior... */
1089 } else if (isidchar(*p) ||
1090 ((*p == '!' || *p == '%' || *p == '$') &&
1091 isidchar(p[1]))) {
1092 do {
1093 p++;
1095 while (isidchar(*p));
1096 type = TOK_PREPROC_ID;
1097 } else {
1098 type = TOK_OTHER;
1099 if (*p == '%')
1100 p++;
1102 } else if (isidstart(*p) || (*p == '$' && isidstart(p[1]))) {
1103 type = TOK_ID;
1104 p++;
1105 while (*p && isidchar(*p))
1106 p++;
1107 } else if (*p == '\'' || *p == '"' || *p == '`') {
1109 * A string token.
1111 type = TOK_STRING;
1112 p = nasm_skip_string(p);
1114 if (*p) {
1115 p++;
1116 } else if(verbose) {
1117 error(ERR_WARNING|ERR_PASS1, "unterminated string");
1118 /* Handling unterminated strings by UNV */
1119 /* type = -1; */
1121 } else if (p[0] == '$' && p[1] == '$') {
1122 type = TOK_OTHER; /* TOKEN_BASE */
1123 p += 2;
1124 } else if (isnumstart(*p)) {
1125 bool is_hex = false;
1126 bool is_float = false;
1127 bool has_e = false;
1128 char c, *r;
1131 * A numeric token.
1134 if (*p == '$') {
1135 p++;
1136 is_hex = true;
1139 for (;;) {
1140 c = *p++;
1142 if (!is_hex && (c == 'e' || c == 'E')) {
1143 has_e = true;
1144 if (*p == '+' || *p == '-') {
1146 * e can only be followed by +/- if it is either a
1147 * prefixed hex number or a floating-point number
1149 p++;
1150 is_float = true;
1152 } else if (c == 'H' || c == 'h' || c == 'X' || c == 'x') {
1153 is_hex = true;
1154 } else if (c == 'P' || c == 'p') {
1155 is_float = true;
1156 if (*p == '+' || *p == '-')
1157 p++;
1158 } else if (isnumchar(c) || c == '_')
1159 ; /* just advance */
1160 else if (c == '.') {
1162 * we need to deal with consequences of the legacy
1163 * parser, like "1.nolist" being two tokens
1164 * (TOK_NUMBER, TOK_ID) here; at least give it
1165 * a shot for now. In the future, we probably need
1166 * a flex-based scanner with proper pattern matching
1167 * to do it as well as it can be done. Nothing in
1168 * the world is going to help the person who wants
1169 * 0x123.p16 interpreted as two tokens, though.
1171 r = p;
1172 while (*r == '_')
1173 r++;
1175 if (nasm_isdigit(*r) || (is_hex && nasm_isxdigit(*r)) ||
1176 (!is_hex && (*r == 'e' || *r == 'E')) ||
1177 (*r == 'p' || *r == 'P')) {
1178 p = r;
1179 is_float = true;
1180 } else
1181 break; /* Terminate the token */
1182 } else
1183 break;
1185 p--; /* Point to first character beyond number */
1187 if (p == line+1 && *line == '$') {
1188 type = TOK_OTHER; /* TOKEN_HERE */
1189 } else {
1190 if (has_e && !is_hex) {
1191 /* 1e13 is floating-point, but 1e13h is not */
1192 is_float = true;
1195 type = is_float ? TOK_FLOAT : TOK_NUMBER;
1197 } else if (nasm_isspace(*p)) {
1198 type = TOK_WHITESPACE;
1199 p = nasm_skip_spaces(p);
1201 * Whitespace just before end-of-line is discarded by
1202 * pretending it's a comment; whitespace just before a
1203 * comment gets lumped into the comment.
1205 if (!*p || *p == ';') {
1206 type = TOK_COMMENT;
1207 while (*p)
1208 p++;
1210 } else if (*p == ';') {
1211 type = TOK_COMMENT;
1212 while (*p)
1213 p++;
1214 } else {
1216 * Anything else is an operator of some kind. We check
1217 * for all the double-character operators (>>, <<, //,
1218 * %%, <=, >=, ==, !=, <>, &&, ||, ^^), but anything
1219 * else is a single-character operator.
1221 type = TOK_OTHER;
1222 if ((p[0] == '>' && p[1] == '>') ||
1223 (p[0] == '<' && p[1] == '<') ||
1224 (p[0] == '/' && p[1] == '/') ||
1225 (p[0] == '<' && p[1] == '=') ||
1226 (p[0] == '>' && p[1] == '=') ||
1227 (p[0] == '=' && p[1] == '=') ||
1228 (p[0] == '!' && p[1] == '=') ||
1229 (p[0] == '<' && p[1] == '>') ||
1230 (p[0] == '&' && p[1] == '&') ||
1231 (p[0] == '|' && p[1] == '|') ||
1232 (p[0] == '^' && p[1] == '^')) {
1233 p++;
1235 p++;
1238 /* Handling unterminated string by UNV */
1239 /*if (type == -1)
1241 *tail = t = new_Token(NULL, TOK_STRING, line, p-line+1);
1242 t->text[p-line] = *line;
1243 tail = &t->next;
1245 else */
1246 if (type != TOK_COMMENT) {
1247 *tail = t = new_Token(NULL, type, line, p - line);
1248 tail = &t->next;
1250 line = p;
1253 nasm_dump_token(list);
1255 return list;
1259 * this function allocates a new managed block of memory and
1260 * returns a pointer to the block. The managed blocks are
1261 * deleted only all at once by the delete_Blocks function.
1263 static void *new_Block(size_t size)
1265 Blocks *b = &blocks;
1267 /* first, get to the end of the linked list */
1268 while (b->next)
1269 b = b->next;
1271 /* now allocate the requested chunk */
1272 b->chunk = nasm_malloc(size);
1274 /* now allocate a new block for the next request */
1275 b->next = nasm_zalloc(sizeof(Blocks));
1277 return b->chunk;
1281 * this function deletes all managed blocks of memory
1283 static void delete_Blocks(void)
1285 Blocks *a, *b = &blocks;
1288 * keep in mind that the first block, pointed to by blocks
1289 * is a static and not dynamically allocated, so we don't
1290 * free it.
1292 while (b) {
1293 nasm_free(b->chunk);
1294 a = b;
1295 b = b->next;
1296 if (a != &blocks)
1297 nasm_free(a);
1302 * this function creates a new Token and passes a pointer to it
1303 * back to the caller. It sets the type and text elements, and
1304 * also the a.mac and next elements to NULL.
1306 static Token *new_Token(Token * next, enum pp_token_type type,
1307 const char *text, int txtlen)
1309 Token *t;
1310 int i;
1312 if (!freeTokens) {
1313 freeTokens = (Token *) new_Block(TOKEN_BLOCKSIZE * sizeof(Token));
1314 for (i = 0; i < TOKEN_BLOCKSIZE - 1; i++)
1315 freeTokens[i].next = &freeTokens[i + 1];
1316 freeTokens[i].next = NULL;
1318 t = freeTokens;
1319 freeTokens = t->next;
1320 t->next = next;
1321 t->a.mac = NULL;
1322 t->type = type;
1323 if (type == TOK_WHITESPACE || !text) {
1324 t->text = NULL;
1325 } else {
1326 if (txtlen == 0)
1327 txtlen = strlen(text);
1328 t->text = nasm_malloc(txtlen+1);
1329 memcpy(t->text, text, txtlen);
1330 t->text[txtlen] = '\0';
1332 return t;
1335 static Token *copy_Token(Token * tline)
1337 Token *t, *tt, *first = NULL, *prev = NULL;
1338 int i;
1339 for (tt = tline; tt != NULL; tt = tt->next) {
1340 if (!freeTokens) {
1341 freeTokens = (Token *) new_Block(TOKEN_BLOCKSIZE * sizeof(Token));
1342 for (i = 0; i < TOKEN_BLOCKSIZE - 1; i++)
1343 freeTokens[i].next = &freeTokens[i + 1];
1344 freeTokens[i].next = NULL;
1346 t = freeTokens;
1347 freeTokens = t->next;
1348 t->next = NULL;
1349 t->text = tt->text ? nasm_strdup(tt->text) : NULL;
1350 t->a.mac = tt->a.mac;
1351 t->a.len = tt->a.len;
1352 t->type = tt->type;
1353 if (prev != NULL) {
1354 prev->next = t;
1355 } else {
1356 first = t;
1358 prev = t;
1360 return first;
1363 static Token *delete_Token(Token * t)
1365 Token *next = t->next;
1366 nasm_free(t->text);
1367 t->next = freeTokens;
1368 freeTokens = t;
1369 return next;
1373 * Convert a line of tokens back into text.
1374 * If expand_locals is not zero, identifiers of the form "%$*xxx"
1375 * will be transformed into ..@ctxnum.xxx
1377 static char *detoken(Token * tlist, bool expand_locals)
1379 Token *t;
1380 char *line, *p;
1381 const char *q;
1382 int len = 0;
1384 list_for_each(t, tlist) {
1385 if (t->type == TOK_PREPROC_ID && t->text[1] == '!') {
1386 char *v;
1387 char *q = t->text;
1389 v = t->text + 2;
1390 if (*v == '\'' || *v == '\"' || *v == '`') {
1391 size_t len = nasm_unquote(v, NULL);
1392 size_t clen = strlen(v);
1394 if (len != clen) {
1395 error(ERR_NONFATAL | ERR_PASS1,
1396 "NUL character in %! string");
1397 v = NULL;
1401 if (v) {
1402 char *p = getenv(v);
1403 if (!p) {
1404 error(ERR_NONFATAL | ERR_PASS1,
1405 "nonexistent environment variable `%s'", v);
1406 p = "";
1408 t->text = nasm_strdup(p);
1410 nasm_free(q);
1413 /* Expand local macros here and not during preprocessing */
1414 if (expand_locals &&
1415 t->type == TOK_PREPROC_ID && t->text &&
1416 t->text[0] == '%' && t->text[1] == '$') {
1417 const char *q;
1418 char *p;
1419 Context *ctx = get_ctx(t->text, &q);
1420 if (ctx) {
1421 char buffer[40];
1422 snprintf(buffer, sizeof(buffer), "..@%"PRIu32".", ctx->number);
1423 p = nasm_strcat(buffer, q);
1424 nasm_free(t->text);
1425 t->text = p;
1429 /* Expand %? and %?? directives */
1430 if ((istk->expansion != NULL) &&
1431 ((t->type == TOK_PREPROC_Q) ||
1432 (t->type == TOK_PREPROC_QQ))) {
1433 ExpInv *ei;
1434 for (ei = istk->expansion; ei != NULL; ei = ei->prev){
1435 if (ei->type == EXP_MMACRO) {
1436 nasm_free(t->text);
1437 if (t->type == TOK_PREPROC_Q) {
1438 t->text = nasm_strdup(ei->name);
1439 } else {
1440 t->text = nasm_strdup(ei->def->name);
1442 break;
1447 if (t->type == TOK_WHITESPACE)
1448 len++;
1449 else if (t->text)
1450 len += strlen(t->text);
1453 p = line = nasm_malloc(len + 1);
1455 list_for_each(t, tlist) {
1456 if (t->type == TOK_WHITESPACE) {
1457 *p++ = ' ';
1458 } else if (t->text) {
1459 q = t->text;
1460 while (*q)
1461 *p++ = *q++;
1464 *p = '\0';
1466 return line;
1470 * Initialize a new Line
1472 static inline Line *new_Line(void)
1474 return (Line *)nasm_zalloc(sizeof(Line));
1479 * Initialize a new Expansion Definition
1481 static ExpDef *new_ExpDef(int exp_type)
1483 ExpDef *ed = (ExpDef*)nasm_zalloc(sizeof(ExpDef));
1484 ed->type = exp_type;
1485 ed->casesense = true;
1486 ed->state = COND_NEVER;
1488 return ed;
1493 * Initialize a new Expansion Instance
1495 static ExpInv *new_ExpInv(int exp_type, ExpDef *ed)
1497 ExpInv *ei = (ExpInv*)nasm_zalloc(sizeof(ExpInv));
1498 ei->type = exp_type;
1499 ei->def = ed;
1500 ei->unique = ++unique;
1502 if ((istk->mmac_depth < 1) &&
1503 (istk->expansion == NULL) &&
1504 (ed != NULL) &&
1505 (ed->type != EXP_MMACRO) &&
1506 (ed->type != EXP_REP) &&
1507 (ed->type != EXP_WHILE)) {
1508 ei->linnum = src_get_linnum();
1509 src_set_linnum(ei->linnum - ed->linecount - 1);
1510 } else {
1511 ei->linnum = -1;
1513 if ((istk->expansion == NULL) ||
1514 (ei->type == EXP_MMACRO)) {
1515 ei->relno = 0;
1516 } else {
1517 ei->relno = istk->expansion->lineno;
1518 if (ed != NULL) {
1519 ei->relno -= (ed->linecount + 1);
1522 return ei;
1526 * A scanner, suitable for use by the expression evaluator, which
1527 * operates on a line of Tokens. Expects a pointer to a pointer to
1528 * the first token in the line to be passed in as its private_data
1529 * field.
1531 * FIX: This really needs to be unified with stdscan.
1533 static int ppscan(void *private_data, struct tokenval *tokval)
1535 Token **tlineptr = private_data;
1536 Token *tline;
1537 char ourcopy[MAX_KEYWORD+1], *p, *r, *s;
1539 do {
1540 tline = *tlineptr;
1541 *tlineptr = tline ? tline->next : NULL;
1542 } while (tline && (tline->type == TOK_WHITESPACE ||
1543 tline->type == TOK_COMMENT));
1545 if (!tline)
1546 return tokval->t_type = TOKEN_EOS;
1548 tokval->t_charptr = tline->text;
1550 if (tline->text[0] == '$' && !tline->text[1])
1551 return tokval->t_type = TOKEN_HERE;
1552 if (tline->text[0] == '$' && tline->text[1] == '$' && !tline->text[2])
1553 return tokval->t_type = TOKEN_BASE;
1555 if (tline->type == TOK_ID) {
1556 p = tokval->t_charptr = tline->text;
1557 if (p[0] == '$') {
1558 tokval->t_charptr++;
1559 return tokval->t_type = TOKEN_ID;
1562 for (r = p, s = ourcopy; *r; r++) {
1563 if (r >= p+MAX_KEYWORD)
1564 return tokval->t_type = TOKEN_ID; /* Not a keyword */
1565 *s++ = nasm_tolower(*r);
1567 *s = '\0';
1568 /* right, so we have an identifier sitting in temp storage. now,
1569 * is it actually a register or instruction name, or what? */
1570 return nasm_token_hash(ourcopy, tokval);
1573 if (tline->type == TOK_NUMBER) {
1574 bool rn_error;
1575 tokval->t_integer = readnum(tline->text, &rn_error);
1576 tokval->t_charptr = tline->text;
1577 if (rn_error)
1578 return tokval->t_type = TOKEN_ERRNUM;
1579 else
1580 return tokval->t_type = TOKEN_NUM;
1583 if (tline->type == TOK_FLOAT) {
1584 return tokval->t_type = TOKEN_FLOAT;
1587 if (tline->type == TOK_STRING) {
1588 char bq, *ep;
1590 bq = tline->text[0];
1591 tokval->t_charptr = tline->text;
1592 tokval->t_inttwo = nasm_unquote(tline->text, &ep);
1594 if (ep[0] != bq || ep[1] != '\0')
1595 return tokval->t_type = TOKEN_ERRSTR;
1596 else
1597 return tokval->t_type = TOKEN_STR;
1600 if (tline->type == TOK_OTHER) {
1601 if (!strcmp(tline->text, "<<"))
1602 return tokval->t_type = TOKEN_SHL;
1603 if (!strcmp(tline->text, ">>"))
1604 return tokval->t_type = TOKEN_SHR;
1605 if (!strcmp(tline->text, "//"))
1606 return tokval->t_type = TOKEN_SDIV;
1607 if (!strcmp(tline->text, "%%"))
1608 return tokval->t_type = TOKEN_SMOD;
1609 if (!strcmp(tline->text, "=="))
1610 return tokval->t_type = TOKEN_EQ;
1611 if (!strcmp(tline->text, "<>"))
1612 return tokval->t_type = TOKEN_NE;
1613 if (!strcmp(tline->text, "!="))
1614 return tokval->t_type = TOKEN_NE;
1615 if (!strcmp(tline->text, "<="))
1616 return tokval->t_type = TOKEN_LE;
1617 if (!strcmp(tline->text, ">="))
1618 return tokval->t_type = TOKEN_GE;
1619 if (!strcmp(tline->text, "&&"))
1620 return tokval->t_type = TOKEN_DBL_AND;
1621 if (!strcmp(tline->text, "^^"))
1622 return tokval->t_type = TOKEN_DBL_XOR;
1623 if (!strcmp(tline->text, "||"))
1624 return tokval->t_type = TOKEN_DBL_OR;
1628 * We have no other options: just return the first character of
1629 * the token text.
1631 return tokval->t_type = tline->text[0];
1635 * Compare a string to the name of an existing macro; this is a
1636 * simple wrapper which calls either strcmp or nasm_stricmp
1637 * depending on the value of the `casesense' parameter.
1639 static int mstrcmp(const char *p, const char *q, bool casesense)
1641 return casesense ? strcmp(p, q) : nasm_stricmp(p, q);
1645 * Compare a string to the name of an existing macro; this is a
1646 * simple wrapper which calls either strcmp or nasm_stricmp
1647 * depending on the value of the `casesense' parameter.
1649 static int mmemcmp(const char *p, const char *q, size_t l, bool casesense)
1651 return casesense ? memcmp(p, q, l) : nasm_memicmp(p, q, l);
1655 * Return the Context structure associated with a %$ token. Return
1656 * NULL, having _already_ reported an error condition, if the
1657 * context stack isn't deep enough for the supplied number of $
1658 * signs.
1660 * If "namep" is non-NULL, set it to the pointer to the macro name
1661 * tail, i.e. the part beyond %$...
1663 static Context *get_ctx(const char *name, const char **namep)
1665 Context *ctx;
1666 int i;
1668 if (namep)
1669 *namep = name;
1671 if (!name || name[0] != '%' || name[1] != '$')
1672 return NULL;
1674 if (!cstk) {
1675 error(ERR_NONFATAL, "`%s': context stack is empty", name);
1676 return NULL;
1679 name += 2;
1680 ctx = cstk;
1681 i = 0;
1682 while (ctx && *name == '$') {
1683 name++;
1684 i++;
1685 ctx = ctx->next;
1688 if (!ctx) {
1689 error(ERR_NONFATAL, "`%s': context stack is only"
1690 " %d level%s deep", name, i, (i == 1 ? "" : "s"));
1691 return NULL;
1694 if (namep)
1695 *namep = name;
1697 return ctx;
1701 * Check to see if a file is already in a string list
1703 static bool in_list(const StrList *list, const char *str)
1705 while (list) {
1706 if (!strcmp(list->str, str))
1707 return true;
1708 list = list->next;
1710 return false;
1714 * Open an include file. This routine must always return a valid
1715 * file pointer if it returns - it's responsible for throwing an
1716 * ERR_FATAL and bombing out completely if not. It should also try
1717 * the include path one by one until it finds the file or reaches
1718 * the end of the path.
1720 static FILE *inc_fopen(const char *file, StrList **dhead, StrList ***dtail,
1721 bool missing_ok)
1723 FILE *fp;
1724 char *prefix = "";
1725 IncPath *ip = ipath;
1726 int len = strlen(file);
1727 size_t prefix_len = 0;
1728 StrList *sl;
1730 while (1) {
1731 sl = nasm_malloc(prefix_len+len+1+sizeof sl->next);
1732 sl->next = NULL;
1733 memcpy(sl->str, prefix, prefix_len);
1734 memcpy(sl->str+prefix_len, file, len+1);
1735 fp = fopen(sl->str, "r");
1736 if (fp && dhead && !in_list(*dhead, sl->str)) {
1737 **dtail = sl;
1738 *dtail = &sl->next;
1739 } else {
1740 nasm_free(sl);
1742 if (fp)
1743 return fp;
1744 if (!ip) {
1745 if (!missing_ok)
1746 break;
1747 prefix = NULL;
1748 } else {
1749 prefix = ip->path;
1750 ip = ip->next;
1752 if (prefix) {
1753 prefix_len = strlen(prefix);
1754 } else {
1755 /* -MG given and file not found */
1756 if (dhead && !in_list(*dhead, file)) {
1757 sl = nasm_malloc(len+1+sizeof sl->next);
1758 sl->next = NULL;
1759 strcpy(sl->str, file);
1760 **dtail = sl;
1761 *dtail = &sl->next;
1763 return NULL;
1767 error(ERR_FATAL, "unable to open include file `%s'", file);
1768 return NULL;
1772 * Determine if we should warn on defining a single-line macro of
1773 * name `name', with `nparam' parameters. If nparam is 0 or -1, will
1774 * return true if _any_ single-line macro of that name is defined.
1775 * Otherwise, will return true if a single-line macro with either
1776 * `nparam' or no parameters is defined.
1778 * If a macro with precisely the right number of parameters is
1779 * defined, or nparam is -1, the address of the definition structure
1780 * will be returned in `defn'; otherwise NULL will be returned. If `defn'
1781 * is NULL, no action will be taken regarding its contents, and no
1782 * error will occur.
1784 * Note that this is also called with nparam zero to resolve
1785 * `ifdef'.
1787 * If you already know which context macro belongs to, you can pass
1788 * the context pointer as first parameter; if you won't but name begins
1789 * with %$ the context will be automatically computed. If all_contexts
1790 * is true, macro will be searched in outer contexts as well.
1792 static bool
1793 smacro_defined(Context * ctx, const char *name, int nparam, SMacro ** defn,
1794 bool nocase)
1796 struct hash_table *smtbl;
1797 SMacro *m;
1799 if (ctx) {
1800 smtbl = &ctx->localmac;
1801 } else if (name[0] == '%' && name[1] == '$') {
1802 if (cstk)
1803 ctx = get_ctx(name, &name);
1804 if (!ctx)
1805 return false; /* got to return _something_ */
1806 smtbl = &ctx->localmac;
1807 } else {
1808 smtbl = &smacros;
1810 m = (SMacro *) hash_findix(smtbl, name);
1812 while (m) {
1813 if (!mstrcmp(m->name, name, m->casesense && nocase) &&
1814 (nparam <= 0 || m->nparam == 0 || nparam == (int) m->nparam)) {
1815 if (defn) {
1816 if (nparam == (int) m->nparam || nparam == -1)
1817 *defn = m;
1818 else
1819 *defn = NULL;
1821 return true;
1823 m = m->next;
1826 return false;
1830 * Count and mark off the parameters in a multi-line macro call.
1831 * This is called both from within the multi-line macro expansion
1832 * code, and also to mark off the default parameters when provided
1833 * in a %macro definition line.
1835 static void count_mmac_params(Token * t, int *nparam, Token *** params)
1837 int paramsize, brace;
1839 *nparam = paramsize = 0;
1840 *params = NULL;
1841 while (t) {
1842 /* +1: we need space for the final NULL */
1843 if (*nparam+1 >= paramsize) {
1844 paramsize += PARAM_DELTA;
1845 *params = nasm_realloc(*params, sizeof(**params) * paramsize);
1847 skip_white_(t);
1848 brace = false;
1849 if (tok_is_(t, "{"))
1850 brace = true;
1851 (*params)[(*nparam)++] = t;
1852 while (tok_isnt_(t, brace ? "}" : ","))
1853 t = t->next;
1854 if (t) { /* got a comma/brace */
1855 t = t->next;
1856 if (brace) {
1858 * Now we've found the closing brace, look further
1859 * for the comma.
1861 skip_white_(t);
1862 if (tok_isnt_(t, ",")) {
1863 error(ERR_NONFATAL,
1864 "braces do not enclose all of macro parameter");
1865 while (tok_isnt_(t, ","))
1866 t = t->next;
1868 if (t)
1869 t = t->next; /* eat the comma */
1876 * Determine whether one of the various `if' conditions is true or
1877 * not.
1879 * We must free the tline we get passed.
1881 static bool if_condition(Token * tline, enum preproc_token ct)
1883 enum pp_conditional i = PP_COND(ct);
1884 bool j;
1885 Token *t, *tt, **tptr, *origline;
1886 struct tokenval tokval;
1887 expr *evalresult;
1888 enum pp_token_type needtype;
1889 char *p;
1891 origline = tline;
1893 switch (i) {
1894 case PPC_IFCTX:
1895 j = false; /* have we matched yet? */
1896 while (true) {
1897 skip_white_(tline);
1898 if (!tline)
1899 break;
1900 if (tline->type != TOK_ID) {
1901 error(ERR_NONFATAL,
1902 "`%s' expects context identifiers", pp_directives[ct]);
1903 free_tlist(origline);
1904 return -1;
1906 if (cstk && cstk->name && !nasm_stricmp(tline->text, cstk->name))
1907 j = true;
1908 tline = tline->next;
1910 break;
1912 case PPC_IFDEF:
1913 j = false; /* have we matched yet? */
1914 while (tline) {
1915 skip_white_(tline);
1916 if (!tline || (tline->type != TOK_ID &&
1917 (tline->type != TOK_PREPROC_ID ||
1918 tline->text[1] != '$'))) {
1919 error(ERR_NONFATAL,
1920 "`%s' expects macro identifiers", pp_directives[ct]);
1921 goto fail;
1923 if (smacro_defined(NULL, tline->text, 0, NULL, true))
1924 j = true;
1925 tline = tline->next;
1927 break;
1929 case PPC_IFENV:
1930 tline = expand_smacro(tline);
1931 j = false; /* have we matched yet? */
1932 while (tline) {
1933 skip_white_(tline);
1934 if (!tline || (tline->type != TOK_ID &&
1935 tline->type != TOK_STRING &&
1936 (tline->type != TOK_PREPROC_ID ||
1937 tline->text[1] != '!'))) {
1938 error(ERR_NONFATAL,
1939 "`%s' expects environment variable names",
1940 pp_directives[ct]);
1941 goto fail;
1943 p = tline->text;
1944 if (tline->type == TOK_PREPROC_ID)
1945 p += 2; /* Skip leading %! */
1946 if (*p == '\'' || *p == '\"' || *p == '`')
1947 nasm_unquote_cstr(p, ct);
1948 if (getenv(p))
1949 j = true;
1950 tline = tline->next;
1952 break;
1954 case PPC_IFIDN:
1955 case PPC_IFIDNI:
1956 tline = expand_smacro(tline);
1957 t = tt = tline;
1958 while (tok_isnt_(tt, ","))
1959 tt = tt->next;
1960 if (!tt) {
1961 error(ERR_NONFATAL,
1962 "`%s' expects two comma-separated arguments",
1963 pp_directives[ct]);
1964 goto fail;
1966 tt = tt->next;
1967 j = true; /* assume equality unless proved not */
1968 while ((t->type != TOK_OTHER || strcmp(t->text, ",")) && tt) {
1969 if (tt->type == TOK_OTHER && !strcmp(tt->text, ",")) {
1970 error(ERR_NONFATAL, "`%s': more than one comma on line",
1971 pp_directives[ct]);
1972 goto fail;
1974 if (t->type == TOK_WHITESPACE) {
1975 t = t->next;
1976 continue;
1978 if (tt->type == TOK_WHITESPACE) {
1979 tt = tt->next;
1980 continue;
1982 if (tt->type != t->type) {
1983 j = false; /* found mismatching tokens */
1984 break;
1986 /* When comparing strings, need to unquote them first */
1987 if (t->type == TOK_STRING) {
1988 size_t l1 = nasm_unquote(t->text, NULL);
1989 size_t l2 = nasm_unquote(tt->text, NULL);
1991 if (l1 != l2) {
1992 j = false;
1993 break;
1995 if (mmemcmp(t->text, tt->text, l1, i == PPC_IFIDN)) {
1996 j = false;
1997 break;
1999 } else if (mstrcmp(tt->text, t->text, i == PPC_IFIDN) != 0) {
2000 j = false; /* found mismatching tokens */
2001 break;
2004 t = t->next;
2005 tt = tt->next;
2007 if ((t->type != TOK_OTHER || strcmp(t->text, ",")) || tt)
2008 j = false; /* trailing gunk on one end or other */
2009 break;
2011 case PPC_IFMACRO:
2013 bool found = false;
2014 ExpDef searching, *ed;
2016 skip_white_(tline);
2017 tline = expand_id(tline);
2018 if (!tok_type_(tline, TOK_ID)) {
2019 error(ERR_NONFATAL,
2020 "`%s' expects a macro name", pp_directives[ct]);
2021 goto fail;
2023 memset(&searching, 0, sizeof(searching));
2024 searching.name = nasm_strdup(tline->text);
2025 searching.casesense = true;
2026 searching.nparam_max = INT_MAX;
2027 tline = expand_smacro(tline->next);
2028 skip_white_(tline);
2029 if (!tline) {
2030 } else if (!tok_type_(tline, TOK_NUMBER)) {
2031 error(ERR_NONFATAL,
2032 "`%s' expects a parameter count or nothing",
2033 pp_directives[ct]);
2034 } else {
2035 searching.nparam_min = searching.nparam_max =
2036 readnum(tline->text, &j);
2037 if (j)
2038 error(ERR_NONFATAL,
2039 "unable to parse parameter count `%s'",
2040 tline->text);
2042 if (tline && tok_is_(tline->next, "-")) {
2043 tline = tline->next->next;
2044 if (tok_is_(tline, "*"))
2045 searching.nparam_max = INT_MAX;
2046 else if (!tok_type_(tline, TOK_NUMBER))
2047 error(ERR_NONFATAL,
2048 "`%s' expects a parameter count after `-'",
2049 pp_directives[ct]);
2050 else {
2051 searching.nparam_max = readnum(tline->text, &j);
2052 if (j)
2053 error(ERR_NONFATAL,
2054 "unable to parse parameter count `%s'",
2055 tline->text);
2056 if (searching.nparam_min > searching.nparam_max)
2057 error(ERR_NONFATAL,
2058 "minimum parameter count exceeds maximum");
2061 if (tline && tok_is_(tline->next, "+")) {
2062 tline = tline->next;
2063 searching.plus = true;
2065 ed = (ExpDef *) hash_findix(&expdefs, searching.name);
2066 while (ed != NULL) {
2067 if (!strcmp(ed->name, searching.name) &&
2068 (ed->nparam_min <= searching.nparam_max || searching.plus) &&
2069 (searching.nparam_min <= ed->nparam_max || ed->plus)) {
2070 found = true;
2071 break;
2073 ed = ed->next;
2075 if (tline && tline->next)
2076 error(ERR_WARNING|ERR_PASS1,
2077 "trailing garbage after %%ifmacro ignored");
2078 nasm_free(searching.name);
2079 j = found;
2080 break;
2083 case PPC_IFID:
2084 needtype = TOK_ID;
2085 goto iftype;
2086 case PPC_IFNUM:
2087 needtype = TOK_NUMBER;
2088 goto iftype;
2089 case PPC_IFSTR:
2090 needtype = TOK_STRING;
2091 goto iftype;
2093 iftype:
2094 t = tline = expand_smacro(tline);
2096 while (tok_type_(t, TOK_WHITESPACE) ||
2097 (needtype == TOK_NUMBER &&
2098 tok_type_(t, TOK_OTHER) &&
2099 (t->text[0] == '-' || t->text[0] == '+') &&
2100 !t->text[1]))
2101 t = t->next;
2103 j = tok_type_(t, needtype);
2104 break;
2106 case PPC_IFTOKEN:
2107 t = tline = expand_smacro(tline);
2108 while (tok_type_(t, TOK_WHITESPACE))
2109 t = t->next;
2111 j = false;
2112 if (t) {
2113 t = t->next; /* Skip the actual token */
2114 while (tok_type_(t, TOK_WHITESPACE))
2115 t = t->next;
2116 j = !t; /* Should be nothing left */
2118 break;
2120 case PPC_IFEMPTY:
2121 t = tline = expand_smacro(tline);
2122 while (tok_type_(t, TOK_WHITESPACE))
2123 t = t->next;
2125 j = !t; /* Should be empty */
2126 break;
2128 case PPC_IF:
2129 t = tline = expand_smacro(tline);
2130 tptr = &t;
2131 tokval.t_type = TOKEN_INVALID;
2132 evalresult = evaluate(ppscan, tptr, &tokval,
2133 NULL, pass | CRITICAL, error, NULL);
2134 if (!evalresult)
2135 return -1;
2136 if (tokval.t_type)
2137 error(ERR_WARNING|ERR_PASS1,
2138 "trailing garbage after expression ignored");
2139 if (!is_simple(evalresult)) {
2140 error(ERR_NONFATAL,
2141 "non-constant value given to `%s'", pp_directives[ct]);
2142 goto fail;
2144 j = reloc_value(evalresult) != 0;
2145 break;
2147 default:
2148 error(ERR_FATAL,
2149 "preprocessor directive `%s' not yet implemented",
2150 pp_directives[ct]);
2151 goto fail;
2154 free_tlist(origline);
2155 return j ^ PP_NEGATIVE(ct);
2157 fail:
2158 free_tlist(origline);
2159 return -1;
2163 * Common code for defining an smacro
2165 static bool define_smacro(Context *ctx, const char *mname, bool casesense,
2166 int nparam, Token *expansion)
2168 SMacro *smac, **smhead;
2169 struct hash_table *smtbl;
2171 if (smacro_defined(ctx, mname, nparam, &smac, casesense)) {
2172 if (!smac) {
2173 error(ERR_WARNING|ERR_PASS1,
2174 "single-line macro `%s' defined both with and"
2175 " without parameters", mname);
2177 * Some instances of the old code considered this a failure,
2178 * some others didn't. What is the right thing to do here?
2180 free_tlist(expansion);
2181 return false; /* Failure */
2182 } else {
2184 * We're redefining, so we have to take over an
2185 * existing SMacro structure. This means freeing
2186 * what was already in it.
2188 nasm_free(smac->name);
2189 free_tlist(smac->expansion);
2191 } else {
2192 smtbl = ctx ? &ctx->localmac : &smacros;
2193 smhead = (SMacro **) hash_findi_add(smtbl, mname);
2194 smac = nasm_zalloc(sizeof(SMacro));
2195 smac->next = *smhead;
2196 *smhead = smac;
2198 smac->name = nasm_strdup(mname);
2199 smac->casesense = casesense;
2200 smac->nparam = nparam;
2201 smac->expansion = expansion;
2202 smac->in_progress = false;
2203 return true; /* Success */
2207 * Undefine an smacro
2209 static void undef_smacro(Context *ctx, const char *mname)
2211 SMacro **smhead, *s, **sp;
2212 struct hash_table *smtbl;
2214 smtbl = ctx ? &ctx->localmac : &smacros;
2215 smhead = (SMacro **)hash_findi(smtbl, mname, NULL);
2217 if (smhead) {
2219 * We now have a macro name... go hunt for it.
2221 sp = smhead;
2222 while ((s = *sp) != NULL) {
2223 if (!mstrcmp(s->name, mname, s->casesense)) {
2224 *sp = s->next;
2225 nasm_free(s->name);
2226 free_tlist(s->expansion);
2227 nasm_free(s);
2228 } else {
2229 sp = &s->next;
2236 * Parse a mmacro specification.
2238 static bool parse_mmacro_spec(Token *tline, ExpDef *def, const char *directive)
2240 bool err;
2242 tline = tline->next;
2243 skip_white_(tline);
2244 tline = expand_id(tline);
2245 if (!tok_type_(tline, TOK_ID)) {
2246 error(ERR_NONFATAL, "`%s' expects a macro name", directive);
2247 return false;
2250 def->name = nasm_strdup(tline->text);
2251 def->plus = false;
2252 def->nolist = false;
2253 // def->in_progress = 0;
2254 // def->rep_nest = NULL;
2255 def->nparam_min = 0;
2256 def->nparam_max = 0;
2258 tline = expand_smacro(tline->next);
2259 skip_white_(tline);
2260 if (!tok_type_(tline, TOK_NUMBER)) {
2261 error(ERR_NONFATAL, "`%s' expects a parameter count", directive);
2262 } else {
2263 def->nparam_min = def->nparam_max =
2264 readnum(tline->text, &err);
2265 if (err)
2266 error(ERR_NONFATAL,
2267 "unable to parse parameter count `%s'", tline->text);
2269 if (tline && tok_is_(tline->next, "-")) {
2270 tline = tline->next->next;
2271 if (tok_is_(tline, "*")) {
2272 def->nparam_max = INT_MAX;
2273 } else if (!tok_type_(tline, TOK_NUMBER)) {
2274 error(ERR_NONFATAL,
2275 "`%s' expects a parameter count after `-'", directive);
2276 } else {
2277 def->nparam_max = readnum(tline->text, &err);
2278 if (err) {
2279 error(ERR_NONFATAL, "unable to parse parameter count `%s'",
2280 tline->text);
2282 if (def->nparam_min > def->nparam_max) {
2283 error(ERR_NONFATAL, "minimum parameter count exceeds maximum");
2287 if (tline && tok_is_(tline->next, "+")) {
2288 tline = tline->next;
2289 def->plus = true;
2291 if (tline && tok_type_(tline->next, TOK_ID) &&
2292 !nasm_stricmp(tline->next->text, ".nolist")) {
2293 tline = tline->next;
2294 def->nolist = true;
2298 * Handle default parameters.
2300 if (tline && tline->next) {
2301 def->dlist = tline->next;
2302 tline->next = NULL;
2303 count_mmac_params(def->dlist, &def->ndefs, &def->defaults);
2304 } else {
2305 def->dlist = NULL;
2306 def->defaults = NULL;
2308 def->line = NULL;
2310 if (def->defaults && def->ndefs > def->nparam_max - def->nparam_min &&
2311 !def->plus)
2312 error(ERR_WARNING|ERR_PASS1|ERR_WARN_MDP,
2313 "too many default macro parameters");
2315 return true;
2320 * Decode a size directive
2322 static int parse_size(const char *str) {
2323 static const char *size_names[] =
2324 { "byte", "dword", "oword", "qword", "tword", "word", "yword" };
2325 static const int sizes[] =
2326 { 0, 1, 4, 16, 8, 10, 2, 32 };
2328 return sizes[bsii(str, size_names, ARRAY_SIZE(size_names))+1];
2332 * find and process preprocessor directive in passed line
2333 * Find out if a line contains a preprocessor directive, and deal
2334 * with it if so.
2336 * If a directive _is_ found, it is the responsibility of this routine
2337 * (and not the caller) to free_tlist() the line.
2339 * @param tline a pointer to the current tokeninzed line linked list
2340 * @return DIRECTIVE_FOUND or NO_DIRECTIVE_FOUND
2343 static int do_directive(Token * tline)
2345 enum preproc_token i;
2346 int j;
2347 bool err;
2348 int nparam;
2349 bool nolist;
2350 bool casesense;
2351 int k, m;
2352 int offset;
2353 char *p, *pp;
2354 const char *mname;
2355 Include *inc;
2356 Context *ctx;
2357 Line *l;
2358 Token *t, *tt, *param_start, *macro_start, *last, **tptr, *origline;
2359 struct tokenval tokval;
2360 expr *evalresult;
2361 ExpDef *ed, *eed, **edhead;
2362 ExpInv *ei, *eei;
2363 int64_t count;
2364 size_t len;
2365 int severity;
2367 origline = tline;
2369 skip_white_(tline);
2370 if (!tline || !tok_type_(tline, TOK_PREPROC_ID) ||
2371 (tline->text[1] == '%' || tline->text[1] == '$'
2372 || tline->text[1] == '!'))
2373 return NO_DIRECTIVE_FOUND;
2375 i = pp_token_hash(tline->text);
2377 switch (i) {
2378 case PP_INVALID:
2379 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2380 error(ERR_NONFATAL, "unknown preprocessor directive `%s'",
2381 tline->text);
2382 return NO_DIRECTIVE_FOUND; /* didn't get it */
2384 case PP_STACKSIZE:
2385 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2386 /* Directive to tell NASM what the default stack size is. The
2387 * default is for a 16-bit stack, and this can be overriden with
2388 * %stacksize large.
2390 tline = tline->next;
2391 if (tline && tline->type == TOK_WHITESPACE)
2392 tline = tline->next;
2393 if (!tline || tline->type != TOK_ID) {
2394 error(ERR_NONFATAL, "`%%stacksize' missing size parameter");
2395 free_tlist(origline);
2396 return DIRECTIVE_FOUND;
2398 if (nasm_stricmp(tline->text, "flat") == 0) {
2399 /* All subsequent ARG directives are for a 32-bit stack */
2400 StackSize = 4;
2401 StackPointer = "ebp";
2402 ArgOffset = 8;
2403 LocalOffset = 0;
2404 } else if (nasm_stricmp(tline->text, "flat64") == 0) {
2405 /* All subsequent ARG directives are for a 64-bit stack */
2406 StackSize = 8;
2407 StackPointer = "rbp";
2408 ArgOffset = 16;
2409 LocalOffset = 0;
2410 } else if (nasm_stricmp(tline->text, "large") == 0) {
2411 /* All subsequent ARG directives are for a 16-bit stack,
2412 * far function call.
2414 StackSize = 2;
2415 StackPointer = "bp";
2416 ArgOffset = 4;
2417 LocalOffset = 0;
2418 } else if (nasm_stricmp(tline->text, "small") == 0) {
2419 /* All subsequent ARG directives are for a 16-bit stack,
2420 * far function call. We don't support near functions.
2422 StackSize = 2;
2423 StackPointer = "bp";
2424 ArgOffset = 6;
2425 LocalOffset = 0;
2426 } else {
2427 error(ERR_NONFATAL, "`%%stacksize' invalid size type");
2428 free_tlist(origline);
2429 return DIRECTIVE_FOUND;
2431 free_tlist(origline);
2432 return DIRECTIVE_FOUND;
2434 case PP_ARG:
2435 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2436 /* TASM like ARG directive to define arguments to functions, in
2437 * the following form:
2439 * ARG arg1:WORD, arg2:DWORD, arg4:QWORD
2441 offset = ArgOffset;
2442 do {
2443 char *arg, directive[256];
2444 int size = StackSize;
2446 /* Find the argument name */
2447 tline = tline->next;
2448 if (tline && tline->type == TOK_WHITESPACE)
2449 tline = tline->next;
2450 if (!tline || tline->type != TOK_ID) {
2451 error(ERR_NONFATAL, "`%%arg' missing argument parameter");
2452 free_tlist(origline);
2453 return DIRECTIVE_FOUND;
2455 arg = tline->text;
2457 /* Find the argument size type */
2458 tline = tline->next;
2459 if (!tline || tline->type != TOK_OTHER
2460 || tline->text[0] != ':') {
2461 error(ERR_NONFATAL,
2462 "Syntax error processing `%%arg' directive");
2463 free_tlist(origline);
2464 return DIRECTIVE_FOUND;
2466 tline = tline->next;
2467 if (!tline || tline->type != TOK_ID) {
2468 error(ERR_NONFATAL, "`%%arg' missing size type parameter");
2469 free_tlist(origline);
2470 return DIRECTIVE_FOUND;
2473 /* Allow macro expansion of type parameter */
2474 tt = tokenize(tline->text);
2475 tt = expand_smacro(tt);
2476 size = parse_size(tt->text);
2477 if (!size) {
2478 error(ERR_NONFATAL,
2479 "Invalid size type for `%%arg' missing directive");
2480 free_tlist(tt);
2481 free_tlist(origline);
2482 return DIRECTIVE_FOUND;
2484 free_tlist(tt);
2486 /* Round up to even stack slots */
2487 size = ALIGN(size, StackSize);
2489 /* Now define the macro for the argument */
2490 snprintf(directive, sizeof(directive), "%%define %s (%s+%d)",
2491 arg, StackPointer, offset);
2492 do_directive(tokenize(directive));
2493 offset += size;
2495 /* Move to the next argument in the list */
2496 tline = tline->next;
2497 if (tline && tline->type == TOK_WHITESPACE)
2498 tline = tline->next;
2499 } while (tline && tline->type == TOK_OTHER && tline->text[0] == ',');
2500 ArgOffset = offset;
2501 free_tlist(origline);
2502 return DIRECTIVE_FOUND;
2504 case PP_LOCAL:
2505 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2506 /* TASM like LOCAL directive to define local variables for a
2507 * function, in the following form:
2509 * LOCAL local1:WORD, local2:DWORD, local4:QWORD = LocalSize
2511 * The '= LocalSize' at the end is ignored by NASM, but is
2512 * required by TASM to define the local parameter size (and used
2513 * by the TASM macro package).
2515 offset = LocalOffset;
2516 do {
2517 char *local, directive[256];
2518 int size = StackSize;
2520 /* Find the argument name */
2521 tline = tline->next;
2522 if (tline && tline->type == TOK_WHITESPACE)
2523 tline = tline->next;
2524 if (!tline || tline->type != TOK_ID) {
2525 error(ERR_NONFATAL,
2526 "`%%local' missing argument parameter");
2527 free_tlist(origline);
2528 return DIRECTIVE_FOUND;
2530 local = tline->text;
2532 /* Find the argument size type */
2533 tline = tline->next;
2534 if (!tline || tline->type != TOK_OTHER
2535 || tline->text[0] != ':') {
2536 error(ERR_NONFATAL,
2537 "Syntax error processing `%%local' directive");
2538 free_tlist(origline);
2539 return DIRECTIVE_FOUND;
2541 tline = tline->next;
2542 if (!tline || tline->type != TOK_ID) {
2543 error(ERR_NONFATAL,
2544 "`%%local' missing size type parameter");
2545 free_tlist(origline);
2546 return DIRECTIVE_FOUND;
2549 /* Allow macro expansion of type parameter */
2550 tt = tokenize(tline->text);
2551 tt = expand_smacro(tt);
2552 size = parse_size(tt->text);
2553 if (!size) {
2554 error(ERR_NONFATAL,
2555 "Invalid size type for `%%local' missing directive");
2556 free_tlist(tt);
2557 free_tlist(origline);
2558 return DIRECTIVE_FOUND;
2560 free_tlist(tt);
2562 /* Round up to even stack slots */
2563 size = ALIGN(size, StackSize);
2565 offset += size; /* Negative offset, increment before */
2567 /* Now define the macro for the argument */
2568 snprintf(directive, sizeof(directive), "%%define %s (%s-%d)",
2569 local, StackPointer, offset);
2570 do_directive(tokenize(directive));
2572 /* Now define the assign to setup the enter_c macro correctly */
2573 snprintf(directive, sizeof(directive),
2574 "%%assign %%$localsize %%$localsize+%d", size);
2575 do_directive(tokenize(directive));
2577 /* Move to the next argument in the list */
2578 tline = tline->next;
2579 if (tline && tline->type == TOK_WHITESPACE)
2580 tline = tline->next;
2581 } while (tline && tline->type == TOK_OTHER && tline->text[0] == ',');
2582 LocalOffset = offset;
2583 free_tlist(origline);
2584 return DIRECTIVE_FOUND;
2586 case PP_CLEAR:
2587 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2588 if (tline->next)
2589 error(ERR_WARNING|ERR_PASS1,
2590 "trailing garbage after `%%clear' ignored");
2591 free_macros();
2592 init_macros();
2593 free_tlist(origline);
2594 return DIRECTIVE_FOUND;
2596 case PP_DEPEND:
2597 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2598 t = tline->next = expand_smacro(tline->next);
2599 skip_white_(t);
2600 if (!t || (t->type != TOK_STRING &&
2601 t->type != TOK_INTERNAL_STRING)) {
2602 error(ERR_NONFATAL, "`%%depend' expects a file name");
2603 free_tlist(origline);
2604 return DIRECTIVE_FOUND; /* but we did _something_ */
2606 if (t->next)
2607 error(ERR_WARNING|ERR_PASS1,
2608 "trailing garbage after `%%depend' ignored");
2609 p = t->text;
2610 if (t->type != TOK_INTERNAL_STRING)
2611 nasm_unquote_cstr(p, i);
2612 if (dephead && !in_list(*dephead, p)) {
2613 StrList *sl = nasm_malloc(strlen(p)+1+sizeof sl->next);
2614 sl->next = NULL;
2615 strcpy(sl->str, p);
2616 *deptail = sl;
2617 deptail = &sl->next;
2619 free_tlist(origline);
2620 return DIRECTIVE_FOUND;
2622 case PP_INCLUDE:
2623 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2624 t = tline->next = expand_smacro(tline->next);
2625 skip_white_(t);
2627 if (!t || (t->type != TOK_STRING &&
2628 t->type != TOK_INTERNAL_STRING)) {
2629 error(ERR_NONFATAL, "`%%include' expects a file name");
2630 free_tlist(origline);
2631 return DIRECTIVE_FOUND; /* but we did _something_ */
2633 if (t->next)
2634 error(ERR_WARNING|ERR_PASS1,
2635 "trailing garbage after `%%include' ignored");
2636 p = t->text;
2637 if (t->type != TOK_INTERNAL_STRING)
2638 nasm_unquote_cstr(p, i);
2639 inc = nasm_zalloc(sizeof(Include));
2640 inc->next = istk;
2641 inc->fp = inc_fopen(p, dephead, &deptail, pass == 0);
2642 if (!inc->fp) {
2643 /* -MG given but file not found */
2644 nasm_free(inc);
2645 } else {
2646 inc->fname = src_set_fname(nasm_strdup(p));
2647 inc->lineno = src_set_linnum(0);
2648 inc->lineinc = 1;
2649 inc->expansion = NULL;
2650 istk = inc;
2651 list->uplevel(LIST_INCLUDE);
2653 free_tlist(origline);
2654 return DIRECTIVE_FOUND;
2656 case PP_USE:
2657 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2659 static macros_t *use_pkg;
2660 const char *pkg_macro = NULL;
2662 tline = tline->next;
2663 skip_white_(tline);
2664 tline = expand_id(tline);
2666 if (!tline || (tline->type != TOK_STRING &&
2667 tline->type != TOK_INTERNAL_STRING &&
2668 tline->type != TOK_ID)) {
2669 error(ERR_NONFATAL, "`%%use' expects a package name");
2670 free_tlist(origline);
2671 return DIRECTIVE_FOUND; /* but we did _something_ */
2673 if (tline->next)
2674 error(ERR_WARNING|ERR_PASS1,
2675 "trailing garbage after `%%use' ignored");
2676 if (tline->type == TOK_STRING)
2677 nasm_unquote_cstr(tline->text, i);
2678 use_pkg = nasm_stdmac_find_package(tline->text);
2679 if (!use_pkg)
2680 error(ERR_NONFATAL, "unknown `%%use' package: %s", tline->text);
2681 else
2682 pkg_macro = (char *)use_pkg + 1; /* The first string will be <%define>__USE_*__ */
2683 if (use_pkg && ! smacro_defined(NULL, pkg_macro, 0, NULL, true)) {
2684 /* Not already included, go ahead and include it */
2685 stdmacpos = use_pkg;
2687 free_tlist(origline);
2688 return DIRECTIVE_FOUND;
2690 case PP_PUSH:
2691 case PP_REPL:
2692 case PP_POP:
2693 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2694 tline = tline->next;
2695 skip_white_(tline);
2696 tline = expand_id(tline);
2697 if (tline) {
2698 if (!tok_type_(tline, TOK_ID)) {
2699 error(ERR_NONFATAL, "`%s' expects a context identifier",
2700 pp_directives[i]);
2701 free_tlist(origline);
2702 return DIRECTIVE_FOUND; /* but we did _something_ */
2704 if (tline->next)
2705 error(ERR_WARNING|ERR_PASS1,
2706 "trailing garbage after `%s' ignored",
2707 pp_directives[i]);
2708 p = nasm_strdup(tline->text);
2709 } else {
2710 p = NULL; /* Anonymous */
2713 if (i == PP_PUSH) {
2714 ctx = nasm_zalloc(sizeof(Context));
2715 ctx->next = cstk;
2716 hash_init(&ctx->localmac, HASH_SMALL);
2717 ctx->name = p;
2718 ctx->number = unique++;
2719 cstk = ctx;
2720 } else {
2721 /* %pop or %repl */
2722 if (!cstk) {
2723 error(ERR_NONFATAL, "`%s': context stack is empty",
2724 pp_directives[i]);
2725 } else if (i == PP_POP) {
2726 if (p && (!cstk->name || nasm_stricmp(p, cstk->name)))
2727 error(ERR_NONFATAL, "`%%pop' in wrong context: %s, "
2728 "expected %s",
2729 cstk->name ? cstk->name : "anonymous", p);
2730 else
2731 ctx_pop();
2732 } else {
2733 /* i == PP_REPL */
2734 nasm_free(cstk->name);
2735 cstk->name = p;
2736 p = NULL;
2738 nasm_free(p);
2740 free_tlist(origline);
2741 return DIRECTIVE_FOUND;
2742 case PP_FATAL:
2743 severity = ERR_FATAL;
2744 goto issue_error;
2745 case PP_ERROR:
2746 severity = ERR_NONFATAL;
2747 goto issue_error;
2748 case PP_WARNING:
2749 severity = ERR_WARNING|ERR_WARN_USER;
2750 goto issue_error;
2752 issue_error:
2753 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2755 /* Only error out if this is the final pass */
2756 if (pass != 2 && i != PP_FATAL)
2757 return DIRECTIVE_FOUND;
2759 tline->next = expand_smacro(tline->next);
2760 tline = tline->next;
2761 skip_white_(tline);
2762 t = tline ? tline->next : NULL;
2763 skip_white_(t);
2764 if (tok_type_(tline, TOK_STRING) && !t) {
2765 /* The line contains only a quoted string */
2766 p = tline->text;
2767 nasm_unquote(p, NULL); /* Ignore NUL character truncation */
2768 error(severity, "%s", p);
2769 } else {
2770 /* Not a quoted string, or more than a quoted string */
2771 p = detoken(tline, false);
2772 error(severity, "%s", p);
2773 nasm_free(p);
2775 free_tlist(origline);
2776 return DIRECTIVE_FOUND;
2779 CASE_PP_IF:
2780 if (defining != NULL) {
2781 if (defining->type == EXP_IF) {
2782 defining->def_depth ++;
2784 return NO_DIRECTIVE_FOUND;
2786 if ((istk->expansion != NULL) &&
2787 (istk->expansion->emitting == false)) {
2788 j = COND_NEVER;
2789 } else {
2790 j = if_condition(tline->next, i);
2791 tline->next = NULL; /* it got freed */
2792 j = (((j < 0) ? COND_NEVER : j) ? COND_IF_TRUE : COND_IF_FALSE);
2794 ed = new_ExpDef(EXP_IF);
2795 ed->state = j;
2796 ed->ignoring = ((ed->state == COND_IF_TRUE) ? false : true);
2797 ed->prev = defining;
2798 defining = ed;
2799 free_tlist(origline);
2800 return DIRECTIVE_FOUND;
2802 CASE_PP_ELIF:
2803 if (defining != NULL) {
2804 if ((defining->type != EXP_IF) || (defining->def_depth > 0)) {
2805 return NO_DIRECTIVE_FOUND;
2808 if ((defining == NULL) || (defining->type != EXP_IF)) {
2809 error(ERR_FATAL, "`%s': no matching `%%if'", pp_directives[i]);
2811 switch (defining->state) {
2812 case COND_IF_TRUE:
2813 defining->state = COND_DONE;
2814 defining->ignoring = true;
2815 break;
2817 case COND_DONE:
2818 case COND_NEVER:
2819 defining->ignoring = true;
2820 break;
2822 case COND_ELSE_TRUE:
2823 case COND_ELSE_FALSE:
2824 error_precond(ERR_WARNING|ERR_PASS1,
2825 "`%%elif' after `%%else' ignored");
2826 defining->state = COND_NEVER;
2827 defining->ignoring = true;
2828 break;
2830 case COND_IF_FALSE:
2832 * IMPORTANT: In the case of %if, we will already have
2833 * called expand_mmac_params(); however, if we're
2834 * processing an %elif we must have been in a
2835 * non-emitting mode, which would have inhibited
2836 * the normal invocation of expand_mmac_params().
2837 * Therefore, we have to do it explicitly here.
2839 j = if_condition(expand_mmac_params(tline->next), i);
2840 tline->next = NULL; /* it got freed */
2841 defining->state =
2842 j < 0 ? COND_NEVER : j ? COND_IF_TRUE : COND_IF_FALSE;
2843 defining->ignoring = ((defining->state == COND_IF_TRUE) ? false : true);
2844 break;
2846 free_tlist(origline);
2847 return DIRECTIVE_FOUND;
2849 case PP_ELSE:
2850 if (defining != NULL) {
2851 if ((defining->type != EXP_IF) || (defining->def_depth > 0)) {
2852 return NO_DIRECTIVE_FOUND;
2855 if (tline->next)
2856 error_precond(ERR_WARNING|ERR_PASS1,
2857 "trailing garbage after `%%else' ignored");
2858 if ((defining == NULL) || (defining->type != EXP_IF)) {
2859 error(ERR_FATAL, "`%s': no matching `%%if'", pp_directives[i]);
2861 switch (defining->state) {
2862 case COND_IF_TRUE:
2863 case COND_DONE:
2864 defining->state = COND_ELSE_FALSE;
2865 defining->ignoring = true;
2866 break;
2868 case COND_NEVER:
2869 defining->ignoring = true;
2870 break;
2872 case COND_IF_FALSE:
2873 defining->state = COND_ELSE_TRUE;
2874 defining->ignoring = false;
2875 break;
2877 case COND_ELSE_TRUE:
2878 case COND_ELSE_FALSE:
2879 error_precond(ERR_WARNING|ERR_PASS1,
2880 "`%%else' after `%%else' ignored.");
2881 defining->state = COND_NEVER;
2882 defining->ignoring = true;
2883 break;
2885 free_tlist(origline);
2886 return DIRECTIVE_FOUND;
2888 case PP_ENDIF:
2889 if (defining != NULL) {
2890 if (defining->type == EXP_IF) {
2891 if (defining->def_depth > 0) {
2892 defining->def_depth --;
2893 return NO_DIRECTIVE_FOUND;
2895 } else {
2896 return NO_DIRECTIVE_FOUND;
2899 if (tline->next)
2900 error_precond(ERR_WARNING|ERR_PASS1,
2901 "trailing garbage after `%%endif' ignored");
2902 if ((defining == NULL) || (defining->type != EXP_IF)) {
2903 error(ERR_NONFATAL, "`%%endif': no matching `%%if'");
2904 return DIRECTIVE_FOUND;
2906 ed = defining;
2907 defining = ed->prev;
2908 ed->prev = expansions;
2909 expansions = ed;
2910 ei = new_ExpInv(EXP_IF, ed);
2911 ei->current = ed->line;
2912 ei->emitting = true;
2913 ei->prev = istk->expansion;
2914 istk->expansion = ei;
2915 free_tlist(origline);
2916 return DIRECTIVE_FOUND;
2918 case PP_RMACRO:
2919 case PP_IRMACRO:
2920 case PP_MACRO:
2921 case PP_IMACRO:
2922 if (defining != NULL) {
2923 if (defining->type == EXP_MMACRO) {
2924 defining->def_depth ++;
2926 return NO_DIRECTIVE_FOUND;
2928 ed = new_ExpDef(EXP_MMACRO);
2929 ed->max_depth =
2930 (i == PP_RMACRO) || (i == PP_IRMACRO) ? DEADMAN_LIMIT : 0;
2931 ed->casesense = (i == PP_MACRO) || (i == PP_RMACRO);
2932 if (!parse_mmacro_spec(tline, ed, pp_directives[i])) {
2933 nasm_free(ed);
2934 ed = NULL;
2935 return DIRECTIVE_FOUND;
2937 ed->def_depth = 0;
2938 ed->cur_depth = 0;
2939 ed->max_depth = (ed->max_depth + 1);
2940 ed->ignoring = false;
2941 ed->prev = defining;
2942 defining = ed;
2944 eed = (ExpDef *) hash_findix(&expdefs, ed->name);
2945 while (eed) {
2946 if (!strcmp(eed->name, ed->name) &&
2947 (eed->nparam_min <= ed->nparam_max || ed->plus) &&
2948 (ed->nparam_min <= eed->nparam_max || eed->plus)) {
2949 error(ERR_WARNING|ERR_PASS1,
2950 "redefining multi-line macro `%s'", ed->name);
2951 return DIRECTIVE_FOUND;
2953 eed = eed->next;
2955 free_tlist(origline);
2956 return DIRECTIVE_FOUND;
2958 case PP_ENDM:
2959 case PP_ENDMACRO:
2960 if (defining != NULL) {
2961 if (defining->type == EXP_MMACRO) {
2962 if (defining->def_depth > 0) {
2963 defining->def_depth --;
2964 return NO_DIRECTIVE_FOUND;
2966 } else {
2967 return NO_DIRECTIVE_FOUND;
2970 if (!(defining) || (defining->type != EXP_MMACRO)) {
2971 error(ERR_NONFATAL, "`%s': not defining a macro", tline->text);
2972 return DIRECTIVE_FOUND;
2974 edhead = (ExpDef **) hash_findi_add(&expdefs, defining->name);
2975 defining->next = *edhead;
2976 *edhead = defining;
2977 ed = defining;
2978 defining = ed->prev;
2979 ed->prev = expansions;
2980 expansions = ed;
2981 ed = NULL;
2982 free_tlist(origline);
2983 return DIRECTIVE_FOUND;
2985 case PP_EXITMACRO:
2986 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2988 * We must search along istk->expansion until we hit a
2989 * macro invocation. Then we disable the emitting state(s)
2990 * between exitmacro and endmacro.
2992 for (ei = istk->expansion; ei != NULL; ei = ei->prev) {
2993 if(ei->type == EXP_MMACRO) {
2994 break;
2998 if (ei != NULL) {
3000 * Set all invocations leading back to the macro
3001 * invocation to a non-emitting state.
3003 for (eei = istk->expansion; eei != ei; eei = eei->prev) {
3004 eei->emitting = false;
3006 eei->emitting = false;
3007 } else {
3008 error(ERR_NONFATAL, "`%%exitmacro' not within `%%macro' block");
3010 free_tlist(origline);
3011 return DIRECTIVE_FOUND;
3013 case PP_UNMACRO:
3014 case PP_UNIMACRO:
3015 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3017 ExpDef **ed_p;
3018 ExpDef spec;
3020 spec.casesense = (i == PP_UNMACRO);
3021 if (!parse_mmacro_spec(tline, &spec, pp_directives[i])) {
3022 return DIRECTIVE_FOUND;
3024 ed_p = (ExpDef **) hash_findi(&expdefs, spec.name, NULL);
3025 while (ed_p && *ed_p) {
3026 ed = *ed_p;
3027 if (ed->casesense == spec.casesense &&
3028 !mstrcmp(ed->name, spec.name, spec.casesense) &&
3029 ed->nparam_min == spec.nparam_min &&
3030 ed->nparam_max == spec.nparam_max &&
3031 ed->plus == spec.plus) {
3032 if (ed->cur_depth > 0) {
3033 error(ERR_NONFATAL, "`%s' ignored on active macro",
3034 pp_directives[i]);
3035 break;
3036 } else {
3037 *ed_p = ed->next;
3038 free_expdef(ed);
3040 } else {
3041 ed_p = &ed->next;
3044 free_tlist(origline);
3045 free_tlist(spec.dlist);
3046 return DIRECTIVE_FOUND;
3049 case PP_ROTATE:
3050 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3051 if (tline->next && tline->next->type == TOK_WHITESPACE)
3052 tline = tline->next;
3053 if (!tline->next) {
3054 free_tlist(origline);
3055 error(ERR_NONFATAL, "`%%rotate' missing rotate count");
3056 return DIRECTIVE_FOUND;
3058 t = expand_smacro(tline->next);
3059 tline->next = NULL;
3060 free_tlist(origline);
3061 tline = t;
3062 tptr = &t;
3063 tokval.t_type = TOKEN_INVALID;
3064 evalresult =
3065 evaluate(ppscan, tptr, &tokval, NULL, pass, error, NULL);
3066 free_tlist(tline);
3067 if (!evalresult)
3068 return DIRECTIVE_FOUND;
3069 if (tokval.t_type)
3070 error(ERR_WARNING|ERR_PASS1,
3071 "trailing garbage after expression ignored");
3072 if (!is_simple(evalresult)) {
3073 error(ERR_NONFATAL, "non-constant value given to `%%rotate'");
3074 return DIRECTIVE_FOUND;
3076 for (ei = istk->expansion; ei != NULL; ei = ei->prev) {
3077 if (ei->type == EXP_MMACRO) {
3078 break;
3081 if (ei == NULL) {
3082 error(ERR_NONFATAL, "`%%rotate' invoked outside a macro call");
3083 } else if (ei->nparam == 0) {
3084 error(ERR_NONFATAL,
3085 "`%%rotate' invoked within macro without parameters");
3086 } else {
3087 int rotate = ei->rotate + reloc_value(evalresult);
3089 rotate %= (int)ei->nparam;
3090 if (rotate < 0)
3091 rotate += ei->nparam;
3092 ei->rotate = rotate;
3094 return DIRECTIVE_FOUND;
3096 case PP_REP:
3097 if (defining != NULL) {
3098 if (defining->type == EXP_REP) {
3099 defining->def_depth ++;
3101 return NO_DIRECTIVE_FOUND;
3103 nolist = false;
3104 do {
3105 tline = tline->next;
3106 } while (tok_type_(tline, TOK_WHITESPACE));
3108 if (tok_type_(tline, TOK_ID) &&
3109 nasm_stricmp(tline->text, ".nolist") == 0) {
3110 nolist = true;
3111 do {
3112 tline = tline->next;
3113 } while (tok_type_(tline, TOK_WHITESPACE));
3116 if (tline) {
3117 t = expand_smacro(tline);
3118 tptr = &t;
3119 tokval.t_type = TOKEN_INVALID;
3120 evalresult =
3121 evaluate(ppscan, tptr, &tokval, NULL, pass, error, NULL);
3122 if (!evalresult) {
3123 free_tlist(origline);
3124 return DIRECTIVE_FOUND;
3126 if (tokval.t_type)
3127 error(ERR_WARNING|ERR_PASS1,
3128 "trailing garbage after expression ignored");
3129 if (!is_simple(evalresult)) {
3130 error(ERR_NONFATAL, "non-constant value given to `%%rep'");
3131 return DIRECTIVE_FOUND;
3133 count = reloc_value(evalresult);
3134 if (count >= REP_LIMIT) {
3135 error(ERR_NONFATAL, "`%%rep' value exceeds limit");
3136 count = 0;
3137 } else
3138 count++;
3139 } else {
3140 error(ERR_NONFATAL, "`%%rep' expects a repeat count");
3141 count = 0;
3143 free_tlist(origline);
3144 ed = new_ExpDef(EXP_REP);
3145 ed->nolist = nolist;
3146 ed->def_depth = 0;
3147 ed->cur_depth = 1;
3148 ed->max_depth = (count - 1);
3149 ed->ignoring = false;
3150 ed->prev = defining;
3151 defining = ed;
3152 return DIRECTIVE_FOUND;
3154 case PP_ENDREP:
3155 if (defining != NULL) {
3156 if (defining->type == EXP_REP) {
3157 if (defining->def_depth > 0) {
3158 defining->def_depth --;
3159 return NO_DIRECTIVE_FOUND;
3161 } else {
3162 return NO_DIRECTIVE_FOUND;
3165 if ((defining == NULL) || (defining->type != EXP_REP)) {
3166 error(ERR_NONFATAL, "`%%endrep': no matching `%%rep'");
3167 return DIRECTIVE_FOUND;
3171 * Now we have a "macro" defined - although it has no name
3172 * and we won't be entering it in the hash tables - we must
3173 * push a macro-end marker for it on to istk->expansion.
3174 * After that, it will take care of propagating itself (a
3175 * macro-end marker line for a macro which is really a %rep
3176 * block will cause the macro to be re-expanded, complete
3177 * with another macro-end marker to ensure the process
3178 * continues) until the whole expansion is forcibly removed
3179 * from istk->expansion by a %exitrep.
3181 ed = defining;
3182 defining = ed->prev;
3183 ed->prev = expansions;
3184 expansions = ed;
3185 ei = new_ExpInv(EXP_REP, ed);
3186 ei->current = ed->line;
3187 ei->emitting = ((ed->max_depth > 0) ? true : false);
3188 list->uplevel(ed->nolist ? LIST_MACRO_NOLIST : LIST_MACRO);
3189 ei->prev = istk->expansion;
3190 istk->expansion = ei;
3191 free_tlist(origline);
3192 return DIRECTIVE_FOUND;
3194 case PP_EXITREP:
3195 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3197 * We must search along istk->expansion until we hit a
3198 * rep invocation. Then we disable the emitting state(s)
3199 * between exitrep and endrep.
3201 for (ei = istk->expansion; ei != NULL; ei = ei->prev) {
3202 if (ei->type == EXP_REP) {
3203 break;
3207 if (ei != NULL) {
3209 * Set all invocations leading back to the rep
3210 * invocation to a non-emitting state.
3212 for (eei = istk->expansion; eei != ei; eei = eei->prev) {
3213 eei->emitting = false;
3215 eei->emitting = false;
3216 eei->current = NULL;
3217 eei->def->cur_depth = eei->def->max_depth;
3218 } else {
3219 error(ERR_NONFATAL, "`%%exitrep' not within `%%rep' block");
3221 free_tlist(origline);
3222 return DIRECTIVE_FOUND;
3224 case PP_XDEFINE:
3225 case PP_IXDEFINE:
3226 case PP_DEFINE:
3227 case PP_IDEFINE:
3228 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3229 casesense = (i == PP_DEFINE || i == PP_XDEFINE);
3231 tline = tline->next;
3232 skip_white_(tline);
3233 tline = expand_id(tline);
3234 if (!tline || (tline->type != TOK_ID &&
3235 (tline->type != TOK_PREPROC_ID ||
3236 tline->text[1] != '$'))) {
3237 error(ERR_NONFATAL, "`%s' expects a macro identifier",
3238 pp_directives[i]);
3239 free_tlist(origline);
3240 return DIRECTIVE_FOUND;
3243 ctx = get_ctx(tline->text, &mname);
3244 last = tline;
3245 param_start = tline = tline->next;
3246 nparam = 0;
3248 /* Expand the macro definition now for %xdefine and %ixdefine */
3249 if ((i == PP_XDEFINE) || (i == PP_IXDEFINE))
3250 tline = expand_smacro(tline);
3252 if (tok_is_(tline, "(")) {
3254 * This macro has parameters.
3257 tline = tline->next;
3258 while (1) {
3259 skip_white_(tline);
3260 if (!tline) {
3261 error(ERR_NONFATAL, "parameter identifier expected");
3262 free_tlist(origline);
3263 return DIRECTIVE_FOUND;
3265 if (tline->type != TOK_ID) {
3266 error(ERR_NONFATAL,
3267 "`%s': parameter identifier expected",
3268 tline->text);
3269 free_tlist(origline);
3270 return DIRECTIVE_FOUND;
3273 smacro_set_param_idx(tline, nparam);
3274 nparam++;
3276 tline = tline->next;
3277 skip_white_(tline);
3278 if (tok_is_(tline, ",")) {
3279 tline = tline->next;
3280 } else {
3281 if (!tok_is_(tline, ")")) {
3282 error(ERR_NONFATAL,
3283 "`)' expected to terminate macro template");
3284 free_tlist(origline);
3285 return DIRECTIVE_FOUND;
3287 break;
3290 last = tline;
3291 tline = tline->next;
3293 if (tok_type_(tline, TOK_WHITESPACE))
3294 last = tline, tline = tline->next;
3295 macro_start = NULL;
3296 last->next = NULL;
3297 t = tline;
3298 while (t) {
3299 if (t->type == TOK_ID) {
3300 list_for_each(tt, param_start)
3301 if (is_smacro_param(tt) &&
3302 !strcmp(tt->text, t->text))
3303 t->type = tt->type;
3305 tt = t->next;
3306 t->next = macro_start;
3307 macro_start = t;
3308 t = tt;
3311 * Good. We now have a macro name, a parameter count, and a
3312 * token list (in reverse order) for an expansion. We ought
3313 * to be OK just to create an SMacro, store it, and let
3314 * free_tlist have the rest of the line (which we have
3315 * carefully re-terminated after chopping off the expansion
3316 * from the end).
3318 define_smacro(ctx, mname, casesense, nparam, macro_start);
3319 free_tlist(origline);
3320 return DIRECTIVE_FOUND;
3322 case PP_UNDEF:
3323 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3324 tline = tline->next;
3325 skip_white_(tline);
3326 tline = expand_id(tline);
3327 if (!tline || (tline->type != TOK_ID &&
3328 (tline->type != TOK_PREPROC_ID ||
3329 tline->text[1] != '$'))) {
3330 error(ERR_NONFATAL, "`%%undef' expects a macro identifier");
3331 free_tlist(origline);
3332 return DIRECTIVE_FOUND;
3334 if (tline->next) {
3335 error(ERR_WARNING|ERR_PASS1,
3336 "trailing garbage after macro name ignored");
3339 /* Find the context that symbol belongs to */
3340 ctx = get_ctx(tline->text, &mname);
3341 undef_smacro(ctx, mname);
3342 free_tlist(origline);
3343 return DIRECTIVE_FOUND;
3345 case PP_DEFSTR:
3346 case PP_IDEFSTR:
3347 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3348 casesense = (i == PP_DEFSTR);
3350 tline = tline->next;
3351 skip_white_(tline);
3352 tline = expand_id(tline);
3353 if (!tline || (tline->type != TOK_ID &&
3354 (tline->type != TOK_PREPROC_ID ||
3355 tline->text[1] != '$'))) {
3356 error(ERR_NONFATAL, "`%s' expects a macro identifier",
3357 pp_directives[i]);
3358 free_tlist(origline);
3359 return DIRECTIVE_FOUND;
3362 ctx = get_ctx(tline->text, &mname);
3363 last = tline;
3364 tline = expand_smacro(tline->next);
3365 last->next = NULL;
3367 while (tok_type_(tline, TOK_WHITESPACE))
3368 tline = delete_Token(tline);
3370 p = detoken(tline, false);
3371 macro_start = nasm_zalloc(sizeof(*macro_start));
3372 macro_start->text = nasm_quote(p, strlen(p));
3373 macro_start->type = TOK_STRING;
3374 nasm_free(p);
3377 * We now have a macro name, an implicit parameter count of
3378 * zero, and a string token to use as an expansion. Create
3379 * and store an SMacro.
3381 define_smacro(ctx, mname, casesense, 0, macro_start);
3382 free_tlist(origline);
3383 return DIRECTIVE_FOUND;
3385 case PP_DEFTOK:
3386 case PP_IDEFTOK:
3387 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3388 casesense = (i == PP_DEFTOK);
3390 tline = tline->next;
3391 skip_white_(tline);
3392 tline = expand_id(tline);
3393 if (!tline || (tline->type != TOK_ID &&
3394 (tline->type != TOK_PREPROC_ID ||
3395 tline->text[1] != '$'))) {
3396 error(ERR_NONFATAL,
3397 "`%s' expects a macro identifier as first parameter",
3398 pp_directives[i]);
3399 free_tlist(origline);
3400 return DIRECTIVE_FOUND;
3402 ctx = get_ctx(tline->text, &mname);
3403 last = tline;
3404 tline = expand_smacro(tline->next);
3405 last->next = NULL;
3407 t = tline;
3408 while (tok_type_(t, TOK_WHITESPACE))
3409 t = t->next;
3410 /* t should now point to the string */
3411 if (!tok_type_(t, TOK_STRING)) {
3412 error(ERR_NONFATAL,
3413 "`%s` requires string as second parameter",
3414 pp_directives[i]);
3415 free_tlist(tline);
3416 free_tlist(origline);
3417 return DIRECTIVE_FOUND;
3421 * Convert the string to a token stream. Note that smacros
3422 * are stored with the token stream reversed, so we have to
3423 * reverse the output of tokenize().
3425 nasm_unquote_cstr(t->text, i);
3426 macro_start = reverse_tokens(tokenize(t->text));
3429 * We now have a macro name, an implicit parameter count of
3430 * zero, and a numeric token to use as an expansion. Create
3431 * and store an SMacro.
3433 define_smacro(ctx, mname, casesense, 0, macro_start);
3434 free_tlist(tline);
3435 free_tlist(origline);
3436 return DIRECTIVE_FOUND;
3438 case PP_PATHSEARCH:
3439 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3441 FILE *fp;
3442 StrList *xsl = NULL;
3443 StrList **xst = &xsl;
3445 casesense = true;
3447 tline = tline->next;
3448 skip_white_(tline);
3449 tline = expand_id(tline);
3450 if (!tline || (tline->type != TOK_ID &&
3451 (tline->type != TOK_PREPROC_ID ||
3452 tline->text[1] != '$'))) {
3453 error(ERR_NONFATAL,
3454 "`%%pathsearch' expects a macro identifier as first parameter");
3455 free_tlist(origline);
3456 return DIRECTIVE_FOUND;
3458 ctx = get_ctx(tline->text, &mname);
3459 last = tline;
3460 tline = expand_smacro(tline->next);
3461 last->next = NULL;
3463 t = tline;
3464 while (tok_type_(t, TOK_WHITESPACE))
3465 t = t->next;
3467 if (!t || (t->type != TOK_STRING &&
3468 t->type != TOK_INTERNAL_STRING)) {
3469 error(ERR_NONFATAL, "`%%pathsearch' expects a file name");
3470 free_tlist(tline);
3471 free_tlist(origline);
3472 return DIRECTIVE_FOUND; /* but we did _something_ */
3474 if (t->next)
3475 error(ERR_WARNING|ERR_PASS1,
3476 "trailing garbage after `%%pathsearch' ignored");
3477 p = t->text;
3478 if (t->type != TOK_INTERNAL_STRING)
3479 nasm_unquote(p, NULL);
3481 fp = inc_fopen(p, &xsl, &xst, true);
3482 if (fp) {
3483 p = xsl->str;
3484 fclose(fp); /* Don't actually care about the file */
3486 macro_start = nasm_zalloc(sizeof(*macro_start));
3487 macro_start->text = nasm_quote(p, strlen(p));
3488 macro_start->type = TOK_STRING;
3489 nasm_free(xsl);
3492 * We now have a macro name, an implicit parameter count of
3493 * zero, and a string token to use as an expansion. Create
3494 * and store an SMacro.
3496 define_smacro(ctx, mname, casesense, 0, macro_start);
3497 free_tlist(tline);
3498 free_tlist(origline);
3499 return DIRECTIVE_FOUND;
3502 case PP_STRLEN:
3503 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3504 casesense = true;
3506 tline = tline->next;
3507 skip_white_(tline);
3508 tline = expand_id(tline);
3509 if (!tline || (tline->type != TOK_ID &&
3510 (tline->type != TOK_PREPROC_ID ||
3511 tline->text[1] != '$'))) {
3512 error(ERR_NONFATAL,
3513 "`%%strlen' expects a macro identifier as first parameter");
3514 free_tlist(origline);
3515 return DIRECTIVE_FOUND;
3517 ctx = get_ctx(tline->text, &mname);
3518 last = tline;
3519 tline = expand_smacro(tline->next);
3520 last->next = NULL;
3522 t = tline;
3523 while (tok_type_(t, TOK_WHITESPACE))
3524 t = t->next;
3525 /* t should now point to the string */
3526 if (!tok_type_(t, TOK_STRING)) {
3527 error(ERR_NONFATAL,
3528 "`%%strlen` requires string as second parameter");
3529 free_tlist(tline);
3530 free_tlist(origline);
3531 return DIRECTIVE_FOUND;
3534 macro_start = nasm_zalloc(sizeof(*macro_start));
3535 make_tok_num(macro_start, nasm_unquote(t->text, NULL));
3538 * We now have a macro name, an implicit parameter count of
3539 * zero, and a numeric token to use as an expansion. Create
3540 * and store an SMacro.
3542 define_smacro(ctx, mname, casesense, 0, macro_start);
3543 free_tlist(tline);
3544 free_tlist(origline);
3545 return DIRECTIVE_FOUND;
3547 case PP_STRCAT:
3548 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3549 casesense = true;
3551 tline = tline->next;
3552 skip_white_(tline);
3553 tline = expand_id(tline);
3554 if (!tline || (tline->type != TOK_ID &&
3555 (tline->type != TOK_PREPROC_ID ||
3556 tline->text[1] != '$'))) {
3557 error(ERR_NONFATAL,
3558 "`%%strcat' expects a macro identifier as first parameter");
3559 free_tlist(origline);
3560 return DIRECTIVE_FOUND;
3562 ctx = get_ctx(tline->text, &mname);
3563 last = tline;
3564 tline = expand_smacro(tline->next);
3565 last->next = NULL;
3567 len = 0;
3568 list_for_each(t, tline) {
3569 switch (t->type) {
3570 case TOK_WHITESPACE:
3571 break;
3572 case TOK_STRING:
3573 len += t->a.len = nasm_unquote(t->text, NULL);
3574 break;
3575 case TOK_OTHER:
3576 if (!strcmp(t->text, ",")) /* permit comma separators */
3577 break;
3578 /* else fall through */
3579 default:
3580 error(ERR_NONFATAL,
3581 "non-string passed to `%%strcat' (%d)", t->type);
3582 free_tlist(tline);
3583 free_tlist(origline);
3584 return DIRECTIVE_FOUND;
3588 p = pp = nasm_malloc(len);
3589 list_for_each(t, tline) {
3590 if (t->type == TOK_STRING) {
3591 memcpy(p, t->text, t->a.len);
3592 p += t->a.len;
3597 * We now have a macro name, an implicit parameter count of
3598 * zero, and a numeric token to use as an expansion. Create
3599 * and store an SMacro.
3601 macro_start = new_Token(NULL, TOK_STRING, NULL, 0);
3602 macro_start->text = nasm_quote(pp, len);
3603 nasm_free(pp);
3604 define_smacro(ctx, mname, casesense, 0, macro_start);
3605 free_tlist(tline);
3606 free_tlist(origline);
3607 return DIRECTIVE_FOUND;
3609 case PP_SUBSTR:
3610 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3612 int64_t start, count;
3613 size_t len;
3615 casesense = true;
3617 tline = tline->next;
3618 skip_white_(tline);
3619 tline = expand_id(tline);
3620 if (!tline || (tline->type != TOK_ID &&
3621 (tline->type != TOK_PREPROC_ID ||
3622 tline->text[1] != '$'))) {
3623 error(ERR_NONFATAL,
3624 "`%%substr' expects a macro identifier as first parameter");
3625 free_tlist(origline);
3626 return DIRECTIVE_FOUND;
3628 ctx = get_ctx(tline->text, &mname);
3629 last = tline;
3630 tline = expand_smacro(tline->next);
3631 last->next = NULL;
3633 if (tline) /* skip expanded id */
3634 t = tline->next;
3635 while (tok_type_(t, TOK_WHITESPACE))
3636 t = t->next;
3638 /* t should now point to the string */
3639 if (!tok_type_(t, TOK_STRING)) {
3640 error(ERR_NONFATAL,
3641 "`%%substr` requires string as second parameter");
3642 free_tlist(tline);
3643 free_tlist(origline);
3644 return DIRECTIVE_FOUND;
3647 tt = t->next;
3648 tptr = &tt;
3649 tokval.t_type = TOKEN_INVALID;
3650 evalresult = evaluate(ppscan, tptr, &tokval, NULL,
3651 pass, error, NULL);
3652 if (!evalresult) {
3653 free_tlist(tline);
3654 free_tlist(origline);
3655 return DIRECTIVE_FOUND;
3656 } else if (!is_simple(evalresult)) {
3657 error(ERR_NONFATAL, "non-constant value given to `%%substr`");
3658 free_tlist(tline);
3659 free_tlist(origline);
3660 return DIRECTIVE_FOUND;
3662 start = evalresult->value - 1;
3664 while (tok_type_(tt, TOK_WHITESPACE))
3665 tt = tt->next;
3666 if (!tt) {
3667 count = 1; /* Backwards compatibility: one character */
3668 } else {
3669 tokval.t_type = TOKEN_INVALID;
3670 evalresult = evaluate(ppscan, tptr, &tokval, NULL,
3671 pass, error, NULL);
3672 if (!evalresult) {
3673 free_tlist(tline);
3674 free_tlist(origline);
3675 return DIRECTIVE_FOUND;
3676 } else if (!is_simple(evalresult)) {
3677 error(ERR_NONFATAL, "non-constant value given to `%%substr`");
3678 free_tlist(tline);
3679 free_tlist(origline);
3680 return DIRECTIVE_FOUND;
3682 count = evalresult->value;
3685 len = nasm_unquote(t->text, NULL);
3686 /* make start and count being in range */
3687 if (start < 0)
3688 start = 0;
3689 if (count < 0)
3690 count = len + count + 1 - start;
3691 if (start + count > (int64_t)len)
3692 count = len - start;
3693 if (!len || count < 0 || start >=(int64_t)len)
3694 start = -1, count = 0; /* empty string */
3696 macro_start = nasm_zalloc(sizeof(*macro_start));
3697 macro_start->text = nasm_quote((start < 0) ? "" : t->text + start, count);
3698 macro_start->type = TOK_STRING;
3701 * We now have a macro name, an implicit parameter count of
3702 * zero, and a numeric token to use as an expansion. Create
3703 * and store an SMacro.
3705 define_smacro(ctx, mname, casesense, 0, macro_start);
3706 free_tlist(tline);
3707 free_tlist(origline);
3708 return DIRECTIVE_FOUND;
3711 case PP_ASSIGN:
3712 case PP_IASSIGN:
3713 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3714 casesense = (i == PP_ASSIGN);
3716 tline = tline->next;
3717 skip_white_(tline);
3718 tline = expand_id(tline);
3719 if (!tline || (tline->type != TOK_ID &&
3720 (tline->type != TOK_PREPROC_ID ||
3721 tline->text[1] != '$'))) {
3722 error(ERR_NONFATAL,
3723 "`%%%sassign' expects a macro identifier",
3724 (i == PP_IASSIGN ? "i" : ""));
3725 free_tlist(origline);
3726 return DIRECTIVE_FOUND;
3728 ctx = get_ctx(tline->text, &mname);
3729 last = tline;
3730 tline = expand_smacro(tline->next);
3731 last->next = NULL;
3733 t = tline;
3734 tptr = &t;
3735 tokval.t_type = TOKEN_INVALID;
3736 evalresult =
3737 evaluate(ppscan, tptr, &tokval, NULL, pass, error, NULL);
3738 free_tlist(tline);
3739 if (!evalresult) {
3740 free_tlist(origline);
3741 return DIRECTIVE_FOUND;
3744 if (tokval.t_type)
3745 error(ERR_WARNING|ERR_PASS1,
3746 "trailing garbage after expression ignored");
3748 if (!is_simple(evalresult)) {
3749 error(ERR_NONFATAL,
3750 "non-constant value given to `%%%sassign'",
3751 (i == PP_IASSIGN ? "i" : ""));
3752 free_tlist(origline);
3753 return DIRECTIVE_FOUND;
3756 macro_start = nasm_zalloc(sizeof(*macro_start));
3757 make_tok_num(macro_start, reloc_value(evalresult));
3760 * We now have a macro name, an implicit parameter count of
3761 * zero, and a numeric token to use as an expansion. Create
3762 * and store an SMacro.
3764 define_smacro(ctx, mname, casesense, 0, macro_start);
3765 free_tlist(origline);
3766 return DIRECTIVE_FOUND;
3768 case PP_LINE:
3769 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3771 * Syntax is `%line nnn[+mmm] [filename]'
3773 tline = tline->next;
3774 skip_white_(tline);
3775 if (!tok_type_(tline, TOK_NUMBER)) {
3776 error(ERR_NONFATAL, "`%%line' expects line number");
3777 free_tlist(origline);
3778 return DIRECTIVE_FOUND;
3780 k = readnum(tline->text, &err);
3781 m = 1;
3782 tline = tline->next;
3783 if (tok_is_(tline, "+")) {
3784 tline = tline->next;
3785 if (!tok_type_(tline, TOK_NUMBER)) {
3786 error(ERR_NONFATAL, "`%%line' expects line increment");
3787 free_tlist(origline);
3788 return DIRECTIVE_FOUND;
3790 m = readnum(tline->text, &err);
3791 tline = tline->next;
3793 skip_white_(tline);
3794 src_set_linnum(k);
3795 istk->lineinc = m;
3796 if (tline) {
3797 nasm_free(src_set_fname(detoken(tline, false)));
3799 free_tlist(origline);
3800 return DIRECTIVE_FOUND;
3802 case PP_WHILE:
3803 if (defining != NULL) {
3804 if (defining->type == EXP_WHILE) {
3805 defining->def_depth ++;
3807 return NO_DIRECTIVE_FOUND;
3809 l = NULL;
3810 if ((istk->expansion != NULL) &&
3811 (istk->expansion->emitting == false)) {
3812 j = COND_NEVER;
3813 } else {
3814 l = new_Line();
3815 l->first = copy_Token(tline->next);
3816 j = if_condition(tline->next, i);
3817 tline->next = NULL; /* it got freed */
3818 j = (((j < 0) ? COND_NEVER : j) ? COND_IF_TRUE : COND_IF_FALSE);
3820 ed = new_ExpDef(EXP_WHILE);
3821 ed->state = j;
3822 ed->cur_depth = 1;
3823 ed->max_depth = DEADMAN_LIMIT;
3824 ed->ignoring = ((ed->state == COND_IF_TRUE) ? false : true);
3825 if (ed->ignoring == false) {
3826 ed->line = l;
3827 ed->last = l;
3828 } else if (l != NULL) {
3829 delete_Token(l->first);
3830 nasm_free(l);
3831 l = NULL;
3833 ed->prev = defining;
3834 defining = ed;
3835 free_tlist(origline);
3836 return DIRECTIVE_FOUND;
3838 case PP_ENDWHILE:
3839 if (defining != NULL) {
3840 if (defining->type == EXP_WHILE) {
3841 if (defining->def_depth > 0) {
3842 defining->def_depth --;
3843 return NO_DIRECTIVE_FOUND;
3845 } else {
3846 return NO_DIRECTIVE_FOUND;
3849 if (tline->next != NULL) {
3850 error_precond(ERR_WARNING|ERR_PASS1,
3851 "trailing garbage after `%%endwhile' ignored");
3853 if ((defining == NULL) || (defining->type != EXP_WHILE)) {
3854 error(ERR_NONFATAL, "`%%endwhile': no matching `%%while'");
3855 return DIRECTIVE_FOUND;
3857 ed = defining;
3858 defining = ed->prev;
3859 if (ed->ignoring == false) {
3860 ed->prev = expansions;
3861 expansions = ed;
3862 ei = new_ExpInv(EXP_WHILE, ed);
3863 ei->current = ed->line->next;
3864 ei->emitting = true;
3865 ei->prev = istk->expansion;
3866 istk->expansion = ei;
3867 } else {
3868 nasm_free(ed);
3870 free_tlist(origline);
3871 return DIRECTIVE_FOUND;
3873 case PP_EXITWHILE:
3874 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3876 * We must search along istk->expansion until we hit a
3877 * while invocation. Then we disable the emitting state(s)
3878 * between exitwhile and endwhile.
3880 for (ei = istk->expansion; ei != NULL; ei = ei->prev) {
3881 if (ei->type == EXP_WHILE) {
3882 break;
3886 if (ei != NULL) {
3888 * Set all invocations leading back to the while
3889 * invocation to a non-emitting state.
3891 for (eei = istk->expansion; eei != ei; eei = eei->prev) {
3892 eei->emitting = false;
3894 eei->emitting = false;
3895 eei->current = NULL;
3896 eei->def->cur_depth = eei->def->max_depth;
3897 } else {
3898 error(ERR_NONFATAL, "`%%exitwhile' not within `%%while' block");
3900 free_tlist(origline);
3901 return DIRECTIVE_FOUND;
3903 case PP_COMMENT:
3904 if (defining != NULL) {
3905 if (defining->type == EXP_COMMENT) {
3906 defining->def_depth ++;
3908 return NO_DIRECTIVE_FOUND;
3910 ed = new_ExpDef(EXP_COMMENT);
3911 ed->ignoring = true;
3912 ed->prev = defining;
3913 defining = ed;
3914 free_tlist(origline);
3915 return DIRECTIVE_FOUND;
3917 case PP_ENDCOMMENT:
3918 if (defining != NULL) {
3919 if (defining->type == EXP_COMMENT) {
3920 if (defining->def_depth > 0) {
3921 defining->def_depth --;
3922 return NO_DIRECTIVE_FOUND;
3924 } else {
3925 return NO_DIRECTIVE_FOUND;
3928 if ((defining == NULL) || (defining->type != EXP_COMMENT)) {
3929 error(ERR_NONFATAL, "`%%endcomment': no matching `%%comment'");
3930 return DIRECTIVE_FOUND;
3932 ed = defining;
3933 defining = ed->prev;
3934 nasm_free(ed);
3935 free_tlist(origline);
3936 return DIRECTIVE_FOUND;
3938 case PP_FINAL:
3939 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3940 if (in_final != false) {
3941 error(ERR_FATAL, "`%%final' cannot be used recursively");
3943 tline = tline->next;
3944 skip_white_(tline);
3945 if (tline == NULL) {
3946 error(ERR_NONFATAL, "`%%final' expects at least one parameter");
3947 } else {
3948 l = new_Line();
3949 l->first = copy_Token(tline);
3950 l->next = finals;
3951 finals = l;
3953 free_tlist(origline);
3954 return DIRECTIVE_FOUND;
3956 default:
3957 error(ERR_FATAL,
3958 "preprocessor directive `%s' not yet implemented",
3959 pp_directives[i]);
3960 return DIRECTIVE_FOUND;
3965 * Ensure that a macro parameter contains a condition code and
3966 * nothing else. Return the condition code index if so, or -1
3967 * otherwise.
3969 static int find_cc(Token * t)
3971 Token *tt;
3972 int i, j, k, m;
3974 if (!t)
3975 return -1; /* Probably a %+ without a space */
3977 skip_white_(t);
3978 if (t->type != TOK_ID)
3979 return -1;
3980 tt = t->next;
3981 skip_white_(tt);
3982 if (tt && (tt->type != TOK_OTHER || strcmp(tt->text, ",")))
3983 return -1;
3985 i = -1;
3986 j = ARRAY_SIZE(conditions);
3987 while (j - i > 1) {
3988 k = (j + i) / 2;
3989 m = nasm_stricmp(t->text, conditions[k]);
3990 if (m == 0) {
3991 i = k;
3992 j = -2;
3993 break;
3994 } else if (m < 0) {
3995 j = k;
3996 } else
3997 i = k;
3999 if (j != -2)
4000 return -1;
4001 return i;
4004 static bool paste_tokens(Token **head, const struct tokseq_match *m,
4005 int mnum, bool handle_paste_tokens)
4007 Token **tail, *t, *tt;
4008 Token **paste_head;
4009 bool did_paste = false;
4010 char *tmp;
4011 int i;
4013 /* Now handle token pasting... */
4014 paste_head = NULL;
4015 tail = head;
4016 while ((t = *tail) && (tt = t->next)) {
4017 switch (t->type) {
4018 case TOK_WHITESPACE:
4019 if (tt->type == TOK_WHITESPACE) {
4020 /* Zap adjacent whitespace tokens */
4021 t->next = delete_Token(tt);
4022 } else {
4023 /* Do not advance paste_head here */
4024 tail = &t->next;
4026 break;
4027 case TOK_PASTE: /* %+ */
4028 if (handle_paste_tokens) {
4029 /* Zap %+ and whitespace tokens to the right */
4030 while (t && (t->type == TOK_WHITESPACE ||
4031 t->type == TOK_PASTE))
4032 t = *tail = delete_Token(t);
4033 if (!paste_head || !t)
4034 break; /* Nothing to paste with */
4035 tail = paste_head;
4036 t = *tail;
4037 tt = t->next;
4038 while (tok_type_(tt, TOK_WHITESPACE))
4039 tt = t->next = delete_Token(tt);
4040 if (tt) {
4041 tmp = nasm_strcat(t->text, tt->text);
4042 delete_Token(t);
4043 tt = delete_Token(tt);
4044 t = *tail = tokenize(tmp);
4045 nasm_free(tmp);
4046 while (t->next) {
4047 tail = &t->next;
4048 t = t->next;
4050 t->next = tt; /* Attach the remaining token chain */
4051 did_paste = true;
4053 paste_head = tail;
4054 tail = &t->next;
4055 break;
4057 /* else fall through */
4058 default:
4060 * Concatenation of tokens might look nontrivial
4061 * but in real it's pretty simple -- the caller
4062 * prepares the masks of token types to be concatenated
4063 * and we simply find matched sequences and slip
4064 * them together
4066 for (i = 0; i < mnum; i++) {
4067 if (PP_CONCAT_MASK(t->type) & m[i].mask_head) {
4068 size_t len = 0;
4069 char *tmp, *p;
4071 while (tt && (PP_CONCAT_MASK(tt->type) & m[i].mask_tail)) {
4072 len += strlen(tt->text);
4073 tt = tt->next;
4076 nasm_dump_token(tt);
4079 * Now tt points to the first token after
4080 * the potential paste area...
4082 if (tt != t->next) {
4083 /* We have at least two tokens... */
4084 len += strlen(t->text);
4085 p = tmp = nasm_malloc(len+1);
4086 while (t != tt) {
4087 strcpy(p, t->text);
4088 p = strchr(p, '\0');
4089 t = delete_Token(t);
4091 t = *tail = tokenize(tmp);
4092 nasm_free(tmp);
4093 while (t->next) {
4094 tail = &t->next;
4095 t = t->next;
4097 t->next = tt; /* Attach the remaining token chain */
4098 did_paste = true;
4100 paste_head = tail;
4101 tail = &t->next;
4102 break;
4105 if (i >= mnum) { /* no match */
4106 tail = &t->next;
4107 if (!tok_type_(t->next, TOK_WHITESPACE))
4108 paste_head = tail;
4110 break;
4113 return did_paste;
4117 * expands to a list of tokens from %{x:y}
4119 static Token *expand_mmac_params_range(ExpInv *ei, Token *tline, Token ***last)
4121 Token *t = tline, **tt, *tm, *head;
4122 char *pos;
4123 int fst, lst, j, i;
4125 pos = strchr(tline->text, ':');
4126 nasm_assert(pos);
4128 lst = atoi(pos + 1);
4129 fst = atoi(tline->text + 1);
4132 * only macros params are accounted so
4133 * if someone passes %0 -- we reject such
4134 * value(s)
4136 if (lst == 0 || fst == 0)
4137 goto err;
4139 /* the values should be sane */
4140 if ((fst > (int)ei->nparam || fst < (-(int)ei->nparam)) ||
4141 (lst > (int)ei->nparam || lst < (-(int)ei->nparam)))
4142 goto err;
4144 fst = fst < 0 ? fst + (int)ei->nparam + 1: fst;
4145 lst = lst < 0 ? lst + (int)ei->nparam + 1: lst;
4147 /* counted from zero */
4148 fst--, lst--;
4151 * it will be at least one token
4153 tm = ei->params[(fst + ei->rotate) % ei->nparam];
4154 t = new_Token(NULL, tm->type, tm->text, 0);
4155 head = t, tt = &t->next;
4156 if (fst < lst) {
4157 for (i = fst + 1; i <= lst; i++) {
4158 t = new_Token(NULL, TOK_OTHER, ",", 0);
4159 *tt = t, tt = &t->next;
4160 j = (i + ei->rotate) % ei->nparam;
4161 tm = ei->params[j];
4162 t = new_Token(NULL, tm->type, tm->text, 0);
4163 *tt = t, tt = &t->next;
4165 } else {
4166 for (i = fst - 1; i >= lst; i--) {
4167 t = new_Token(NULL, TOK_OTHER, ",", 0);
4168 *tt = t, tt = &t->next;
4169 j = (i + ei->rotate) % ei->nparam;
4170 tm = ei->params[j];
4171 t = new_Token(NULL, tm->type, tm->text, 0);
4172 *tt = t, tt = &t->next;
4176 *last = tt;
4177 return head;
4179 err:
4180 error(ERR_NONFATAL, "`%%{%s}': macro parameters out of range",
4181 &tline->text[1]);
4182 return tline;
4186 * Expand MMacro-local things: parameter references (%0, %n, %+n,
4187 * %-n) and MMacro-local identifiers (%%foo) as well as
4188 * macro indirection (%[...]) and range (%{..:..}).
4190 static Token *expand_mmac_params(Token * tline)
4192 Token *t, *tt, **tail, *thead;
4193 bool changed = false;
4194 char *pos;
4196 tail = &thead;
4197 thead = NULL;
4199 nasm_dump_stream(tline);
4201 while (tline) {
4202 if (tline->type == TOK_PREPROC_ID &&
4203 (((tline->text[1] == '+' || tline->text[1] == '-') && tline->text[2]) ||
4204 (tline->text[1] >= '0' && tline->text[1] <= '9') ||
4205 tline->text[1] == '%')) {
4206 char *text = NULL;
4207 int type = 0, cc; /* type = 0 to placate optimisers */
4208 char tmpbuf[30];
4209 unsigned int n;
4210 int i;
4211 ExpInv *ei;
4213 t = tline;
4214 tline = tline->next;
4216 for (ei = istk->expansion; ei != NULL; ei = ei->prev) {
4217 if (ei->type == EXP_MMACRO) {
4218 break;
4221 if (ei == NULL) {
4222 error(ERR_NONFATAL, "`%s': not in a macro call", t->text);
4223 } else {
4224 pos = strchr(t->text, ':');
4225 if (!pos) {
4226 switch (t->text[1]) {
4228 * We have to make a substitution of one of the
4229 * forms %1, %-1, %+1, %%foo, %0.
4231 case '0':
4232 if ((strlen(t->text) > 2) && (t->text[2] == '0')) {
4233 type = TOK_ID;
4234 text = nasm_strdup(ei->label_text);
4235 } else {
4236 type = TOK_NUMBER;
4237 snprintf(tmpbuf, sizeof(tmpbuf), "%d", ei->nparam);
4238 text = nasm_strdup(tmpbuf);
4240 break;
4241 case '%':
4242 type = TOK_ID;
4243 snprintf(tmpbuf, sizeof(tmpbuf), "..@%"PRIu64".",
4244 ei->unique);
4245 text = nasm_strcat(tmpbuf, t->text + 2);
4246 break;
4247 case '-':
4248 n = atoi(t->text + 2) - 1;
4249 if (n >= ei->nparam)
4250 tt = NULL;
4251 else {
4252 if (ei->nparam > 1)
4253 n = (n + ei->rotate) % ei->nparam;
4254 tt = ei->params[n];
4256 cc = find_cc(tt);
4257 if (cc == -1) {
4258 error(ERR_NONFATAL,
4259 "macro parameter %d is not a condition code",
4260 n + 1);
4261 text = NULL;
4262 } else {
4263 type = TOK_ID;
4264 if (inverse_ccs[cc] == -1) {
4265 error(ERR_NONFATAL,
4266 "condition code `%s' is not invertible",
4267 conditions[cc]);
4268 text = NULL;
4269 } else
4270 text = nasm_strdup(conditions[inverse_ccs[cc]]);
4272 break;
4273 case '+':
4274 n = atoi(t->text + 2) - 1;
4275 if (n >= ei->nparam)
4276 tt = NULL;
4277 else {
4278 if (ei->nparam > 1)
4279 n = (n + ei->rotate) % ei->nparam;
4280 tt = ei->params[n];
4282 cc = find_cc(tt);
4283 if (cc == -1) {
4284 error(ERR_NONFATAL,
4285 "macro parameter %d is not a condition code",
4286 n + 1);
4287 text = NULL;
4288 } else {
4289 type = TOK_ID;
4290 text = nasm_strdup(conditions[cc]);
4292 break;
4293 default:
4294 n = atoi(t->text + 1) - 1;
4295 if (n >= ei->nparam)
4296 tt = NULL;
4297 else {
4298 if (ei->nparam > 1)
4299 n = (n + ei->rotate) % ei->nparam;
4300 tt = ei->params[n];
4302 if (tt) {
4303 for (i = 0; i < ei->paramlen[n]; i++) {
4304 *tail = new_Token(NULL, tt->type, tt->text, 0);
4305 tail = &(*tail)->next;
4306 tt = tt->next;
4309 text = NULL; /* we've done it here */
4310 break;
4312 } else {
4314 * seems we have a parameters range here
4316 Token *head, **last;
4317 head = expand_mmac_params_range(ei, t, &last);
4318 if (head != t) {
4319 *tail = head;
4320 *last = tline;
4321 tline = head;
4322 text = NULL;
4326 if (!text) {
4327 delete_Token(t);
4328 } else {
4329 *tail = t;
4330 tail = &t->next;
4331 t->type = type;
4332 nasm_free(t->text);
4333 t->text = text;
4334 t->a.mac = NULL;
4336 changed = true;
4337 continue;
4338 } else if (tline->type == TOK_INDIRECT) {
4339 t = tline;
4340 tline = tline->next;
4341 tt = tokenize(t->text);
4342 tt = expand_mmac_params(tt);
4343 tt = expand_smacro(tt);
4344 *tail = tt;
4345 while (tt) {
4346 tt->a.mac = NULL; /* Necessary? */
4347 tail = &tt->next;
4348 tt = tt->next;
4350 delete_Token(t);
4351 changed = true;
4352 } else {
4353 t = *tail = tline;
4354 tline = tline->next;
4355 t->a.mac = NULL;
4356 tail = &t->next;
4359 *tail = NULL;
4361 if (changed) {
4362 const struct tokseq_match t[] = {
4364 PP_CONCAT_MASK(TOK_ID) |
4365 PP_CONCAT_MASK(TOK_FLOAT), /* head */
4366 PP_CONCAT_MASK(TOK_ID) |
4367 PP_CONCAT_MASK(TOK_NUMBER) |
4368 PP_CONCAT_MASK(TOK_FLOAT) |
4369 PP_CONCAT_MASK(TOK_OTHER) /* tail */
4372 PP_CONCAT_MASK(TOK_NUMBER), /* head */
4373 PP_CONCAT_MASK(TOK_NUMBER) /* tail */
4376 paste_tokens(&thead, t, ARRAY_SIZE(t), false);
4379 nasm_dump_token(thead);
4381 return thead;
4385 * Expand all single-line macro calls made in the given line.
4386 * Return the expanded version of the line. The original is deemed
4387 * to be destroyed in the process. (In reality we'll just move
4388 * Tokens from input to output a lot of the time, rather than
4389 * actually bothering to destroy and replicate.)
4392 static Token *expand_smacro(Token * tline)
4394 Token *t, *tt, *mstart, **tail, *thead;
4395 SMacro *head = NULL, *m;
4396 Token **params;
4397 int *paramsize;
4398 unsigned int nparam, sparam;
4399 int brackets;
4400 Token *org_tline = tline;
4401 Context *ctx;
4402 const char *mname;
4403 int deadman = DEADMAN_LIMIT;
4404 bool expanded;
4407 * Trick: we should avoid changing the start token pointer since it can
4408 * be contained in "next" field of other token. Because of this
4409 * we allocate a copy of first token and work with it; at the end of
4410 * routine we copy it back
4412 if (org_tline) {
4413 tline = new_Token(org_tline->next, org_tline->type,
4414 org_tline->text, 0);
4415 tline->a.mac = org_tline->a.mac;
4416 nasm_free(org_tline->text);
4417 org_tline->text = NULL;
4420 expanded = true; /* Always expand %+ at least once */
4422 again:
4423 thead = NULL;
4424 tail = &thead;
4426 while (tline) { /* main token loop */
4427 if (!--deadman) {
4428 error(ERR_NONFATAL, "interminable macro recursion");
4429 goto err;
4432 if ((mname = tline->text)) {
4433 /* if this token is a local macro, look in local context */
4434 if (tline->type == TOK_ID) {
4435 head = (SMacro *)hash_findix(&smacros, mname);
4436 } else if (tline->type == TOK_PREPROC_ID) {
4437 ctx = get_ctx(mname, &mname);
4438 head = ctx ? (SMacro *)hash_findix(&ctx->localmac, mname) : NULL;
4439 } else
4440 head = NULL;
4443 * We've hit an identifier. As in is_mmacro below, we first
4444 * check whether the identifier is a single-line macro at
4445 * all, then think about checking for parameters if
4446 * necessary.
4448 list_for_each(m, head)
4449 if (!mstrcmp(m->name, mname, m->casesense))
4450 break;
4451 if (m) {
4452 mstart = tline;
4453 params = NULL;
4454 paramsize = NULL;
4455 if (m->nparam == 0) {
4457 * Simple case: the macro is parameterless. Discard the
4458 * one token that the macro call took, and push the
4459 * expansion back on the to-do stack.
4461 if (!m->expansion) {
4462 if (!strcmp("__FILE__", m->name)) {
4463 int32_t num = 0;
4464 char *file = NULL;
4465 src_get(&num, &file);
4466 tline->text = nasm_quote(file, strlen(file));
4467 tline->type = TOK_STRING;
4468 nasm_free(file);
4469 continue;
4471 if (!strcmp("__LINE__", m->name)) {
4472 nasm_free(tline->text);
4473 make_tok_num(tline, src_get_linnum());
4474 continue;
4476 if (!strcmp("__BITS__", m->name)) {
4477 nasm_free(tline->text);
4478 make_tok_num(tline, globalbits);
4479 continue;
4481 tline = delete_Token(tline);
4482 continue;
4484 } else {
4486 * Complicated case: at least one macro with this name
4487 * exists and takes parameters. We must find the
4488 * parameters in the call, count them, find the SMacro
4489 * that corresponds to that form of the macro call, and
4490 * substitute for the parameters when we expand. What a
4491 * pain.
4493 /*tline = tline->next;
4494 skip_white_(tline); */
4495 do {
4496 t = tline->next;
4497 while (tok_type_(t, TOK_SMAC_END)) {
4498 t->a.mac->in_progress = false;
4499 t->text = NULL;
4500 t = tline->next = delete_Token(t);
4502 tline = t;
4503 } while (tok_type_(tline, TOK_WHITESPACE));
4504 if (!tok_is_(tline, "(")) {
4506 * This macro wasn't called with parameters: ignore
4507 * the call. (Behaviour borrowed from gnu cpp.)
4509 tline = mstart;
4510 m = NULL;
4511 } else {
4512 int paren = 0;
4513 int white = 0;
4514 brackets = 0;
4515 nparam = 0;
4516 sparam = PARAM_DELTA;
4517 params = nasm_malloc(sparam * sizeof(Token *));
4518 params[0] = tline->next;
4519 paramsize = nasm_malloc(sparam * sizeof(int));
4520 paramsize[0] = 0;
4521 while (true) { /* parameter loop */
4523 * For some unusual expansions
4524 * which concatenates function call
4526 t = tline->next;
4527 while (tok_type_(t, TOK_SMAC_END)) {
4528 t->a.mac->in_progress = false;
4529 t->text = NULL;
4530 t = tline->next = delete_Token(t);
4532 tline = t;
4534 if (!tline) {
4535 error(ERR_NONFATAL,
4536 "macro call expects terminating `)'");
4537 break;
4539 if (tline->type == TOK_WHITESPACE
4540 && brackets <= 0) {
4541 if (paramsize[nparam])
4542 white++;
4543 else
4544 params[nparam] = tline->next;
4545 continue; /* parameter loop */
4547 if (tline->type == TOK_OTHER
4548 && tline->text[1] == 0) {
4549 char ch = tline->text[0];
4550 if (ch == ',' && !paren && brackets <= 0) {
4551 if (++nparam >= sparam) {
4552 sparam += PARAM_DELTA;
4553 params = nasm_realloc(params,
4554 sparam * sizeof(Token *));
4555 paramsize = nasm_realloc(paramsize,
4556 sparam * sizeof(int));
4558 params[nparam] = tline->next;
4559 paramsize[nparam] = 0;
4560 white = 0;
4561 continue; /* parameter loop */
4563 if (ch == '{' &&
4564 (brackets > 0 || (brackets == 0 &&
4565 !paramsize[nparam])))
4567 if (!(brackets++)) {
4568 params[nparam] = tline->next;
4569 continue; /* parameter loop */
4572 if (ch == '}' && brackets > 0)
4573 if (--brackets == 0) {
4574 brackets = -1;
4575 continue; /* parameter loop */
4577 if (ch == '(' && !brackets)
4578 paren++;
4579 if (ch == ')' && brackets <= 0)
4580 if (--paren < 0)
4581 break;
4583 if (brackets < 0) {
4584 brackets = 0;
4585 error(ERR_NONFATAL, "braces do not "
4586 "enclose all of macro parameter");
4588 paramsize[nparam] += white + 1;
4589 white = 0;
4590 } /* parameter loop */
4591 nparam++;
4592 while (m && (m->nparam != nparam ||
4593 mstrcmp(m->name, mname,
4594 m->casesense)))
4595 m = m->next;
4596 if (!m)
4597 error(ERR_WARNING|ERR_PASS1|ERR_WARN_MNP,
4598 "macro `%s' exists, "
4599 "but not taking %d parameters",
4600 mstart->text, nparam);
4603 if (m && m->in_progress)
4604 m = NULL;
4605 if (!m) { /* in progess or didn't find '(' or wrong nparam */
4607 * Design question: should we handle !tline, which
4608 * indicates missing ')' here, or expand those
4609 * macros anyway, which requires the (t) test a few
4610 * lines down?
4612 nasm_free(params);
4613 nasm_free(paramsize);
4614 tline = mstart;
4615 } else {
4617 * Expand the macro: we are placed on the last token of the
4618 * call, so that we can easily split the call from the
4619 * following tokens. We also start by pushing an SMAC_END
4620 * token for the cycle removal.
4622 t = tline;
4623 if (t) {
4624 tline = t->next;
4625 t->next = NULL;
4627 tt = new_Token(tline, TOK_SMAC_END, NULL, 0);
4628 tt->a.mac = m;
4629 m->in_progress = true;
4630 tline = tt;
4631 list_for_each(t, m->expansion) {
4632 if (is_smacro_param(t)) {
4633 Token *pcopy = tline, **ptail = &pcopy;
4634 Token *ttt;
4635 int i, idx;
4637 idx = smacro_get_param_idx(t);
4638 ttt = params[idx];
4641 * We need smacro paramters appended.
4643 for (i = paramsize[idx]; i > 0; i--) {
4644 *ptail = new_Token(tline, ttt->type, ttt->text, 0);
4645 ptail = &(*ptail)->next;
4646 ttt = ttt->next;
4649 tline = pcopy;
4650 } else if (t->type == TOK_PREPROC_Q) {
4651 tt = new_Token(tline, TOK_ID, mname, 0);
4652 tline = tt;
4653 } else if (t->type == TOK_PREPROC_QQ) {
4654 tt = new_Token(tline, TOK_ID, m->name, 0);
4655 tline = tt;
4656 } else {
4657 tt = new_Token(tline, t->type, t->text, 0);
4658 tline = tt;
4663 * Having done that, get rid of the macro call, and clean
4664 * up the parameters.
4666 nasm_free(params);
4667 nasm_free(paramsize);
4668 free_tlist(mstart);
4669 expanded = true;
4670 continue; /* main token loop */
4675 if (tline->type == TOK_SMAC_END) {
4676 tline->a.mac->in_progress = false;
4677 tline = delete_Token(tline);
4678 } else {
4679 t = *tail = tline;
4680 tline = tline->next;
4681 t->a.mac = NULL;
4682 t->next = NULL;
4683 tail = &t->next;
4688 * Now scan the entire line and look for successive TOK_IDs that resulted
4689 * after expansion (they can't be produced by tokenize()). The successive
4690 * TOK_IDs should be concatenated.
4691 * Also we look for %+ tokens and concatenate the tokens before and after
4692 * them (without white spaces in between).
4694 if (expanded) {
4695 const struct tokseq_match t[] = {
4697 PP_CONCAT_MASK(TOK_ID) |
4698 PP_CONCAT_MASK(TOK_PREPROC_ID), /* head */
4699 PP_CONCAT_MASK(TOK_ID) |
4700 PP_CONCAT_MASK(TOK_PREPROC_ID) |
4701 PP_CONCAT_MASK(TOK_NUMBER) /* tail */
4704 if (paste_tokens(&thead, t, ARRAY_SIZE(t), true)) {
4706 * If we concatenated something, *and* we had previously expanded
4707 * an actual macro, scan the lines again for macros...
4709 tline = thead;
4710 expanded = false;
4711 goto again;
4715 err:
4716 if (org_tline) {
4717 if (thead) {
4718 *org_tline = *thead;
4719 /* since we just gave text to org_line, don't free it */
4720 thead->text = NULL;
4721 delete_Token(thead);
4722 } else {
4723 /* the expression expanded to empty line;
4724 we can't return NULL for some reasons
4725 we just set the line to a single WHITESPACE token. */
4726 memset(org_tline, 0, sizeof(*org_tline));
4727 org_tline->text = NULL;
4728 org_tline->type = TOK_WHITESPACE;
4730 thead = org_tline;
4733 return thead;
4737 * Similar to expand_smacro but used exclusively with macro identifiers
4738 * right before they are fetched in. The reason is that there can be
4739 * identifiers consisting of several subparts. We consider that if there
4740 * are more than one element forming the name, user wants a expansion,
4741 * otherwise it will be left as-is. Example:
4743 * %define %$abc cde
4745 * the identifier %$abc will be left as-is so that the handler for %define
4746 * will suck it and define the corresponding value. Other case:
4748 * %define _%$abc cde
4750 * In this case user wants name to be expanded *before* %define starts
4751 * working, so we'll expand %$abc into something (if it has a value;
4752 * otherwise it will be left as-is) then concatenate all successive
4753 * PP_IDs into one.
4755 static Token *expand_id(Token * tline)
4757 Token *cur, *oldnext = NULL;
4759 if (!tline || !tline->next)
4760 return tline;
4762 cur = tline;
4763 while (cur->next &&
4764 (cur->next->type == TOK_ID ||
4765 cur->next->type == TOK_PREPROC_ID ||
4766 cur->next->type == TOK_NUMBER))
4767 cur = cur->next;
4769 /* If identifier consists of just one token, don't expand */
4770 if (cur == tline)
4771 return tline;
4773 if (cur) {
4774 oldnext = cur->next; /* Detach the tail past identifier */
4775 cur->next = NULL; /* so that expand_smacro stops here */
4778 tline = expand_smacro(tline);
4780 if (cur) {
4781 /* expand_smacro possibly changhed tline; re-scan for EOL */
4782 cur = tline;
4783 while (cur && cur->next)
4784 cur = cur->next;
4785 if (cur)
4786 cur->next = oldnext;
4789 return tline;
4793 * Determine whether the given line constitutes a multi-line macro
4794 * call, and return the ExpDef structure called if so. Doesn't have
4795 * to check for an initial label - that's taken care of in
4796 * expand_mmacro - but must check numbers of parameters. Guaranteed
4797 * to be called with tline->type == TOK_ID, so the putative macro
4798 * name is easy to find.
4800 static ExpDef *is_mmacro(Token * tline, Token *** params_array)
4802 ExpDef *head, *ed;
4803 Token **params;
4804 int nparam;
4806 head = (ExpDef *) hash_findix(&expdefs, tline->text);
4809 * Efficiency: first we see if any macro exists with the given
4810 * name. If not, we can return NULL immediately. _Then_ we
4811 * count the parameters, and then we look further along the
4812 * list if necessary to find the proper ExpDef.
4814 list_for_each(ed, head)
4815 if (!mstrcmp(ed->name, tline->text, ed->casesense))
4816 break;
4817 if (!ed)
4818 return NULL;
4821 * OK, we have a potential macro. Count and demarcate the
4822 * parameters.
4824 count_mmac_params(tline->next, &nparam, &params);
4827 * So we know how many parameters we've got. Find the ExpDef
4828 * structure that handles this number.
4830 while (ed) {
4831 if (ed->nparam_min <= nparam
4832 && (ed->plus || nparam <= ed->nparam_max)) {
4834 * It's right, and we can use it. Add its default
4835 * parameters to the end of our list if necessary.
4837 if (ed->defaults && nparam < ed->nparam_min + ed->ndefs) {
4838 params =
4839 nasm_realloc(params,
4840 ((ed->nparam_min + ed->ndefs +
4841 1) * sizeof(*params)));
4842 while (nparam < ed->nparam_min + ed->ndefs) {
4843 params[nparam] = ed->defaults[nparam - ed->nparam_min];
4844 nparam++;
4848 * If we've gone over the maximum parameter count (and
4849 * we're in Plus mode), ignore parameters beyond
4850 * nparam_max.
4852 if (ed->plus && nparam > ed->nparam_max)
4853 nparam = ed->nparam_max;
4855 * Then terminate the parameter list, and leave.
4857 if (!params) { /* need this special case */
4858 params = nasm_malloc(sizeof(*params));
4859 nparam = 0;
4861 params[nparam] = NULL;
4862 *params_array = params;
4863 return ed;
4866 * This one wasn't right: look for the next one with the
4867 * same name.
4869 list_for_each(ed, ed->next)
4870 if (!mstrcmp(ed->name, tline->text, ed->casesense))
4871 break;
4875 * After all that, we didn't find one with the right number of
4876 * parameters. Issue a warning, and fail to expand the macro.
4878 error(ERR_WARNING|ERR_PASS1|ERR_WARN_MNP,
4879 "macro `%s' exists, but not taking %d parameters",
4880 tline->text, nparam);
4881 nasm_free(params);
4882 return NULL;
4886 * Expand the multi-line macro call made by the given line, if
4887 * there is one to be expanded. If there is, push the expansion on
4888 * istk->expansion and return true. Otherwise return false.
4890 static bool expand_mmacro(Token * tline)
4892 Token *label = NULL;
4893 int dont_prepend = 0;
4894 Token **params, *t;
4895 Line *l = NULL;
4896 ExpDef *ed;
4897 ExpInv *ei;
4898 int i, nparam, *paramlen;
4899 const char *mname;
4901 t = tline;
4902 skip_white_(t);
4903 /* if (!tok_type_(t, TOK_ID)) Lino 02/25/02 */
4904 if (!tok_type_(t, TOK_ID) && !tok_type_(t, TOK_PREPROC_ID))
4905 return false;
4906 ed = is_mmacro(t, &params);
4907 if (ed != NULL) {
4908 mname = t->text;
4909 } else {
4910 Token *last;
4912 * We have an id which isn't a macro call. We'll assume
4913 * it might be a label; we'll also check to see if a
4914 * colon follows it. Then, if there's another id after
4915 * that lot, we'll check it again for macro-hood.
4917 label = last = t;
4918 t = t->next;
4919 if (tok_type_(t, TOK_WHITESPACE))
4920 last = t, t = t->next;
4921 if (tok_is_(t, ":")) {
4922 dont_prepend = 1;
4923 last = t, t = t->next;
4924 if (tok_type_(t, TOK_WHITESPACE))
4925 last = t, t = t->next;
4927 if (!tok_type_(t, TOK_ID) || !(ed = is_mmacro(t, &params)))
4928 return false;
4929 last->next = NULL;
4930 mname = t->text;
4931 tline = t;
4935 * Fix up the parameters: this involves stripping leading and
4936 * trailing whitespace, then stripping braces if they are
4937 * present.
4939 for (nparam = 0; params[nparam]; nparam++) ;
4940 paramlen = nparam ? nasm_malloc(nparam * sizeof(*paramlen)) : NULL;
4942 for (i = 0; params[i]; i++) {
4943 int brace = false;
4944 int comma = (!ed->plus || i < nparam - 1);
4946 t = params[i];
4947 skip_white_(t);
4948 if (tok_is_(t, "{"))
4949 t = t->next, brace = true, comma = false;
4950 params[i] = t;
4951 paramlen[i] = 0;
4952 while (t) {
4953 if (comma && t->type == TOK_OTHER && !strcmp(t->text, ","))
4954 break; /* ... because we have hit a comma */
4955 if (comma && t->type == TOK_WHITESPACE
4956 && tok_is_(t->next, ","))
4957 break; /* ... or a space then a comma */
4958 if (brace && t->type == TOK_OTHER && !strcmp(t->text, "}"))
4959 break; /* ... or a brace */
4960 t = t->next;
4961 paramlen[i]++;
4965 if (ed->cur_depth >= ed->max_depth) {
4966 if (ed->max_depth > 1) {
4967 error(ERR_WARNING,
4968 "reached maximum macro recursion depth of %i for %s",
4969 ed->max_depth,ed->name);
4971 return false;
4972 } else {
4973 ed->cur_depth ++;
4977 * OK, we have found a ExpDef structure representing a
4978 * previously defined mmacro. Create an expansion invocation
4979 * and point it back to the expansion definition. Substitution of
4980 * parameter tokens and macro-local tokens doesn't get done
4981 * until the single-line macro substitution process; this is
4982 * because delaying them allows us to change the semantics
4983 * later through %rotate.
4985 ei = new_ExpInv(EXP_MMACRO, ed);
4986 ei->name = nasm_strdup(mname);
4987 //ei->label = label;
4988 //ei->label_text = detoken(label, false);
4989 ei->current = ed->line;
4990 ei->emitting = true;
4991 //ei->iline = tline;
4992 ei->params = params;
4993 ei->nparam = nparam;
4994 ei->rotate = 0;
4995 ei->paramlen = paramlen;
4996 ei->lineno = 0;
4998 ei->prev = istk->expansion;
4999 istk->expansion = ei;
5002 * Special case: detect %00 on first invocation; if found,
5003 * avoid emitting any labels that precede the mmacro call.
5004 * ed->prepend is set to -1 when %00 is detected, else 1.
5006 if (ed->prepend == 0) {
5007 for (l = ed->line; l != NULL; l = l->next) {
5008 for (t = l->first; t != NULL; t = t->next) {
5009 if ((t->type == TOK_PREPROC_ID) &&
5010 (strlen(t->text) == 3) &&
5011 (t->text[1] == '0') && (t->text[2] == '0')) {
5012 dont_prepend = -1;
5013 break;
5016 if (dont_prepend < 0) {
5017 break;
5020 ed->prepend = ((dont_prepend < 0) ? -1 : 1);
5024 * If we had a label, push it on as the first line of
5025 * the macro expansion.
5027 if (label != NULL) {
5028 if (ed->prepend < 0) {
5029 ei->label_text = detoken(label, false);
5030 } else {
5031 if (dont_prepend == 0) {
5032 t = label;
5033 while (t->next != NULL) {
5034 t = t->next;
5036 t->next = new_Token(NULL, TOK_OTHER, ":", 0);
5038 l = new_Line();
5039 l->first = copy_Token(label);
5040 l->next = ei->current;
5041 ei->current = l;
5045 list->uplevel(ed->nolist ? LIST_MACRO_NOLIST : LIST_MACRO);
5047 istk->mmac_depth++;
5048 return true;
5051 /* The function that actually does the error reporting */
5052 static void verror(int severity, const char *fmt, va_list arg)
5054 char buff[1024];
5056 vsnprintf(buff, sizeof(buff), fmt, arg);
5058 if (istk && istk->mmac_depth > 0) {
5059 ExpInv *ei = istk->expansion;
5060 int lineno = ei->lineno;
5061 while (ei) {
5062 if (ei->type == EXP_MMACRO)
5063 break;
5064 lineno += ei->relno;
5065 ei = ei->prev;
5067 nasm_error(severity, "(%s:%d) %s", ei->def->name,
5068 lineno, buff);
5069 } else
5070 nasm_error(severity, "%s", buff);
5074 * Since preprocessor always operate only on the line that didn't
5075 * arrived yet, we should always use ERR_OFFBY1.
5077 static void error(int severity, const char *fmt, ...)
5079 va_list arg;
5080 va_start(arg, fmt);
5081 verror(severity, fmt, arg);
5082 va_end(arg);
5086 * Because %else etc are evaluated in the state context
5087 * of the previous branch, errors might get lost with error():
5088 * %if 0 ... %else trailing garbage ... %endif
5089 * So %else etc should report errors with this function.
5091 static void error_precond(int severity, const char *fmt, ...)
5093 va_list arg;
5095 /* Only ignore the error if it's really in a dead branch */
5096 if ((istk != NULL) &&
5097 (istk->expansion != NULL) &&
5098 (istk->expansion->type == EXP_IF) &&
5099 (istk->expansion->def->state == COND_NEVER))
5100 return;
5102 va_start(arg, fmt);
5103 verror(severity, fmt, arg);
5104 va_end(arg);
5107 static void
5108 pp_reset(char *file, int apass, ListGen * listgen, StrList **deplist)
5110 Token *t;
5112 cstk = NULL;
5113 istk = nasm_zalloc(sizeof(Include));
5114 istk->fp = fopen(file, "r");
5115 src_set_fname(nasm_strdup(file));
5116 src_set_linnum(0);
5117 istk->lineinc = 1;
5118 if (!istk->fp)
5119 error(ERR_FATAL|ERR_NOFILE, "unable to open input file `%s'",
5120 file);
5121 defining = NULL;
5122 finals = NULL;
5123 in_final = false;
5124 nested_mac_count = 0;
5125 nested_rep_count = 0;
5126 init_macros();
5127 unique = 0;
5128 if (tasm_compatible_mode) {
5129 stdmacpos = nasm_stdmac;
5130 } else {
5131 stdmacpos = nasm_stdmac_after_tasm;
5133 any_extrastdmac = extrastdmac && *extrastdmac;
5134 do_predef = true;
5135 list = listgen;
5138 * 0 for dependencies, 1 for preparatory passes, 2 for final pass.
5139 * The caller, however, will also pass in 3 for preprocess-only so
5140 * we can set __PASS__ accordingly.
5142 pass = apass > 2 ? 2 : apass;
5144 dephead = deptail = deplist;
5145 if (deplist) {
5146 StrList *sl = nasm_malloc(strlen(file)+1+sizeof sl->next);
5147 sl->next = NULL;
5148 strcpy(sl->str, file);
5149 *deptail = sl;
5150 deptail = &sl->next;
5154 * Define the __PASS__ macro. This is defined here unlike
5155 * all the other builtins, because it is special -- it varies between
5156 * passes.
5158 t = nasm_zalloc(sizeof(*t));
5159 make_tok_num(t, apass);
5160 define_smacro(NULL, "__PASS__", true, 0, t);
5163 static char *pp_getline(void)
5165 char *line;
5166 Token *tline;
5167 ExpDef *ed;
5168 ExpInv *ei;
5169 Line *l;
5170 int j;
5172 while (1) {
5174 * Fetch a tokenized line, either from the expansion
5175 * buffer or from the input file.
5177 tline = NULL;
5179 while (1) { /* until we get a line we can use */
5181 * Fetch a tokenized line from the expansion buffer
5183 if (istk->expansion != NULL) {
5184 ei = istk->expansion;
5185 if (ei->current != NULL) {
5186 if (ei->emitting == false) {
5187 ei->current = NULL;
5188 continue;
5190 l = ei->current;
5191 ei->current = l->next;
5192 ei->lineno++;
5193 tline = copy_Token(l->first);
5194 if (((ei->type == EXP_REP) ||
5195 (ei->type == EXP_MMACRO) ||
5196 (ei->type == EXP_WHILE))
5197 && (ei->def->nolist == false)) {
5198 char *p = detoken(tline, false);
5199 list->line(LIST_MACRO, p);
5200 nasm_free(p);
5202 if (ei->linnum > -1) {
5203 src_set_linnum(src_get_linnum() + 1);
5205 break;
5206 } else if ((ei->type == EXP_REP) &&
5207 (ei->def->cur_depth < ei->def->max_depth)) {
5208 ei->def->cur_depth ++;
5209 ei->current = ei->def->line;
5210 ei->lineno = 0;
5211 continue;
5212 } else if ((ei->type == EXP_WHILE) &&
5213 (ei->def->cur_depth < ei->def->max_depth)) {
5214 ei->current = ei->def->line;
5215 ei->lineno = 0;
5216 tline = copy_Token(ei->current->first);
5217 j = if_condition(tline, PP_WHILE);
5218 tline = NULL;
5219 j = (((j < 0) ? COND_NEVER : j) ? COND_IF_TRUE : COND_IF_FALSE);
5220 if (j == COND_IF_TRUE) {
5221 ei->current = ei->current->next;
5222 ei->def->cur_depth ++;
5223 } else {
5224 ei->emitting = false;
5225 ei->current = NULL;
5226 ei->def->cur_depth = ei->def->max_depth;
5228 continue;
5229 } else {
5230 istk->expansion = ei->prev;
5231 ed = ei->def;
5232 if (ed != NULL) {
5233 if ((ei->emitting == true) &&
5234 (ed->max_depth == DEADMAN_LIMIT) &&
5235 (ed->cur_depth == DEADMAN_LIMIT)
5237 error(ERR_FATAL, "runaway expansion detected, aborting");
5239 if (ed->cur_depth > 0) {
5240 ed->cur_depth --;
5241 } else if (ed->type != EXP_MMACRO) {
5242 expansions = ed->prev;
5243 free_expdef(ed);
5245 if ((ei->type == EXP_REP) ||
5246 (ei->type == EXP_MMACRO) ||
5247 (ei->type == EXP_WHILE)) {
5248 list->downlevel(LIST_MACRO);
5249 if (ei->type == EXP_MMACRO) {
5250 istk->mmac_depth--;
5254 if (ei->linnum > -1) {
5255 src_set_linnum(ei->linnum);
5257 free_expinv(ei);
5258 continue;
5263 * Read in line from input and tokenize
5265 line = read_line();
5266 if (line) { /* from the current input file */
5267 line = prepreproc(line);
5268 tline = tokenize(line);
5269 nasm_free(line);
5270 break;
5274 * The current file has ended; work down the istk
5277 Include *i = istk;
5278 fclose(i->fp);
5279 if (i->expansion != NULL) {
5280 error(ERR_FATAL,
5281 "end of file while still in an expansion");
5283 /* only set line and file name if there's a next node */
5284 if (i->next) {
5285 src_set_linnum(i->lineno);
5286 nasm_free(src_set_fname(nasm_strdup(i->fname)));
5288 if ((i->next == NULL) && (finals != NULL)) {
5289 in_final = true;
5290 ei = new_ExpInv(EXP_FINAL, NULL);
5291 ei->emitting = true;
5292 ei->current = finals;
5293 istk->expansion = ei;
5294 finals = NULL;
5295 continue;
5297 istk = i->next;
5298 list->downlevel(LIST_INCLUDE);
5299 nasm_free(i);
5300 if (istk == NULL) {
5301 if (finals != NULL) {
5302 in_final = true;
5303 } else {
5304 return NULL;
5307 continue;
5311 if (defining == NULL) {
5312 tline = expand_mmac_params(tline);
5316 * Check the line to see if it's a preprocessor directive.
5318 if (do_directive(tline) == DIRECTIVE_FOUND) {
5319 continue;
5320 } else if (defining != NULL) {
5322 * We're defining an expansion. We emit nothing at all,
5323 * and just shove the tokenized line on to the definition.
5325 if (defining->ignoring == false) {
5326 Line *l = new_Line();
5327 l->first = tline;
5328 if (defining->line == NULL) {
5329 defining->line = l;
5330 defining->last = l;
5331 } else {
5332 defining->last->next = l;
5333 defining->last = l;
5335 } else {
5336 free_tlist(tline);
5338 defining->linecount++;
5339 continue;
5340 } else if ((istk->expansion != NULL) &&
5341 (istk->expansion->emitting != true)) {
5343 * We're in a non-emitting branch of an expansion.
5344 * Emit nothing at all, not even a blank line: when we
5345 * emerge from the expansion we'll give a line-number
5346 * directive so we keep our place correctly.
5348 free_tlist(tline);
5349 continue;
5350 } else {
5351 tline = expand_smacro(tline);
5352 if (expand_mmacro(tline) != true) {
5354 * De-tokenize the line again, and emit it.
5356 line = detoken(tline, true);
5357 free_tlist(tline);
5358 break;
5359 } else {
5360 continue;
5364 return line;
5367 static void pp_cleanup(int pass)
5369 if (defining != NULL) {
5370 error(ERR_NONFATAL, "end of file while still defining an expansion");
5371 while (defining != NULL) {
5372 ExpDef *ed = defining;
5373 defining = ed->prev;
5374 free_expdef(ed);
5376 defining = NULL;
5378 while (cstk != NULL)
5379 ctx_pop();
5380 free_macros();
5381 while (istk != NULL) {
5382 Include *i = istk;
5383 istk = istk->next;
5384 fclose(i->fp);
5385 nasm_free(i->fname);
5386 while (i->expansion != NULL) {
5387 ExpInv *ei = i->expansion;
5388 i->expansion = ei->prev;
5389 free_expinv(ei);
5391 nasm_free(i);
5393 while (cstk)
5394 ctx_pop();
5395 nasm_free(src_set_fname(NULL));
5396 if (pass == 0) {
5397 IncPath *i;
5398 free_llist(predef);
5399 delete_Blocks();
5400 while ((i = ipath)) {
5401 ipath = i->next;
5402 nasm_free(i->path);
5403 nasm_free(i);
5408 void pp_include_path(char *path)
5410 IncPath *i = nasm_zalloc(sizeof(IncPath));
5412 if (path)
5413 i->path = nasm_strdup(path);
5415 if (ipath) {
5416 IncPath *j = ipath;
5417 while (j->next)
5418 j = j->next;
5419 j->next = i;
5420 } else {
5421 ipath = i;
5425 void pp_pre_include(char *fname)
5427 Token *inc, *space, *name;
5428 Line *l;
5430 name = new_Token(NULL, TOK_INTERNAL_STRING, fname, 0);
5431 space = new_Token(name, TOK_WHITESPACE, NULL, 0);
5432 inc = new_Token(space, TOK_PREPROC_ID, "%include", 0);
5434 l = new_Line();
5435 l->next = predef;
5436 l->first = inc;
5437 predef = l;
5440 void pp_pre_define(char *definition)
5442 Token *def, *space;
5443 Line *l;
5444 char *equals;
5446 equals = strchr(definition, '=');
5447 space = new_Token(NULL, TOK_WHITESPACE, NULL, 0);
5448 def = new_Token(space, TOK_PREPROC_ID, "%define", 0);
5449 if (equals)
5450 *equals = ' ';
5451 space->next = tokenize(definition);
5452 if (equals)
5453 *equals = '=';
5455 l = new_Line();
5456 l->next = predef;
5457 l->first = def;
5458 predef = l;
5461 void pp_pre_undefine(char *definition)
5463 Token *def, *space;
5464 Line *l;
5466 space = new_Token(NULL, TOK_WHITESPACE, NULL, 0);
5467 def = new_Token(space, TOK_PREPROC_ID, "%undef", 0);
5468 space->next = tokenize(definition);
5470 l = new_Line();
5471 l->next = predef;
5472 l->first = def;
5473 predef = l;
5477 * This function is used to assist with "runtime" preprocessor
5478 * directives, e.g. pp_runtime("%define __BITS__ 64");
5480 * ERRORS ARE IGNORED HERE, SO MAKE COMPLETELY SURE THAT YOU
5481 * PASS A VALID STRING TO THIS FUNCTION!!!!!
5484 void pp_runtime(char *definition)
5486 Token *def;
5488 def = tokenize(definition);
5489 if (do_directive(def) == NO_DIRECTIVE_FOUND)
5490 free_tlist(def);
5494 void pp_extra_stdmac(macros_t *macros)
5496 extrastdmac = macros;
5499 static void make_tok_num(Token * tok, int64_t val)
5501 char numbuf[20];
5502 snprintf(numbuf, sizeof(numbuf), "%"PRId64"", val);
5503 tok->text = nasm_strdup(numbuf);
5504 tok->type = TOK_NUMBER;
5507 struct preproc_ops nasmpp = {
5508 pp_reset,
5509 pp_getline,
5510 pp_cleanup