BR3104852: only warn once for repeated prefixes
[nasm/avx512.git] / preproc.c
blobd062072125d2ea1d614ee166f07439420795d165
1 /* ----------------------------------------------------------------------- *
3 * Copyright 1996-2010 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 bool casesense;
111 bool in_progress;
112 unsigned int nparam;
113 Token *expansion;
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, nparam_max;
216 bool casesense;
217 bool plus; /* is the last parameter greedy? */
218 bool nolist; /* is this expansion listing-inhibited? */
219 Token *dlist; /* all defaults as one list */
220 Token **defaults; /* parameter default pointers */
221 int ndefs; /* number of default parameters */
223 int prepend; /* label prepend state */
224 Line *label;
225 Line *line;
226 Line *last;
227 int linecount; /* number of lines within expansion */
229 int64_t def_depth; /* current number of definition pairs deep */
230 int64_t cur_depth; /* current number of expansions */
231 int64_t max_depth; /* maximum number of expansions allowed */
233 int state; /* condition state */
234 bool ignoring; /* ignoring definition lines */
238 * Store the invocation of an expansion.
240 * The `prev' field is for the `istk->expansion` linked-list.
242 * When an expansion is being expanded, `params', `iline', `nparam',
243 * `paramlen', `rotate' and `unique' are local to the invocation.
245 struct ExpInv {
246 ExpInv *prev; /* previous invocation */
247 enum pp_exp_type type; /* expansion type */
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 unsigned int nparam, rotate;
257 int *paramlen;
259 uint64_t unique;
260 bool emitting;
261 int lineno; /* current line number in expansion */
262 int linnum; /* line number at invocation */
263 int relno; /* relative line number at invocation */
267 * To handle an arbitrary level of file inclusion, we maintain a
268 * stack (ie linked list) of these things.
270 struct Include {
271 Include *next;
272 FILE *fp;
273 Cond *conds;
274 ExpInv *expansion;
275 char *fname;
276 int lineno, lineinc;
277 int mmac_depth;
281 * Include search path. This is simply a list of strings which get
282 * prepended, in turn, to the name of an include file, in an
283 * attempt to find the file if it's not in the current directory.
285 struct IncPath {
286 IncPath *next;
287 char *path;
291 * Conditional assembly: we maintain a separate stack of these for
292 * each level of file inclusion. (The only reason we keep the
293 * stacks separate is to ensure that a stray `%endif' in a file
294 * included from within the true branch of a `%if' won't terminate
295 * it and cause confusion: instead, rightly, it'll cause an error.)
297 enum {
299 * These states are for use just after %if or %elif: IF_TRUE
300 * means the condition has evaluated to truth so we are
301 * currently emitting, whereas IF_FALSE means we are not
302 * currently emitting but will start doing so if a %else comes
303 * up. In these states, all directives are admissible: %elif,
304 * %else and %endif. (And of course %if.)
306 COND_IF_TRUE, COND_IF_FALSE,
308 * These states come up after a %else: ELSE_TRUE means we're
309 * emitting, and ELSE_FALSE means we're not. In ELSE_* states,
310 * any %elif or %else will cause an error.
312 COND_ELSE_TRUE, COND_ELSE_FALSE,
314 * These states mean that we're not emitting now, and also that
315 * nothing until %endif will be emitted at all. COND_DONE is
316 * used when we've had our moment of emission
317 * and have now started seeing %elifs. COND_NEVER is used when
318 * the condition construct in question is contained within a
319 * non-emitting branch of a larger condition construct,
320 * or if there is an error.
322 COND_DONE, COND_NEVER
324 #define emitting(x) ( (x) == COND_IF_TRUE || (x) == COND_ELSE_TRUE )
327 * These defines are used as the possible return values for do_directive
329 #define NO_DIRECTIVE_FOUND 0
330 #define DIRECTIVE_FOUND 1
333 * This define sets the upper limit for smacro and expansions
335 #define DEADMAN_LIMIT (1 << 20)
337 /* max reps */
338 #define REP_LIMIT ((INT64_C(1) << 62))
341 * Condition codes. Note that we use c_ prefix not C_ because C_ is
342 * used in nasm.h for the "real" condition codes. At _this_ level,
343 * we treat CXZ and ECXZ as condition codes, albeit non-invertible
344 * ones, so we need a different enum...
346 static const char * const conditions[] = {
347 "a", "ae", "b", "be", "c", "cxz", "e", "ecxz", "g", "ge", "l", "le",
348 "na", "nae", "nb", "nbe", "nc", "ne", "ng", "nge", "nl", "nle", "no",
349 "np", "ns", "nz", "o", "p", "pe", "po", "rcxz", "s", "z"
351 enum pp_conds {
352 c_A, c_AE, c_B, c_BE, c_C, c_CXZ, c_E, c_ECXZ, c_G, c_GE, c_L, c_LE,
353 c_NA, c_NAE, c_NB, c_NBE, c_NC, c_NE, c_NG, c_NGE, c_NL, c_NLE, c_NO,
354 c_NP, c_NS, c_NZ, c_O, c_P, c_PE, c_PO, c_RCXZ, c_S, c_Z,
355 c_none = -1
357 static const enum pp_conds inverse_ccs[] = {
358 c_NA, c_NAE, c_NB, c_NBE, c_NC, -1, c_NE, -1, c_NG, c_NGE, c_NL, c_NLE,
359 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,
360 c_Z, c_NO, c_NP, c_PO, c_PE, -1, c_NS, c_NZ
363 /* For TASM compatibility we need to be able to recognise TASM compatible
364 * conditional compilation directives. Using the NASM pre-processor does
365 * not work, so we look for them specifically from the following list and
366 * then jam in the equivalent NASM directive into the input stream.
369 enum {
370 TM_ARG, TM_ELIF, TM_ELSE, TM_ENDIF, TM_IF, TM_IFDEF, TM_IFDIFI,
371 TM_IFNDEF, TM_INCLUDE, TM_LOCAL
374 static const char * const tasm_directives[] = {
375 "arg", "elif", "else", "endif", "if", "ifdef", "ifdifi",
376 "ifndef", "include", "local"
379 static int StackSize = 4;
380 static char *StackPointer = "ebp";
381 static int ArgOffset = 8;
382 static int LocalOffset = 0;
384 static Context *cstk;
385 static Include *istk;
386 static IncPath *ipath = NULL;
388 static int pass; /* HACK: pass 0 = generate dependencies only */
389 static StrList **dephead, **deptail; /* Dependency list */
391 static uint64_t unique; /* unique identifier numbers */
393 static Line *predef = NULL;
394 static bool do_predef;
396 static ListGen *list;
399 * The current set of expansion definitions we have defined.
401 static struct hash_table expdefs;
404 * The current set of single-line macros we have defined.
406 static struct hash_table smacros;
409 * Linked List of all active expansion definitions
411 struct ExpDef *expansions = NULL;
414 * The expansion we are currently defining
416 static ExpDef *defining = NULL;
418 static uint64_t nested_mac_count;
419 static uint64_t nested_rep_count;
422 * Linked-list of lines to preprocess, prior to cleanup
424 static Line *finals = NULL;
425 static bool in_final = false;
428 * The number of macro parameters to allocate space for at a time.
430 #define PARAM_DELTA 16
433 * The standard macro set: defined in macros.c in the array nasm_stdmac.
434 * This gives our position in the macro set, when we're processing it.
436 static macros_t *stdmacpos;
439 * The extra standard macros that come from the object format, if
440 * any.
442 static macros_t *extrastdmac = NULL;
443 static bool any_extrastdmac;
446 * Tokens are allocated in blocks to improve speed
448 #define TOKEN_BLOCKSIZE 4096
449 static Token *freeTokens = NULL;
450 struct Blocks {
451 Blocks *next;
452 void *chunk;
455 static Blocks blocks = { NULL, NULL };
458 * Forward declarations.
460 static Token *expand_mmac_params(Token * tline);
461 static Token *expand_smacro(Token * tline);
462 static Token *expand_id(Token * tline);
463 static Context *get_ctx(const char *name, const char **namep,
464 bool all_contexts);
465 static void make_tok_num(Token * tok, int64_t val);
466 static void error(int severity, const char *fmt, ...);
467 static void error_precond(int severity, const char *fmt, ...);
468 static void *new_Block(size_t size);
469 static void delete_Blocks(void);
470 static Token *new_Token(Token * next, enum pp_token_type type,
471 const char *text, int txtlen);
472 static Token *copy_Token(Token * tline);
473 static Token *delete_Token(Token * t);
474 static Line *new_Line(void);
475 static ExpDef *new_ExpDef(int exp_type);
476 static ExpInv *new_ExpInv(int exp_type, ExpDef *ed);
479 * Macros for safe checking of token pointers, avoid *(NULL)
481 #define tok_type_(x,t) ((x) && (x)->type == (t))
482 #define skip_white_(x) if (tok_type_((x), TOK_WHITESPACE)) (x)=(x)->next
483 #define tok_is_(x,v) (tok_type_((x), TOK_OTHER) && !strcmp((x)->text,(v)))
484 #define tok_isnt_(x,v) ((x) && ((x)->type!=TOK_OTHER || strcmp((x)->text,(v))))
487 * nasm_unquote with error if the string contains NUL characters.
488 * If the string contains NUL characters, issue an error and return
489 * the C len, i.e. truncate at the NUL.
491 static size_t nasm_unquote_cstr(char *qstr, enum preproc_token directive)
493 size_t len = nasm_unquote(qstr, NULL);
494 size_t clen = strlen(qstr);
496 if (len != clen)
497 error(ERR_NONFATAL, "NUL character in `%s' directive",
498 pp_directives[directive]);
500 return clen;
504 * In-place reverse a list of tokens.
506 static Token *reverse_tokens(Token *t)
508 Token *prev = NULL;
509 Token *next;
511 while (t) {
512 next = t->next;
513 t->next = prev;
514 prev = t;
515 t = next;
518 return prev;
522 * Handle TASM specific directives, which do not contain a % in
523 * front of them. We do it here because I could not find any other
524 * place to do it for the moment, and it is a hack (ideally it would
525 * be nice to be able to use the NASM pre-processor to do it).
527 static char *check_tasm_directive(char *line)
529 int32_t i, j, k, m, len;
530 char *p, *q, *oldline, oldchar;
532 p = nasm_skip_spaces(line);
534 /* Binary search for the directive name */
535 i = -1;
536 j = ARRAY_SIZE(tasm_directives);
537 q = nasm_skip_word(p);
538 len = q - p;
539 if (len) {
540 oldchar = p[len];
541 p[len] = 0;
542 while (j - i > 1) {
543 k = (j + i) / 2;
544 m = nasm_stricmp(p, tasm_directives[k]);
545 if (m == 0) {
546 /* We have found a directive, so jam a % in front of it
547 * so that NASM will then recognise it as one if it's own.
549 p[len] = oldchar;
550 len = strlen(p);
551 oldline = line;
552 line = nasm_malloc(len + 2);
553 line[0] = '%';
554 if (k == TM_IFDIFI) {
556 * NASM does not recognise IFDIFI, so we convert
557 * it to %if 0. This is not used in NASM
558 * compatible code, but does need to parse for the
559 * TASM macro package.
561 strcpy(line + 1, "if 0");
562 } else {
563 memcpy(line + 1, p, len + 1);
565 nasm_free(oldline);
566 return line;
567 } else if (m < 0) {
568 j = k;
569 } else
570 i = k;
572 p[len] = oldchar;
574 return line;
578 * The pre-preprocessing stage... This function translates line
579 * number indications as they emerge from GNU cpp (`# lineno "file"
580 * flags') into NASM preprocessor line number indications (`%line
581 * lineno file').
583 static char *prepreproc(char *line)
585 int lineno, fnlen;
586 char *fname, *oldline;
588 if (line[0] == '#' && line[1] == ' ') {
589 oldline = line;
590 fname = oldline + 2;
591 lineno = atoi(fname);
592 fname += strspn(fname, "0123456789 ");
593 if (*fname == '"')
594 fname++;
595 fnlen = strcspn(fname, "\"");
596 line = nasm_malloc(20 + fnlen);
597 snprintf(line, 20 + fnlen, "%%line %d %.*s", lineno, fnlen, fname);
598 nasm_free(oldline);
600 if (tasm_compatible_mode)
601 return check_tasm_directive(line);
602 return line;
606 * Free a linked list of tokens.
608 static void free_tlist(Token * list)
610 while (list)
611 list = delete_Token(list);
615 * Free a linked list of lines.
617 static void free_llist(Line * list)
619 Line *l, *tmp;
620 list_for_each_safe(l, tmp, list) {
621 free_tlist(l->first);
622 nasm_free(l);
627 * Free an ExpDef
629 static void free_expdef(ExpDef * ed)
631 nasm_free(ed->name);
632 free_tlist(ed->dlist);
633 nasm_free(ed->defaults);
634 free_llist(ed->line);
635 nasm_free(ed);
639 * Free an ExpInv
641 static void free_expinv(ExpInv * ei)
643 if (ei->name != NULL)
644 nasm_free(ei->name);
645 if (ei->label_text != NULL)
646 nasm_free(ei->label_text);
647 nasm_free(ei);
651 * Free all currently defined macros, and free the hash tables
653 static void free_smacro_table(struct hash_table *smt)
655 SMacro *s, *tmp;
656 const char *key;
657 struct hash_tbl_node *it = NULL;
659 while ((s = hash_iterate(smt, &it, &key)) != NULL) {
660 nasm_free((void *)key);
661 list_for_each_safe(s, tmp, s) {
662 nasm_free(s->name);
663 free_tlist(s->expansion);
664 nasm_free(s);
667 hash_free(smt);
670 static void free_expdef_table(struct hash_table *edt)
672 ExpDef *ed, *tmp;
673 const char *key;
674 struct hash_tbl_node *it = NULL;
676 it = NULL;
677 while ((ed = hash_iterate(edt, &it, &key)) != NULL) {
678 nasm_free((void *)key);
679 list_for_each_safe(ed ,tmp, ed)
680 free_expdef(ed);
682 hash_free(edt);
685 static void free_macros(void)
687 free_smacro_table(&smacros);
688 free_expdef_table(&expdefs);
692 * Initialize the hash tables
694 static void init_macros(void)
696 hash_init(&smacros, HASH_LARGE);
697 hash_init(&expdefs, HASH_LARGE);
701 * Pop the context stack.
703 static void ctx_pop(void)
705 Context *c = cstk;
707 cstk = cstk->next;
708 free_smacro_table(&c->localmac);
709 nasm_free(c->name);
710 nasm_free(c);
714 * Search for a key in the hash index; adding it if necessary
715 * (in which case we initialize the data pointer to NULL.)
717 static void **
718 hash_findi_add(struct hash_table *hash, const char *str)
720 struct hash_insert hi;
721 void **r;
722 char *strx;
724 r = hash_findi(hash, str, &hi);
725 if (r)
726 return r;
728 strx = nasm_strdup(str); /* Use a more efficient allocator here? */
729 return hash_add(&hi, strx, NULL);
733 * Like hash_findi, but returns the data element rather than a pointer
734 * to it. Used only when not adding a new element, hence no third
735 * argument.
737 static void *
738 hash_findix(struct hash_table *hash, const char *str)
740 void **p;
742 p = hash_findi(hash, str, NULL);
743 return p ? *p : NULL;
747 * read line from standard macros set,
748 * if there no more left -- return NULL
750 static char *line_from_stdmac(void)
752 unsigned char c;
753 const unsigned char *p = stdmacpos;
754 char *line, *q;
755 size_t len = 0;
757 if (!stdmacpos)
758 return NULL;
760 while ((c = *p++)) {
761 if (c >= 0x80)
762 len += pp_directives_len[c - 0x80] + 1;
763 else
764 len++;
767 line = nasm_malloc(len + 1);
768 q = line;
769 while ((c = *stdmacpos++)) {
770 if (c >= 0x80) {
771 memcpy(q, pp_directives[c - 0x80], pp_directives_len[c - 0x80]);
772 q += pp_directives_len[c - 0x80];
773 *q++ = ' ';
774 } else {
775 *q++ = c;
778 stdmacpos = p;
779 *q = '\0';
781 if (!*stdmacpos) {
782 /* This was the last of the standard macro chain... */
783 stdmacpos = NULL;
784 if (any_extrastdmac) {
785 stdmacpos = extrastdmac;
786 any_extrastdmac = false;
787 } else if (do_predef) {
788 ExpInv *ei;
789 Line *pd, *l;
790 Token *head, **tail, *t;
793 * Nasty hack: here we push the contents of
794 * `predef' on to the top-level expansion stack,
795 * since this is the most convenient way to
796 * implement the pre-include and pre-define
797 * features.
799 list_for_each(pd, predef) {
800 head = NULL;
801 tail = &head;
802 list_for_each(t, pd->first) {
803 *tail = new_Token(NULL, t->type, t->text, 0);
804 tail = &(*tail)->next;
807 l = new_Line();
808 l->first = head;
809 ei = new_ExpInv(EXP_PREDEF, NULL);
810 ei->current = l;
811 ei->emitting = true;
812 ei->prev = istk->expansion;
813 istk->expansion = ei;
815 do_predef = false;
819 return line;
822 #define BUF_DELTA 512
824 * Read a line from the top file in istk, handling multiple CR/LFs
825 * at the end of the line read, and handling spurious ^Zs. Will
826 * return lines from the standard macro set if this has not already
827 * been done.
829 static char *read_line(void)
831 char *buffer, *p, *q;
832 int bufsize, continued_count;
835 * standart macros set (predefined) goes first
837 p = line_from_stdmac();
838 if (p)
839 return p;
842 * regular read from a file
844 bufsize = BUF_DELTA;
845 buffer = nasm_malloc(BUF_DELTA);
846 p = buffer;
847 continued_count = 0;
848 while (1) {
849 q = fgets(p, bufsize - (p - buffer), istk->fp);
850 if (!q)
851 break;
852 p += strlen(p);
853 if (p > buffer && p[-1] == '\n') {
855 * Convert backslash-CRLF line continuation sequences into
856 * nothing at all (for DOS and Windows)
858 if (((p - 2) > buffer) && (p[-3] == '\\') && (p[-2] == '\r')) {
859 p -= 3;
860 *p = 0;
861 continued_count++;
864 * Also convert backslash-LF line continuation sequences into
865 * nothing at all (for Unix)
867 else if (((p - 1) > buffer) && (p[-2] == '\\')) {
868 p -= 2;
869 *p = 0;
870 continued_count++;
871 } else {
872 break;
875 if (p - buffer > bufsize - 10) {
876 int32_t offset = p - buffer;
877 bufsize += BUF_DELTA;
878 buffer = nasm_realloc(buffer, bufsize);
879 p = buffer + offset; /* prevent stale-pointer problems */
883 if (!q && p == buffer) {
884 nasm_free(buffer);
885 return NULL;
888 src_set_linnum(src_get_linnum() + istk->lineinc +
889 (continued_count * istk->lineinc));
892 * Play safe: remove CRs as well as LFs, if any of either are
893 * present at the end of the line.
895 while (--p >= buffer && (*p == '\n' || *p == '\r'))
896 *p = '\0';
899 * Handle spurious ^Z, which may be inserted into source files
900 * by some file transfer utilities.
902 buffer[strcspn(buffer, "\032")] = '\0';
904 list->line(LIST_READ, buffer);
906 return buffer;
910 * Tokenize a line of text. This is a very simple process since we
911 * don't need to parse the value out of e.g. numeric tokens: we
912 * simply split one string into many.
914 static Token *tokenize(char *line)
916 char c, *p = line;
917 enum pp_token_type type;
918 Token *list = NULL;
919 Token *t, **tail = &list;
921 while (*line) {
922 p = line;
923 if (*p == '%') {
924 p++;
925 if (*p == '+' && !nasm_isdigit(p[1])) {
926 p++;
927 type = TOK_PASTE;
928 } else if (nasm_isdigit(*p) ||
929 ((*p == '-' || *p == '+') && nasm_isdigit(p[1]))) {
930 do {
931 p++;
933 while (nasm_isdigit(*p));
934 type = TOK_PREPROC_ID;
935 } else if (*p == '{') {
936 p++;
937 while (*p && *p != '}') {
938 p[-1] = *p;
939 p++;
941 p[-1] = '\0';
942 if (*p)
943 p++;
944 type = TOK_PREPROC_ID;
945 } else if (*p == '[') {
946 int lvl = 1;
947 line += 2; /* Skip the leading %[ */
948 p++;
949 while (lvl && (c = *p++)) {
950 switch (c) {
951 case ']':
952 lvl--;
953 break;
954 case '%':
955 if (*p == '[')
956 lvl++;
957 break;
958 case '\'':
959 case '\"':
960 case '`':
961 p = nasm_skip_string(p - 1) + 1;
962 break;
963 default:
964 break;
967 p--;
968 if (*p)
969 *p++ = '\0';
970 if (lvl)
971 error(ERR_NONFATAL, "unterminated %[ construct");
972 type = TOK_INDIRECT;
973 } else if (*p == '?') {
974 type = TOK_PREPROC_Q; /* %? */
975 p++;
976 if (*p == '?') {
977 type = TOK_PREPROC_QQ; /* %?? */
978 p++;
980 } else if (*p == '!') {
981 type = TOK_PREPROC_ID;
982 p++;
983 if (isidchar(*p)) {
984 do {
985 p++;
986 } while (isidchar(*p));
987 } else if (*p == '\'' || *p == '\"' || *p == '`') {
988 p = nasm_skip_string(p);
989 if (*p)
990 p++;
991 else
992 error(ERR_NONFATAL|ERR_PASS1, "unterminated %! string");
993 } else {
994 /* %! without string or identifier */
995 type = TOK_OTHER; /* Legacy behavior... */
997 } else if (isidchar(*p) ||
998 ((*p == '!' || *p == '%' || *p == '$') &&
999 isidchar(p[1]))) {
1000 do {
1001 p++;
1003 while (isidchar(*p));
1004 type = TOK_PREPROC_ID;
1005 } else {
1006 type = TOK_OTHER;
1007 if (*p == '%')
1008 p++;
1010 } else if (isidstart(*p) || (*p == '$' && isidstart(p[1]))) {
1011 type = TOK_ID;
1012 p++;
1013 while (*p && isidchar(*p))
1014 p++;
1015 } else if (*p == '\'' || *p == '"' || *p == '`') {
1017 * A string token.
1019 type = TOK_STRING;
1020 p = nasm_skip_string(p);
1022 if (*p) {
1023 p++;
1024 } else {
1025 error(ERR_WARNING|ERR_PASS1, "unterminated string");
1026 /* Handling unterminated strings by UNV */
1027 /* type = -1; */
1029 } else if (p[0] == '$' && p[1] == '$') {
1030 type = TOK_OTHER; /* TOKEN_BASE */
1031 p += 2;
1032 } else if (isnumstart(*p)) {
1033 bool is_hex = false;
1034 bool is_float = false;
1035 bool has_e = false;
1036 char c, *r;
1039 * A numeric token.
1042 if (*p == '$') {
1043 p++;
1044 is_hex = true;
1047 for (;;) {
1048 c = *p++;
1050 if (!is_hex && (c == 'e' || c == 'E')) {
1051 has_e = true;
1052 if (*p == '+' || *p == '-') {
1054 * e can only be followed by +/- if it is either a
1055 * prefixed hex number or a floating-point number
1057 p++;
1058 is_float = true;
1060 } else if (c == 'H' || c == 'h' || c == 'X' || c == 'x') {
1061 is_hex = true;
1062 } else if (c == 'P' || c == 'p') {
1063 is_float = true;
1064 if (*p == '+' || *p == '-')
1065 p++;
1066 } else if (isnumchar(c) || c == '_')
1067 ; /* just advance */
1068 else if (c == '.') {
1070 * we need to deal with consequences of the legacy
1071 * parser, like "1.nolist" being two tokens
1072 * (TOK_NUMBER, TOK_ID) here; at least give it
1073 * a shot for now. In the future, we probably need
1074 * a flex-based scanner with proper pattern matching
1075 * to do it as well as it can be done. Nothing in
1076 * the world is going to help the person who wants
1077 * 0x123.p16 interpreted as two tokens, though.
1079 r = p;
1080 while (*r == '_')
1081 r++;
1083 if (nasm_isdigit(*r) || (is_hex && nasm_isxdigit(*r)) ||
1084 (!is_hex && (*r == 'e' || *r == 'E')) ||
1085 (*r == 'p' || *r == 'P')) {
1086 p = r;
1087 is_float = true;
1088 } else
1089 break; /* Terminate the token */
1090 } else
1091 break;
1093 p--; /* Point to first character beyond number */
1095 if (p == line+1 && *line == '$') {
1096 type = TOK_OTHER; /* TOKEN_HERE */
1097 } else {
1098 if (has_e && !is_hex) {
1099 /* 1e13 is floating-point, but 1e13h is not */
1100 is_float = true;
1103 type = is_float ? TOK_FLOAT : TOK_NUMBER;
1105 } else if (nasm_isspace(*p)) {
1106 type = TOK_WHITESPACE;
1107 p = nasm_skip_spaces(p);
1109 * Whitespace just before end-of-line is discarded by
1110 * pretending it's a comment; whitespace just before a
1111 * comment gets lumped into the comment.
1113 if (!*p || *p == ';') {
1114 type = TOK_COMMENT;
1115 while (*p)
1116 p++;
1118 } else if (*p == ';') {
1119 type = TOK_COMMENT;
1120 while (*p)
1121 p++;
1122 } else {
1124 * Anything else is an operator of some kind. We check
1125 * for all the double-character operators (>>, <<, //,
1126 * %%, <=, >=, ==, !=, <>, &&, ||, ^^), but anything
1127 * else is a single-character operator.
1129 type = TOK_OTHER;
1130 if ((p[0] == '>' && p[1] == '>') ||
1131 (p[0] == '<' && p[1] == '<') ||
1132 (p[0] == '/' && p[1] == '/') ||
1133 (p[0] == '<' && p[1] == '=') ||
1134 (p[0] == '>' && p[1] == '=') ||
1135 (p[0] == '=' && p[1] == '=') ||
1136 (p[0] == '!' && p[1] == '=') ||
1137 (p[0] == '<' && p[1] == '>') ||
1138 (p[0] == '&' && p[1] == '&') ||
1139 (p[0] == '|' && p[1] == '|') ||
1140 (p[0] == '^' && p[1] == '^')) {
1141 p++;
1143 p++;
1146 /* Handling unterminated string by UNV */
1147 /*if (type == -1)
1149 *tail = t = new_Token(NULL, TOK_STRING, line, p-line+1);
1150 t->text[p-line] = *line;
1151 tail = &t->next;
1153 else */
1154 if (type != TOK_COMMENT) {
1155 *tail = t = new_Token(NULL, type, line, p - line);
1156 tail = &t->next;
1158 line = p;
1160 return list;
1164 * this function allocates a new managed block of memory and
1165 * returns a pointer to the block. The managed blocks are
1166 * deleted only all at once by the delete_Blocks function.
1168 static void *new_Block(size_t size)
1170 Blocks *b = &blocks;
1172 /* first, get to the end of the linked list */
1173 while (b->next)
1174 b = b->next;
1175 /* now allocate the requested chunk */
1176 b->chunk = nasm_malloc(size);
1178 /* now allocate a new block for the next request */
1179 b->next = nasm_malloc(sizeof(Blocks));
1180 /* and initialize the contents of the new block */
1181 b->next->next = NULL;
1182 b->next->chunk = NULL;
1183 return b->chunk;
1187 * this function deletes all managed blocks of memory
1189 static void delete_Blocks(void)
1191 Blocks *a, *b = &blocks;
1194 * keep in mind that the first block, pointed to by blocks
1195 * is a static and not dynamically allocated, so we don't
1196 * free it.
1198 while (b) {
1199 if (b->chunk)
1200 nasm_free(b->chunk);
1201 a = b;
1202 b = b->next;
1203 if (a != &blocks)
1204 nasm_free(a);
1209 * this function creates a new Token and passes a pointer to it
1210 * back to the caller. It sets the type and text elements, and
1211 * also the a.mac and next elements to NULL.
1213 static Token *new_Token(Token * next, enum pp_token_type type,
1214 const char *text, int txtlen)
1216 Token *t;
1217 int i;
1219 if (!freeTokens) {
1220 freeTokens = (Token *) new_Block(TOKEN_BLOCKSIZE * sizeof(Token));
1221 for (i = 0; i < TOKEN_BLOCKSIZE - 1; i++)
1222 freeTokens[i].next = &freeTokens[i + 1];
1223 freeTokens[i].next = NULL;
1225 t = freeTokens;
1226 freeTokens = t->next;
1227 t->next = next;
1228 t->a.mac = NULL;
1229 t->type = type;
1230 if (type == TOK_WHITESPACE || !text) {
1231 t->text = NULL;
1232 } else {
1233 if (txtlen == 0)
1234 txtlen = strlen(text);
1235 t->text = nasm_malloc(txtlen+1);
1236 memcpy(t->text, text, txtlen);
1237 t->text[txtlen] = '\0';
1239 return t;
1242 static Token *copy_Token(Token * tline)
1244 Token *t, *tt, *first = NULL, *prev = NULL;
1245 int i;
1246 for (tt = tline; tt != NULL; tt = tt->next) {
1247 if (!freeTokens) {
1248 freeTokens = (Token *) new_Block(TOKEN_BLOCKSIZE * sizeof(Token));
1249 for (i = 0; i < TOKEN_BLOCKSIZE - 1; i++)
1250 freeTokens[i].next = &freeTokens[i + 1];
1251 freeTokens[i].next = NULL;
1253 t = freeTokens;
1254 freeTokens = t->next;
1255 t->next = NULL;
1256 t->text = ((tt->text != NULL) ? strdup(tt->text) : NULL);
1257 t->a.mac = tt->a.mac;
1258 t->a.len = tt->a.len;
1259 t->type = tt->type;
1260 if (prev != NULL) {
1261 prev->next = t;
1262 } else {
1263 first = t;
1265 prev = t;
1267 return first;
1270 static Token *delete_Token(Token * t)
1272 Token *next = t->next;
1273 nasm_free(t->text);
1274 t->next = freeTokens;
1275 freeTokens = t;
1276 return next;
1280 * Convert a line of tokens back into text.
1281 * If expand_locals is not zero, identifiers of the form "%$*xxx"
1282 * will be transformed into ..@ctxnum.xxx
1284 static char *detoken(Token * tlist, bool expand_locals)
1286 Token *t;
1287 char *line, *p;
1288 const char *q;
1289 int len = 0;
1291 list_for_each(t, tlist) {
1292 if (t->type == TOK_PREPROC_ID && t->text[1] == '!') {
1293 char *v;
1294 char *q = t->text;
1296 v = t->text + 2;
1297 if (*v == '\'' || *v == '\"' || *v == '`') {
1298 size_t len = nasm_unquote(v, NULL);
1299 size_t clen = strlen(v);
1301 if (len != clen) {
1302 error(ERR_NONFATAL | ERR_PASS1,
1303 "NUL character in %! string");
1304 v = NULL;
1308 if (v) {
1309 char *p = getenv(v);
1310 if (!p) {
1311 error(ERR_NONFATAL | ERR_PASS1,
1312 "nonexistent environment variable `%s'", v);
1313 p = "";
1315 t->text = nasm_strdup(p);
1317 nasm_free(q);
1320 /* Expand local macros here and not during preprocessing */
1321 if (expand_locals &&
1322 t->type == TOK_PREPROC_ID && t->text &&
1323 t->text[0] == '%' && t->text[1] == '$') {
1324 const char *q;
1325 char *p;
1326 Context *ctx = get_ctx(t->text, &q, false);
1327 if (ctx) {
1328 char buffer[40];
1329 snprintf(buffer, sizeof(buffer), "..@%"PRIu32".", ctx->number);
1330 p = nasm_strcat(buffer, q);
1331 nasm_free(t->text);
1332 t->text = p;
1336 /* Expand %? and %?? directives */
1337 if (expand_locals && (istk->expansion != NULL) &&
1338 ((t->type == TOK_PREPROC_Q) ||
1339 (t->type == TOK_PREPROC_QQ))) {
1340 ExpInv *ei;
1341 for (ei = istk->expansion; ei != NULL; ei = ei->prev){
1342 if (ei->type == EXP_MMACRO) {
1343 nasm_free(t->text);
1344 if (t->type == TOK_PREPROC_Q) {
1345 t->text = nasm_strdup(ei->name);
1346 } else {
1347 t->text = nasm_strdup(ei->def->name);
1349 break;
1354 if (t->type == TOK_WHITESPACE)
1355 len++;
1356 else if (t->text)
1357 len += strlen(t->text);
1360 p = line = nasm_malloc(len + 1);
1362 list_for_each(t, tlist) {
1363 if (t->type == TOK_WHITESPACE) {
1364 *p++ = ' ';
1365 } else if (t->text) {
1366 q = t->text;
1367 while (*q)
1368 *p++ = *q++;
1371 *p = '\0';
1373 return line;
1377 * Initialize a new Line
1379 static Line *new_Line(void)
1381 Line *l = nasm_malloc(sizeof(Line));
1382 l->next = NULL;
1383 l->first = NULL;
1384 return l;
1389 * Initialize a new Expansion Definition
1391 static ExpDef *new_ExpDef(int exp_type)
1393 ExpDef *ed = (ExpDef*)nasm_malloc(sizeof(ExpDef));
1394 ed->prev = NULL;
1395 ed->next = NULL;
1396 ed->type = exp_type;
1397 ed->name = NULL;
1398 ed->nparam_min = 0;
1399 ed->nparam_max = 0;
1400 ed->casesense = true;
1401 ed->plus = false;
1402 ed->prepend = 0;
1403 ed->label = NULL;
1404 ed->line = NULL;
1405 ed->last = NULL;
1406 ed->linecount = 0;
1407 ed->dlist = NULL;
1408 ed->defaults = NULL;
1409 ed->ndefs = 0;
1410 ed->state = COND_NEVER;
1411 ed->nolist = false;
1412 ed->def_depth = 0;
1413 ed->cur_depth = 0;
1414 ed->max_depth = 0;
1415 ed->ignoring = false;
1416 return ed;
1421 * Initialize a new Expansion Instance
1423 static ExpInv *new_ExpInv(int exp_type, ExpDef *ed)
1425 ExpInv *ei = (ExpInv*)nasm_malloc(sizeof(ExpInv));
1426 ei->prev = NULL;
1427 ei->type = exp_type;
1428 ei->def = ed;
1429 ei->name = NULL;
1430 ei->label = NULL;
1431 ei->label_text = NULL;
1432 ei->current = NULL;
1433 ei->params = NULL;
1434 ei->iline = NULL;
1435 ei->nparam = 0;
1436 ei->rotate = 0;
1437 ei->paramlen = NULL;
1438 ei->unique = ++unique;
1439 ei->emitting = false;
1440 ei->lineno = 0;
1441 if ((istk->mmac_depth < 1) &&
1442 (istk->expansion == NULL) &&
1443 (ed != NULL) &&
1444 (ed->type != EXP_MMACRO) &&
1445 (ed->type != EXP_REP) &&
1446 (ed->type != EXP_WHILE)) {
1447 ei->linnum = src_get_linnum();
1448 src_set_linnum(ei->linnum - ed->linecount - 1);
1449 } else {
1450 ei->linnum = -1;
1452 if ((istk->expansion == NULL) ||
1453 (ei->type == EXP_MMACRO)) {
1454 ei->relno = 0;
1455 } else {
1456 ei->relno = istk->expansion->lineno;
1457 if (ed != NULL) {
1458 ei->relno -= (ed->linecount + 1);
1461 return ei;
1465 * A scanner, suitable for use by the expression evaluator, which
1466 * operates on a line of Tokens. Expects a pointer to a pointer to
1467 * the first token in the line to be passed in as its private_data
1468 * field.
1470 * FIX: This really needs to be unified with stdscan.
1472 static int ppscan(void *private_data, struct tokenval *tokval)
1474 Token **tlineptr = private_data;
1475 Token *tline;
1476 char ourcopy[MAX_KEYWORD+1], *p, *r, *s;
1478 do {
1479 tline = *tlineptr;
1480 *tlineptr = tline ? tline->next : NULL;
1481 } while (tline && (tline->type == TOK_WHITESPACE ||
1482 tline->type == TOK_COMMENT));
1484 if (!tline)
1485 return tokval->t_type = TOKEN_EOS;
1487 tokval->t_charptr = tline->text;
1489 if (tline->text[0] == '$' && !tline->text[1])
1490 return tokval->t_type = TOKEN_HERE;
1491 if (tline->text[0] == '$' && tline->text[1] == '$' && !tline->text[2])
1492 return tokval->t_type = TOKEN_BASE;
1494 if (tline->type == TOK_ID) {
1495 p = tokval->t_charptr = tline->text;
1496 if (p[0] == '$') {
1497 tokval->t_charptr++;
1498 return tokval->t_type = TOKEN_ID;
1501 for (r = p, s = ourcopy; *r; r++) {
1502 if (r >= p+MAX_KEYWORD)
1503 return tokval->t_type = TOKEN_ID; /* Not a keyword */
1504 *s++ = nasm_tolower(*r);
1506 *s = '\0';
1507 /* right, so we have an identifier sitting in temp storage. now,
1508 * is it actually a register or instruction name, or what? */
1509 return nasm_token_hash(ourcopy, tokval);
1512 if (tline->type == TOK_NUMBER) {
1513 bool rn_error;
1514 tokval->t_integer = readnum(tline->text, &rn_error);
1515 tokval->t_charptr = tline->text;
1516 if (rn_error)
1517 return tokval->t_type = TOKEN_ERRNUM;
1518 else
1519 return tokval->t_type = TOKEN_NUM;
1522 if (tline->type == TOK_FLOAT) {
1523 return tokval->t_type = TOKEN_FLOAT;
1526 if (tline->type == TOK_STRING) {
1527 char bq, *ep;
1529 bq = tline->text[0];
1530 tokval->t_charptr = tline->text;
1531 tokval->t_inttwo = nasm_unquote(tline->text, &ep);
1533 if (ep[0] != bq || ep[1] != '\0')
1534 return tokval->t_type = TOKEN_ERRSTR;
1535 else
1536 return tokval->t_type = TOKEN_STR;
1539 if (tline->type == TOK_OTHER) {
1540 if (!strcmp(tline->text, "<<"))
1541 return tokval->t_type = TOKEN_SHL;
1542 if (!strcmp(tline->text, ">>"))
1543 return tokval->t_type = TOKEN_SHR;
1544 if (!strcmp(tline->text, "//"))
1545 return tokval->t_type = TOKEN_SDIV;
1546 if (!strcmp(tline->text, "%%"))
1547 return tokval->t_type = TOKEN_SMOD;
1548 if (!strcmp(tline->text, "=="))
1549 return tokval->t_type = TOKEN_EQ;
1550 if (!strcmp(tline->text, "<>"))
1551 return tokval->t_type = TOKEN_NE;
1552 if (!strcmp(tline->text, "!="))
1553 return tokval->t_type = TOKEN_NE;
1554 if (!strcmp(tline->text, "<="))
1555 return tokval->t_type = TOKEN_LE;
1556 if (!strcmp(tline->text, ">="))
1557 return tokval->t_type = TOKEN_GE;
1558 if (!strcmp(tline->text, "&&"))
1559 return tokval->t_type = TOKEN_DBL_AND;
1560 if (!strcmp(tline->text, "^^"))
1561 return tokval->t_type = TOKEN_DBL_XOR;
1562 if (!strcmp(tline->text, "||"))
1563 return tokval->t_type = TOKEN_DBL_OR;
1567 * We have no other options: just return the first character of
1568 * the token text.
1570 return tokval->t_type = tline->text[0];
1574 * Compare a string to the name of an existing macro; this is a
1575 * simple wrapper which calls either strcmp or nasm_stricmp
1576 * depending on the value of the `casesense' parameter.
1578 static int mstrcmp(const char *p, const char *q, bool casesense)
1580 return casesense ? strcmp(p, q) : nasm_stricmp(p, q);
1584 * Compare a string to the name of an existing macro; this is a
1585 * simple wrapper which calls either strcmp or nasm_stricmp
1586 * depending on the value of the `casesense' parameter.
1588 static int mmemcmp(const char *p, const char *q, size_t l, bool casesense)
1590 return casesense ? memcmp(p, q, l) : nasm_memicmp(p, q, l);
1594 * Return the Context structure associated with a %$ token. Return
1595 * NULL, having _already_ reported an error condition, if the
1596 * context stack isn't deep enough for the supplied number of $
1597 * signs.
1598 * If all_contexts == true, contexts that enclose current are
1599 * also scanned for such smacro, until it is found; if not -
1600 * only the context that directly results from the number of $'s
1601 * in variable's name.
1603 * If "namep" is non-NULL, set it to the pointer to the macro name
1604 * tail, i.e. the part beyond %$...
1606 static Context *get_ctx(const char *name, const char **namep,
1607 bool all_contexts)
1609 Context *ctx;
1610 SMacro *m;
1611 int i;
1613 if (namep)
1614 *namep = name;
1616 if (!name || name[0] != '%' || name[1] != '$')
1617 return NULL;
1619 if (!cstk) {
1620 error(ERR_NONFATAL, "`%s': context stack is empty", name);
1621 return NULL;
1624 name += 2;
1625 ctx = cstk;
1626 i = 0;
1627 while (ctx && *name == '$') {
1628 name++;
1629 i++;
1630 ctx = ctx->next;
1632 if (!ctx) {
1633 error(ERR_NONFATAL, "`%s': context stack is only"
1634 " %d level%s deep", name, i, (i == 1 ? "" : "s"));
1635 return NULL;
1638 if (namep)
1639 *namep = name;
1641 if (!all_contexts)
1642 return ctx;
1644 do {
1645 /* Search for this smacro in found context */
1646 m = hash_findix(&ctx->localmac, name);
1647 while (m) {
1648 if (!mstrcmp(m->name, name, m->casesense))
1649 return ctx;
1650 m = m->next;
1652 ctx = ctx->next;
1654 while (ctx);
1655 return NULL;
1659 * Check to see if a file is already in a string list
1661 static bool in_list(const StrList *list, const char *str)
1663 while (list) {
1664 if (!strcmp(list->str, str))
1665 return true;
1666 list = list->next;
1668 return false;
1672 * Open an include file. This routine must always return a valid
1673 * file pointer if it returns - it's responsible for throwing an
1674 * ERR_FATAL and bombing out completely if not. It should also try
1675 * the include path one by one until it finds the file or reaches
1676 * the end of the path.
1678 static FILE *inc_fopen(const char *file, StrList **dhead, StrList ***dtail,
1679 bool missing_ok)
1681 FILE *fp;
1682 char *prefix = "";
1683 IncPath *ip = ipath;
1684 int len = strlen(file);
1685 size_t prefix_len = 0;
1686 StrList *sl;
1688 while (1) {
1689 sl = nasm_malloc(prefix_len+len+1+sizeof sl->next);
1690 memcpy(sl->str, prefix, prefix_len);
1691 memcpy(sl->str+prefix_len, file, len+1);
1692 fp = fopen(sl->str, "r");
1693 if (fp && dhead && !in_list(*dhead, sl->str)) {
1694 sl->next = NULL;
1695 **dtail = sl;
1696 *dtail = &sl->next;
1697 } else {
1698 nasm_free(sl);
1700 if (fp)
1701 return fp;
1702 if (!ip) {
1703 if (!missing_ok)
1704 break;
1705 prefix = NULL;
1706 } else {
1707 prefix = ip->path;
1708 ip = ip->next;
1710 if (prefix) {
1711 prefix_len = strlen(prefix);
1712 } else {
1713 /* -MG given and file not found */
1714 if (dhead && !in_list(*dhead, file)) {
1715 sl = nasm_malloc(len+1+sizeof sl->next);
1716 sl->next = NULL;
1717 strcpy(sl->str, file);
1718 **dtail = sl;
1719 *dtail = &sl->next;
1721 return NULL;
1725 error(ERR_FATAL, "unable to open include file `%s'", file);
1726 return NULL;
1730 * Determine if we should warn on defining a single-line macro of
1731 * name `name', with `nparam' parameters. If nparam is 0 or -1, will
1732 * return true if _any_ single-line macro of that name is defined.
1733 * Otherwise, will return true if a single-line macro with either
1734 * `nparam' or no parameters is defined.
1736 * If a macro with precisely the right number of parameters is
1737 * defined, or nparam is -1, the address of the definition structure
1738 * will be returned in `defn'; otherwise NULL will be returned. If `defn'
1739 * is NULL, no action will be taken regarding its contents, and no
1740 * error will occur.
1742 * Note that this is also called with nparam zero to resolve
1743 * `ifdef'.
1745 * If you already know which context macro belongs to, you can pass
1746 * the context pointer as first parameter; if you won't but name begins
1747 * with %$ the context will be automatically computed. If all_contexts
1748 * is true, macro will be searched in outer contexts as well.
1750 static bool
1751 smacro_defined(Context * ctx, const char *name, int nparam, SMacro ** defn,
1752 bool nocase)
1754 struct hash_table *smtbl;
1755 SMacro *m;
1757 if (ctx) {
1758 smtbl = &ctx->localmac;
1759 } else if (name[0] == '%' && name[1] == '$') {
1760 if (cstk)
1761 ctx = get_ctx(name, &name, false);
1762 if (!ctx)
1763 return false; /* got to return _something_ */
1764 smtbl = &ctx->localmac;
1765 } else {
1766 smtbl = &smacros;
1768 m = (SMacro *) hash_findix(smtbl, name);
1770 while (m) {
1771 if (!mstrcmp(m->name, name, m->casesense && nocase) &&
1772 (nparam <= 0 || m->nparam == 0 || nparam == (int) m->nparam)) {
1773 if (defn) {
1774 if (nparam == (int) m->nparam || nparam == -1)
1775 *defn = m;
1776 else
1777 *defn = NULL;
1779 return true;
1781 m = m->next;
1784 return false;
1788 * Count and mark off the parameters in a multi-line macro call.
1789 * This is called both from within the multi-line macro expansion
1790 * code, and also to mark off the default parameters when provided
1791 * in a %macro definition line.
1793 static void count_mmac_params(Token * t, int *nparam, Token *** params)
1795 int paramsize, brace;
1797 *nparam = paramsize = 0;
1798 *params = NULL;
1799 while (t) {
1800 /* +1: we need space for the final NULL */
1801 if (*nparam+1 >= paramsize) {
1802 paramsize += PARAM_DELTA;
1803 *params = nasm_realloc(*params, sizeof(**params) * paramsize);
1805 skip_white_(t);
1806 brace = false;
1807 if (tok_is_(t, "{"))
1808 brace = true;
1809 (*params)[(*nparam)++] = t;
1810 while (tok_isnt_(t, brace ? "}" : ","))
1811 t = t->next;
1812 if (t) { /* got a comma/brace */
1813 t = t->next;
1814 if (brace) {
1816 * Now we've found the closing brace, look further
1817 * for the comma.
1819 skip_white_(t);
1820 if (tok_isnt_(t, ",")) {
1821 error(ERR_NONFATAL,
1822 "braces do not enclose all of macro parameter");
1823 while (tok_isnt_(t, ","))
1824 t = t->next;
1826 if (t)
1827 t = t->next; /* eat the comma */
1834 * Determine whether one of the various `if' conditions is true or
1835 * not.
1837 * We must free the tline we get passed.
1839 static bool if_condition(Token * tline, enum preproc_token ct)
1841 enum pp_conditional i = PP_COND(ct);
1842 bool j;
1843 Token *t, *tt, **tptr, *origline;
1844 struct tokenval tokval;
1845 expr *evalresult;
1846 enum pp_token_type needtype;
1847 char *p;
1849 origline = tline;
1851 switch (i) {
1852 case PPC_IFCTX:
1853 j = false; /* have we matched yet? */
1854 while (true) {
1855 skip_white_(tline);
1856 if (!tline)
1857 break;
1858 if (tline->type != TOK_ID) {
1859 error(ERR_NONFATAL,
1860 "`%s' expects context identifiers", pp_directives[ct]);
1861 free_tlist(origline);
1862 return -1;
1864 if (cstk && cstk->name && !nasm_stricmp(tline->text, cstk->name))
1865 j = true;
1866 tline = tline->next;
1868 break;
1870 case PPC_IFDEF:
1871 j = false; /* have we matched yet? */
1872 while (tline) {
1873 skip_white_(tline);
1874 if (!tline || (tline->type != TOK_ID &&
1875 (tline->type != TOK_PREPROC_ID ||
1876 tline->text[1] != '$'))) {
1877 error(ERR_NONFATAL,
1878 "`%s' expects macro identifiers", pp_directives[ct]);
1879 goto fail;
1881 if (smacro_defined(NULL, tline->text, 0, NULL, true))
1882 j = true;
1883 tline = tline->next;
1885 break;
1887 case PPC_IFENV:
1888 tline = expand_smacro(tline);
1889 j = false; /* have we matched yet? */
1890 while (tline) {
1891 skip_white_(tline);
1892 if (!tline || (tline->type != TOK_ID &&
1893 tline->type != TOK_STRING &&
1894 (tline->type != TOK_PREPROC_ID ||
1895 tline->text[1] != '!'))) {
1896 error(ERR_NONFATAL,
1897 "`%s' expects environment variable names",
1898 pp_directives[ct]);
1899 goto fail;
1901 p = tline->text;
1902 if (tline->type == TOK_PREPROC_ID)
1903 p += 2; /* Skip leading %! */
1904 if (*p == '\'' || *p == '\"' || *p == '`')
1905 nasm_unquote_cstr(p, ct);
1906 if (getenv(p))
1907 j = true;
1908 tline = tline->next;
1910 break;
1912 case PPC_IFIDN:
1913 case PPC_IFIDNI:
1914 tline = expand_smacro(tline);
1915 t = tt = tline;
1916 while (tok_isnt_(tt, ","))
1917 tt = tt->next;
1918 if (!tt) {
1919 error(ERR_NONFATAL,
1920 "`%s' expects two comma-separated arguments",
1921 pp_directives[ct]);
1922 goto fail;
1924 tt = tt->next;
1925 j = true; /* assume equality unless proved not */
1926 while ((t->type != TOK_OTHER || strcmp(t->text, ",")) && tt) {
1927 if (tt->type == TOK_OTHER && !strcmp(tt->text, ",")) {
1928 error(ERR_NONFATAL, "`%s': more than one comma on line",
1929 pp_directives[ct]);
1930 goto fail;
1932 if (t->type == TOK_WHITESPACE) {
1933 t = t->next;
1934 continue;
1936 if (tt->type == TOK_WHITESPACE) {
1937 tt = tt->next;
1938 continue;
1940 if (tt->type != t->type) {
1941 j = false; /* found mismatching tokens */
1942 break;
1944 /* When comparing strings, need to unquote them first */
1945 if (t->type == TOK_STRING) {
1946 size_t l1 = nasm_unquote(t->text, NULL);
1947 size_t l2 = nasm_unquote(tt->text, NULL);
1949 if (l1 != l2) {
1950 j = false;
1951 break;
1953 if (mmemcmp(t->text, tt->text, l1, i == PPC_IFIDN)) {
1954 j = false;
1955 break;
1957 } else if (mstrcmp(tt->text, t->text, i == PPC_IFIDN) != 0) {
1958 j = false; /* found mismatching tokens */
1959 break;
1962 t = t->next;
1963 tt = tt->next;
1965 if ((t->type != TOK_OTHER || strcmp(t->text, ",")) || tt)
1966 j = false; /* trailing gunk on one end or other */
1967 break;
1969 case PPC_IFMACRO:
1971 bool found = false;
1972 ExpDef searching, *ed;
1974 skip_white_(tline);
1975 tline = expand_id(tline);
1976 if (!tok_type_(tline, TOK_ID)) {
1977 error(ERR_NONFATAL,
1978 "`%s' expects a macro name", pp_directives[ct]);
1979 goto fail;
1981 searching.name = nasm_strdup(tline->text);
1982 searching.casesense = true;
1983 searching.plus = false;
1984 searching.nolist = false;
1985 //searching.in_progress = 0;
1986 searching.max_depth = 0;
1987 //searching.rep_nest = NULL;
1988 searching.nparam_min = 0;
1989 searching.nparam_max = INT_MAX;
1990 tline = expand_smacro(tline->next);
1991 skip_white_(tline);
1992 if (!tline) {
1993 } else if (!tok_type_(tline, TOK_NUMBER)) {
1994 error(ERR_NONFATAL,
1995 "`%s' expects a parameter count or nothing",
1996 pp_directives[ct]);
1997 } else {
1998 searching.nparam_min = searching.nparam_max =
1999 readnum(tline->text, &j);
2000 if (j)
2001 error(ERR_NONFATAL,
2002 "unable to parse parameter count `%s'",
2003 tline->text);
2005 if (tline && tok_is_(tline->next, "-")) {
2006 tline = tline->next->next;
2007 if (tok_is_(tline, "*"))
2008 searching.nparam_max = INT_MAX;
2009 else if (!tok_type_(tline, TOK_NUMBER))
2010 error(ERR_NONFATAL,
2011 "`%s' expects a parameter count after `-'",
2012 pp_directives[ct]);
2013 else {
2014 searching.nparam_max = readnum(tline->text, &j);
2015 if (j)
2016 error(ERR_NONFATAL,
2017 "unable to parse parameter count `%s'",
2018 tline->text);
2019 if (searching.nparam_min > searching.nparam_max)
2020 error(ERR_NONFATAL,
2021 "minimum parameter count exceeds maximum");
2024 if (tline && tok_is_(tline->next, "+")) {
2025 tline = tline->next;
2026 searching.plus = true;
2028 ed = (ExpDef *) hash_findix(&expdefs, searching.name);
2029 while (ed != NULL) {
2030 if (!strcmp(ed->name, searching.name) &&
2031 (ed->nparam_min <= searching.nparam_max
2032 || searching.plus)
2033 && (searching.nparam_min <= ed->nparam_max
2034 || ed->plus)) {
2035 found = true;
2036 break;
2038 ed = ed->next;
2040 if (tline && tline->next)
2041 error(ERR_WARNING|ERR_PASS1,
2042 "trailing garbage after %%ifmacro ignored");
2043 nasm_free(searching.name);
2044 j = found;
2045 break;
2048 case PPC_IFID:
2049 needtype = TOK_ID;
2050 goto iftype;
2051 case PPC_IFNUM:
2052 needtype = TOK_NUMBER;
2053 goto iftype;
2054 case PPC_IFSTR:
2055 needtype = TOK_STRING;
2056 goto iftype;
2058 iftype:
2059 t = tline = expand_smacro(tline);
2061 while (tok_type_(t, TOK_WHITESPACE) ||
2062 (needtype == TOK_NUMBER &&
2063 tok_type_(t, TOK_OTHER) &&
2064 (t->text[0] == '-' || t->text[0] == '+') &&
2065 !t->text[1]))
2066 t = t->next;
2068 j = tok_type_(t, needtype);
2069 break;
2071 case PPC_IFTOKEN:
2072 t = tline = expand_smacro(tline);
2073 while (tok_type_(t, TOK_WHITESPACE))
2074 t = t->next;
2076 j = false;
2077 if (t) {
2078 t = t->next; /* Skip the actual token */
2079 while (tok_type_(t, TOK_WHITESPACE))
2080 t = t->next;
2081 j = !t; /* Should be nothing left */
2083 break;
2085 case PPC_IFEMPTY:
2086 t = tline = expand_smacro(tline);
2087 while (tok_type_(t, TOK_WHITESPACE))
2088 t = t->next;
2090 j = !t; /* Should be empty */
2091 break;
2093 case PPC_IF:
2094 t = tline = expand_smacro(tline);
2095 tptr = &t;
2096 tokval.t_type = TOKEN_INVALID;
2097 evalresult = evaluate(ppscan, tptr, &tokval,
2098 NULL, pass | CRITICAL, error, NULL);
2099 if (!evalresult)
2100 return -1;
2101 if (tokval.t_type)
2102 error(ERR_WARNING|ERR_PASS1,
2103 "trailing garbage after expression ignored");
2104 if (!is_simple(evalresult)) {
2105 error(ERR_NONFATAL,
2106 "non-constant value given to `%s'", pp_directives[ct]);
2107 goto fail;
2109 j = reloc_value(evalresult) != 0;
2110 break;
2112 default:
2113 error(ERR_FATAL,
2114 "preprocessor directive `%s' not yet implemented",
2115 pp_directives[ct]);
2116 goto fail;
2119 free_tlist(origline);
2120 return j ^ PP_NEGATIVE(ct);
2122 fail:
2123 free_tlist(origline);
2124 return -1;
2128 * Common code for defining an smacro
2130 static bool define_smacro(Context *ctx, const char *mname, bool casesense,
2131 int nparam, Token *expansion)
2133 SMacro *smac, **smhead;
2134 struct hash_table *smtbl;
2136 if (smacro_defined(ctx, mname, nparam, &smac, casesense)) {
2137 if (!smac) {
2138 error(ERR_WARNING|ERR_PASS1,
2139 "single-line macro `%s' defined both with and"
2140 " without parameters", mname);
2142 * Some instances of the old code considered this a failure,
2143 * some others didn't. What is the right thing to do here?
2145 free_tlist(expansion);
2146 return false; /* Failure */
2147 } else {
2149 * We're redefining, so we have to take over an
2150 * existing SMacro structure. This means freeing
2151 * what was already in it.
2153 nasm_free(smac->name);
2154 free_tlist(smac->expansion);
2156 } else {
2157 smtbl = ctx ? &ctx->localmac : &smacros;
2158 smhead = (SMacro **) hash_findi_add(smtbl, mname);
2159 smac = nasm_malloc(sizeof(SMacro));
2160 smac->next = *smhead;
2161 *smhead = smac;
2163 smac->name = nasm_strdup(mname);
2164 smac->casesense = casesense;
2165 smac->nparam = nparam;
2166 smac->expansion = expansion;
2167 smac->in_progress = false;
2168 return true; /* Success */
2172 * Undefine an smacro
2174 static void undef_smacro(Context *ctx, const char *mname)
2176 SMacro **smhead, *s, **sp;
2177 struct hash_table *smtbl;
2179 smtbl = ctx ? &ctx->localmac : &smacros;
2180 smhead = (SMacro **)hash_findi(smtbl, mname, NULL);
2182 if (smhead) {
2184 * We now have a macro name... go hunt for it.
2186 sp = smhead;
2187 while ((s = *sp) != NULL) {
2188 if (!mstrcmp(s->name, mname, s->casesense)) {
2189 *sp = s->next;
2190 nasm_free(s->name);
2191 free_tlist(s->expansion);
2192 nasm_free(s);
2193 } else {
2194 sp = &s->next;
2201 * Parse a mmacro specification.
2203 static bool parse_mmacro_spec(Token *tline, ExpDef *def, const char *directive)
2205 bool err;
2207 tline = tline->next;
2208 skip_white_(tline);
2209 tline = expand_id(tline);
2210 if (!tok_type_(tline, TOK_ID)) {
2211 error(ERR_NONFATAL, "`%s' expects a macro name", directive);
2212 return false;
2215 def->name = nasm_strdup(tline->text);
2216 def->plus = false;
2217 def->nolist = false;
2218 // def->in_progress = 0;
2219 // def->rep_nest = NULL;
2220 def->nparam_min = 0;
2221 def->nparam_max = 0;
2223 tline = expand_smacro(tline->next);
2224 skip_white_(tline);
2225 if (!tok_type_(tline, TOK_NUMBER)) {
2226 error(ERR_NONFATAL, "`%s' expects a parameter count", directive);
2227 } else {
2228 def->nparam_min = def->nparam_max =
2229 readnum(tline->text, &err);
2230 if (err)
2231 error(ERR_NONFATAL,
2232 "unable to parse parameter count `%s'", tline->text);
2234 if (tline && tok_is_(tline->next, "-")) {
2235 tline = tline->next->next;
2236 if (tok_is_(tline, "*")) {
2237 def->nparam_max = INT_MAX;
2238 } else if (!tok_type_(tline, TOK_NUMBER)) {
2239 error(ERR_NONFATAL,
2240 "`%s' expects a parameter count after `-'", directive);
2241 } else {
2242 def->nparam_max = readnum(tline->text, &err);
2243 if (err) {
2244 error(ERR_NONFATAL, "unable to parse parameter count `%s'",
2245 tline->text);
2247 if (def->nparam_min > def->nparam_max) {
2248 error(ERR_NONFATAL, "minimum parameter count exceeds maximum");
2252 if (tline && tok_is_(tline->next, "+")) {
2253 tline = tline->next;
2254 def->plus = true;
2256 if (tline && tok_type_(tline->next, TOK_ID) &&
2257 !nasm_stricmp(tline->next->text, ".nolist")) {
2258 tline = tline->next;
2259 def->nolist = true;
2263 * Handle default parameters.
2265 if (tline && tline->next) {
2266 def->dlist = tline->next;
2267 tline->next = NULL;
2268 count_mmac_params(def->dlist, &def->ndefs, &def->defaults);
2269 } else {
2270 def->dlist = NULL;
2271 def->defaults = NULL;
2273 def->line = NULL;
2275 if (def->defaults && def->ndefs > def->nparam_max - def->nparam_min &&
2276 !def->plus)
2277 error(ERR_WARNING|ERR_PASS1|ERR_WARN_MDP,
2278 "too many default macro parameters");
2280 return true;
2285 * Decode a size directive
2287 static int parse_size(const char *str) {
2288 static const char *size_names[] =
2289 { "byte", "dword", "oword", "qword", "tword", "word", "yword" };
2290 static const int sizes[] =
2291 { 0, 1, 4, 16, 8, 10, 2, 32 };
2293 return sizes[bsii(str, size_names, ARRAY_SIZE(size_names))+1];
2297 * find and process preprocessor directive in passed line
2298 * Find out if a line contains a preprocessor directive, and deal
2299 * with it if so.
2301 * If a directive _is_ found, it is the responsibility of this routine
2302 * (and not the caller) to free_tlist() the line.
2304 * @param tline a pointer to the current tokeninzed line linked list
2305 * @return DIRECTIVE_FOUND or NO_DIRECTIVE_FOUND
2308 static int do_directive(Token * tline)
2310 enum preproc_token i;
2311 int j;
2312 bool err;
2313 int nparam;
2314 bool nolist;
2315 bool casesense;
2316 int k, m;
2317 int offset;
2318 char *p, *pp;
2319 const char *mname;
2320 Include *inc;
2321 Context *ctx;
2322 Line *l;
2323 Token *t, *tt, *param_start, *macro_start, *last, **tptr, *origline;
2324 struct tokenval tokval;
2325 expr *evalresult;
2326 ExpDef *ed, *eed, **edhead;
2327 ExpInv *ei, *eei;
2328 int64_t count;
2329 size_t len;
2330 int severity;
2332 origline = tline;
2334 skip_white_(tline);
2335 if (!tline || !tok_type_(tline, TOK_PREPROC_ID) ||
2336 (tline->text[1] == '%' || tline->text[1] == '$'
2337 || tline->text[1] == '!'))
2338 return NO_DIRECTIVE_FOUND;
2340 i = pp_token_hash(tline->text);
2342 switch (i) {
2343 case PP_INVALID:
2344 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2345 error(ERR_NONFATAL, "unknown preprocessor directive `%s'",
2346 tline->text);
2347 return NO_DIRECTIVE_FOUND; /* didn't get it */
2349 case PP_STACKSIZE:
2350 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2351 /* Directive to tell NASM what the default stack size is. The
2352 * default is for a 16-bit stack, and this can be overriden with
2353 * %stacksize large.
2355 tline = tline->next;
2356 if (tline && tline->type == TOK_WHITESPACE)
2357 tline = tline->next;
2358 if (!tline || tline->type != TOK_ID) {
2359 error(ERR_NONFATAL, "`%%stacksize' missing size parameter");
2360 free_tlist(origline);
2361 return DIRECTIVE_FOUND;
2363 if (nasm_stricmp(tline->text, "flat") == 0) {
2364 /* All subsequent ARG directives are for a 32-bit stack */
2365 StackSize = 4;
2366 StackPointer = "ebp";
2367 ArgOffset = 8;
2368 LocalOffset = 0;
2369 } else if (nasm_stricmp(tline->text, "flat64") == 0) {
2370 /* All subsequent ARG directives are for a 64-bit stack */
2371 StackSize = 8;
2372 StackPointer = "rbp";
2373 ArgOffset = 16;
2374 LocalOffset = 0;
2375 } else if (nasm_stricmp(tline->text, "large") == 0) {
2376 /* All subsequent ARG directives are for a 16-bit stack,
2377 * far function call.
2379 StackSize = 2;
2380 StackPointer = "bp";
2381 ArgOffset = 4;
2382 LocalOffset = 0;
2383 } else if (nasm_stricmp(tline->text, "small") == 0) {
2384 /* All subsequent ARG directives are for a 16-bit stack,
2385 * far function call. We don't support near functions.
2387 StackSize = 2;
2388 StackPointer = "bp";
2389 ArgOffset = 6;
2390 LocalOffset = 0;
2391 } else {
2392 error(ERR_NONFATAL, "`%%stacksize' invalid size type");
2393 free_tlist(origline);
2394 return DIRECTIVE_FOUND;
2396 free_tlist(origline);
2397 return DIRECTIVE_FOUND;
2399 case PP_ARG:
2400 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2401 /* TASM like ARG directive to define arguments to functions, in
2402 * the following form:
2404 * ARG arg1:WORD, arg2:DWORD, arg4:QWORD
2406 offset = ArgOffset;
2407 do {
2408 char *arg, directive[256];
2409 int size = StackSize;
2411 /* Find the argument name */
2412 tline = tline->next;
2413 if (tline && tline->type == TOK_WHITESPACE)
2414 tline = tline->next;
2415 if (!tline || tline->type != TOK_ID) {
2416 error(ERR_NONFATAL, "`%%arg' missing argument parameter");
2417 free_tlist(origline);
2418 return DIRECTIVE_FOUND;
2420 arg = tline->text;
2422 /* Find the argument size type */
2423 tline = tline->next;
2424 if (!tline || tline->type != TOK_OTHER
2425 || tline->text[0] != ':') {
2426 error(ERR_NONFATAL,
2427 "Syntax error processing `%%arg' directive");
2428 free_tlist(origline);
2429 return DIRECTIVE_FOUND;
2431 tline = tline->next;
2432 if (!tline || tline->type != TOK_ID) {
2433 error(ERR_NONFATAL, "`%%arg' missing size type parameter");
2434 free_tlist(origline);
2435 return DIRECTIVE_FOUND;
2438 /* Allow macro expansion of type parameter */
2439 tt = tokenize(tline->text);
2440 tt = expand_smacro(tt);
2441 size = parse_size(tt->text);
2442 if (!size) {
2443 error(ERR_NONFATAL,
2444 "Invalid size type for `%%arg' missing directive");
2445 free_tlist(tt);
2446 free_tlist(origline);
2447 return DIRECTIVE_FOUND;
2449 free_tlist(tt);
2451 /* Round up to even stack slots */
2452 size = ALIGN(size, StackSize);
2454 /* Now define the macro for the argument */
2455 snprintf(directive, sizeof(directive), "%%define %s (%s+%d)",
2456 arg, StackPointer, offset);
2457 do_directive(tokenize(directive));
2458 offset += size;
2460 /* Move to the next argument in the list */
2461 tline = tline->next;
2462 if (tline && tline->type == TOK_WHITESPACE)
2463 tline = tline->next;
2464 } while (tline && tline->type == TOK_OTHER && tline->text[0] == ',');
2465 ArgOffset = offset;
2466 free_tlist(origline);
2467 return DIRECTIVE_FOUND;
2469 case PP_LOCAL:
2470 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2471 /* TASM like LOCAL directive to define local variables for a
2472 * function, in the following form:
2474 * LOCAL local1:WORD, local2:DWORD, local4:QWORD = LocalSize
2476 * The '= LocalSize' at the end is ignored by NASM, but is
2477 * required by TASM to define the local parameter size (and used
2478 * by the TASM macro package).
2480 offset = LocalOffset;
2481 do {
2482 char *local, directive[256];
2483 int size = StackSize;
2485 /* Find the argument name */
2486 tline = tline->next;
2487 if (tline && tline->type == TOK_WHITESPACE)
2488 tline = tline->next;
2489 if (!tline || tline->type != TOK_ID) {
2490 error(ERR_NONFATAL,
2491 "`%%local' missing argument parameter");
2492 free_tlist(origline);
2493 return DIRECTIVE_FOUND;
2495 local = tline->text;
2497 /* Find the argument size type */
2498 tline = tline->next;
2499 if (!tline || tline->type != TOK_OTHER
2500 || tline->text[0] != ':') {
2501 error(ERR_NONFATAL,
2502 "Syntax error processing `%%local' directive");
2503 free_tlist(origline);
2504 return DIRECTIVE_FOUND;
2506 tline = tline->next;
2507 if (!tline || tline->type != TOK_ID) {
2508 error(ERR_NONFATAL,
2509 "`%%local' missing size type parameter");
2510 free_tlist(origline);
2511 return DIRECTIVE_FOUND;
2514 /* Allow macro expansion of type parameter */
2515 tt = tokenize(tline->text);
2516 tt = expand_smacro(tt);
2517 size = parse_size(tt->text);
2518 if (!size) {
2519 error(ERR_NONFATAL,
2520 "Invalid size type for `%%local' missing directive");
2521 free_tlist(tt);
2522 free_tlist(origline);
2523 return DIRECTIVE_FOUND;
2525 free_tlist(tt);
2527 /* Round up to even stack slots */
2528 size = ALIGN(size, StackSize);
2530 offset += size; /* Negative offset, increment before */
2532 /* Now define the macro for the argument */
2533 snprintf(directive, sizeof(directive), "%%define %s (%s-%d)",
2534 local, StackPointer, offset);
2535 do_directive(tokenize(directive));
2537 /* Now define the assign to setup the enter_c macro correctly */
2538 snprintf(directive, sizeof(directive),
2539 "%%assign %%$localsize %%$localsize+%d", size);
2540 do_directive(tokenize(directive));
2542 /* Move to the next argument in the list */
2543 tline = tline->next;
2544 if (tline && tline->type == TOK_WHITESPACE)
2545 tline = tline->next;
2546 } while (tline && tline->type == TOK_OTHER && tline->text[0] == ',');
2547 LocalOffset = offset;
2548 free_tlist(origline);
2549 return DIRECTIVE_FOUND;
2551 case PP_CLEAR:
2552 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2553 if (tline->next)
2554 error(ERR_WARNING|ERR_PASS1,
2555 "trailing garbage after `%%clear' ignored");
2556 free_macros();
2557 init_macros();
2558 free_tlist(origline);
2559 return DIRECTIVE_FOUND;
2561 case PP_DEPEND:
2562 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2563 t = tline->next = expand_smacro(tline->next);
2564 skip_white_(t);
2565 if (!t || (t->type != TOK_STRING &&
2566 t->type != TOK_INTERNAL_STRING)) {
2567 error(ERR_NONFATAL, "`%%depend' expects a file name");
2568 free_tlist(origline);
2569 return DIRECTIVE_FOUND; /* but we did _something_ */
2571 if (t->next)
2572 error(ERR_WARNING|ERR_PASS1,
2573 "trailing garbage after `%%depend' ignored");
2574 p = t->text;
2575 if (t->type != TOK_INTERNAL_STRING)
2576 nasm_unquote_cstr(p, i);
2577 if (dephead && !in_list(*dephead, p)) {
2578 StrList *sl = nasm_malloc(strlen(p)+1+sizeof sl->next);
2579 sl->next = NULL;
2580 strcpy(sl->str, p);
2581 *deptail = sl;
2582 deptail = &sl->next;
2584 free_tlist(origline);
2585 return DIRECTIVE_FOUND;
2587 case PP_INCLUDE:
2588 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2589 t = tline->next = expand_smacro(tline->next);
2590 skip_white_(t);
2592 if (!t || (t->type != TOK_STRING &&
2593 t->type != TOK_INTERNAL_STRING)) {
2594 error(ERR_NONFATAL, "`%%include' expects a file name");
2595 free_tlist(origline);
2596 return DIRECTIVE_FOUND; /* but we did _something_ */
2598 if (t->next)
2599 error(ERR_WARNING|ERR_PASS1,
2600 "trailing garbage after `%%include' ignored");
2601 p = t->text;
2602 if (t->type != TOK_INTERNAL_STRING)
2603 nasm_unquote_cstr(p, i);
2604 inc = nasm_malloc(sizeof(Include));
2605 inc->next = istk;
2606 inc->fp = inc_fopen(p, dephead, &deptail, pass == 0);
2607 if (!inc->fp) {
2608 /* -MG given but file not found */
2609 nasm_free(inc);
2610 } else {
2611 inc->fname = src_set_fname(nasm_strdup(p));
2612 inc->lineno = src_set_linnum(0);
2613 inc->lineinc = 1;
2614 inc->expansion = NULL;
2615 istk = inc;
2616 list->uplevel(LIST_INCLUDE);
2618 free_tlist(origline);
2619 return DIRECTIVE_FOUND;
2621 case PP_USE:
2622 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2624 static macros_t *use_pkg;
2625 const char *pkg_macro = NULL;
2627 tline = tline->next;
2628 skip_white_(tline);
2629 tline = expand_id(tline);
2631 if (!tline || (tline->type != TOK_STRING &&
2632 tline->type != TOK_INTERNAL_STRING &&
2633 tline->type != TOK_ID)) {
2634 error(ERR_NONFATAL, "`%%use' expects a package name");
2635 free_tlist(origline);
2636 return DIRECTIVE_FOUND; /* but we did _something_ */
2638 if (tline->next)
2639 error(ERR_WARNING|ERR_PASS1,
2640 "trailing garbage after `%%use' ignored");
2641 if (tline->type == TOK_STRING)
2642 nasm_unquote_cstr(tline->text, i);
2643 use_pkg = nasm_stdmac_find_package(tline->text);
2644 if (!use_pkg)
2645 error(ERR_NONFATAL, "unknown `%%use' package: %s", tline->text);
2646 else
2647 pkg_macro = (char *)use_pkg + 1; /* The first string will be <%define>__USE_*__ */
2648 if (use_pkg && ! smacro_defined(NULL, pkg_macro, 0, NULL, true)) {
2649 /* Not already included, go ahead and include it */
2650 stdmacpos = use_pkg;
2652 free_tlist(origline);
2653 return DIRECTIVE_FOUND;
2655 case PP_PUSH:
2656 case PP_REPL:
2657 case PP_POP:
2658 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2659 tline = tline->next;
2660 skip_white_(tline);
2661 tline = expand_id(tline);
2662 if (tline) {
2663 if (!tok_type_(tline, TOK_ID)) {
2664 error(ERR_NONFATAL, "`%s' expects a context identifier",
2665 pp_directives[i]);
2666 free_tlist(origline);
2667 return DIRECTIVE_FOUND; /* but we did _something_ */
2669 if (tline->next)
2670 error(ERR_WARNING|ERR_PASS1,
2671 "trailing garbage after `%s' ignored",
2672 pp_directives[i]);
2673 p = nasm_strdup(tline->text);
2674 } else {
2675 p = NULL; /* Anonymous */
2678 if (i == PP_PUSH) {
2679 ctx = nasm_malloc(sizeof(Context));
2680 ctx->next = cstk;
2681 hash_init(&ctx->localmac, HASH_SMALL);
2682 ctx->name = p;
2683 ctx->number = unique++;
2684 cstk = ctx;
2685 } else {
2686 /* %pop or %repl */
2687 if (!cstk) {
2688 error(ERR_NONFATAL, "`%s': context stack is empty",
2689 pp_directives[i]);
2690 } else if (i == PP_POP) {
2691 if (p && (!cstk->name || nasm_stricmp(p, cstk->name)))
2692 error(ERR_NONFATAL, "`%%pop' in wrong context: %s, "
2693 "expected %s",
2694 cstk->name ? cstk->name : "anonymous", p);
2695 else
2696 ctx_pop();
2697 } else {
2698 /* i == PP_REPL */
2699 nasm_free(cstk->name);
2700 cstk->name = p;
2701 p = NULL;
2703 nasm_free(p);
2705 free_tlist(origline);
2706 return DIRECTIVE_FOUND;
2707 case PP_FATAL:
2708 severity = ERR_FATAL;
2709 goto issue_error;
2710 case PP_ERROR:
2711 severity = ERR_NONFATAL;
2712 goto issue_error;
2713 case PP_WARNING:
2714 severity = ERR_WARNING|ERR_WARN_USER;
2715 goto issue_error;
2717 issue_error:
2718 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2720 /* Only error out if this is the final pass */
2721 if (pass != 2 && i != PP_FATAL)
2722 return DIRECTIVE_FOUND;
2724 tline->next = expand_smacro(tline->next);
2725 tline = tline->next;
2726 skip_white_(tline);
2727 t = tline ? tline->next : NULL;
2728 skip_white_(t);
2729 if (tok_type_(tline, TOK_STRING) && !t) {
2730 /* The line contains only a quoted string */
2731 p = tline->text;
2732 nasm_unquote(p, NULL); /* Ignore NUL character truncation */
2733 error(severity, "%s", p);
2734 } else {
2735 /* Not a quoted string, or more than a quoted string */
2736 p = detoken(tline, false);
2737 error(severity, "%s", p);
2738 nasm_free(p);
2740 free_tlist(origline);
2741 return DIRECTIVE_FOUND;
2744 CASE_PP_IF:
2745 if (defining != NULL) {
2746 if (defining->type == EXP_IF) {
2747 defining->def_depth ++;
2749 return NO_DIRECTIVE_FOUND;
2751 if ((istk->expansion != NULL) &&
2752 (istk->expansion->emitting == false)) {
2753 j = COND_NEVER;
2754 } else {
2755 j = if_condition(tline->next, i);
2756 tline->next = NULL; /* it got freed */
2757 j = (((j < 0) ? COND_NEVER : j) ? COND_IF_TRUE : COND_IF_FALSE);
2759 ed = new_ExpDef(EXP_IF);
2760 ed->state = j;
2761 ed->nolist = NULL;
2762 ed->def_depth = 0;
2763 ed->cur_depth = 0;
2764 ed->max_depth = 0;
2765 ed->ignoring = ((ed->state == COND_IF_TRUE) ? false : true);
2766 ed->prev = defining;
2767 defining = ed;
2768 free_tlist(origline);
2769 return DIRECTIVE_FOUND;
2771 CASE_PP_ELIF:
2772 if (defining != NULL) {
2773 if ((defining->type != EXP_IF) || (defining->def_depth > 0)) {
2774 return NO_DIRECTIVE_FOUND;
2777 if ((defining == NULL) || (defining->type != EXP_IF)) {
2778 error(ERR_FATAL, "`%s': no matching `%%if'", pp_directives[i]);
2780 switch (defining->state) {
2781 case COND_IF_TRUE:
2782 defining->state = COND_DONE;
2783 defining->ignoring = true;
2784 break;
2786 case COND_DONE:
2787 case COND_NEVER:
2788 defining->ignoring = true;
2789 break;
2791 case COND_ELSE_TRUE:
2792 case COND_ELSE_FALSE:
2793 error_precond(ERR_WARNING|ERR_PASS1,
2794 "`%%elif' after `%%else' ignored");
2795 defining->state = COND_NEVER;
2796 defining->ignoring = true;
2797 break;
2799 case COND_IF_FALSE:
2801 * IMPORTANT: In the case of %if, we will already have
2802 * called expand_mmac_params(); however, if we're
2803 * processing an %elif we must have been in a
2804 * non-emitting mode, which would have inhibited
2805 * the normal invocation of expand_mmac_params().
2806 * Therefore, we have to do it explicitly here.
2808 j = if_condition(expand_mmac_params(tline->next), i);
2809 tline->next = NULL; /* it got freed */
2810 defining->state =
2811 j < 0 ? COND_NEVER : j ? COND_IF_TRUE : COND_IF_FALSE;
2812 defining->ignoring = ((defining->state == COND_IF_TRUE) ? false : true);
2813 break;
2815 free_tlist(origline);
2816 return DIRECTIVE_FOUND;
2818 case PP_ELSE:
2819 if (defining != NULL) {
2820 if ((defining->type != EXP_IF) || (defining->def_depth > 0)) {
2821 return NO_DIRECTIVE_FOUND;
2824 if (tline->next)
2825 error_precond(ERR_WARNING|ERR_PASS1,
2826 "trailing garbage after `%%else' ignored");
2827 if ((defining == NULL) || (defining->type != EXP_IF)) {
2828 error(ERR_FATAL, "`%s': no matching `%%if'", pp_directives[i]);
2830 switch (defining->state) {
2831 case COND_IF_TRUE:
2832 case COND_DONE:
2833 defining->state = COND_ELSE_FALSE;
2834 defining->ignoring = true;
2835 break;
2837 case COND_NEVER:
2838 defining->ignoring = true;
2839 break;
2841 case COND_IF_FALSE:
2842 defining->state = COND_ELSE_TRUE;
2843 defining->ignoring = false;
2844 break;
2846 case COND_ELSE_TRUE:
2847 case COND_ELSE_FALSE:
2848 error_precond(ERR_WARNING|ERR_PASS1,
2849 "`%%else' after `%%else' ignored.");
2850 defining->state = COND_NEVER;
2851 defining->ignoring = true;
2852 break;
2854 free_tlist(origline);
2855 return DIRECTIVE_FOUND;
2857 case PP_ENDIF:
2858 if (defining != NULL) {
2859 if (defining->type == EXP_IF) {
2860 if (defining->def_depth > 0) {
2861 defining->def_depth --;
2862 return NO_DIRECTIVE_FOUND;
2864 } else {
2865 return NO_DIRECTIVE_FOUND;
2868 if (tline->next)
2869 error_precond(ERR_WARNING|ERR_PASS1,
2870 "trailing garbage after `%%endif' ignored");
2871 if ((defining == NULL) || (defining->type != EXP_IF)) {
2872 error(ERR_NONFATAL, "`%%endif': no matching `%%if'");
2873 return DIRECTIVE_FOUND;
2875 ed = defining;
2876 defining = ed->prev;
2877 ed->prev = expansions;
2878 expansions = ed;
2879 ei = new_ExpInv(EXP_IF, ed);
2880 ei->current = ed->line;
2881 ei->emitting = true;
2882 ei->prev = istk->expansion;
2883 istk->expansion = ei;
2884 free_tlist(origline);
2885 return DIRECTIVE_FOUND;
2887 case PP_RMACRO:
2888 case PP_IRMACRO:
2889 case PP_MACRO:
2890 case PP_IMACRO:
2891 if (defining != NULL) {
2892 if (defining->type == EXP_MMACRO) {
2893 defining->def_depth ++;
2895 return NO_DIRECTIVE_FOUND;
2897 ed = new_ExpDef(EXP_MMACRO);
2898 ed->max_depth =
2899 (i == PP_RMACRO) || (i == PP_IRMACRO) ? DEADMAN_LIMIT : 0;
2900 ed->casesense = (i == PP_MACRO) || (i == PP_RMACRO);
2901 if (!parse_mmacro_spec(tline, ed, pp_directives[i])) {
2902 nasm_free(ed);
2903 ed = NULL;
2904 return DIRECTIVE_FOUND;
2906 ed->def_depth = 0;
2907 ed->cur_depth = 0;
2908 ed->max_depth = (ed->max_depth + 1);
2909 ed->ignoring = false;
2910 ed->prev = defining;
2911 defining = ed;
2913 eed = (ExpDef *) hash_findix(&expdefs, ed->name);
2914 while (eed) {
2915 if (!strcmp(eed->name, ed->name) &&
2916 (eed->nparam_min <= ed->nparam_max
2917 || ed->plus)
2918 && (ed->nparam_min <= eed->nparam_max
2919 || eed->plus)) {
2920 error(ERR_WARNING|ERR_PASS1,
2921 "redefining multi-line macro `%s'", ed->name);
2922 return DIRECTIVE_FOUND;
2924 eed = eed->next;
2926 free_tlist(origline);
2927 return DIRECTIVE_FOUND;
2929 case PP_ENDM:
2930 case PP_ENDMACRO:
2931 if (defining != NULL) {
2932 if (defining->type == EXP_MMACRO) {
2933 if (defining->def_depth > 0) {
2934 defining->def_depth --;
2935 return NO_DIRECTIVE_FOUND;
2937 } else {
2938 return NO_DIRECTIVE_FOUND;
2941 if (!(defining) || (defining->type != EXP_MMACRO)) {
2942 error(ERR_NONFATAL, "`%s': not defining a macro", tline->text);
2943 return DIRECTIVE_FOUND;
2945 edhead = (ExpDef **) hash_findi_add(&expdefs, defining->name);
2946 defining->next = *edhead;
2947 *edhead = defining;
2948 ed = defining;
2949 defining = ed->prev;
2950 ed->prev = expansions;
2951 expansions = ed;
2952 ed = NULL;
2953 free_tlist(origline);
2954 return DIRECTIVE_FOUND;
2956 case PP_EXITMACRO:
2957 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2959 * We must search along istk->expansion until we hit a
2960 * macro invocation. Then we disable the emitting state(s)
2961 * between exitmacro and endmacro.
2963 for (ei = istk->expansion; ei != NULL; ei = ei->prev) {
2964 if(ei->type == EXP_MMACRO) {
2965 break;
2969 if (ei != NULL) {
2971 * Set all invocations leading back to the macro
2972 * invocation to a non-emitting state.
2974 for (eei = istk->expansion; eei != ei; eei = eei->prev) {
2975 eei->emitting = false;
2977 eei->emitting = false;
2978 } else {
2979 error(ERR_NONFATAL, "`%%exitmacro' not within `%%macro' block");
2981 free_tlist(origline);
2982 return DIRECTIVE_FOUND;
2984 case PP_UNMACRO:
2985 case PP_UNIMACRO:
2986 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2988 ExpDef **ed_p;
2989 ExpDef spec;
2991 spec.casesense = (i == PP_UNMACRO);
2992 if (!parse_mmacro_spec(tline, &spec, pp_directives[i])) {
2993 return DIRECTIVE_FOUND;
2995 ed_p = (ExpDef **) hash_findi(&expdefs, spec.name, NULL);
2996 while (ed_p && *ed_p) {
2997 ed = *ed_p;
2998 if (ed->casesense == spec.casesense &&
2999 !mstrcmp(ed->name, spec.name, spec.casesense) &&
3000 ed->nparam_min == spec.nparam_min &&
3001 ed->nparam_max == spec.nparam_max &&
3002 ed->plus == spec.plus) {
3003 *ed_p = ed->next;
3004 free_expdef(ed);
3005 } else {
3006 ed_p = &ed->next;
3009 free_tlist(origline);
3010 free_tlist(spec.dlist);
3011 return DIRECTIVE_FOUND;
3014 case PP_ROTATE:
3015 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3016 if (tline->next && tline->next->type == TOK_WHITESPACE)
3017 tline = tline->next;
3018 if (!tline->next) {
3019 free_tlist(origline);
3020 error(ERR_NONFATAL, "`%%rotate' missing rotate count");
3021 return DIRECTIVE_FOUND;
3023 t = expand_smacro(tline->next);
3024 tline->next = NULL;
3025 free_tlist(origline);
3026 tline = t;
3027 tptr = &t;
3028 tokval.t_type = TOKEN_INVALID;
3029 evalresult =
3030 evaluate(ppscan, tptr, &tokval, NULL, pass, error, NULL);
3031 free_tlist(tline);
3032 if (!evalresult)
3033 return DIRECTIVE_FOUND;
3034 if (tokval.t_type)
3035 error(ERR_WARNING|ERR_PASS1,
3036 "trailing garbage after expression ignored");
3037 if (!is_simple(evalresult)) {
3038 error(ERR_NONFATAL, "non-constant value given to `%%rotate'");
3039 return DIRECTIVE_FOUND;
3041 for (ei = istk->expansion; ei != NULL; ei = ei->prev) {
3042 if (ei->type == EXP_MMACRO) {
3043 break;
3046 if (ei == NULL) {
3047 error(ERR_NONFATAL, "`%%rotate' invoked outside a macro call");
3048 } else if (ei->nparam == 0) {
3049 error(ERR_NONFATAL,
3050 "`%%rotate' invoked within macro without parameters");
3051 } else {
3052 int rotate = ei->rotate + reloc_value(evalresult);
3054 rotate %= (int)ei->nparam;
3055 if (rotate < 0)
3056 rotate += ei->nparam;
3057 ei->rotate = rotate;
3059 return DIRECTIVE_FOUND;
3061 case PP_REP:
3062 if (defining != NULL) {
3063 if (defining->type == EXP_REP) {
3064 defining->def_depth ++;
3066 return NO_DIRECTIVE_FOUND;
3068 nolist = false;
3069 do {
3070 tline = tline->next;
3071 } while (tok_type_(tline, TOK_WHITESPACE));
3073 if (tok_type_(tline, TOK_ID) &&
3074 nasm_stricmp(tline->text, ".nolist") == 0) {
3075 nolist = true;
3076 do {
3077 tline = tline->next;
3078 } while (tok_type_(tline, TOK_WHITESPACE));
3081 if (tline) {
3082 t = expand_smacro(tline);
3083 tptr = &t;
3084 tokval.t_type = TOKEN_INVALID;
3085 evalresult =
3086 evaluate(ppscan, tptr, &tokval, NULL, pass, error, NULL);
3087 if (!evalresult) {
3088 free_tlist(origline);
3089 return DIRECTIVE_FOUND;
3091 if (tokval.t_type)
3092 error(ERR_WARNING|ERR_PASS1,
3093 "trailing garbage after expression ignored");
3094 if (!is_simple(evalresult)) {
3095 error(ERR_NONFATAL, "non-constant value given to `%%rep'");
3096 return DIRECTIVE_FOUND;
3098 count = reloc_value(evalresult);
3099 if (count >= REP_LIMIT) {
3100 error(ERR_NONFATAL, "`%%rep' value exceeds limit");
3101 count = 0;
3102 } else
3103 count++;
3104 } else {
3105 error(ERR_NONFATAL, "`%%rep' expects a repeat count");
3106 count = 0;
3108 free_tlist(origline);
3109 ed = new_ExpDef(EXP_REP);
3110 ed->nolist = nolist;
3111 ed->def_depth = 0;
3112 ed->cur_depth = 1;
3113 ed->max_depth = (count - 1);
3114 ed->ignoring = false;
3115 ed->prev = defining;
3116 defining = ed;
3117 return DIRECTIVE_FOUND;
3119 case PP_ENDREP:
3120 if (defining != NULL) {
3121 if (defining->type == EXP_REP) {
3122 if (defining->def_depth > 0) {
3123 defining->def_depth --;
3124 return NO_DIRECTIVE_FOUND;
3126 } else {
3127 return NO_DIRECTIVE_FOUND;
3130 if ((defining == NULL) || (defining->type != EXP_REP)) {
3131 error(ERR_NONFATAL, "`%%endrep': no matching `%%rep'");
3132 return DIRECTIVE_FOUND;
3136 * Now we have a "macro" defined - although it has no name
3137 * and we won't be entering it in the hash tables - we must
3138 * push a macro-end marker for it on to istk->expansion.
3139 * After that, it will take care of propagating itself (a
3140 * macro-end marker line for a macro which is really a %rep
3141 * block will cause the macro to be re-expanded, complete
3142 * with another macro-end marker to ensure the process
3143 * continues) until the whole expansion is forcibly removed
3144 * from istk->expansion by a %exitrep.
3146 ed = defining;
3147 defining = ed->prev;
3148 ed->prev = expansions;
3149 expansions = ed;
3150 ei = new_ExpInv(EXP_REP, ed);
3151 ei->current = ed->line;
3152 ei->emitting = ((ed->max_depth > 0) ? true : false);
3153 list->uplevel(ed->nolist ? LIST_MACRO_NOLIST : LIST_MACRO);
3154 ei->prev = istk->expansion;
3155 istk->expansion = ei;
3156 free_tlist(origline);
3157 return DIRECTIVE_FOUND;
3159 case PP_EXITREP:
3160 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3162 * We must search along istk->expansion until we hit a
3163 * rep invocation. Then we disable the emitting state(s)
3164 * between exitrep and endrep.
3166 for (ei = istk->expansion; ei != NULL; ei = ei->prev) {
3167 if (ei->type == EXP_REP) {
3168 break;
3172 if (ei != NULL) {
3174 * Set all invocations leading back to the rep
3175 * invocation to a non-emitting state.
3177 for (eei = istk->expansion; eei != ei; eei = eei->prev) {
3178 eei->emitting = false;
3180 eei->emitting = false;
3181 eei->current = NULL;
3182 eei->def->cur_depth = eei->def->max_depth;
3183 } else {
3184 error(ERR_NONFATAL, "`%%exitrep' not within `%%rep' block");
3186 free_tlist(origline);
3187 return DIRECTIVE_FOUND;
3189 case PP_XDEFINE:
3190 case PP_IXDEFINE:
3191 case PP_DEFINE:
3192 case PP_IDEFINE:
3193 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3194 casesense = (i == PP_DEFINE || i == PP_XDEFINE);
3196 tline = tline->next;
3197 skip_white_(tline);
3198 tline = expand_id(tline);
3199 if (!tline || (tline->type != TOK_ID &&
3200 (tline->type != TOK_PREPROC_ID ||
3201 tline->text[1] != '$'))) {
3202 error(ERR_NONFATAL, "`%s' expects a macro identifier",
3203 pp_directives[i]);
3204 free_tlist(origline);
3205 return DIRECTIVE_FOUND;
3208 ctx = get_ctx(tline->text, &mname, false);
3209 last = tline;
3210 param_start = tline = tline->next;
3211 nparam = 0;
3213 /* Expand the macro definition now for %xdefine and %ixdefine */
3214 if ((i == PP_XDEFINE) || (i == PP_IXDEFINE))
3215 tline = expand_smacro(tline);
3217 if (tok_is_(tline, "(")) {
3219 * This macro has parameters.
3222 tline = tline->next;
3223 while (1) {
3224 skip_white_(tline);
3225 if (!tline) {
3226 error(ERR_NONFATAL, "parameter identifier expected");
3227 free_tlist(origline);
3228 return DIRECTIVE_FOUND;
3230 if (tline->type != TOK_ID) {
3231 error(ERR_NONFATAL,
3232 "`%s': parameter identifier expected",
3233 tline->text);
3234 free_tlist(origline);
3235 return DIRECTIVE_FOUND;
3237 tline->type = TOK_SMAC_PARAM + nparam++;
3238 tline = tline->next;
3239 skip_white_(tline);
3240 if (tok_is_(tline, ",")) {
3241 tline = tline->next;
3242 } else {
3243 if (!tok_is_(tline, ")")) {
3244 error(ERR_NONFATAL,
3245 "`)' expected to terminate macro template");
3246 free_tlist(origline);
3247 return DIRECTIVE_FOUND;
3249 break;
3252 last = tline;
3253 tline = tline->next;
3255 if (tok_type_(tline, TOK_WHITESPACE))
3256 last = tline, tline = tline->next;
3257 macro_start = NULL;
3258 last->next = NULL;
3259 t = tline;
3260 while (t) {
3261 if (t->type == TOK_ID) {
3262 list_for_each(tt, param_start)
3263 if (tt->type >= TOK_SMAC_PARAM &&
3264 !strcmp(tt->text, t->text))
3265 t->type = tt->type;
3267 tt = t->next;
3268 t->next = macro_start;
3269 macro_start = t;
3270 t = tt;
3273 * Good. We now have a macro name, a parameter count, and a
3274 * token list (in reverse order) for an expansion. We ought
3275 * to be OK just to create an SMacro, store it, and let
3276 * free_tlist have the rest of the line (which we have
3277 * carefully re-terminated after chopping off the expansion
3278 * from the end).
3280 define_smacro(ctx, mname, casesense, nparam, macro_start);
3281 free_tlist(origline);
3282 return DIRECTIVE_FOUND;
3284 case PP_UNDEF:
3285 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3286 tline = tline->next;
3287 skip_white_(tline);
3288 tline = expand_id(tline);
3289 if (!tline || (tline->type != TOK_ID &&
3290 (tline->type != TOK_PREPROC_ID ||
3291 tline->text[1] != '$'))) {
3292 error(ERR_NONFATAL, "`%%undef' expects a macro identifier");
3293 free_tlist(origline);
3294 return DIRECTIVE_FOUND;
3296 if (tline->next) {
3297 error(ERR_WARNING|ERR_PASS1,
3298 "trailing garbage after macro name ignored");
3301 /* Find the context that symbol belongs to */
3302 ctx = get_ctx(tline->text, &mname, false);
3303 undef_smacro(ctx, mname);
3304 free_tlist(origline);
3305 return DIRECTIVE_FOUND;
3307 case PP_DEFSTR:
3308 case PP_IDEFSTR:
3309 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3310 casesense = (i == PP_DEFSTR);
3312 tline = tline->next;
3313 skip_white_(tline);
3314 tline = expand_id(tline);
3315 if (!tline || (tline->type != TOK_ID &&
3316 (tline->type != TOK_PREPROC_ID ||
3317 tline->text[1] != '$'))) {
3318 error(ERR_NONFATAL, "`%s' expects a macro identifier",
3319 pp_directives[i]);
3320 free_tlist(origline);
3321 return DIRECTIVE_FOUND;
3324 ctx = get_ctx(tline->text, &mname, false);
3325 last = tline;
3326 tline = expand_smacro(tline->next);
3327 last->next = NULL;
3329 while (tok_type_(tline, TOK_WHITESPACE))
3330 tline = delete_Token(tline);
3332 p = detoken(tline, false);
3333 macro_start = nasm_malloc(sizeof(*macro_start));
3334 macro_start->next = NULL;
3335 macro_start->text = nasm_quote(p, strlen(p));
3336 macro_start->type = TOK_STRING;
3337 macro_start->a.mac = NULL;
3338 nasm_free(p);
3341 * We now have a macro name, an implicit parameter count of
3342 * zero, and a string token to use as an expansion. Create
3343 * and store an SMacro.
3345 define_smacro(ctx, mname, casesense, 0, macro_start);
3346 free_tlist(origline);
3347 return DIRECTIVE_FOUND;
3349 case PP_DEFTOK:
3350 case PP_IDEFTOK:
3351 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3352 casesense = (i == PP_DEFTOK);
3354 tline = tline->next;
3355 skip_white_(tline);
3356 tline = expand_id(tline);
3357 if (!tline || (tline->type != TOK_ID &&
3358 (tline->type != TOK_PREPROC_ID ||
3359 tline->text[1] != '$'))) {
3360 error(ERR_NONFATAL,
3361 "`%s' expects a macro identifier as first parameter",
3362 pp_directives[i]);
3363 free_tlist(origline);
3364 return DIRECTIVE_FOUND;
3366 ctx = get_ctx(tline->text, &mname, false);
3367 last = tline;
3368 tline = expand_smacro(tline->next);
3369 last->next = NULL;
3371 t = tline;
3372 while (tok_type_(t, TOK_WHITESPACE))
3373 t = t->next;
3374 /* t should now point to the string */
3375 if (!tok_type_(t, TOK_STRING)) {
3376 error(ERR_NONFATAL,
3377 "`%s` requires string as second parameter",
3378 pp_directives[i]);
3379 free_tlist(tline);
3380 free_tlist(origline);
3381 return DIRECTIVE_FOUND;
3385 * Convert the string to a token stream. Note that smacros
3386 * are stored with the token stream reversed, so we have to
3387 * reverse the output of tokenize().
3389 nasm_unquote_cstr(t->text, i);
3390 macro_start = reverse_tokens(tokenize(t->text));
3393 * We now have a macro name, an implicit parameter count of
3394 * zero, and a numeric token to use as an expansion. Create
3395 * and store an SMacro.
3397 define_smacro(ctx, mname, casesense, 0, macro_start);
3398 free_tlist(tline);
3399 free_tlist(origline);
3400 return DIRECTIVE_FOUND;
3402 case PP_PATHSEARCH:
3403 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3405 FILE *fp;
3406 StrList *xsl = NULL;
3407 StrList **xst = &xsl;
3409 casesense = true;
3411 tline = tline->next;
3412 skip_white_(tline);
3413 tline = expand_id(tline);
3414 if (!tline || (tline->type != TOK_ID &&
3415 (tline->type != TOK_PREPROC_ID ||
3416 tline->text[1] != '$'))) {
3417 error(ERR_NONFATAL,
3418 "`%%pathsearch' expects a macro identifier as first parameter");
3419 free_tlist(origline);
3420 return DIRECTIVE_FOUND;
3422 ctx = get_ctx(tline->text, &mname, false);
3423 last = tline;
3424 tline = expand_smacro(tline->next);
3425 last->next = NULL;
3427 t = tline;
3428 while (tok_type_(t, TOK_WHITESPACE))
3429 t = t->next;
3431 if (!t || (t->type != TOK_STRING &&
3432 t->type != TOK_INTERNAL_STRING)) {
3433 error(ERR_NONFATAL, "`%%pathsearch' expects a file name");
3434 free_tlist(tline);
3435 free_tlist(origline);
3436 return DIRECTIVE_FOUND; /* but we did _something_ */
3438 if (t->next)
3439 error(ERR_WARNING|ERR_PASS1,
3440 "trailing garbage after `%%pathsearch' ignored");
3441 p = t->text;
3442 if (t->type != TOK_INTERNAL_STRING)
3443 nasm_unquote(p, NULL);
3445 fp = inc_fopen(p, &xsl, &xst, true);
3446 if (fp) {
3447 p = xsl->str;
3448 fclose(fp); /* Don't actually care about the file */
3450 macro_start = nasm_malloc(sizeof(*macro_start));
3451 macro_start->next = NULL;
3452 macro_start->text = nasm_quote(p, strlen(p));
3453 macro_start->type = TOK_STRING;
3454 macro_start->a.mac = NULL;
3455 if (xsl)
3456 nasm_free(xsl);
3459 * We now have a macro name, an implicit parameter count of
3460 * zero, and a string token to use as an expansion. Create
3461 * and store an SMacro.
3463 define_smacro(ctx, mname, casesense, 0, macro_start);
3464 free_tlist(tline);
3465 free_tlist(origline);
3466 return DIRECTIVE_FOUND;
3469 case PP_STRLEN:
3470 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3471 casesense = true;
3473 tline = tline->next;
3474 skip_white_(tline);
3475 tline = expand_id(tline);
3476 if (!tline || (tline->type != TOK_ID &&
3477 (tline->type != TOK_PREPROC_ID ||
3478 tline->text[1] != '$'))) {
3479 error(ERR_NONFATAL,
3480 "`%%strlen' expects a macro identifier as first parameter");
3481 free_tlist(origline);
3482 return DIRECTIVE_FOUND;
3484 ctx = get_ctx(tline->text, &mname, false);
3485 last = tline;
3486 tline = expand_smacro(tline->next);
3487 last->next = NULL;
3489 t = tline;
3490 while (tok_type_(t, TOK_WHITESPACE))
3491 t = t->next;
3492 /* t should now point to the string */
3493 if (!tok_type_(t, TOK_STRING)) {
3494 error(ERR_NONFATAL,
3495 "`%%strlen` requires string as second parameter");
3496 free_tlist(tline);
3497 free_tlist(origline);
3498 return DIRECTIVE_FOUND;
3501 macro_start = nasm_malloc(sizeof(*macro_start));
3502 macro_start->next = NULL;
3503 make_tok_num(macro_start, nasm_unquote(t->text, NULL));
3504 macro_start->a.mac = NULL;
3507 * We now have a macro name, an implicit parameter count of
3508 * zero, and a numeric token to use as an expansion. Create
3509 * and store an SMacro.
3511 define_smacro(ctx, mname, casesense, 0, macro_start);
3512 free_tlist(tline);
3513 free_tlist(origline);
3514 return DIRECTIVE_FOUND;
3516 case PP_STRCAT:
3517 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3518 casesense = true;
3520 tline = tline->next;
3521 skip_white_(tline);
3522 tline = expand_id(tline);
3523 if (!tline || (tline->type != TOK_ID &&
3524 (tline->type != TOK_PREPROC_ID ||
3525 tline->text[1] != '$'))) {
3526 error(ERR_NONFATAL,
3527 "`%%strcat' expects a macro identifier as first parameter");
3528 free_tlist(origline);
3529 return DIRECTIVE_FOUND;
3531 ctx = get_ctx(tline->text, &mname, false);
3532 last = tline;
3533 tline = expand_smacro(tline->next);
3534 last->next = NULL;
3536 len = 0;
3537 list_for_each(t, tline) {
3538 switch (t->type) {
3539 case TOK_WHITESPACE:
3540 break;
3541 case TOK_STRING:
3542 len += t->a.len = nasm_unquote(t->text, NULL);
3543 break;
3544 case TOK_OTHER:
3545 if (!strcmp(t->text, ",")) /* permit comma separators */
3546 break;
3547 /* else fall through */
3548 default:
3549 error(ERR_NONFATAL,
3550 "non-string passed to `%%strcat' (%d)", t->type);
3551 free_tlist(tline);
3552 free_tlist(origline);
3553 return DIRECTIVE_FOUND;
3557 p = pp = nasm_malloc(len);
3558 list_for_each(t, tline) {
3559 if (t->type == TOK_STRING) {
3560 memcpy(p, t->text, t->a.len);
3561 p += t->a.len;
3566 * We now have a macro name, an implicit parameter count of
3567 * zero, and a numeric token to use as an expansion. Create
3568 * and store an SMacro.
3570 macro_start = new_Token(NULL, TOK_STRING, NULL, 0);
3571 macro_start->text = nasm_quote(pp, len);
3572 nasm_free(pp);
3573 define_smacro(ctx, mname, casesense, 0, macro_start);
3574 free_tlist(tline);
3575 free_tlist(origline);
3576 return DIRECTIVE_FOUND;
3578 case PP_SUBSTR:
3579 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3581 int64_t start, count;
3582 size_t len;
3584 casesense = true;
3586 tline = tline->next;
3587 skip_white_(tline);
3588 tline = expand_id(tline);
3589 if (!tline || (tline->type != TOK_ID &&
3590 (tline->type != TOK_PREPROC_ID ||
3591 tline->text[1] != '$'))) {
3592 error(ERR_NONFATAL,
3593 "`%%substr' expects a macro identifier as first parameter");
3594 free_tlist(origline);
3595 return DIRECTIVE_FOUND;
3597 ctx = get_ctx(tline->text, &mname, false);
3598 last = tline;
3599 tline = expand_smacro(tline->next);
3600 last->next = NULL;
3602 if (tline) /* skip expanded id */
3603 t = tline->next;
3604 while (tok_type_(t, TOK_WHITESPACE))
3605 t = t->next;
3607 /* t should now point to the string */
3608 if (!tok_type_(t, TOK_STRING)) {
3609 error(ERR_NONFATAL,
3610 "`%%substr` requires string as second parameter");
3611 free_tlist(tline);
3612 free_tlist(origline);
3613 return DIRECTIVE_FOUND;
3616 tt = t->next;
3617 tptr = &tt;
3618 tokval.t_type = TOKEN_INVALID;
3619 evalresult = evaluate(ppscan, tptr, &tokval, NULL,
3620 pass, error, NULL);
3621 if (!evalresult) {
3622 free_tlist(tline);
3623 free_tlist(origline);
3624 return DIRECTIVE_FOUND;
3625 } else if (!is_simple(evalresult)) {
3626 error(ERR_NONFATAL, "non-constant value given to `%%substr`");
3627 free_tlist(tline);
3628 free_tlist(origline);
3629 return DIRECTIVE_FOUND;
3631 start = evalresult->value - 1;
3633 while (tok_type_(tt, TOK_WHITESPACE))
3634 tt = tt->next;
3635 if (!tt) {
3636 count = 1; /* Backwards compatibility: one character */
3637 } else {
3638 tokval.t_type = TOKEN_INVALID;
3639 evalresult = evaluate(ppscan, tptr, &tokval, NULL,
3640 pass, error, NULL);
3641 if (!evalresult) {
3642 free_tlist(tline);
3643 free_tlist(origline);
3644 return DIRECTIVE_FOUND;
3645 } else if (!is_simple(evalresult)) {
3646 error(ERR_NONFATAL, "non-constant value given to `%%substr`");
3647 free_tlist(tline);
3648 free_tlist(origline);
3649 return DIRECTIVE_FOUND;
3651 count = evalresult->value;
3654 len = nasm_unquote(t->text, NULL);
3655 /* make start and count being in range */
3656 if (start < 0)
3657 start = 0;
3658 if (count < 0)
3659 count = len + count + 1 - start;
3660 if (start + count > (int64_t)len)
3661 count = len - start;
3662 if (!len || count < 0 || start >=(int64_t)len)
3663 start = -1, count = 0; /* empty string */
3665 macro_start = nasm_malloc(sizeof(*macro_start));
3666 macro_start->next = NULL;
3667 macro_start->text = nasm_quote((start < 0) ? "" : t->text + start, count);
3668 macro_start->type = TOK_STRING;
3669 macro_start->a.mac = NULL;
3672 * We now have a macro name, an implicit parameter count of
3673 * zero, and a numeric token to use as an expansion. Create
3674 * and store an SMacro.
3676 define_smacro(ctx, mname, casesense, 0, macro_start);
3677 free_tlist(tline);
3678 free_tlist(origline);
3679 return DIRECTIVE_FOUND;
3682 case PP_ASSIGN:
3683 case PP_IASSIGN:
3684 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3685 casesense = (i == PP_ASSIGN);
3687 tline = tline->next;
3688 skip_white_(tline);
3689 tline = expand_id(tline);
3690 if (!tline || (tline->type != TOK_ID &&
3691 (tline->type != TOK_PREPROC_ID ||
3692 tline->text[1] != '$'))) {
3693 error(ERR_NONFATAL,
3694 "`%%%sassign' expects a macro identifier",
3695 (i == PP_IASSIGN ? "i" : ""));
3696 free_tlist(origline);
3697 return DIRECTIVE_FOUND;
3699 ctx = get_ctx(tline->text, &mname, false);
3700 last = tline;
3701 tline = expand_smacro(tline->next);
3702 last->next = NULL;
3704 t = tline;
3705 tptr = &t;
3706 tokval.t_type = TOKEN_INVALID;
3707 evalresult =
3708 evaluate(ppscan, tptr, &tokval, NULL, pass, error, NULL);
3709 free_tlist(tline);
3710 if (!evalresult) {
3711 free_tlist(origline);
3712 return DIRECTIVE_FOUND;
3715 if (tokval.t_type)
3716 error(ERR_WARNING|ERR_PASS1,
3717 "trailing garbage after expression ignored");
3719 if (!is_simple(evalresult)) {
3720 error(ERR_NONFATAL,
3721 "non-constant value given to `%%%sassign'",
3722 (i == PP_IASSIGN ? "i" : ""));
3723 free_tlist(origline);
3724 return DIRECTIVE_FOUND;
3727 macro_start = nasm_malloc(sizeof(*macro_start));
3728 macro_start->next = NULL;
3729 make_tok_num(macro_start, reloc_value(evalresult));
3730 macro_start->a.mac = NULL;
3733 * We now have a macro name, an implicit parameter count of
3734 * zero, and a numeric token to use as an expansion. Create
3735 * and store an SMacro.
3737 define_smacro(ctx, mname, casesense, 0, macro_start);
3738 free_tlist(origline);
3739 return DIRECTIVE_FOUND;
3741 case PP_LINE:
3742 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3744 * Syntax is `%line nnn[+mmm] [filename]'
3746 tline = tline->next;
3747 skip_white_(tline);
3748 if (!tok_type_(tline, TOK_NUMBER)) {
3749 error(ERR_NONFATAL, "`%%line' expects line number");
3750 free_tlist(origline);
3751 return DIRECTIVE_FOUND;
3753 k = readnum(tline->text, &err);
3754 m = 1;
3755 tline = tline->next;
3756 if (tok_is_(tline, "+")) {
3757 tline = tline->next;
3758 if (!tok_type_(tline, TOK_NUMBER)) {
3759 error(ERR_NONFATAL, "`%%line' expects line increment");
3760 free_tlist(origline);
3761 return DIRECTIVE_FOUND;
3763 m = readnum(tline->text, &err);
3764 tline = tline->next;
3766 skip_white_(tline);
3767 src_set_linnum(k);
3768 istk->lineinc = m;
3769 if (tline) {
3770 nasm_free(src_set_fname(detoken(tline, false)));
3772 free_tlist(origline);
3773 return DIRECTIVE_FOUND;
3775 case PP_WHILE:
3776 if (defining != NULL) {
3777 if (defining->type == EXP_WHILE) {
3778 defining->def_depth ++;
3780 return NO_DIRECTIVE_FOUND;
3782 l = NULL;
3783 if ((istk->expansion != NULL) &&
3784 (istk->expansion->emitting == false)) {
3785 j = COND_NEVER;
3786 } else {
3787 l = new_Line();
3788 l->first = copy_Token(tline->next);
3789 j = if_condition(tline->next, i);
3790 tline->next = NULL; /* it got freed */
3791 j = (((j < 0) ? COND_NEVER : j) ? COND_IF_TRUE : COND_IF_FALSE);
3793 ed = new_ExpDef(EXP_WHILE);
3794 ed->state = j;
3795 ed->cur_depth = 1;
3796 ed->max_depth = DEADMAN_LIMIT;
3797 ed->ignoring = ((ed->state == COND_IF_TRUE) ? false : true);
3798 if (ed->ignoring == false) {
3799 ed->line = l;
3800 ed->last = l;
3801 } else if (l != NULL) {
3802 delete_Token(l->first);
3803 nasm_free(l);
3804 l = NULL;
3806 ed->prev = defining;
3807 defining = ed;
3808 free_tlist(origline);
3809 return DIRECTIVE_FOUND;
3811 case PP_ENDWHILE:
3812 if (defining != NULL) {
3813 if (defining->type == EXP_WHILE) {
3814 if (defining->def_depth > 0) {
3815 defining->def_depth --;
3816 return NO_DIRECTIVE_FOUND;
3818 } else {
3819 return NO_DIRECTIVE_FOUND;
3822 if (tline->next != NULL) {
3823 error_precond(ERR_WARNING|ERR_PASS1,
3824 "trailing garbage after `%%endwhile' ignored");
3826 if ((defining == NULL) || (defining->type != EXP_WHILE)) {
3827 error(ERR_NONFATAL, "`%%endwhile': no matching `%%while'");
3828 return DIRECTIVE_FOUND;
3830 ed = defining;
3831 defining = ed->prev;
3832 if (ed->ignoring == false) {
3833 ed->prev = expansions;
3834 expansions = ed;
3835 ei = new_ExpInv(EXP_WHILE, ed);
3836 ei->current = ed->line->next;
3837 ei->emitting = true;
3838 ei->prev = istk->expansion;
3839 istk->expansion = ei;
3840 } else {
3841 nasm_free(ed);
3843 free_tlist(origline);
3844 return DIRECTIVE_FOUND;
3846 case PP_EXITWHILE:
3847 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3849 * We must search along istk->expansion until we hit a
3850 * while invocation. Then we disable the emitting state(s)
3851 * between exitwhile and endwhile.
3853 for (ei = istk->expansion; ei != NULL; ei = ei->prev) {
3854 if (ei->type == EXP_WHILE) {
3855 break;
3859 if (ei != NULL) {
3861 * Set all invocations leading back to the while
3862 * invocation to a non-emitting state.
3864 for (eei = istk->expansion; eei != ei; eei = eei->prev) {
3865 eei->emitting = false;
3867 eei->emitting = false;
3868 eei->current = NULL;
3869 eei->def->cur_depth = eei->def->max_depth;
3870 } else {
3871 error(ERR_NONFATAL, "`%%exitwhile' not within `%%while' block");
3873 free_tlist(origline);
3874 return DIRECTIVE_FOUND;
3876 case PP_COMMENT:
3877 if (defining != NULL) {
3878 if (defining->type == EXP_COMMENT) {
3879 defining->def_depth ++;
3881 return NO_DIRECTIVE_FOUND;
3883 ed = new_ExpDef(EXP_COMMENT);
3884 ed->ignoring = true;
3885 ed->prev = defining;
3886 defining = ed;
3887 free_tlist(origline);
3888 return DIRECTIVE_FOUND;
3890 case PP_ENDCOMMENT:
3891 if (defining != NULL) {
3892 if (defining->type == EXP_COMMENT) {
3893 if (defining->def_depth > 0) {
3894 defining->def_depth --;
3895 return NO_DIRECTIVE_FOUND;
3897 } else {
3898 return NO_DIRECTIVE_FOUND;
3901 if ((defining == NULL) || (defining->type != EXP_COMMENT)) {
3902 error(ERR_NONFATAL, "`%%endcomment': no matching `%%comment'");
3903 return DIRECTIVE_FOUND;
3905 ed = defining;
3906 defining = ed->prev;
3907 nasm_free(ed);
3908 free_tlist(origline);
3909 return DIRECTIVE_FOUND;
3911 case PP_FINAL:
3912 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3913 if (in_final != false) {
3914 error(ERR_FATAL, "`%%final' cannot be used recursively");
3916 tline = tline->next;
3917 skip_white_(tline);
3918 if (tline == NULL) {
3919 error(ERR_NONFATAL, "`%%final' expects at least one parameter");
3920 } else {
3921 l = new_Line();
3922 l->first = copy_Token(tline);
3923 l->next = finals;
3924 finals = l;
3926 free_tlist(origline);
3927 return DIRECTIVE_FOUND;
3929 default:
3930 error(ERR_FATAL,
3931 "preprocessor directive `%s' not yet implemented",
3932 pp_directives[i]);
3933 return DIRECTIVE_FOUND;
3938 * Ensure that a macro parameter contains a condition code and
3939 * nothing else. Return the condition code index if so, or -1
3940 * otherwise.
3942 static int find_cc(Token * t)
3944 Token *tt;
3945 int i, j, k, m;
3947 if (!t)
3948 return -1; /* Probably a %+ without a space */
3950 skip_white_(t);
3951 if (t->type != TOK_ID)
3952 return -1;
3953 tt = t->next;
3954 skip_white_(tt);
3955 if (tt && (tt->type != TOK_OTHER || strcmp(tt->text, ",")))
3956 return -1;
3958 i = -1;
3959 j = ARRAY_SIZE(conditions);
3960 while (j - i > 1) {
3961 k = (j + i) / 2;
3962 m = nasm_stricmp(t->text, conditions[k]);
3963 if (m == 0) {
3964 i = k;
3965 j = -2;
3966 break;
3967 } else if (m < 0) {
3968 j = k;
3969 } else
3970 i = k;
3972 if (j != -2)
3973 return -1;
3974 return i;
3977 static bool paste_tokens(Token **head, const struct tokseq_match *m,
3978 int mnum, bool handle_paste_tokens)
3980 Token **tail, *t, *tt;
3981 Token **paste_head;
3982 bool did_paste = false;
3983 char *tmp;
3984 int i;
3986 /* Now handle token pasting... */
3987 paste_head = NULL;
3988 tail = head;
3989 while ((t = *tail) && (tt = t->next)) {
3990 switch (t->type) {
3991 case TOK_WHITESPACE:
3992 if (tt->type == TOK_WHITESPACE) {
3993 /* Zap adjacent whitespace tokens */
3994 t->next = delete_Token(tt);
3995 } else {
3996 /* Do not advance paste_head here */
3997 tail = &t->next;
3999 break;
4000 case TOK_PASTE: /* %+ */
4001 if (handle_paste_tokens) {
4002 /* Zap %+ and whitespace tokens to the right */
4003 while (t && (t->type == TOK_WHITESPACE ||
4004 t->type == TOK_PASTE))
4005 t = *tail = delete_Token(t);
4006 if (!paste_head || !t)
4007 break; /* Nothing to paste with */
4008 tail = paste_head;
4009 t = *tail;
4010 tt = t->next;
4011 while (tok_type_(tt, TOK_WHITESPACE))
4012 tt = t->next = delete_Token(tt);
4013 if (tt) {
4014 tmp = nasm_strcat(t->text, tt->text);
4015 delete_Token(t);
4016 tt = delete_Token(tt);
4017 t = *tail = tokenize(tmp);
4018 nasm_free(tmp);
4019 while (t->next) {
4020 tail = &t->next;
4021 t = t->next;
4023 t->next = tt; /* Attach the remaining token chain */
4024 did_paste = true;
4026 paste_head = tail;
4027 tail = &t->next;
4028 break;
4030 /* else fall through */
4031 default:
4033 * Concatenation of tokens might look nontrivial
4034 * but in real it's pretty simple -- the caller
4035 * prepares the masks of token types to be concatenated
4036 * and we simply find matched sequences and slip
4037 * them together
4039 for (i = 0; i < mnum; i++) {
4040 if (PP_CONCAT_MASK(t->type) & m[i].mask_head) {
4041 size_t len = 0;
4042 char *tmp, *p;
4044 while (tt && (PP_CONCAT_MASK(tt->type) & m[i].mask_tail)) {
4045 len += strlen(tt->text);
4046 tt = tt->next;
4050 * Now tt points to the first token after
4051 * the potential paste area...
4053 if (tt != t->next) {
4054 /* We have at least two tokens... */
4055 len += strlen(t->text);
4056 p = tmp = nasm_malloc(len+1);
4057 while (t != tt) {
4058 strcpy(p, t->text);
4059 p = strchr(p, '\0');
4060 t = delete_Token(t);
4062 t = *tail = tokenize(tmp);
4063 nasm_free(tmp);
4064 while (t->next) {
4065 tail = &t->next;
4066 t = t->next;
4068 t->next = tt; /* Attach the remaining token chain */
4069 did_paste = true;
4071 paste_head = tail;
4072 tail = &t->next;
4073 break;
4076 if (i >= mnum) { /* no match */
4077 tail = &t->next;
4078 if (!tok_type_(t->next, TOK_WHITESPACE))
4079 paste_head = tail;
4081 break;
4084 return did_paste;
4088 * expands to a list of tokens from %{x:y}
4090 static Token *expand_mmac_params_range(ExpInv *ei, Token *tline, Token ***last)
4092 Token *t = tline, **tt, *tm, *head;
4093 char *pos;
4094 int fst, lst, j, i;
4096 pos = strchr(tline->text, ':');
4097 nasm_assert(pos);
4099 lst = atoi(pos + 1);
4100 fst = atoi(tline->text + 1);
4103 * only macros params are accounted so
4104 * if someone passes %0 -- we reject such
4105 * value(s)
4107 if (lst == 0 || fst == 0)
4108 goto err;
4110 /* the values should be sane */
4111 if ((fst > (int)ei->nparam || fst < (-(int)ei->nparam)) ||
4112 (lst > (int)ei->nparam || lst < (-(int)ei->nparam)))
4113 goto err;
4115 fst = fst < 0 ? fst + (int)ei->nparam + 1: fst;
4116 lst = lst < 0 ? lst + (int)ei->nparam + 1: lst;
4118 /* counted from zero */
4119 fst--, lst--;
4122 * it will be at least one token
4124 tm = ei->params[(fst + ei->rotate) % ei->nparam];
4125 t = new_Token(NULL, tm->type, tm->text, 0);
4126 head = t, tt = &t->next;
4127 if (fst < lst) {
4128 for (i = fst + 1; i <= lst; i++) {
4129 t = new_Token(NULL, TOK_OTHER, ",", 0);
4130 *tt = t, tt = &t->next;
4131 j = (i + ei->rotate) % ei->nparam;
4132 tm = ei->params[j];
4133 t = new_Token(NULL, tm->type, tm->text, 0);
4134 *tt = t, tt = &t->next;
4136 } else {
4137 for (i = fst - 1; i >= lst; i--) {
4138 t = new_Token(NULL, TOK_OTHER, ",", 0);
4139 *tt = t, tt = &t->next;
4140 j = (i + ei->rotate) % ei->nparam;
4141 tm = ei->params[j];
4142 t = new_Token(NULL, tm->type, tm->text, 0);
4143 *tt = t, tt = &t->next;
4147 *last = tt;
4148 return head;
4150 err:
4151 error(ERR_NONFATAL, "`%%{%s}': macro parameters out of range",
4152 &tline->text[1]);
4153 return tline;
4157 * Expand MMacro-local things: parameter references (%0, %n, %+n,
4158 * %-n) and MMacro-local identifiers (%%foo) as well as
4159 * macro indirection (%[...]) and range (%{..:..}).
4161 static Token *expand_mmac_params(Token * tline)
4163 Token *t, *tt, **tail, *thead;
4164 bool changed = false;
4165 char *pos;
4167 tail = &thead;
4168 thead = NULL;
4170 while (tline) {
4171 if (tline->type == TOK_PREPROC_ID &&
4172 (((tline->text[1] == '+' || tline->text[1] == '-') && tline->text[2]) ||
4173 (tline->text[1] >= '0' && tline->text[1] <= '9') ||
4174 tline->text[1] == '%')) {
4175 char *text = NULL;
4176 int type = 0, cc; /* type = 0 to placate optimisers */
4177 char tmpbuf[30];
4178 unsigned int n;
4179 int i;
4180 ExpInv *ei;
4182 t = tline;
4183 tline = tline->next;
4185 for (ei = istk->expansion; ei != NULL; ei = ei->prev) {
4186 if (ei->type == EXP_MMACRO) {
4187 break;
4190 if (ei == NULL) {
4191 error(ERR_NONFATAL, "`%s': not in a macro call", t->text);
4192 } else {
4193 pos = strchr(t->text, ':');
4194 if (!pos) {
4195 switch (t->text[1]) {
4197 * We have to make a substitution of one of the
4198 * forms %1, %-1, %+1, %%foo, %0.
4200 case '0':
4201 if ((strlen(t->text) > 2) && (t->text[2] == '0')) {
4202 type = TOK_ID;
4203 text = nasm_strdup(ei->label_text);
4204 } else {
4205 type = TOK_NUMBER;
4206 snprintf(tmpbuf, sizeof(tmpbuf), "%d", ei->nparam);
4207 text = nasm_strdup(tmpbuf);
4209 break;
4210 case '%':
4211 type = TOK_ID;
4212 snprintf(tmpbuf, sizeof(tmpbuf), "..@%"PRIu64".",
4213 ei->unique);
4214 text = nasm_strcat(tmpbuf, t->text + 2);
4215 break;
4216 case '-':
4217 n = atoi(t->text + 2) - 1;
4218 if (n >= ei->nparam)
4219 tt = NULL;
4220 else {
4221 if (ei->nparam > 1)
4222 n = (n + ei->rotate) % ei->nparam;
4223 tt = ei->params[n];
4225 cc = find_cc(tt);
4226 if (cc == -1) {
4227 error(ERR_NONFATAL,
4228 "macro parameter %d is not a condition code",
4229 n + 1);
4230 text = NULL;
4231 } else {
4232 type = TOK_ID;
4233 if (inverse_ccs[cc] == -1) {
4234 error(ERR_NONFATAL,
4235 "condition code `%s' is not invertible",
4236 conditions[cc]);
4237 text = NULL;
4238 } else
4239 text = nasm_strdup(conditions[inverse_ccs[cc]]);
4241 break;
4242 case '+':
4243 n = atoi(t->text + 2) - 1;
4244 if (n >= ei->nparam)
4245 tt = NULL;
4246 else {
4247 if (ei->nparam > 1)
4248 n = (n + ei->rotate) % ei->nparam;
4249 tt = ei->params[n];
4251 cc = find_cc(tt);
4252 if (cc == -1) {
4253 error(ERR_NONFATAL,
4254 "macro parameter %d is not a condition code",
4255 n + 1);
4256 text = NULL;
4257 } else {
4258 type = TOK_ID;
4259 text = nasm_strdup(conditions[cc]);
4261 break;
4262 default:
4263 n = atoi(t->text + 1) - 1;
4264 if (n >= ei->nparam)
4265 tt = NULL;
4266 else {
4267 if (ei->nparam > 1)
4268 n = (n + ei->rotate) % ei->nparam;
4269 tt = ei->params[n];
4271 if (tt) {
4272 for (i = 0; i < ei->paramlen[n]; i++) {
4273 *tail = new_Token(NULL, tt->type, tt->text, 0);
4274 tail = &(*tail)->next;
4275 tt = tt->next;
4278 text = NULL; /* we've done it here */
4279 break;
4281 } else {
4283 * seems we have a parameters range here
4285 Token *head, **last;
4286 head = expand_mmac_params_range(ei, t, &last);
4287 if (head != t) {
4288 *tail = head;
4289 *last = tline;
4290 tline = head;
4291 text = NULL;
4295 if (!text) {
4296 delete_Token(t);
4297 } else {
4298 *tail = t;
4299 tail = &t->next;
4300 t->type = type;
4301 nasm_free(t->text);
4302 t->text = text;
4303 t->a.mac = NULL;
4305 changed = true;
4306 continue;
4307 } else if (tline->type == TOK_INDIRECT) {
4308 t = tline;
4309 tline = tline->next;
4310 tt = tokenize(t->text);
4311 tt = expand_mmac_params(tt);
4312 tt = expand_smacro(tt);
4313 *tail = tt;
4314 while (tt) {
4315 tt->a.mac = NULL; /* Necessary? */
4316 tail = &tt->next;
4317 tt = tt->next;
4319 delete_Token(t);
4320 changed = true;
4321 } else {
4322 t = *tail = tline;
4323 tline = tline->next;
4324 t->a.mac = NULL;
4325 tail = &t->next;
4328 *tail = NULL;
4330 if (changed) {
4331 const struct tokseq_match t[] = {
4333 PP_CONCAT_MASK(TOK_ID) |
4334 PP_CONCAT_MASK(TOK_FLOAT), /* head */
4335 PP_CONCAT_MASK(TOK_ID) |
4336 PP_CONCAT_MASK(TOK_NUMBER) |
4337 PP_CONCAT_MASK(TOK_FLOAT) |
4338 PP_CONCAT_MASK(TOK_OTHER) /* tail */
4341 PP_CONCAT_MASK(TOK_NUMBER), /* head */
4342 PP_CONCAT_MASK(TOK_NUMBER) /* tail */
4345 paste_tokens(&thead, t, ARRAY_SIZE(t), false);
4348 return thead;
4352 * Expand all single-line macro calls made in the given line.
4353 * Return the expanded version of the line. The original is deemed
4354 * to be destroyed in the process. (In reality we'll just move
4355 * Tokens from input to output a lot of the time, rather than
4356 * actually bothering to destroy and replicate.)
4359 static Token *expand_smacro(Token * tline)
4361 Token *t, *tt, *mstart, **tail, *thead;
4362 SMacro *head = NULL, *m;
4363 Token **params;
4364 int *paramsize;
4365 unsigned int nparam, sparam;
4366 int brackets;
4367 Token *org_tline = tline;
4368 Context *ctx;
4369 const char *mname;
4370 int deadman = DEADMAN_LIMIT;
4371 bool expanded;
4374 * Trick: we should avoid changing the start token pointer since it can
4375 * be contained in "next" field of other token. Because of this
4376 * we allocate a copy of first token and work with it; at the end of
4377 * routine we copy it back
4379 if (org_tline) {
4380 tline = new_Token(org_tline->next, org_tline->type,
4381 org_tline->text, 0);
4382 tline->a.mac = org_tline->a.mac;
4383 nasm_free(org_tline->text);
4384 org_tline->text = NULL;
4387 expanded = true; /* Always expand %+ at least once */
4389 again:
4390 thead = NULL;
4391 tail = &thead;
4393 while (tline) { /* main token loop */
4394 if (!--deadman) {
4395 error(ERR_NONFATAL, "interminable macro recursion");
4396 goto err;
4399 if ((mname = tline->text)) {
4400 /* if this token is a local macro, look in local context */
4401 if (tline->type == TOK_ID) {
4402 head = (SMacro *)hash_findix(&smacros, mname);
4403 } else if (tline->type == TOK_PREPROC_ID) {
4404 ctx = get_ctx(mname, &mname, false);
4405 head = ctx ? (SMacro *)hash_findix(&ctx->localmac, mname) : NULL;
4406 } else
4407 head = NULL;
4410 * We've hit an identifier. As in is_mmacro below, we first
4411 * check whether the identifier is a single-line macro at
4412 * all, then think about checking for parameters if
4413 * necessary.
4415 list_for_each(m, head)
4416 if (!mstrcmp(m->name, mname, m->casesense))
4417 break;
4418 if (m) {
4419 mstart = tline;
4420 params = NULL;
4421 paramsize = NULL;
4422 if (m->nparam == 0) {
4424 * Simple case: the macro is parameterless. Discard the
4425 * one token that the macro call took, and push the
4426 * expansion back on the to-do stack.
4428 if (!m->expansion) {
4429 if (!strcmp("__FILE__", m->name)) {
4430 int32_t num = 0;
4431 char *file = NULL;
4432 src_get(&num, &file);
4433 tline->text = nasm_quote(file, strlen(file));
4434 tline->type = TOK_STRING;
4435 nasm_free(file);
4436 continue;
4438 if (!strcmp("__LINE__", m->name)) {
4439 nasm_free(tline->text);
4440 make_tok_num(tline, src_get_linnum());
4441 continue;
4443 if (!strcmp("__BITS__", m->name)) {
4444 nasm_free(tline->text);
4445 make_tok_num(tline, globalbits);
4446 continue;
4448 tline = delete_Token(tline);
4449 continue;
4451 } else {
4453 * Complicated case: at least one macro with this name
4454 * exists and takes parameters. We must find the
4455 * parameters in the call, count them, find the SMacro
4456 * that corresponds to that form of the macro call, and
4457 * substitute for the parameters when we expand. What a
4458 * pain.
4460 /*tline = tline->next;
4461 skip_white_(tline); */
4462 do {
4463 t = tline->next;
4464 while (tok_type_(t, TOK_SMAC_END)) {
4465 t->a.mac->in_progress = false;
4466 t->text = NULL;
4467 t = tline->next = delete_Token(t);
4469 tline = t;
4470 } while (tok_type_(tline, TOK_WHITESPACE));
4471 if (!tok_is_(tline, "(")) {
4473 * This macro wasn't called with parameters: ignore
4474 * the call. (Behaviour borrowed from gnu cpp.)
4476 tline = mstart;
4477 m = NULL;
4478 } else {
4479 int paren = 0;
4480 int white = 0;
4481 brackets = 0;
4482 nparam = 0;
4483 sparam = PARAM_DELTA;
4484 params = nasm_malloc(sparam * sizeof(Token *));
4485 params[0] = tline->next;
4486 paramsize = nasm_malloc(sparam * sizeof(int));
4487 paramsize[0] = 0;
4488 while (true) { /* parameter loop */
4490 * For some unusual expansions
4491 * which concatenates function call
4493 t = tline->next;
4494 while (tok_type_(t, TOK_SMAC_END)) {
4495 t->a.mac->in_progress = false;
4496 t->text = NULL;
4497 t = tline->next = delete_Token(t);
4499 tline = t;
4501 if (!tline) {
4502 error(ERR_NONFATAL,
4503 "macro call expects terminating `)'");
4504 break;
4506 if (tline->type == TOK_WHITESPACE
4507 && brackets <= 0) {
4508 if (paramsize[nparam])
4509 white++;
4510 else
4511 params[nparam] = tline->next;
4512 continue; /* parameter loop */
4514 if (tline->type == TOK_OTHER
4515 && tline->text[1] == 0) {
4516 char ch = tline->text[0];
4517 if (ch == ',' && !paren && brackets <= 0) {
4518 if (++nparam >= sparam) {
4519 sparam += PARAM_DELTA;
4520 params = nasm_realloc(params,
4521 sparam * sizeof(Token *));
4522 paramsize = nasm_realloc(paramsize,
4523 sparam * sizeof(int));
4525 params[nparam] = tline->next;
4526 paramsize[nparam] = 0;
4527 white = 0;
4528 continue; /* parameter loop */
4530 if (ch == '{' &&
4531 (brackets > 0 || (brackets == 0 &&
4532 !paramsize[nparam])))
4534 if (!(brackets++)) {
4535 params[nparam] = tline->next;
4536 continue; /* parameter loop */
4539 if (ch == '}' && brackets > 0)
4540 if (--brackets == 0) {
4541 brackets = -1;
4542 continue; /* parameter loop */
4544 if (ch == '(' && !brackets)
4545 paren++;
4546 if (ch == ')' && brackets <= 0)
4547 if (--paren < 0)
4548 break;
4550 if (brackets < 0) {
4551 brackets = 0;
4552 error(ERR_NONFATAL, "braces do not "
4553 "enclose all of macro parameter");
4555 paramsize[nparam] += white + 1;
4556 white = 0;
4557 } /* parameter loop */
4558 nparam++;
4559 while (m && (m->nparam != nparam ||
4560 mstrcmp(m->name, mname,
4561 m->casesense)))
4562 m = m->next;
4563 if (!m)
4564 error(ERR_WARNING|ERR_PASS1|ERR_WARN_MNP,
4565 "macro `%s' exists, "
4566 "but not taking %d parameters",
4567 mstart->text, nparam);
4570 if (m && m->in_progress)
4571 m = NULL;
4572 if (!m) { /* in progess or didn't find '(' or wrong nparam */
4574 * Design question: should we handle !tline, which
4575 * indicates missing ')' here, or expand those
4576 * macros anyway, which requires the (t) test a few
4577 * lines down?
4579 nasm_free(params);
4580 nasm_free(paramsize);
4581 tline = mstart;
4582 } else {
4584 * Expand the macro: we are placed on the last token of the
4585 * call, so that we can easily split the call from the
4586 * following tokens. We also start by pushing an SMAC_END
4587 * token for the cycle removal.
4589 t = tline;
4590 if (t) {
4591 tline = t->next;
4592 t->next = NULL;
4594 tt = new_Token(tline, TOK_SMAC_END, NULL, 0);
4595 tt->a.mac = m;
4596 m->in_progress = true;
4597 tline = tt;
4598 list_for_each(t, m->expansion) {
4599 if (t->type >= TOK_SMAC_PARAM) {
4600 Token *pcopy = tline, **ptail = &pcopy;
4601 Token *ttt, *pt;
4602 int i;
4604 ttt = params[t->type - TOK_SMAC_PARAM];
4605 i = paramsize[t->type - TOK_SMAC_PARAM];
4606 while (--i >= 0) {
4607 pt = *ptail = new_Token(tline, ttt->type,
4608 ttt->text, 0);
4609 ptail = &pt->next;
4610 ttt = ttt->next;
4612 tline = pcopy;
4613 } else if (t->type == TOK_PREPROC_Q) {
4614 tt = new_Token(tline, TOK_ID, mname, 0);
4615 tline = tt;
4616 } else if (t->type == TOK_PREPROC_QQ) {
4617 tt = new_Token(tline, TOK_ID, m->name, 0);
4618 tline = tt;
4619 } else {
4620 tt = new_Token(tline, t->type, t->text, 0);
4621 tline = tt;
4626 * Having done that, get rid of the macro call, and clean
4627 * up the parameters.
4629 nasm_free(params);
4630 nasm_free(paramsize);
4631 free_tlist(mstart);
4632 expanded = true;
4633 continue; /* main token loop */
4638 if (tline->type == TOK_SMAC_END) {
4639 tline->a.mac->in_progress = false;
4640 tline = delete_Token(tline);
4641 } else {
4642 t = *tail = tline;
4643 tline = tline->next;
4644 t->a.mac = NULL;
4645 t->next = NULL;
4646 tail = &t->next;
4651 * Now scan the entire line and look for successive TOK_IDs that resulted
4652 * after expansion (they can't be produced by tokenize()). The successive
4653 * TOK_IDs should be concatenated.
4654 * Also we look for %+ tokens and concatenate the tokens before and after
4655 * them (without white spaces in between).
4657 if (expanded) {
4658 const struct tokseq_match t[] = {
4660 PP_CONCAT_MASK(TOK_ID) |
4661 PP_CONCAT_MASK(TOK_PREPROC_ID), /* head */
4662 PP_CONCAT_MASK(TOK_ID) |
4663 PP_CONCAT_MASK(TOK_PREPROC_ID) |
4664 PP_CONCAT_MASK(TOK_NUMBER) /* tail */
4667 if (paste_tokens(&thead, t, ARRAY_SIZE(t), true)) {
4669 * If we concatenated something, *and* we had previously expanded
4670 * an actual macro, scan the lines again for macros...
4672 tline = thead;
4673 expanded = false;
4674 goto again;
4678 err:
4679 if (org_tline) {
4680 if (thead) {
4681 *org_tline = *thead;
4682 /* since we just gave text to org_line, don't free it */
4683 thead->text = NULL;
4684 delete_Token(thead);
4685 } else {
4686 /* the expression expanded to empty line;
4687 we can't return NULL for some reasons
4688 we just set the line to a single WHITESPACE token. */
4689 memset(org_tline, 0, sizeof(*org_tline));
4690 org_tline->text = NULL;
4691 org_tline->type = TOK_WHITESPACE;
4693 thead = org_tline;
4696 return thead;
4700 * Similar to expand_smacro but used exclusively with macro identifiers
4701 * right before they are fetched in. The reason is that there can be
4702 * identifiers consisting of several subparts. We consider that if there
4703 * are more than one element forming the name, user wants a expansion,
4704 * otherwise it will be left as-is. Example:
4706 * %define %$abc cde
4708 * the identifier %$abc will be left as-is so that the handler for %define
4709 * will suck it and define the corresponding value. Other case:
4711 * %define _%$abc cde
4713 * In this case user wants name to be expanded *before* %define starts
4714 * working, so we'll expand %$abc into something (if it has a value;
4715 * otherwise it will be left as-is) then concatenate all successive
4716 * PP_IDs into one.
4718 static Token *expand_id(Token * tline)
4720 Token *cur, *oldnext = NULL;
4722 if (!tline || !tline->next)
4723 return tline;
4725 cur = tline;
4726 while (cur->next &&
4727 (cur->next->type == TOK_ID ||
4728 cur->next->type == TOK_PREPROC_ID
4729 || cur->next->type == TOK_NUMBER))
4730 cur = cur->next;
4732 /* If identifier consists of just one token, don't expand */
4733 if (cur == tline)
4734 return tline;
4736 if (cur) {
4737 oldnext = cur->next; /* Detach the tail past identifier */
4738 cur->next = NULL; /* so that expand_smacro stops here */
4741 tline = expand_smacro(tline);
4743 if (cur) {
4744 /* expand_smacro possibly changhed tline; re-scan for EOL */
4745 cur = tline;
4746 while (cur && cur->next)
4747 cur = cur->next;
4748 if (cur)
4749 cur->next = oldnext;
4752 return tline;
4756 * Determine whether the given line constitutes a multi-line macro
4757 * call, and return the ExpDef structure called if so. Doesn't have
4758 * to check for an initial label - that's taken care of in
4759 * expand_mmacro - but must check numbers of parameters. Guaranteed
4760 * to be called with tline->type == TOK_ID, so the putative macro
4761 * name is easy to find.
4763 static ExpDef *is_mmacro(Token * tline, Token *** params_array)
4765 ExpDef *head, *ed;
4766 Token **params;
4767 int nparam;
4769 head = (ExpDef *) hash_findix(&expdefs, tline->text);
4772 * Efficiency: first we see if any macro exists with the given
4773 * name. If not, we can return NULL immediately. _Then_ we
4774 * count the parameters, and then we look further along the
4775 * list if necessary to find the proper ExpDef.
4777 list_for_each(ed, head)
4778 if (!mstrcmp(ed->name, tline->text, ed->casesense))
4779 break;
4780 if (!ed)
4781 return NULL;
4784 * OK, we have a potential macro. Count and demarcate the
4785 * parameters.
4787 count_mmac_params(tline->next, &nparam, &params);
4790 * So we know how many parameters we've got. Find the ExpDef
4791 * structure that handles this number.
4793 while (ed) {
4794 if (ed->nparam_min <= nparam
4795 && (ed->plus || nparam <= ed->nparam_max)) {
4797 * It's right, and we can use it. Add its default
4798 * parameters to the end of our list if necessary.
4800 if (ed->defaults && nparam < ed->nparam_min + ed->ndefs) {
4801 params =
4802 nasm_realloc(params,
4803 ((ed->nparam_min + ed->ndefs +
4804 1) * sizeof(*params)));
4805 while (nparam < ed->nparam_min + ed->ndefs) {
4806 params[nparam] = ed->defaults[nparam - ed->nparam_min];
4807 nparam++;
4811 * If we've gone over the maximum parameter count (and
4812 * we're in Plus mode), ignore parameters beyond
4813 * nparam_max.
4815 if (ed->plus && nparam > ed->nparam_max)
4816 nparam = ed->nparam_max;
4818 * Then terminate the parameter list, and leave.
4820 if (!params) { /* need this special case */
4821 params = nasm_malloc(sizeof(*params));
4822 nparam = 0;
4824 params[nparam] = NULL;
4825 *params_array = params;
4826 return ed;
4829 * This one wasn't right: look for the next one with the
4830 * same name.
4832 list_for_each(ed, ed->next)
4833 if (!mstrcmp(ed->name, tline->text, ed->casesense))
4834 break;
4838 * After all that, we didn't find one with the right number of
4839 * parameters. Issue a warning, and fail to expand the macro.
4841 error(ERR_WARNING|ERR_PASS1|ERR_WARN_MNP,
4842 "macro `%s' exists, but not taking %d parameters",
4843 tline->text, nparam);
4844 nasm_free(params);
4845 return NULL;
4849 * Expand the multi-line macro call made by the given line, if
4850 * there is one to be expanded. If there is, push the expansion on
4851 * istk->expansion and return true. Otherwise return false.
4853 static bool expand_mmacro(Token * tline)
4855 Token *label = NULL;
4856 int dont_prepend = 0;
4857 Token **params, *t, *mtok;
4858 Line *l = NULL;
4859 ExpDef *ed;
4860 ExpInv *ei;
4861 int i, nparam, *paramlen;
4862 const char *mname;
4864 t = tline;
4865 skip_white_(t);
4866 /* if (!tok_type_(t, TOK_ID)) Lino 02/25/02 */
4867 if (!tok_type_(t, TOK_ID) && !tok_type_(t, TOK_PREPROC_ID))
4868 return false;
4869 mtok = t;
4870 ed = is_mmacro(t, &params);
4871 if (ed != NULL) {
4872 mname = t->text;
4873 } else {
4874 Token *last;
4876 * We have an id which isn't a macro call. We'll assume
4877 * it might be a label; we'll also check to see if a
4878 * colon follows it. Then, if there's another id after
4879 * that lot, we'll check it again for macro-hood.
4881 label = last = t;
4882 t = t->next;
4883 if (tok_type_(t, TOK_WHITESPACE))
4884 last = t, t = t->next;
4885 if (tok_is_(t, ":")) {
4886 dont_prepend = 1;
4887 last = t, t = t->next;
4888 if (tok_type_(t, TOK_WHITESPACE))
4889 last = t, t = t->next;
4891 if (!tok_type_(t, TOK_ID) || !(ed = is_mmacro(t, &params)))
4892 return false;
4893 last->next = NULL;
4894 mname = t->text;
4895 tline = t;
4899 * Fix up the parameters: this involves stripping leading and
4900 * trailing whitespace, then stripping braces if they are
4901 * present.
4903 for (nparam = 0; params[nparam]; nparam++) ;
4904 paramlen = nparam ? nasm_malloc(nparam * sizeof(*paramlen)) : NULL;
4906 for (i = 0; params[i]; i++) {
4907 int brace = false;
4908 int comma = (!ed->plus || i < nparam - 1);
4910 t = params[i];
4911 skip_white_(t);
4912 if (tok_is_(t, "{"))
4913 t = t->next, brace = true, comma = false;
4914 params[i] = t;
4915 paramlen[i] = 0;
4916 while (t) {
4917 if (comma && t->type == TOK_OTHER && !strcmp(t->text, ","))
4918 break; /* ... because we have hit a comma */
4919 if (comma && t->type == TOK_WHITESPACE
4920 && tok_is_(t->next, ","))
4921 break; /* ... or a space then a comma */
4922 if (brace && t->type == TOK_OTHER && !strcmp(t->text, "}"))
4923 break; /* ... or a brace */
4924 t = t->next;
4925 paramlen[i]++;
4929 if (ed->cur_depth >= ed->max_depth) {
4930 if (ed->max_depth > 1) {
4931 error(ERR_WARNING,
4932 "reached maximum macro recursion depth of %i for %s",
4933 ed->max_depth,ed->name);
4935 return false;
4936 } else {
4937 ed->cur_depth ++;
4941 * OK, we have found a ExpDef structure representing a
4942 * previously defined mmacro. Create an expansion invocation
4943 * and point it back to the expansion definition. Substitution of
4944 * parameter tokens and macro-local tokens doesn't get done
4945 * until the single-line macro substitution process; this is
4946 * because delaying them allows us to change the semantics
4947 * later through %rotate.
4949 ei = new_ExpInv(EXP_MMACRO, ed);
4950 ei->name = nasm_strdup(mname);
4951 // ei->label = label;
4952 // ei->label_text = detoken(label, false);
4953 ei->current = ed->line;
4954 ei->emitting = true;
4955 // ei->iline = tline;
4956 ei->params = params;
4957 ei->nparam = nparam;
4958 ei->rotate = 0;
4959 ei->paramlen = paramlen;
4960 ei->lineno = 0;
4962 ei->prev = istk->expansion;
4963 istk->expansion = ei;
4966 * Special case: detect %00 on first invocation; if found,
4967 * avoid emitting any labels that precede the mmacro call.
4968 * ed->prepend is set to -1 when %00 is detected, else 1.
4970 if (ed->prepend == 0) {
4971 for (l = ed->line; l != NULL; l = l->next) {
4972 for (t = l->first; t != NULL; t = t->next) {
4973 if ((t->type == TOK_PREPROC_ID) &&
4974 (strlen(t->text) == 3) &&
4975 (t->text[1] == '0') && (t->text[2] == '0')) {
4976 dont_prepend = -1;
4977 break;
4980 if (dont_prepend < 0) {
4981 break;
4984 ed->prepend = ((dont_prepend < 0) ? -1 : 1);
4988 * If we had a label, push it on as the first line of
4989 * the macro expansion.
4991 if (label != NULL) {
4992 if (ed->prepend < 0) {
4993 ei->label_text = detoken(label, false);
4994 } else {
4995 if (dont_prepend == 0) {
4996 t = label;
4997 while (t->next != NULL) {
4998 t = t->next;
5000 t->next = new_Token(NULL, TOK_OTHER, ":", 0);
5002 Line *l = new_Line();
5003 l->first = copy_Token(label);
5004 l->next = ei->current;
5005 ei->current = l;
5009 list->uplevel(ed->nolist ? LIST_MACRO_NOLIST : LIST_MACRO);
5011 istk->mmac_depth++;
5012 return true;
5015 /* The function that actually does the error reporting */
5016 static void verror(int severity, const char *fmt, va_list arg)
5018 char buff[1024];
5020 vsnprintf(buff, sizeof(buff), fmt, arg);
5022 if ((istk != NULL) && (istk->mmac_depth > 0)) {
5023 ExpInv *ei = istk->expansion;
5024 int lineno = ei->lineno;
5025 while (ei != NULL) {
5026 if (ei->type == EXP_MMACRO) {
5027 break;
5029 lineno += ei->relno;
5030 ei = ei->prev;
5032 nasm_error(severity, "(%s:%d) %s", ei->def->name,
5033 lineno, buff);
5034 } else {
5035 nasm_error(severity, "%s", buff);
5040 * Since preprocessor always operate only on the line that didn't
5041 * arrived yet, we should always use ERR_OFFBY1.
5043 static void error(int severity, const char *fmt, ...)
5045 va_list arg;
5046 va_start(arg, fmt);
5047 verror(severity, fmt, arg);
5048 va_end(arg);
5052 * Because %else etc are evaluated in the state context
5053 * of the previous branch, errors might get lost with error():
5054 * %if 0 ... %else trailing garbage ... %endif
5055 * So %else etc should report errors with this function.
5057 static void error_precond(int severity, const char *fmt, ...)
5059 va_list arg;
5061 /* Only ignore the error if it's really in a dead branch */
5062 if ((istk != NULL) &&
5063 (istk->expansion != NULL) &&
5064 (istk->expansion->type == EXP_IF) &&
5065 (istk->expansion->def->state == COND_NEVER))
5066 return;
5068 va_start(arg, fmt);
5069 verror(severity, fmt, arg);
5070 va_end(arg);
5073 static void
5074 pp_reset(char *file, int apass, ListGen * listgen, StrList **deplist)
5076 Token *t;
5078 cstk = NULL;
5079 istk = nasm_malloc(sizeof(Include));
5080 istk->next = NULL;
5081 istk->expansion = NULL;
5082 istk->fp = fopen(file, "r");
5083 istk->fname = NULL;
5084 src_set_fname(nasm_strdup(file));
5085 src_set_linnum(0);
5086 istk->lineinc = 1;
5087 istk->mmac_depth = 0;
5088 if (!istk->fp)
5089 error(ERR_FATAL|ERR_NOFILE, "unable to open input file `%s'",
5090 file);
5091 defining = NULL;
5092 finals = NULL;
5093 in_final = false;
5094 nested_mac_count = 0;
5095 nested_rep_count = 0;
5096 init_macros();
5097 unique = 0;
5098 if (tasm_compatible_mode) {
5099 stdmacpos = nasm_stdmac;
5100 } else {
5101 stdmacpos = nasm_stdmac_after_tasm;
5103 any_extrastdmac = extrastdmac && *extrastdmac;
5104 do_predef = true;
5105 list = listgen;
5108 * 0 for dependencies, 1 for preparatory passes, 2 for final pass.
5109 * The caller, however, will also pass in 3 for preprocess-only so
5110 * we can set __PASS__ accordingly.
5112 pass = apass > 2 ? 2 : apass;
5114 dephead = deptail = deplist;
5115 if (deplist) {
5116 StrList *sl = nasm_malloc(strlen(file)+1+sizeof sl->next);
5117 sl->next = NULL;
5118 strcpy(sl->str, file);
5119 *deptail = sl;
5120 deptail = &sl->next;
5124 * Define the __PASS__ macro. This is defined here unlike
5125 * all the other builtins, because it is special -- it varies between
5126 * passes.
5128 t = nasm_malloc(sizeof(*t));
5129 t->next = NULL;
5130 make_tok_num(t, apass);
5131 t->a.mac = NULL;
5132 define_smacro(NULL, "__PASS__", true, 0, t);
5135 static char *pp_getline(void)
5137 char *line;
5138 Token *tline;
5139 ExpInv *ei;
5141 while (1) {
5143 * Fetch a tokenized line, either from the expansion
5144 * buffer or from the input file.
5146 tline = NULL;
5148 while (1) { /* until we get a line we can use */
5150 * Fetch a tokenized line from the expansion buffer
5152 if (istk->expansion != NULL) {
5153 ei = istk->expansion;
5154 if (ei->current != NULL) {
5155 if (ei->emitting == false) {
5156 ei->current = NULL;
5157 continue;
5159 Line *l = NULL;
5160 l = ei->current;
5161 ei->current = l->next;
5162 ei->lineno++;
5163 tline = copy_Token(l->first);
5164 if (((ei->type == EXP_REP) ||
5165 (ei->type == EXP_MMACRO) ||
5166 (ei->type == EXP_WHILE))
5167 && (ei->def->nolist == false)) {
5168 char *p = detoken(tline, false);
5169 list->line(LIST_MACRO, p);
5170 nasm_free(p);
5172 if (ei->linnum > -1) {
5173 src_set_linnum(src_get_linnum() + 1);
5175 break;
5176 } else if ((ei->type == EXP_REP) &&
5177 (ei->def->cur_depth < ei->def->max_depth)) {
5178 ei->def->cur_depth ++;
5179 ei->current = ei->def->line;
5180 ei->lineno = 0;
5181 continue;
5182 } else if ((ei->type == EXP_WHILE) &&
5183 (ei->def->cur_depth < ei->def->max_depth)) {
5184 ei->current = ei->def->line;
5185 ei->lineno = 0;
5186 tline = copy_Token(ei->current->first);
5187 int j = if_condition(tline, PP_WHILE);
5188 tline = NULL;
5189 j = (((j < 0) ? COND_NEVER : j) ? COND_IF_TRUE : COND_IF_FALSE);
5190 if (j == COND_IF_TRUE) {
5191 ei->current = ei->current->next;
5192 ei->def->cur_depth ++;
5193 } else {
5194 ei->emitting = false;
5195 ei->current = NULL;
5196 ei->def->cur_depth = ei->def->max_depth;
5198 continue;
5199 } else {
5200 istk->expansion = ei->prev;
5201 ExpDef *ed = ei->def;
5202 if (ed != NULL) {
5203 if ((ei->emitting == true) &&
5204 (ed->max_depth == DEADMAN_LIMIT) &&
5205 (ed->cur_depth == DEADMAN_LIMIT)
5207 error(ERR_FATAL, "runaway expansion detected, aborting");
5209 if (ed->cur_depth > 0) {
5210 ed->cur_depth --;
5211 } else if ((ed->type != EXP_MMACRO) && (ed->type != EXP_IF)) {
5212 /***** should this really be right here??? *****/
5214 Line *l = NULL, *ll = NULL;
5215 for (l = ed->line; l != NULL;) {
5216 if (l->first != NULL) {
5217 free_tlist(l->first);
5218 l->first = NULL;
5220 ll = l;
5221 l = l->next;
5222 nasm_free(ll);
5224 expansions = ed->prev;
5225 nasm_free(ed);
5228 if ((ei->type == EXP_REP) ||
5229 (ei->type == EXP_MMACRO) ||
5230 (ei->type == EXP_WHILE)) {
5231 list->downlevel(LIST_MACRO);
5232 if (ei->type == EXP_MMACRO) {
5233 istk->mmac_depth--;
5237 if (ei->linnum > -1) {
5238 src_set_linnum(ei->linnum);
5240 free_expinv(ei);
5241 continue;
5246 * Read in line from input and tokenize
5248 line = read_line();
5249 if (line) { /* from the current input file */
5250 line = prepreproc(line);
5251 tline = tokenize(line);
5252 nasm_free(line);
5253 break;
5257 * The current file has ended; work down the istk
5260 Include *i = istk;
5261 fclose(i->fp);
5262 if (i->expansion != NULL) {
5263 error(ERR_FATAL,
5264 "end of file while still in an expansion");
5266 /* only set line and file name if there's a next node */
5267 if (i->next) {
5268 src_set_linnum(i->lineno);
5269 nasm_free(src_set_fname(i->fname));
5271 if ((i->next == NULL) && (finals != NULL)) {
5272 in_final = true;
5273 ei = new_ExpInv(EXP_FINAL, NULL);
5274 ei->emitting = true;
5275 ei->current = finals;
5276 istk->expansion = ei;
5277 finals = NULL;
5278 continue;
5280 istk = i->next;
5281 list->downlevel(LIST_INCLUDE);
5282 nasm_free(i);
5283 if (istk == NULL) {
5284 if (finals != NULL) {
5285 in_final = true;
5286 } else {
5287 return NULL;
5290 continue;
5294 if (defining == NULL) {
5295 tline = expand_mmac_params(tline);
5299 * Check the line to see if it's a preprocessor directive.
5301 if (do_directive(tline) == DIRECTIVE_FOUND) {
5302 continue;
5303 } else if (defining != NULL) {
5305 * We're defining an expansion. We emit nothing at all,
5306 * and just shove the tokenized line on to the definition.
5308 if (defining->ignoring == false) {
5309 Line *l = new_Line();
5310 l->first = tline;
5311 if (defining->line == NULL) {
5312 defining->line = l;
5313 defining->last = l;
5314 } else {
5315 defining->last->next = l;
5316 defining->last = l;
5318 } else {
5319 //free_tlist(tline); /***** sanity check: is this supposed to be here? *****/
5321 defining->linecount++;
5322 continue;
5323 } else if ((istk->expansion != NULL) &&
5324 (istk->expansion->emitting != true)) {
5326 * We're in a non-emitting branch of an expansion.
5327 * Emit nothing at all, not even a blank line: when we
5328 * emerge from the expansion we'll give a line-number
5329 * directive so we keep our place correctly.
5331 free_tlist(tline);
5332 continue;
5333 } else {
5334 tline = expand_smacro(tline);
5335 if (expand_mmacro(tline) != true) {
5337 * De-tokenize the line again, and emit it.
5339 line = detoken(tline, true);
5340 free_tlist(tline);
5341 break;
5342 } else {
5343 continue;
5347 return line;
5350 static void pp_cleanup(int pass)
5352 if (defining != NULL) {
5353 error(ERR_NONFATAL, "end of file while still defining an expansion");
5354 while (defining != NULL) {
5355 ExpDef *ed = defining;
5356 defining = ed->prev;
5357 free_expdef(ed);
5359 defining = NULL;
5361 while (cstk != NULL)
5362 ctx_pop();
5363 free_macros();
5364 while (istk != NULL) {
5365 Include *i = istk;
5366 istk = istk->next;
5367 fclose(i->fp);
5368 nasm_free(i->fname);
5369 nasm_free(i);
5370 while (i->expansion != NULL) {
5371 ExpInv *ei = i->expansion;
5372 i->expansion = ei->prev;
5373 free_expinv(ei);
5376 while (cstk)
5377 ctx_pop();
5378 nasm_free(src_set_fname(NULL));
5379 if (pass == 0) {
5380 IncPath *i;
5381 free_llist(predef);
5382 delete_Blocks();
5383 while ((i = ipath)) {
5384 ipath = i->next;
5385 if (i->path)
5386 nasm_free(i->path);
5387 nasm_free(i);
5392 void pp_include_path(char *path)
5394 IncPath *i;
5396 i = nasm_malloc(sizeof(IncPath));
5397 i->path = path ? nasm_strdup(path) : NULL;
5398 i->next = NULL;
5400 if (ipath) {
5401 IncPath *j = ipath;
5402 while (j->next)
5403 j = j->next;
5404 j->next = i;
5405 } else {
5406 ipath = i;
5410 void pp_pre_include(char *fname)
5412 Token *inc, *space, *name;
5413 Line *l;
5415 name = new_Token(NULL, TOK_INTERNAL_STRING, fname, 0);
5416 space = new_Token(name, TOK_WHITESPACE, NULL, 0);
5417 inc = new_Token(space, TOK_PREPROC_ID, "%include", 0);
5419 l = new_Line();
5420 l->next = predef;
5421 l->first = inc;
5422 predef = l;
5425 void pp_pre_define(char *definition)
5427 Token *def, *space;
5428 Line *l;
5429 char *equals;
5431 equals = strchr(definition, '=');
5432 space = new_Token(NULL, TOK_WHITESPACE, NULL, 0);
5433 def = new_Token(space, TOK_PREPROC_ID, "%define", 0);
5434 if (equals)
5435 *equals = ' ';
5436 space->next = tokenize(definition);
5437 if (equals)
5438 *equals = '=';
5440 l = new_Line();
5441 l->next = predef;
5442 l->first = def;
5443 predef = l;
5446 void pp_pre_undefine(char *definition)
5448 Token *def, *space;
5449 Line *l;
5451 space = new_Token(NULL, TOK_WHITESPACE, NULL, 0);
5452 def = new_Token(space, TOK_PREPROC_ID, "%undef", 0);
5453 space->next = tokenize(definition);
5455 l = new_Line();
5456 l->next = predef;
5457 l->first = def;
5458 predef = l;
5462 * This function is used to assist with "runtime" preprocessor
5463 * directives, e.g. pp_runtime("%define __BITS__ 64");
5465 * ERRORS ARE IGNORED HERE, SO MAKE COMPLETELY SURE THAT YOU
5466 * PASS A VALID STRING TO THIS FUNCTION!!!!!
5469 void pp_runtime(char *definition)
5471 Token *def;
5473 def = tokenize(definition);
5474 if (do_directive(def) == NO_DIRECTIVE_FOUND)
5475 free_tlist(def);
5479 void pp_extra_stdmac(macros_t *macros)
5481 extrastdmac = macros;
5484 static void make_tok_num(Token * tok, int64_t val)
5486 char numbuf[20];
5487 snprintf(numbuf, sizeof(numbuf), "%"PRId64"", val);
5488 tok->text = nasm_strdup(numbuf);
5489 tok->type = TOK_NUMBER;
5492 Preproc nasmpp = {
5493 pp_reset,
5494 pp_getline,
5495 pp_cleanup