preproc.c: fix tokenize() warnings for ignored expansion definitions
[nasm.git] / preproc.c
blob5c56db929fa2a0b1b54fc5fd2627c3e7f2b20cb7
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))))
486 #ifdef NASM_TRACE
488 #define dump_token(t) raw_dump_token(t, __FILE__, __LINE__, __func__);
489 static void raw_dump_token(Token *token, const char *file, int line, const char *func)
491 printf("---[%s (%s:%d): %p]---\n", func, file, line, (void *)token);
492 if (token) {
493 Token *t;
494 list_for_each(t, token) {
495 if (t->text)
496 printf("'%s' ", t->text);
498 printf("\n");
502 #endif
505 * nasm_unquote with error if the string contains NUL characters.
506 * If the string contains NUL characters, issue an error and return
507 * the C len, i.e. truncate at the NUL.
509 static size_t nasm_unquote_cstr(char *qstr, enum preproc_token directive)
511 size_t len = nasm_unquote(qstr, NULL);
512 size_t clen = strlen(qstr);
514 if (len != clen)
515 error(ERR_NONFATAL, "NUL character in `%s' directive",
516 pp_directives[directive]);
518 return clen;
522 * In-place reverse a list of tokens.
524 static Token *reverse_tokens(Token *t)
526 Token *prev = NULL;
527 Token *next;
529 while (t) {
530 next = t->next;
531 t->next = prev;
532 prev = t;
533 t = next;
536 return prev;
540 * Handle TASM specific directives, which do not contain a % in
541 * front of them. We do it here because I could not find any other
542 * place to do it for the moment, and it is a hack (ideally it would
543 * be nice to be able to use the NASM pre-processor to do it).
545 static char *check_tasm_directive(char *line)
547 int32_t i, j, k, m, len;
548 char *p, *q, *oldline, oldchar;
550 p = nasm_skip_spaces(line);
552 /* Binary search for the directive name */
553 i = -1;
554 j = ARRAY_SIZE(tasm_directives);
555 q = nasm_skip_word(p);
556 len = q - p;
557 if (len) {
558 oldchar = p[len];
559 p[len] = 0;
560 while (j - i > 1) {
561 k = (j + i) / 2;
562 m = nasm_stricmp(p, tasm_directives[k]);
563 if (m == 0) {
564 /* We have found a directive, so jam a % in front of it
565 * so that NASM will then recognise it as one if it's own.
567 p[len] = oldchar;
568 len = strlen(p);
569 oldline = line;
570 line = nasm_malloc(len + 2);
571 line[0] = '%';
572 if (k == TM_IFDIFI) {
574 * NASM does not recognise IFDIFI, so we convert
575 * it to %if 0. This is not used in NASM
576 * compatible code, but does need to parse for the
577 * TASM macro package.
579 strcpy(line + 1, "if 0");
580 } else {
581 memcpy(line + 1, p, len + 1);
583 nasm_free(oldline);
584 return line;
585 } else if (m < 0) {
586 j = k;
587 } else
588 i = k;
590 p[len] = oldchar;
592 return line;
596 * The pre-preprocessing stage... This function translates line
597 * number indications as they emerge from GNU cpp (`# lineno "file"
598 * flags') into NASM preprocessor line number indications (`%line
599 * lineno file').
601 static char *prepreproc(char *line)
603 int lineno, fnlen;
604 char *fname, *oldline;
606 if (line[0] == '#' && line[1] == ' ') {
607 oldline = line;
608 fname = oldline + 2;
609 lineno = atoi(fname);
610 fname += strspn(fname, "0123456789 ");
611 if (*fname == '"')
612 fname++;
613 fnlen = strcspn(fname, "\"");
614 line = nasm_malloc(20 + fnlen);
615 snprintf(line, 20 + fnlen, "%%line %d %.*s", lineno, fnlen, fname);
616 nasm_free(oldline);
618 if (tasm_compatible_mode)
619 return check_tasm_directive(line);
620 return line;
624 * Free a linked list of tokens.
626 static void free_tlist(Token * list)
628 while (list)
629 list = delete_Token(list);
633 * Free a linked list of lines.
635 static void free_llist(Line * list)
637 Line *l, *tmp;
638 list_for_each_safe(l, tmp, list) {
639 free_tlist(l->first);
640 nasm_free(l);
645 * Free an ExpDef
647 static void free_expdef(ExpDef * ed)
649 nasm_free(ed->name);
650 free_tlist(ed->dlist);
651 nasm_free(ed->defaults);
652 free_llist(ed->line);
653 nasm_free(ed);
657 * Free an ExpInv
659 static void free_expinv(ExpInv * ei)
661 if (ei->name != NULL)
662 nasm_free(ei->name);
663 if (ei->label_text != NULL)
664 nasm_free(ei->label_text);
665 nasm_free(ei);
669 * Free all currently defined macros, and free the hash tables
671 static void free_smacro_table(struct hash_table *smt)
673 SMacro *s, *tmp;
674 const char *key;
675 struct hash_tbl_node *it = NULL;
677 while ((s = hash_iterate(smt, &it, &key)) != NULL) {
678 nasm_free((void *)key);
679 list_for_each_safe(s, tmp, s) {
680 nasm_free(s->name);
681 free_tlist(s->expansion);
682 nasm_free(s);
685 hash_free(smt);
688 static void free_expdef_table(struct hash_table *edt)
690 ExpDef *ed, *tmp;
691 const char *key;
692 struct hash_tbl_node *it = NULL;
694 it = NULL;
695 while ((ed = hash_iterate(edt, &it, &key)) != NULL) {
696 nasm_free((void *)key);
697 list_for_each_safe(ed ,tmp, ed)
698 free_expdef(ed);
700 hash_free(edt);
703 static void free_macros(void)
705 free_smacro_table(&smacros);
706 free_expdef_table(&expdefs);
710 * Initialize the hash tables
712 static void init_macros(void)
714 hash_init(&smacros, HASH_LARGE);
715 hash_init(&expdefs, HASH_LARGE);
719 * Pop the context stack.
721 static void ctx_pop(void)
723 Context *c = cstk;
725 cstk = cstk->next;
726 free_smacro_table(&c->localmac);
727 nasm_free(c->name);
728 nasm_free(c);
732 * Search for a key in the hash index; adding it if necessary
733 * (in which case we initialize the data pointer to NULL.)
735 static void **
736 hash_findi_add(struct hash_table *hash, const char *str)
738 struct hash_insert hi;
739 void **r;
740 char *strx;
742 r = hash_findi(hash, str, &hi);
743 if (r)
744 return r;
746 strx = nasm_strdup(str); /* Use a more efficient allocator here? */
747 return hash_add(&hi, strx, NULL);
751 * Like hash_findi, but returns the data element rather than a pointer
752 * to it. Used only when not adding a new element, hence no third
753 * argument.
755 static void *
756 hash_findix(struct hash_table *hash, const char *str)
758 void **p;
760 p = hash_findi(hash, str, NULL);
761 return p ? *p : NULL;
765 * read line from standard macros set,
766 * if there no more left -- return NULL
768 static char *line_from_stdmac(void)
770 unsigned char c;
771 const unsigned char *p = stdmacpos;
772 char *line, *q;
773 size_t len = 0;
775 if (!stdmacpos)
776 return NULL;
778 while ((c = *p++)) {
779 if (c >= 0x80)
780 len += pp_directives_len[c - 0x80] + 1;
781 else
782 len++;
785 line = nasm_malloc(len + 1);
786 q = line;
787 while ((c = *stdmacpos++)) {
788 if (c >= 0x80) {
789 memcpy(q, pp_directives[c - 0x80], pp_directives_len[c - 0x80]);
790 q += pp_directives_len[c - 0x80];
791 *q++ = ' ';
792 } else {
793 *q++ = c;
796 stdmacpos = p;
797 *q = '\0';
799 if (!*stdmacpos) {
800 /* This was the last of the standard macro chain... */
801 stdmacpos = NULL;
802 if (any_extrastdmac) {
803 stdmacpos = extrastdmac;
804 any_extrastdmac = false;
805 } else if (do_predef) {
806 ExpInv *ei;
807 Line *pd, *l;
808 Token *head, **tail, *t;
811 * Nasty hack: here we push the contents of
812 * `predef' on to the top-level expansion stack,
813 * since this is the most convenient way to
814 * implement the pre-include and pre-define
815 * features.
817 list_for_each(pd, predef) {
818 head = NULL;
819 tail = &head;
820 list_for_each(t, pd->first) {
821 *tail = new_Token(NULL, t->type, t->text, 0);
822 tail = &(*tail)->next;
825 l = new_Line();
826 l->first = head;
827 ei = new_ExpInv(EXP_PREDEF, NULL);
828 ei->current = l;
829 ei->emitting = true;
830 ei->prev = istk->expansion;
831 istk->expansion = ei;
833 do_predef = false;
837 return line;
840 #define BUF_DELTA 512
842 * Read a line from the top file in istk, handling multiple CR/LFs
843 * at the end of the line read, and handling spurious ^Zs. Will
844 * return lines from the standard macro set if this has not already
845 * been done.
847 static char *read_line(void)
849 char *buffer, *p, *q;
850 int bufsize, continued_count;
853 * standart macros set (predefined) goes first
855 p = line_from_stdmac();
856 if (p)
857 return p;
860 * regular read from a file
862 bufsize = BUF_DELTA;
863 buffer = nasm_malloc(BUF_DELTA);
864 p = buffer;
865 continued_count = 0;
866 while (1) {
867 q = fgets(p, bufsize - (p - buffer), istk->fp);
868 if (!q)
869 break;
870 p += strlen(p);
871 if (p > buffer && p[-1] == '\n') {
873 * Convert backslash-CRLF line continuation sequences into
874 * nothing at all (for DOS and Windows)
876 if (((p - 2) > buffer) && (p[-3] == '\\') && (p[-2] == '\r')) {
877 p -= 3;
878 *p = 0;
879 continued_count++;
882 * Also convert backslash-LF line continuation sequences into
883 * nothing at all (for Unix)
885 else if (((p - 1) > buffer) && (p[-2] == '\\')) {
886 p -= 2;
887 *p = 0;
888 continued_count++;
889 } else {
890 break;
893 if (p - buffer > bufsize - 10) {
894 int32_t offset = p - buffer;
895 bufsize += BUF_DELTA;
896 buffer = nasm_realloc(buffer, bufsize);
897 p = buffer + offset; /* prevent stale-pointer problems */
901 if (!q && p == buffer) {
902 nasm_free(buffer);
903 return NULL;
906 src_set_linnum(src_get_linnum() + istk->lineinc +
907 (continued_count * istk->lineinc));
910 * Play safe: remove CRs as well as LFs, if any of either are
911 * present at the end of the line.
913 while (--p >= buffer && (*p == '\n' || *p == '\r'))
914 *p = '\0';
917 * Handle spurious ^Z, which may be inserted into source files
918 * by some file transfer utilities.
920 buffer[strcspn(buffer, "\032")] = '\0';
922 list->line(LIST_READ, buffer);
924 return buffer;
928 * Tokenize a line of text. This is a very simple process since we
929 * don't need to parse the value out of e.g. numeric tokens: we
930 * simply split one string into many.
932 static Token *tokenize(char *line)
934 char c, *p = line;
935 enum pp_token_type type;
936 Token *list = NULL;
937 Token *t, **tail = &list;
938 bool verbose = true;
940 if ((defining != NULL) && (defining->ignoring == true)) {
941 verbose = false;
944 while (*line) {
945 p = line;
946 if (*p == '%') {
947 p++;
948 if (*p == '+' && !nasm_isdigit(p[1])) {
949 p++;
950 type = TOK_PASTE;
951 } else if (nasm_isdigit(*p) ||
952 ((*p == '-' || *p == '+') && nasm_isdigit(p[1]))) {
953 do {
954 p++;
956 while (nasm_isdigit(*p));
957 type = TOK_PREPROC_ID;
958 } else if (*p == '{') {
959 p++;
960 while (*p && *p != '}') {
961 p[-1] = *p;
962 p++;
964 p[-1] = '\0';
965 if (*p)
966 p++;
967 type = TOK_PREPROC_ID;
968 } else if (*p == '[') {
969 int lvl = 1;
970 line += 2; /* Skip the leading %[ */
971 p++;
972 while (lvl && (c = *p++)) {
973 switch (c) {
974 case ']':
975 lvl--;
976 break;
977 case '%':
978 if (*p == '[')
979 lvl++;
980 break;
981 case '\'':
982 case '\"':
983 case '`':
984 p = nasm_skip_string(p - 1) + 1;
985 break;
986 default:
987 break;
990 p--;
991 if (*p)
992 *p++ = '\0';
993 if (lvl && verbose)
994 error(ERR_NONFATAL, "unterminated %[ construct");
995 type = TOK_INDIRECT;
996 } else if (*p == '?') {
997 type = TOK_PREPROC_Q; /* %? */
998 p++;
999 if (*p == '?') {
1000 type = TOK_PREPROC_QQ; /* %?? */
1001 p++;
1003 } else if (*p == '!') {
1004 type = TOK_PREPROC_ID;
1005 p++;
1006 if (isidchar(*p)) {
1007 do {
1008 p++;
1009 } while (isidchar(*p));
1010 } else if (*p == '\'' || *p == '\"' || *p == '`') {
1011 p = nasm_skip_string(p);
1012 if (*p)
1013 p++;
1014 else if(verbose)
1015 error(ERR_NONFATAL|ERR_PASS1, "unterminated %! string");
1016 } else {
1017 /* %! without string or identifier */
1018 type = TOK_OTHER; /* Legacy behavior... */
1020 } else if (isidchar(*p) ||
1021 ((*p == '!' || *p == '%' || *p == '$') &&
1022 isidchar(p[1]))) {
1023 do {
1024 p++;
1026 while (isidchar(*p));
1027 type = TOK_PREPROC_ID;
1028 } else {
1029 type = TOK_OTHER;
1030 if (*p == '%')
1031 p++;
1033 } else if (isidstart(*p) || (*p == '$' && isidstart(p[1]))) {
1034 type = TOK_ID;
1035 p++;
1036 while (*p && isidchar(*p))
1037 p++;
1038 } else if (*p == '\'' || *p == '"' || *p == '`') {
1040 * A string token.
1042 type = TOK_STRING;
1043 p = nasm_skip_string(p);
1045 if (*p) {
1046 p++;
1047 } else if(verbose) {
1048 error(ERR_WARNING|ERR_PASS1, "unterminated string");
1049 /* Handling unterminated strings by UNV */
1050 /* type = -1; */
1052 } else if (p[0] == '$' && p[1] == '$') {
1053 type = TOK_OTHER; /* TOKEN_BASE */
1054 p += 2;
1055 } else if (isnumstart(*p)) {
1056 bool is_hex = false;
1057 bool is_float = false;
1058 bool has_e = false;
1059 char c, *r;
1062 * A numeric token.
1065 if (*p == '$') {
1066 p++;
1067 is_hex = true;
1070 for (;;) {
1071 c = *p++;
1073 if (!is_hex && (c == 'e' || c == 'E')) {
1074 has_e = true;
1075 if (*p == '+' || *p == '-') {
1077 * e can only be followed by +/- if it is either a
1078 * prefixed hex number or a floating-point number
1080 p++;
1081 is_float = true;
1083 } else if (c == 'H' || c == 'h' || c == 'X' || c == 'x') {
1084 is_hex = true;
1085 } else if (c == 'P' || c == 'p') {
1086 is_float = true;
1087 if (*p == '+' || *p == '-')
1088 p++;
1089 } else if (isnumchar(c) || c == '_')
1090 ; /* just advance */
1091 else if (c == '.') {
1093 * we need to deal with consequences of the legacy
1094 * parser, like "1.nolist" being two tokens
1095 * (TOK_NUMBER, TOK_ID) here; at least give it
1096 * a shot for now. In the future, we probably need
1097 * a flex-based scanner with proper pattern matching
1098 * to do it as well as it can be done. Nothing in
1099 * the world is going to help the person who wants
1100 * 0x123.p16 interpreted as two tokens, though.
1102 r = p;
1103 while (*r == '_')
1104 r++;
1106 if (nasm_isdigit(*r) || (is_hex && nasm_isxdigit(*r)) ||
1107 (!is_hex && (*r == 'e' || *r == 'E')) ||
1108 (*r == 'p' || *r == 'P')) {
1109 p = r;
1110 is_float = true;
1111 } else
1112 break; /* Terminate the token */
1113 } else
1114 break;
1116 p--; /* Point to first character beyond number */
1118 if (p == line+1 && *line == '$') {
1119 type = TOK_OTHER; /* TOKEN_HERE */
1120 } else {
1121 if (has_e && !is_hex) {
1122 /* 1e13 is floating-point, but 1e13h is not */
1123 is_float = true;
1126 type = is_float ? TOK_FLOAT : TOK_NUMBER;
1128 } else if (nasm_isspace(*p)) {
1129 type = TOK_WHITESPACE;
1130 p = nasm_skip_spaces(p);
1132 * Whitespace just before end-of-line is discarded by
1133 * pretending it's a comment; whitespace just before a
1134 * comment gets lumped into the comment.
1136 if (!*p || *p == ';') {
1137 type = TOK_COMMENT;
1138 while (*p)
1139 p++;
1141 } else if (*p == ';') {
1142 type = TOK_COMMENT;
1143 while (*p)
1144 p++;
1145 } else {
1147 * Anything else is an operator of some kind. We check
1148 * for all the double-character operators (>>, <<, //,
1149 * %%, <=, >=, ==, !=, <>, &&, ||, ^^), but anything
1150 * else is a single-character operator.
1152 type = TOK_OTHER;
1153 if ((p[0] == '>' && p[1] == '>') ||
1154 (p[0] == '<' && p[1] == '<') ||
1155 (p[0] == '/' && p[1] == '/') ||
1156 (p[0] == '<' && p[1] == '=') ||
1157 (p[0] == '>' && p[1] == '=') ||
1158 (p[0] == '=' && p[1] == '=') ||
1159 (p[0] == '!' && p[1] == '=') ||
1160 (p[0] == '<' && p[1] == '>') ||
1161 (p[0] == '&' && p[1] == '&') ||
1162 (p[0] == '|' && p[1] == '|') ||
1163 (p[0] == '^' && p[1] == '^')) {
1164 p++;
1166 p++;
1169 /* Handling unterminated string by UNV */
1170 /*if (type == -1)
1172 *tail = t = new_Token(NULL, TOK_STRING, line, p-line+1);
1173 t->text[p-line] = *line;
1174 tail = &t->next;
1176 else */
1177 if (type != TOK_COMMENT) {
1178 *tail = t = new_Token(NULL, type, line, p - line);
1179 tail = &t->next;
1181 line = p;
1183 return list;
1187 * this function allocates a new managed block of memory and
1188 * returns a pointer to the block. The managed blocks are
1189 * deleted only all at once by the delete_Blocks function.
1191 static void *new_Block(size_t size)
1193 Blocks *b = &blocks;
1195 /* first, get to the end of the linked list */
1196 while (b->next)
1197 b = b->next;
1198 /* now allocate the requested chunk */
1199 b->chunk = nasm_malloc(size);
1201 /* now allocate a new block for the next request */
1202 b->next = nasm_malloc(sizeof(Blocks));
1203 /* and initialize the contents of the new block */
1204 b->next->next = NULL;
1205 b->next->chunk = NULL;
1206 return b->chunk;
1210 * this function deletes all managed blocks of memory
1212 static void delete_Blocks(void)
1214 Blocks *a, *b = &blocks;
1217 * keep in mind that the first block, pointed to by blocks
1218 * is a static and not dynamically allocated, so we don't
1219 * free it.
1221 while (b) {
1222 if (b->chunk)
1223 nasm_free(b->chunk);
1224 a = b;
1225 b = b->next;
1226 if (a != &blocks)
1227 nasm_free(a);
1232 * this function creates a new Token and passes a pointer to it
1233 * back to the caller. It sets the type and text elements, and
1234 * also the a.mac and next elements to NULL.
1236 static Token *new_Token(Token * next, enum pp_token_type type,
1237 const char *text, int txtlen)
1239 Token *t;
1240 int i;
1242 if (!freeTokens) {
1243 freeTokens = (Token *) new_Block(TOKEN_BLOCKSIZE * sizeof(Token));
1244 for (i = 0; i < TOKEN_BLOCKSIZE - 1; i++)
1245 freeTokens[i].next = &freeTokens[i + 1];
1246 freeTokens[i].next = NULL;
1248 t = freeTokens;
1249 freeTokens = t->next;
1250 t->next = next;
1251 t->a.mac = NULL;
1252 t->type = type;
1253 if (type == TOK_WHITESPACE || !text) {
1254 t->text = NULL;
1255 } else {
1256 if (txtlen == 0)
1257 txtlen = strlen(text);
1258 t->text = nasm_malloc(txtlen+1);
1259 memcpy(t->text, text, txtlen);
1260 t->text[txtlen] = '\0';
1262 return t;
1265 static Token *copy_Token(Token * tline)
1267 Token *t, *tt, *first = NULL, *prev = NULL;
1268 int i;
1269 for (tt = tline; tt != NULL; tt = tt->next) {
1270 if (!freeTokens) {
1271 freeTokens = (Token *) new_Block(TOKEN_BLOCKSIZE * sizeof(Token));
1272 for (i = 0; i < TOKEN_BLOCKSIZE - 1; i++)
1273 freeTokens[i].next = &freeTokens[i + 1];
1274 freeTokens[i].next = NULL;
1276 t = freeTokens;
1277 freeTokens = t->next;
1278 t->next = NULL;
1279 t->text = tt->text ? nasm_strdup(tt->text) : NULL;
1280 t->a.mac = tt->a.mac;
1281 t->a.len = tt->a.len;
1282 t->type = tt->type;
1283 if (prev != NULL) {
1284 prev->next = t;
1285 } else {
1286 first = t;
1288 prev = t;
1290 return first;
1293 static Token *delete_Token(Token * t)
1295 Token *next = t->next;
1296 nasm_free(t->text);
1297 t->next = freeTokens;
1298 freeTokens = t;
1299 return next;
1303 * Convert a line of tokens back into text.
1304 * If expand_locals is not zero, identifiers of the form "%$*xxx"
1305 * will be transformed into ..@ctxnum.xxx
1307 static char *detoken(Token * tlist, bool expand_locals)
1309 Token *t;
1310 char *line, *p;
1311 const char *q;
1312 int len = 0;
1314 list_for_each(t, tlist) {
1315 if (t->type == TOK_PREPROC_ID && t->text[1] == '!') {
1316 char *v;
1317 char *q = t->text;
1319 v = t->text + 2;
1320 if (*v == '\'' || *v == '\"' || *v == '`') {
1321 size_t len = nasm_unquote(v, NULL);
1322 size_t clen = strlen(v);
1324 if (len != clen) {
1325 error(ERR_NONFATAL | ERR_PASS1,
1326 "NUL character in %! string");
1327 v = NULL;
1331 if (v) {
1332 char *p = getenv(v);
1333 if (!p) {
1334 error(ERR_NONFATAL | ERR_PASS1,
1335 "nonexistent environment variable `%s'", v);
1336 p = "";
1338 t->text = nasm_strdup(p);
1340 nasm_free(q);
1343 /* Expand local macros here and not during preprocessing */
1344 if (expand_locals &&
1345 t->type == TOK_PREPROC_ID && t->text &&
1346 t->text[0] == '%' && t->text[1] == '$') {
1347 const char *q;
1348 char *p;
1349 Context *ctx = get_ctx(t->text, &q, false);
1350 if (ctx) {
1351 char buffer[40];
1352 snprintf(buffer, sizeof(buffer), "..@%"PRIu32".", ctx->number);
1353 p = nasm_strcat(buffer, q);
1354 nasm_free(t->text);
1355 t->text = p;
1359 /* Expand %? and %?? directives */
1360 if ((istk->expansion != NULL) &&
1361 ((t->type == TOK_PREPROC_Q) ||
1362 (t->type == TOK_PREPROC_QQ))) {
1363 ExpInv *ei;
1364 for (ei = istk->expansion; ei != NULL; ei = ei->prev){
1365 if (ei->type == EXP_MMACRO) {
1366 nasm_free(t->text);
1367 if (t->type == TOK_PREPROC_Q) {
1368 t->text = nasm_strdup(ei->name);
1369 } else {
1370 t->text = nasm_strdup(ei->def->name);
1372 break;
1377 if (t->type == TOK_WHITESPACE)
1378 len++;
1379 else if (t->text)
1380 len += strlen(t->text);
1383 p = line = nasm_malloc(len + 1);
1385 list_for_each(t, tlist) {
1386 if (t->type == TOK_WHITESPACE) {
1387 *p++ = ' ';
1388 } else if (t->text) {
1389 q = t->text;
1390 while (*q)
1391 *p++ = *q++;
1394 *p = '\0';
1396 return line;
1400 * Initialize a new Line
1402 static inline Line *new_Line(void)
1404 Line *l = nasm_malloc(sizeof(Line));
1405 l->next = NULL;
1406 l->first = NULL;
1407 return l;
1412 * Initialize a new Expansion Definition
1414 static ExpDef *new_ExpDef(int exp_type)
1416 ExpDef *ed = (ExpDef*)nasm_zalloc(sizeof(ExpDef));
1417 ed->type = exp_type;
1418 ed->casesense = true;
1419 ed->state = COND_NEVER;
1421 return ed;
1426 * Initialize a new Expansion Instance
1428 static ExpInv *new_ExpInv(int exp_type, ExpDef *ed)
1430 ExpInv *ei = (ExpInv*)nasm_zalloc(sizeof(ExpInv));
1431 ei->type = exp_type;
1432 ei->def = ed;
1433 ei->unique = ++unique;
1435 if ((istk->mmac_depth < 1) &&
1436 (istk->expansion == NULL) &&
1437 (ed != NULL) &&
1438 (ed->type != EXP_MMACRO) &&
1439 (ed->type != EXP_REP) &&
1440 (ed->type != EXP_WHILE)) {
1441 ei->linnum = src_get_linnum();
1442 src_set_linnum(ei->linnum - ed->linecount - 1);
1443 } else {
1444 ei->linnum = -1;
1446 if ((istk->expansion == NULL) ||
1447 (ei->type == EXP_MMACRO)) {
1448 ei->relno = 0;
1449 } else {
1450 ei->relno = istk->expansion->lineno;
1451 if (ed != NULL) {
1452 ei->relno -= (ed->linecount + 1);
1455 return ei;
1459 * A scanner, suitable for use by the expression evaluator, which
1460 * operates on a line of Tokens. Expects a pointer to a pointer to
1461 * the first token in the line to be passed in as its private_data
1462 * field.
1464 * FIX: This really needs to be unified with stdscan.
1466 static int ppscan(void *private_data, struct tokenval *tokval)
1468 Token **tlineptr = private_data;
1469 Token *tline;
1470 char ourcopy[MAX_KEYWORD+1], *p, *r, *s;
1472 do {
1473 tline = *tlineptr;
1474 *tlineptr = tline ? tline->next : NULL;
1475 } while (tline && (tline->type == TOK_WHITESPACE ||
1476 tline->type == TOK_COMMENT));
1478 if (!tline)
1479 return tokval->t_type = TOKEN_EOS;
1481 tokval->t_charptr = tline->text;
1483 if (tline->text[0] == '$' && !tline->text[1])
1484 return tokval->t_type = TOKEN_HERE;
1485 if (tline->text[0] == '$' && tline->text[1] == '$' && !tline->text[2])
1486 return tokval->t_type = TOKEN_BASE;
1488 if (tline->type == TOK_ID) {
1489 p = tokval->t_charptr = tline->text;
1490 if (p[0] == '$') {
1491 tokval->t_charptr++;
1492 return tokval->t_type = TOKEN_ID;
1495 for (r = p, s = ourcopy; *r; r++) {
1496 if (r >= p+MAX_KEYWORD)
1497 return tokval->t_type = TOKEN_ID; /* Not a keyword */
1498 *s++ = nasm_tolower(*r);
1500 *s = '\0';
1501 /* right, so we have an identifier sitting in temp storage. now,
1502 * is it actually a register or instruction name, or what? */
1503 return nasm_token_hash(ourcopy, tokval);
1506 if (tline->type == TOK_NUMBER) {
1507 bool rn_error;
1508 tokval->t_integer = readnum(tline->text, &rn_error);
1509 tokval->t_charptr = tline->text;
1510 if (rn_error)
1511 return tokval->t_type = TOKEN_ERRNUM;
1512 else
1513 return tokval->t_type = TOKEN_NUM;
1516 if (tline->type == TOK_FLOAT) {
1517 return tokval->t_type = TOKEN_FLOAT;
1520 if (tline->type == TOK_STRING) {
1521 char bq, *ep;
1523 bq = tline->text[0];
1524 tokval->t_charptr = tline->text;
1525 tokval->t_inttwo = nasm_unquote(tline->text, &ep);
1527 if (ep[0] != bq || ep[1] != '\0')
1528 return tokval->t_type = TOKEN_ERRSTR;
1529 else
1530 return tokval->t_type = TOKEN_STR;
1533 if (tline->type == TOK_OTHER) {
1534 if (!strcmp(tline->text, "<<"))
1535 return tokval->t_type = TOKEN_SHL;
1536 if (!strcmp(tline->text, ">>"))
1537 return tokval->t_type = TOKEN_SHR;
1538 if (!strcmp(tline->text, "//"))
1539 return tokval->t_type = TOKEN_SDIV;
1540 if (!strcmp(tline->text, "%%"))
1541 return tokval->t_type = TOKEN_SMOD;
1542 if (!strcmp(tline->text, "=="))
1543 return tokval->t_type = TOKEN_EQ;
1544 if (!strcmp(tline->text, "<>"))
1545 return tokval->t_type = TOKEN_NE;
1546 if (!strcmp(tline->text, "!="))
1547 return tokval->t_type = TOKEN_NE;
1548 if (!strcmp(tline->text, "<="))
1549 return tokval->t_type = TOKEN_LE;
1550 if (!strcmp(tline->text, ">="))
1551 return tokval->t_type = TOKEN_GE;
1552 if (!strcmp(tline->text, "&&"))
1553 return tokval->t_type = TOKEN_DBL_AND;
1554 if (!strcmp(tline->text, "^^"))
1555 return tokval->t_type = TOKEN_DBL_XOR;
1556 if (!strcmp(tline->text, "||"))
1557 return tokval->t_type = TOKEN_DBL_OR;
1561 * We have no other options: just return the first character of
1562 * the token text.
1564 return tokval->t_type = tline->text[0];
1568 * Compare a string to the name of an existing macro; this is a
1569 * simple wrapper which calls either strcmp or nasm_stricmp
1570 * depending on the value of the `casesense' parameter.
1572 static int mstrcmp(const char *p, const char *q, bool casesense)
1574 return casesense ? strcmp(p, q) : nasm_stricmp(p, q);
1578 * Compare a string to the name of an existing macro; this is a
1579 * simple wrapper which calls either strcmp or nasm_stricmp
1580 * depending on the value of the `casesense' parameter.
1582 static int mmemcmp(const char *p, const char *q, size_t l, bool casesense)
1584 return casesense ? memcmp(p, q, l) : nasm_memicmp(p, q, l);
1588 * Return the Context structure associated with a %$ token. Return
1589 * NULL, having _already_ reported an error condition, if the
1590 * context stack isn't deep enough for the supplied number of $
1591 * signs.
1592 * If all_contexts == true, contexts that enclose current are
1593 * also scanned for such smacro, until it is found; if not -
1594 * only the context that directly results from the number of $'s
1595 * in variable's name.
1597 * If "namep" is non-NULL, set it to the pointer to the macro name
1598 * tail, i.e. the part beyond %$...
1600 static Context *get_ctx(const char *name, const char **namep,
1601 bool all_contexts)
1603 Context *ctx;
1604 SMacro *m;
1605 int i;
1607 if (namep)
1608 *namep = name;
1610 if (!name || name[0] != '%' || name[1] != '$')
1611 return NULL;
1613 if (!cstk) {
1614 error(ERR_NONFATAL, "`%s': context stack is empty", name);
1615 return NULL;
1618 name += 2;
1619 ctx = cstk;
1620 i = 0;
1621 while (ctx && *name == '$') {
1622 name++;
1623 i++;
1624 ctx = ctx->next;
1626 if (!ctx) {
1627 error(ERR_NONFATAL, "`%s': context stack is only"
1628 " %d level%s deep", name, i, (i == 1 ? "" : "s"));
1629 return NULL;
1632 if (namep)
1633 *namep = name;
1635 if (!all_contexts)
1636 return ctx;
1638 do {
1639 /* Search for this smacro in found context */
1640 m = hash_findix(&ctx->localmac, name);
1641 while (m) {
1642 if (!mstrcmp(m->name, name, m->casesense))
1643 return ctx;
1644 m = m->next;
1646 ctx = ctx->next;
1648 while (ctx);
1649 return NULL;
1653 * Check to see if a file is already in a string list
1655 static bool in_list(const StrList *list, const char *str)
1657 while (list) {
1658 if (!strcmp(list->str, str))
1659 return true;
1660 list = list->next;
1662 return false;
1666 * Open an include file. This routine must always return a valid
1667 * file pointer if it returns - it's responsible for throwing an
1668 * ERR_FATAL and bombing out completely if not. It should also try
1669 * the include path one by one until it finds the file or reaches
1670 * the end of the path.
1672 static FILE *inc_fopen(const char *file, StrList **dhead, StrList ***dtail,
1673 bool missing_ok)
1675 FILE *fp;
1676 char *prefix = "";
1677 IncPath *ip = ipath;
1678 int len = strlen(file);
1679 size_t prefix_len = 0;
1680 StrList *sl;
1682 while (1) {
1683 sl = nasm_malloc(prefix_len+len+1+sizeof sl->next);
1684 sl->next = NULL;
1685 memcpy(sl->str, prefix, prefix_len);
1686 memcpy(sl->str+prefix_len, file, len+1);
1687 fp = fopen(sl->str, "r");
1688 if (fp && dhead && !in_list(*dhead, sl->str)) {
1689 **dtail = sl;
1690 *dtail = &sl->next;
1691 } else {
1692 nasm_free(sl);
1694 if (fp)
1695 return fp;
1696 if (!ip) {
1697 if (!missing_ok)
1698 break;
1699 prefix = NULL;
1700 } else {
1701 prefix = ip->path;
1702 ip = ip->next;
1704 if (prefix) {
1705 prefix_len = strlen(prefix);
1706 } else {
1707 /* -MG given and file not found */
1708 if (dhead && !in_list(*dhead, file)) {
1709 sl = nasm_malloc(len+1+sizeof sl->next);
1710 sl->next = NULL;
1711 strcpy(sl->str, file);
1712 **dtail = sl;
1713 *dtail = &sl->next;
1715 return NULL;
1719 error(ERR_FATAL, "unable to open include file `%s'", file);
1720 return NULL;
1724 * Determine if we should warn on defining a single-line macro of
1725 * name `name', with `nparam' parameters. If nparam is 0 or -1, will
1726 * return true if _any_ single-line macro of that name is defined.
1727 * Otherwise, will return true if a single-line macro with either
1728 * `nparam' or no parameters is defined.
1730 * If a macro with precisely the right number of parameters is
1731 * defined, or nparam is -1, the address of the definition structure
1732 * will be returned in `defn'; otherwise NULL will be returned. If `defn'
1733 * is NULL, no action will be taken regarding its contents, and no
1734 * error will occur.
1736 * Note that this is also called with nparam zero to resolve
1737 * `ifdef'.
1739 * If you already know which context macro belongs to, you can pass
1740 * the context pointer as first parameter; if you won't but name begins
1741 * with %$ the context will be automatically computed. If all_contexts
1742 * is true, macro will be searched in outer contexts as well.
1744 static bool
1745 smacro_defined(Context * ctx, const char *name, int nparam, SMacro ** defn,
1746 bool nocase)
1748 struct hash_table *smtbl;
1749 SMacro *m;
1751 if (ctx) {
1752 smtbl = &ctx->localmac;
1753 } else if (name[0] == '%' && name[1] == '$') {
1754 if (cstk)
1755 ctx = get_ctx(name, &name, false);
1756 if (!ctx)
1757 return false; /* got to return _something_ */
1758 smtbl = &ctx->localmac;
1759 } else {
1760 smtbl = &smacros;
1762 m = (SMacro *) hash_findix(smtbl, name);
1764 while (m) {
1765 if (!mstrcmp(m->name, name, m->casesense && nocase) &&
1766 (nparam <= 0 || m->nparam == 0 || nparam == (int) m->nparam)) {
1767 if (defn) {
1768 if (nparam == (int) m->nparam || nparam == -1)
1769 *defn = m;
1770 else
1771 *defn = NULL;
1773 return true;
1775 m = m->next;
1778 return false;
1782 * Count and mark off the parameters in a multi-line macro call.
1783 * This is called both from within the multi-line macro expansion
1784 * code, and also to mark off the default parameters when provided
1785 * in a %macro definition line.
1787 static void count_mmac_params(Token * t, int *nparam, Token *** params)
1789 int paramsize, brace;
1791 *nparam = paramsize = 0;
1792 *params = NULL;
1793 while (t) {
1794 /* +1: we need space for the final NULL */
1795 if (*nparam+1 >= paramsize) {
1796 paramsize += PARAM_DELTA;
1797 *params = nasm_realloc(*params, sizeof(**params) * paramsize);
1799 skip_white_(t);
1800 brace = false;
1801 if (tok_is_(t, "{"))
1802 brace = true;
1803 (*params)[(*nparam)++] = t;
1804 while (tok_isnt_(t, brace ? "}" : ","))
1805 t = t->next;
1806 if (t) { /* got a comma/brace */
1807 t = t->next;
1808 if (brace) {
1810 * Now we've found the closing brace, look further
1811 * for the comma.
1813 skip_white_(t);
1814 if (tok_isnt_(t, ",")) {
1815 error(ERR_NONFATAL,
1816 "braces do not enclose all of macro parameter");
1817 while (tok_isnt_(t, ","))
1818 t = t->next;
1820 if (t)
1821 t = t->next; /* eat the comma */
1828 * Determine whether one of the various `if' conditions is true or
1829 * not.
1831 * We must free the tline we get passed.
1833 static bool if_condition(Token * tline, enum preproc_token ct)
1835 enum pp_conditional i = PP_COND(ct);
1836 bool j;
1837 Token *t, *tt, **tptr, *origline;
1838 struct tokenval tokval;
1839 expr *evalresult;
1840 enum pp_token_type needtype;
1841 char *p;
1843 origline = tline;
1845 switch (i) {
1846 case PPC_IFCTX:
1847 j = false; /* have we matched yet? */
1848 while (true) {
1849 skip_white_(tline);
1850 if (!tline)
1851 break;
1852 if (tline->type != TOK_ID) {
1853 error(ERR_NONFATAL,
1854 "`%s' expects context identifiers", pp_directives[ct]);
1855 free_tlist(origline);
1856 return -1;
1858 if (cstk && cstk->name && !nasm_stricmp(tline->text, cstk->name))
1859 j = true;
1860 tline = tline->next;
1862 break;
1864 case PPC_IFDEF:
1865 j = false; /* have we matched yet? */
1866 while (tline) {
1867 skip_white_(tline);
1868 if (!tline || (tline->type != TOK_ID &&
1869 (tline->type != TOK_PREPROC_ID ||
1870 tline->text[1] != '$'))) {
1871 error(ERR_NONFATAL,
1872 "`%s' expects macro identifiers", pp_directives[ct]);
1873 goto fail;
1875 if (smacro_defined(NULL, tline->text, 0, NULL, true))
1876 j = true;
1877 tline = tline->next;
1879 break;
1881 case PPC_IFENV:
1882 tline = expand_smacro(tline);
1883 j = false; /* have we matched yet? */
1884 while (tline) {
1885 skip_white_(tline);
1886 if (!tline || (tline->type != TOK_ID &&
1887 tline->type != TOK_STRING &&
1888 (tline->type != TOK_PREPROC_ID ||
1889 tline->text[1] != '!'))) {
1890 error(ERR_NONFATAL,
1891 "`%s' expects environment variable names",
1892 pp_directives[ct]);
1893 goto fail;
1895 p = tline->text;
1896 if (tline->type == TOK_PREPROC_ID)
1897 p += 2; /* Skip leading %! */
1898 if (*p == '\'' || *p == '\"' || *p == '`')
1899 nasm_unquote_cstr(p, ct);
1900 if (getenv(p))
1901 j = true;
1902 tline = tline->next;
1904 break;
1906 case PPC_IFIDN:
1907 case PPC_IFIDNI:
1908 tline = expand_smacro(tline);
1909 t = tt = tline;
1910 while (tok_isnt_(tt, ","))
1911 tt = tt->next;
1912 if (!tt) {
1913 error(ERR_NONFATAL,
1914 "`%s' expects two comma-separated arguments",
1915 pp_directives[ct]);
1916 goto fail;
1918 tt = tt->next;
1919 j = true; /* assume equality unless proved not */
1920 while ((t->type != TOK_OTHER || strcmp(t->text, ",")) && tt) {
1921 if (tt->type == TOK_OTHER && !strcmp(tt->text, ",")) {
1922 error(ERR_NONFATAL, "`%s': more than one comma on line",
1923 pp_directives[ct]);
1924 goto fail;
1926 if (t->type == TOK_WHITESPACE) {
1927 t = t->next;
1928 continue;
1930 if (tt->type == TOK_WHITESPACE) {
1931 tt = tt->next;
1932 continue;
1934 if (tt->type != t->type) {
1935 j = false; /* found mismatching tokens */
1936 break;
1938 /* When comparing strings, need to unquote them first */
1939 if (t->type == TOK_STRING) {
1940 size_t l1 = nasm_unquote(t->text, NULL);
1941 size_t l2 = nasm_unquote(tt->text, NULL);
1943 if (l1 != l2) {
1944 j = false;
1945 break;
1947 if (mmemcmp(t->text, tt->text, l1, i == PPC_IFIDN)) {
1948 j = false;
1949 break;
1951 } else if (mstrcmp(tt->text, t->text, i == PPC_IFIDN) != 0) {
1952 j = false; /* found mismatching tokens */
1953 break;
1956 t = t->next;
1957 tt = tt->next;
1959 if ((t->type != TOK_OTHER || strcmp(t->text, ",")) || tt)
1960 j = false; /* trailing gunk on one end or other */
1961 break;
1963 case PPC_IFMACRO:
1965 bool found = false;
1966 ExpDef searching, *ed;
1968 skip_white_(tline);
1969 tline = expand_id(tline);
1970 if (!tok_type_(tline, TOK_ID)) {
1971 error(ERR_NONFATAL,
1972 "`%s' expects a macro name", pp_directives[ct]);
1973 goto fail;
1975 memset(&searching, 0, sizeof(searching));
1976 searching.name = nasm_strdup(tline->text);
1977 searching.casesense = true;
1978 searching.nparam_max = INT_MAX;
1979 tline = expand_smacro(tline->next);
1980 skip_white_(tline);
1981 if (!tline) {
1982 } else if (!tok_type_(tline, TOK_NUMBER)) {
1983 error(ERR_NONFATAL,
1984 "`%s' expects a parameter count or nothing",
1985 pp_directives[ct]);
1986 } else {
1987 searching.nparam_min = searching.nparam_max =
1988 readnum(tline->text, &j);
1989 if (j)
1990 error(ERR_NONFATAL,
1991 "unable to parse parameter count `%s'",
1992 tline->text);
1994 if (tline && tok_is_(tline->next, "-")) {
1995 tline = tline->next->next;
1996 if (tok_is_(tline, "*"))
1997 searching.nparam_max = INT_MAX;
1998 else if (!tok_type_(tline, TOK_NUMBER))
1999 error(ERR_NONFATAL,
2000 "`%s' expects a parameter count after `-'",
2001 pp_directives[ct]);
2002 else {
2003 searching.nparam_max = readnum(tline->text, &j);
2004 if (j)
2005 error(ERR_NONFATAL,
2006 "unable to parse parameter count `%s'",
2007 tline->text);
2008 if (searching.nparam_min > searching.nparam_max)
2009 error(ERR_NONFATAL,
2010 "minimum parameter count exceeds maximum");
2013 if (tline && tok_is_(tline->next, "+")) {
2014 tline = tline->next;
2015 searching.plus = true;
2017 ed = (ExpDef *) hash_findix(&expdefs, searching.name);
2018 while (ed != NULL) {
2019 if (!strcmp(ed->name, searching.name) &&
2020 (ed->nparam_min <= searching.nparam_max || searching.plus) &&
2021 (searching.nparam_min <= ed->nparam_max || ed->plus)) {
2022 found = true;
2023 break;
2025 ed = ed->next;
2027 if (tline && tline->next)
2028 error(ERR_WARNING|ERR_PASS1,
2029 "trailing garbage after %%ifmacro ignored");
2030 nasm_free(searching.name);
2031 j = found;
2032 break;
2035 case PPC_IFID:
2036 needtype = TOK_ID;
2037 goto iftype;
2038 case PPC_IFNUM:
2039 needtype = TOK_NUMBER;
2040 goto iftype;
2041 case PPC_IFSTR:
2042 needtype = TOK_STRING;
2043 goto iftype;
2045 iftype:
2046 t = tline = expand_smacro(tline);
2048 while (tok_type_(t, TOK_WHITESPACE) ||
2049 (needtype == TOK_NUMBER &&
2050 tok_type_(t, TOK_OTHER) &&
2051 (t->text[0] == '-' || t->text[0] == '+') &&
2052 !t->text[1]))
2053 t = t->next;
2055 j = tok_type_(t, needtype);
2056 break;
2058 case PPC_IFTOKEN:
2059 t = tline = expand_smacro(tline);
2060 while (tok_type_(t, TOK_WHITESPACE))
2061 t = t->next;
2063 j = false;
2064 if (t) {
2065 t = t->next; /* Skip the actual token */
2066 while (tok_type_(t, TOK_WHITESPACE))
2067 t = t->next;
2068 j = !t; /* Should be nothing left */
2070 break;
2072 case PPC_IFEMPTY:
2073 t = tline = expand_smacro(tline);
2074 while (tok_type_(t, TOK_WHITESPACE))
2075 t = t->next;
2077 j = !t; /* Should be empty */
2078 break;
2080 case PPC_IF:
2081 t = tline = expand_smacro(tline);
2082 tptr = &t;
2083 tokval.t_type = TOKEN_INVALID;
2084 evalresult = evaluate(ppscan, tptr, &tokval,
2085 NULL, pass | CRITICAL, error, NULL);
2086 if (!evalresult)
2087 return -1;
2088 if (tokval.t_type)
2089 error(ERR_WARNING|ERR_PASS1,
2090 "trailing garbage after expression ignored");
2091 if (!is_simple(evalresult)) {
2092 error(ERR_NONFATAL,
2093 "non-constant value given to `%s'", pp_directives[ct]);
2094 goto fail;
2096 j = reloc_value(evalresult) != 0;
2097 break;
2099 default:
2100 error(ERR_FATAL,
2101 "preprocessor directive `%s' not yet implemented",
2102 pp_directives[ct]);
2103 goto fail;
2106 free_tlist(origline);
2107 return j ^ PP_NEGATIVE(ct);
2109 fail:
2110 free_tlist(origline);
2111 return -1;
2115 * Common code for defining an smacro
2117 static bool define_smacro(Context *ctx, const char *mname, bool casesense,
2118 int nparam, Token *expansion)
2120 SMacro *smac, **smhead;
2121 struct hash_table *smtbl;
2123 if (smacro_defined(ctx, mname, nparam, &smac, casesense)) {
2124 if (!smac) {
2125 error(ERR_WARNING|ERR_PASS1,
2126 "single-line macro `%s' defined both with and"
2127 " without parameters", mname);
2129 * Some instances of the old code considered this a failure,
2130 * some others didn't. What is the right thing to do here?
2132 free_tlist(expansion);
2133 return false; /* Failure */
2134 } else {
2136 * We're redefining, so we have to take over an
2137 * existing SMacro structure. This means freeing
2138 * what was already in it.
2140 nasm_free(smac->name);
2141 free_tlist(smac->expansion);
2143 } else {
2144 smtbl = ctx ? &ctx->localmac : &smacros;
2145 smhead = (SMacro **) hash_findi_add(smtbl, mname);
2146 smac = nasm_zalloc(sizeof(SMacro));
2147 smac->next = *smhead;
2148 *smhead = smac;
2150 smac->name = nasm_strdup(mname);
2151 smac->casesense = casesense;
2152 smac->nparam = nparam;
2153 smac->expansion = expansion;
2154 smac->in_progress = false;
2155 return true; /* Success */
2159 * Undefine an smacro
2161 static void undef_smacro(Context *ctx, const char *mname)
2163 SMacro **smhead, *s, **sp;
2164 struct hash_table *smtbl;
2166 smtbl = ctx ? &ctx->localmac : &smacros;
2167 smhead = (SMacro **)hash_findi(smtbl, mname, NULL);
2169 if (smhead) {
2171 * We now have a macro name... go hunt for it.
2173 sp = smhead;
2174 while ((s = *sp) != NULL) {
2175 if (!mstrcmp(s->name, mname, s->casesense)) {
2176 *sp = s->next;
2177 nasm_free(s->name);
2178 free_tlist(s->expansion);
2179 nasm_free(s);
2180 } else {
2181 sp = &s->next;
2188 * Parse a mmacro specification.
2190 static bool parse_mmacro_spec(Token *tline, ExpDef *def, const char *directive)
2192 bool err;
2194 tline = tline->next;
2195 skip_white_(tline);
2196 tline = expand_id(tline);
2197 if (!tok_type_(tline, TOK_ID)) {
2198 error(ERR_NONFATAL, "`%s' expects a macro name", directive);
2199 return false;
2202 def->name = nasm_strdup(tline->text);
2203 def->plus = false;
2204 def->nolist = false;
2205 // def->in_progress = 0;
2206 // def->rep_nest = NULL;
2207 def->nparam_min = 0;
2208 def->nparam_max = 0;
2210 tline = expand_smacro(tline->next);
2211 skip_white_(tline);
2212 if (!tok_type_(tline, TOK_NUMBER)) {
2213 error(ERR_NONFATAL, "`%s' expects a parameter count", directive);
2214 } else {
2215 def->nparam_min = def->nparam_max =
2216 readnum(tline->text, &err);
2217 if (err)
2218 error(ERR_NONFATAL,
2219 "unable to parse parameter count `%s'", tline->text);
2221 if (tline && tok_is_(tline->next, "-")) {
2222 tline = tline->next->next;
2223 if (tok_is_(tline, "*")) {
2224 def->nparam_max = INT_MAX;
2225 } else if (!tok_type_(tline, TOK_NUMBER)) {
2226 error(ERR_NONFATAL,
2227 "`%s' expects a parameter count after `-'", directive);
2228 } else {
2229 def->nparam_max = readnum(tline->text, &err);
2230 if (err) {
2231 error(ERR_NONFATAL, "unable to parse parameter count `%s'",
2232 tline->text);
2234 if (def->nparam_min > def->nparam_max) {
2235 error(ERR_NONFATAL, "minimum parameter count exceeds maximum");
2239 if (tline && tok_is_(tline->next, "+")) {
2240 tline = tline->next;
2241 def->plus = true;
2243 if (tline && tok_type_(tline->next, TOK_ID) &&
2244 !nasm_stricmp(tline->next->text, ".nolist")) {
2245 tline = tline->next;
2246 def->nolist = true;
2250 * Handle default parameters.
2252 if (tline && tline->next) {
2253 def->dlist = tline->next;
2254 tline->next = NULL;
2255 count_mmac_params(def->dlist, &def->ndefs, &def->defaults);
2256 } else {
2257 def->dlist = NULL;
2258 def->defaults = NULL;
2260 def->line = NULL;
2262 if (def->defaults && def->ndefs > def->nparam_max - def->nparam_min &&
2263 !def->plus)
2264 error(ERR_WARNING|ERR_PASS1|ERR_WARN_MDP,
2265 "too many default macro parameters");
2267 return true;
2272 * Decode a size directive
2274 static int parse_size(const char *str) {
2275 static const char *size_names[] =
2276 { "byte", "dword", "oword", "qword", "tword", "word", "yword" };
2277 static const int sizes[] =
2278 { 0, 1, 4, 16, 8, 10, 2, 32 };
2280 return sizes[bsii(str, size_names, ARRAY_SIZE(size_names))+1];
2284 * find and process preprocessor directive in passed line
2285 * Find out if a line contains a preprocessor directive, and deal
2286 * with it if so.
2288 * If a directive _is_ found, it is the responsibility of this routine
2289 * (and not the caller) to free_tlist() the line.
2291 * @param tline a pointer to the current tokeninzed line linked list
2292 * @return DIRECTIVE_FOUND or NO_DIRECTIVE_FOUND
2295 static int do_directive(Token * tline)
2297 enum preproc_token i;
2298 int j;
2299 bool err;
2300 int nparam;
2301 bool nolist;
2302 bool casesense;
2303 int k, m;
2304 int offset;
2305 char *p, *pp;
2306 const char *mname;
2307 Include *inc;
2308 Context *ctx;
2309 Line *l;
2310 Token *t, *tt, *param_start, *macro_start, *last, **tptr, *origline;
2311 struct tokenval tokval;
2312 expr *evalresult;
2313 ExpDef *ed, *eed, **edhead;
2314 ExpInv *ei, *eei;
2315 int64_t count;
2316 size_t len;
2317 int severity;
2319 origline = tline;
2321 skip_white_(tline);
2322 if (!tline || !tok_type_(tline, TOK_PREPROC_ID) ||
2323 (tline->text[1] == '%' || tline->text[1] == '$'
2324 || tline->text[1] == '!'))
2325 return NO_DIRECTIVE_FOUND;
2327 i = pp_token_hash(tline->text);
2329 switch (i) {
2330 case PP_INVALID:
2331 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2332 error(ERR_NONFATAL, "unknown preprocessor directive `%s'",
2333 tline->text);
2334 return NO_DIRECTIVE_FOUND; /* didn't get it */
2336 case PP_STACKSIZE:
2337 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2338 /* Directive to tell NASM what the default stack size is. The
2339 * default is for a 16-bit stack, and this can be overriden with
2340 * %stacksize large.
2342 tline = tline->next;
2343 if (tline && tline->type == TOK_WHITESPACE)
2344 tline = tline->next;
2345 if (!tline || tline->type != TOK_ID) {
2346 error(ERR_NONFATAL, "`%%stacksize' missing size parameter");
2347 free_tlist(origline);
2348 return DIRECTIVE_FOUND;
2350 if (nasm_stricmp(tline->text, "flat") == 0) {
2351 /* All subsequent ARG directives are for a 32-bit stack */
2352 StackSize = 4;
2353 StackPointer = "ebp";
2354 ArgOffset = 8;
2355 LocalOffset = 0;
2356 } else if (nasm_stricmp(tline->text, "flat64") == 0) {
2357 /* All subsequent ARG directives are for a 64-bit stack */
2358 StackSize = 8;
2359 StackPointer = "rbp";
2360 ArgOffset = 16;
2361 LocalOffset = 0;
2362 } else if (nasm_stricmp(tline->text, "large") == 0) {
2363 /* All subsequent ARG directives are for a 16-bit stack,
2364 * far function call.
2366 StackSize = 2;
2367 StackPointer = "bp";
2368 ArgOffset = 4;
2369 LocalOffset = 0;
2370 } else if (nasm_stricmp(tline->text, "small") == 0) {
2371 /* All subsequent ARG directives are for a 16-bit stack,
2372 * far function call. We don't support near functions.
2374 StackSize = 2;
2375 StackPointer = "bp";
2376 ArgOffset = 6;
2377 LocalOffset = 0;
2378 } else {
2379 error(ERR_NONFATAL, "`%%stacksize' invalid size type");
2380 free_tlist(origline);
2381 return DIRECTIVE_FOUND;
2383 free_tlist(origline);
2384 return DIRECTIVE_FOUND;
2386 case PP_ARG:
2387 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2388 /* TASM like ARG directive to define arguments to functions, in
2389 * the following form:
2391 * ARG arg1:WORD, arg2:DWORD, arg4:QWORD
2393 offset = ArgOffset;
2394 do {
2395 char *arg, directive[256];
2396 int size = StackSize;
2398 /* Find the argument name */
2399 tline = tline->next;
2400 if (tline && tline->type == TOK_WHITESPACE)
2401 tline = tline->next;
2402 if (!tline || tline->type != TOK_ID) {
2403 error(ERR_NONFATAL, "`%%arg' missing argument parameter");
2404 free_tlist(origline);
2405 return DIRECTIVE_FOUND;
2407 arg = tline->text;
2409 /* Find the argument size type */
2410 tline = tline->next;
2411 if (!tline || tline->type != TOK_OTHER
2412 || tline->text[0] != ':') {
2413 error(ERR_NONFATAL,
2414 "Syntax error processing `%%arg' directive");
2415 free_tlist(origline);
2416 return DIRECTIVE_FOUND;
2418 tline = tline->next;
2419 if (!tline || tline->type != TOK_ID) {
2420 error(ERR_NONFATAL, "`%%arg' missing size type parameter");
2421 free_tlist(origline);
2422 return DIRECTIVE_FOUND;
2425 /* Allow macro expansion of type parameter */
2426 tt = tokenize(tline->text);
2427 tt = expand_smacro(tt);
2428 size = parse_size(tt->text);
2429 if (!size) {
2430 error(ERR_NONFATAL,
2431 "Invalid size type for `%%arg' missing directive");
2432 free_tlist(tt);
2433 free_tlist(origline);
2434 return DIRECTIVE_FOUND;
2436 free_tlist(tt);
2438 /* Round up to even stack slots */
2439 size = ALIGN(size, StackSize);
2441 /* Now define the macro for the argument */
2442 snprintf(directive, sizeof(directive), "%%define %s (%s+%d)",
2443 arg, StackPointer, offset);
2444 do_directive(tokenize(directive));
2445 offset += size;
2447 /* Move to the next argument in the list */
2448 tline = tline->next;
2449 if (tline && tline->type == TOK_WHITESPACE)
2450 tline = tline->next;
2451 } while (tline && tline->type == TOK_OTHER && tline->text[0] == ',');
2452 ArgOffset = offset;
2453 free_tlist(origline);
2454 return DIRECTIVE_FOUND;
2456 case PP_LOCAL:
2457 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2458 /* TASM like LOCAL directive to define local variables for a
2459 * function, in the following form:
2461 * LOCAL local1:WORD, local2:DWORD, local4:QWORD = LocalSize
2463 * The '= LocalSize' at the end is ignored by NASM, but is
2464 * required by TASM to define the local parameter size (and used
2465 * by the TASM macro package).
2467 offset = LocalOffset;
2468 do {
2469 char *local, directive[256];
2470 int size = StackSize;
2472 /* Find the argument name */
2473 tline = tline->next;
2474 if (tline && tline->type == TOK_WHITESPACE)
2475 tline = tline->next;
2476 if (!tline || tline->type != TOK_ID) {
2477 error(ERR_NONFATAL,
2478 "`%%local' missing argument parameter");
2479 free_tlist(origline);
2480 return DIRECTIVE_FOUND;
2482 local = tline->text;
2484 /* Find the argument size type */
2485 tline = tline->next;
2486 if (!tline || tline->type != TOK_OTHER
2487 || tline->text[0] != ':') {
2488 error(ERR_NONFATAL,
2489 "Syntax error processing `%%local' directive");
2490 free_tlist(origline);
2491 return DIRECTIVE_FOUND;
2493 tline = tline->next;
2494 if (!tline || tline->type != TOK_ID) {
2495 error(ERR_NONFATAL,
2496 "`%%local' missing size type parameter");
2497 free_tlist(origline);
2498 return DIRECTIVE_FOUND;
2501 /* Allow macro expansion of type parameter */
2502 tt = tokenize(tline->text);
2503 tt = expand_smacro(tt);
2504 size = parse_size(tt->text);
2505 if (!size) {
2506 error(ERR_NONFATAL,
2507 "Invalid size type for `%%local' missing directive");
2508 free_tlist(tt);
2509 free_tlist(origline);
2510 return DIRECTIVE_FOUND;
2512 free_tlist(tt);
2514 /* Round up to even stack slots */
2515 size = ALIGN(size, StackSize);
2517 offset += size; /* Negative offset, increment before */
2519 /* Now define the macro for the argument */
2520 snprintf(directive, sizeof(directive), "%%define %s (%s-%d)",
2521 local, StackPointer, offset);
2522 do_directive(tokenize(directive));
2524 /* Now define the assign to setup the enter_c macro correctly */
2525 snprintf(directive, sizeof(directive),
2526 "%%assign %%$localsize %%$localsize+%d", size);
2527 do_directive(tokenize(directive));
2529 /* Move to the next argument in the list */
2530 tline = tline->next;
2531 if (tline && tline->type == TOK_WHITESPACE)
2532 tline = tline->next;
2533 } while (tline && tline->type == TOK_OTHER && tline->text[0] == ',');
2534 LocalOffset = offset;
2535 free_tlist(origline);
2536 return DIRECTIVE_FOUND;
2538 case PP_CLEAR:
2539 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2540 if (tline->next)
2541 error(ERR_WARNING|ERR_PASS1,
2542 "trailing garbage after `%%clear' ignored");
2543 free_macros();
2544 init_macros();
2545 free_tlist(origline);
2546 return DIRECTIVE_FOUND;
2548 case PP_DEPEND:
2549 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2550 t = tline->next = expand_smacro(tline->next);
2551 skip_white_(t);
2552 if (!t || (t->type != TOK_STRING &&
2553 t->type != TOK_INTERNAL_STRING)) {
2554 error(ERR_NONFATAL, "`%%depend' expects a file name");
2555 free_tlist(origline);
2556 return DIRECTIVE_FOUND; /* but we did _something_ */
2558 if (t->next)
2559 error(ERR_WARNING|ERR_PASS1,
2560 "trailing garbage after `%%depend' ignored");
2561 p = t->text;
2562 if (t->type != TOK_INTERNAL_STRING)
2563 nasm_unquote_cstr(p, i);
2564 if (dephead && !in_list(*dephead, p)) {
2565 StrList *sl = nasm_malloc(strlen(p)+1+sizeof sl->next);
2566 sl->next = NULL;
2567 strcpy(sl->str, p);
2568 *deptail = sl;
2569 deptail = &sl->next;
2571 free_tlist(origline);
2572 return DIRECTIVE_FOUND;
2574 case PP_INCLUDE:
2575 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2576 t = tline->next = expand_smacro(tline->next);
2577 skip_white_(t);
2579 if (!t || (t->type != TOK_STRING &&
2580 t->type != TOK_INTERNAL_STRING)) {
2581 error(ERR_NONFATAL, "`%%include' expects a file name");
2582 free_tlist(origline);
2583 return DIRECTIVE_FOUND; /* but we did _something_ */
2585 if (t->next)
2586 error(ERR_WARNING|ERR_PASS1,
2587 "trailing garbage after `%%include' ignored");
2588 p = t->text;
2589 if (t->type != TOK_INTERNAL_STRING)
2590 nasm_unquote_cstr(p, i);
2591 inc = nasm_zalloc(sizeof(Include));
2592 inc->next = istk;
2593 inc->fp = inc_fopen(p, dephead, &deptail, pass == 0);
2594 if (!inc->fp) {
2595 /* -MG given but file not found */
2596 nasm_free(inc);
2597 } else {
2598 inc->fname = src_set_fname(nasm_strdup(p));
2599 inc->lineno = src_set_linnum(0);
2600 inc->lineinc = 1;
2601 inc->expansion = NULL;
2602 istk = inc;
2603 list->uplevel(LIST_INCLUDE);
2605 free_tlist(origline);
2606 return DIRECTIVE_FOUND;
2608 case PP_USE:
2609 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2611 static macros_t *use_pkg;
2612 const char *pkg_macro = NULL;
2614 tline = tline->next;
2615 skip_white_(tline);
2616 tline = expand_id(tline);
2618 if (!tline || (tline->type != TOK_STRING &&
2619 tline->type != TOK_INTERNAL_STRING &&
2620 tline->type != TOK_ID)) {
2621 error(ERR_NONFATAL, "`%%use' expects a package name");
2622 free_tlist(origline);
2623 return DIRECTIVE_FOUND; /* but we did _something_ */
2625 if (tline->next)
2626 error(ERR_WARNING|ERR_PASS1,
2627 "trailing garbage after `%%use' ignored");
2628 if (tline->type == TOK_STRING)
2629 nasm_unquote_cstr(tline->text, i);
2630 use_pkg = nasm_stdmac_find_package(tline->text);
2631 if (!use_pkg)
2632 error(ERR_NONFATAL, "unknown `%%use' package: %s", tline->text);
2633 else
2634 pkg_macro = (char *)use_pkg + 1; /* The first string will be <%define>__USE_*__ */
2635 if (use_pkg && ! smacro_defined(NULL, pkg_macro, 0, NULL, true)) {
2636 /* Not already included, go ahead and include it */
2637 stdmacpos = use_pkg;
2639 free_tlist(origline);
2640 return DIRECTIVE_FOUND;
2642 case PP_PUSH:
2643 case PP_REPL:
2644 case PP_POP:
2645 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2646 tline = tline->next;
2647 skip_white_(tline);
2648 tline = expand_id(tline);
2649 if (tline) {
2650 if (!tok_type_(tline, TOK_ID)) {
2651 error(ERR_NONFATAL, "`%s' expects a context identifier",
2652 pp_directives[i]);
2653 free_tlist(origline);
2654 return DIRECTIVE_FOUND; /* but we did _something_ */
2656 if (tline->next)
2657 error(ERR_WARNING|ERR_PASS1,
2658 "trailing garbage after `%s' ignored",
2659 pp_directives[i]);
2660 p = nasm_strdup(tline->text);
2661 } else {
2662 p = NULL; /* Anonymous */
2665 if (i == PP_PUSH) {
2666 ctx = nasm_zalloc(sizeof(Context));
2667 ctx->next = cstk;
2668 hash_init(&ctx->localmac, HASH_SMALL);
2669 ctx->name = p;
2670 ctx->number = unique++;
2671 cstk = ctx;
2672 } else {
2673 /* %pop or %repl */
2674 if (!cstk) {
2675 error(ERR_NONFATAL, "`%s': context stack is empty",
2676 pp_directives[i]);
2677 } else if (i == PP_POP) {
2678 if (p && (!cstk->name || nasm_stricmp(p, cstk->name)))
2679 error(ERR_NONFATAL, "`%%pop' in wrong context: %s, "
2680 "expected %s",
2681 cstk->name ? cstk->name : "anonymous", p);
2682 else
2683 ctx_pop();
2684 } else {
2685 /* i == PP_REPL */
2686 nasm_free(cstk->name);
2687 cstk->name = p;
2688 p = NULL;
2690 nasm_free(p);
2692 free_tlist(origline);
2693 return DIRECTIVE_FOUND;
2694 case PP_FATAL:
2695 severity = ERR_FATAL;
2696 goto issue_error;
2697 case PP_ERROR:
2698 severity = ERR_NONFATAL;
2699 goto issue_error;
2700 case PP_WARNING:
2701 severity = ERR_WARNING|ERR_WARN_USER;
2702 goto issue_error;
2704 issue_error:
2705 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2707 /* Only error out if this is the final pass */
2708 if (pass != 2 && i != PP_FATAL)
2709 return DIRECTIVE_FOUND;
2711 tline->next = expand_smacro(tline->next);
2712 tline = tline->next;
2713 skip_white_(tline);
2714 t = tline ? tline->next : NULL;
2715 skip_white_(t);
2716 if (tok_type_(tline, TOK_STRING) && !t) {
2717 /* The line contains only a quoted string */
2718 p = tline->text;
2719 nasm_unquote(p, NULL); /* Ignore NUL character truncation */
2720 error(severity, "%s", p);
2721 } else {
2722 /* Not a quoted string, or more than a quoted string */
2723 p = detoken(tline, false);
2724 error(severity, "%s", p);
2725 nasm_free(p);
2727 free_tlist(origline);
2728 return DIRECTIVE_FOUND;
2731 CASE_PP_IF:
2732 if (defining != NULL) {
2733 if (defining->type == EXP_IF) {
2734 defining->def_depth ++;
2736 return NO_DIRECTIVE_FOUND;
2738 if ((istk->expansion != NULL) &&
2739 (istk->expansion->emitting == false)) {
2740 j = COND_NEVER;
2741 } else {
2742 j = if_condition(tline->next, i);
2743 tline->next = NULL; /* it got freed */
2744 j = (((j < 0) ? COND_NEVER : j) ? COND_IF_TRUE : COND_IF_FALSE);
2746 ed = new_ExpDef(EXP_IF);
2747 ed->state = j;
2748 ed->nolist = NULL;
2749 ed->def_depth = 0;
2750 ed->cur_depth = 0;
2751 ed->max_depth = 0;
2752 ed->ignoring = ((ed->state == COND_IF_TRUE) ? false : true);
2753 ed->prev = defining;
2754 defining = ed;
2755 free_tlist(origline);
2756 return DIRECTIVE_FOUND;
2758 CASE_PP_ELIF:
2759 if (defining != NULL) {
2760 if ((defining->type != EXP_IF) || (defining->def_depth > 0)) {
2761 return NO_DIRECTIVE_FOUND;
2764 if ((defining == NULL) || (defining->type != EXP_IF)) {
2765 error(ERR_FATAL, "`%s': no matching `%%if'", pp_directives[i]);
2767 switch (defining->state) {
2768 case COND_IF_TRUE:
2769 defining->state = COND_DONE;
2770 defining->ignoring = true;
2771 break;
2773 case COND_DONE:
2774 case COND_NEVER:
2775 defining->ignoring = true;
2776 break;
2778 case COND_ELSE_TRUE:
2779 case COND_ELSE_FALSE:
2780 error_precond(ERR_WARNING|ERR_PASS1,
2781 "`%%elif' after `%%else' ignored");
2782 defining->state = COND_NEVER;
2783 defining->ignoring = true;
2784 break;
2786 case COND_IF_FALSE:
2788 * IMPORTANT: In the case of %if, we will already have
2789 * called expand_mmac_params(); however, if we're
2790 * processing an %elif we must have been in a
2791 * non-emitting mode, which would have inhibited
2792 * the normal invocation of expand_mmac_params().
2793 * Therefore, we have to do it explicitly here.
2795 j = if_condition(expand_mmac_params(tline->next), i);
2796 tline->next = NULL; /* it got freed */
2797 defining->state =
2798 j < 0 ? COND_NEVER : j ? COND_IF_TRUE : COND_IF_FALSE;
2799 defining->ignoring = ((defining->state == COND_IF_TRUE) ? false : true);
2800 break;
2802 free_tlist(origline);
2803 return DIRECTIVE_FOUND;
2805 case PP_ELSE:
2806 if (defining != NULL) {
2807 if ((defining->type != EXP_IF) || (defining->def_depth > 0)) {
2808 return NO_DIRECTIVE_FOUND;
2811 if (tline->next)
2812 error_precond(ERR_WARNING|ERR_PASS1,
2813 "trailing garbage after `%%else' ignored");
2814 if ((defining == NULL) || (defining->type != EXP_IF)) {
2815 error(ERR_FATAL, "`%s': no matching `%%if'", pp_directives[i]);
2817 switch (defining->state) {
2818 case COND_IF_TRUE:
2819 case COND_DONE:
2820 defining->state = COND_ELSE_FALSE;
2821 defining->ignoring = true;
2822 break;
2824 case COND_NEVER:
2825 defining->ignoring = true;
2826 break;
2828 case COND_IF_FALSE:
2829 defining->state = COND_ELSE_TRUE;
2830 defining->ignoring = false;
2831 break;
2833 case COND_ELSE_TRUE:
2834 case COND_ELSE_FALSE:
2835 error_precond(ERR_WARNING|ERR_PASS1,
2836 "`%%else' after `%%else' ignored.");
2837 defining->state = COND_NEVER;
2838 defining->ignoring = true;
2839 break;
2841 free_tlist(origline);
2842 return DIRECTIVE_FOUND;
2844 case PP_ENDIF:
2845 if (defining != NULL) {
2846 if (defining->type == EXP_IF) {
2847 if (defining->def_depth > 0) {
2848 defining->def_depth --;
2849 return NO_DIRECTIVE_FOUND;
2851 } else {
2852 return NO_DIRECTIVE_FOUND;
2855 if (tline->next)
2856 error_precond(ERR_WARNING|ERR_PASS1,
2857 "trailing garbage after `%%endif' ignored");
2858 if ((defining == NULL) || (defining->type != EXP_IF)) {
2859 error(ERR_NONFATAL, "`%%endif': no matching `%%if'");
2860 return DIRECTIVE_FOUND;
2862 ed = defining;
2863 defining = ed->prev;
2864 ed->prev = expansions;
2865 expansions = ed;
2866 ei = new_ExpInv(EXP_IF, ed);
2867 ei->current = ed->line;
2868 ei->emitting = true;
2869 ei->prev = istk->expansion;
2870 istk->expansion = ei;
2871 free_tlist(origline);
2872 return DIRECTIVE_FOUND;
2874 case PP_RMACRO:
2875 case PP_IRMACRO:
2876 case PP_MACRO:
2877 case PP_IMACRO:
2878 if (defining != NULL) {
2879 if (defining->type == EXP_MMACRO) {
2880 defining->def_depth ++;
2882 return NO_DIRECTIVE_FOUND;
2884 ed = new_ExpDef(EXP_MMACRO);
2885 ed->max_depth =
2886 (i == PP_RMACRO) || (i == PP_IRMACRO) ? DEADMAN_LIMIT : 0;
2887 ed->casesense = (i == PP_MACRO) || (i == PP_RMACRO);
2888 if (!parse_mmacro_spec(tline, ed, pp_directives[i])) {
2889 nasm_free(ed);
2890 ed = NULL;
2891 return DIRECTIVE_FOUND;
2893 ed->def_depth = 0;
2894 ed->cur_depth = 0;
2895 ed->max_depth = (ed->max_depth + 1);
2896 ed->ignoring = false;
2897 ed->prev = defining;
2898 defining = ed;
2900 eed = (ExpDef *) hash_findix(&expdefs, ed->name);
2901 while (eed) {
2902 if (!strcmp(eed->name, ed->name) &&
2903 (eed->nparam_min <= ed->nparam_max || ed->plus) &&
2904 (ed->nparam_min <= eed->nparam_max || eed->plus)) {
2905 error(ERR_WARNING|ERR_PASS1,
2906 "redefining multi-line macro `%s'", ed->name);
2907 return DIRECTIVE_FOUND;
2909 eed = eed->next;
2911 free_tlist(origline);
2912 return DIRECTIVE_FOUND;
2914 case PP_ENDM:
2915 case PP_ENDMACRO:
2916 if (defining != NULL) {
2917 if (defining->type == EXP_MMACRO) {
2918 if (defining->def_depth > 0) {
2919 defining->def_depth --;
2920 return NO_DIRECTIVE_FOUND;
2922 } else {
2923 return NO_DIRECTIVE_FOUND;
2926 if (!(defining) || (defining->type != EXP_MMACRO)) {
2927 error(ERR_NONFATAL, "`%s': not defining a macro", tline->text);
2928 return DIRECTIVE_FOUND;
2930 edhead = (ExpDef **) hash_findi_add(&expdefs, defining->name);
2931 defining->next = *edhead;
2932 *edhead = defining;
2933 ed = defining;
2934 defining = ed->prev;
2935 ed->prev = expansions;
2936 expansions = ed;
2937 ed = NULL;
2938 free_tlist(origline);
2939 return DIRECTIVE_FOUND;
2941 case PP_EXITMACRO:
2942 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2944 * We must search along istk->expansion until we hit a
2945 * macro invocation. Then we disable the emitting state(s)
2946 * between exitmacro and endmacro.
2948 for (ei = istk->expansion; ei != NULL; ei = ei->prev) {
2949 if(ei->type == EXP_MMACRO) {
2950 break;
2954 if (ei != NULL) {
2956 * Set all invocations leading back to the macro
2957 * invocation to a non-emitting state.
2959 for (eei = istk->expansion; eei != ei; eei = eei->prev) {
2960 eei->emitting = false;
2962 eei->emitting = false;
2963 } else {
2964 error(ERR_NONFATAL, "`%%exitmacro' not within `%%macro' block");
2966 free_tlist(origline);
2967 return DIRECTIVE_FOUND;
2969 case PP_UNMACRO:
2970 case PP_UNIMACRO:
2971 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2973 ExpDef **ed_p;
2974 ExpDef spec;
2976 spec.casesense = (i == PP_UNMACRO);
2977 if (!parse_mmacro_spec(tline, &spec, pp_directives[i])) {
2978 return DIRECTIVE_FOUND;
2980 ed_p = (ExpDef **) hash_findi(&expdefs, spec.name, NULL);
2981 while (ed_p && *ed_p) {
2982 ed = *ed_p;
2983 if (ed->casesense == spec.casesense &&
2984 !mstrcmp(ed->name, spec.name, spec.casesense) &&
2985 ed->nparam_min == spec.nparam_min &&
2986 ed->nparam_max == spec.nparam_max &&
2987 ed->plus == spec.plus) {
2988 if (ed->cur_depth > 0) {
2989 error(ERR_NONFATAL, "`%s' ignored on active macro",
2990 pp_directives[i]);
2991 break;
2992 } else {
2993 *ed_p = ed->next;
2994 free_expdef(ed);
2996 } else {
2997 ed_p = &ed->next;
3000 free_tlist(origline);
3001 free_tlist(spec.dlist);
3002 return DIRECTIVE_FOUND;
3005 case PP_ROTATE:
3006 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3007 if (tline->next && tline->next->type == TOK_WHITESPACE)
3008 tline = tline->next;
3009 if (!tline->next) {
3010 free_tlist(origline);
3011 error(ERR_NONFATAL, "`%%rotate' missing rotate count");
3012 return DIRECTIVE_FOUND;
3014 t = expand_smacro(tline->next);
3015 tline->next = NULL;
3016 free_tlist(origline);
3017 tline = t;
3018 tptr = &t;
3019 tokval.t_type = TOKEN_INVALID;
3020 evalresult =
3021 evaluate(ppscan, tptr, &tokval, NULL, pass, error, NULL);
3022 free_tlist(tline);
3023 if (!evalresult)
3024 return DIRECTIVE_FOUND;
3025 if (tokval.t_type)
3026 error(ERR_WARNING|ERR_PASS1,
3027 "trailing garbage after expression ignored");
3028 if (!is_simple(evalresult)) {
3029 error(ERR_NONFATAL, "non-constant value given to `%%rotate'");
3030 return DIRECTIVE_FOUND;
3032 for (ei = istk->expansion; ei != NULL; ei = ei->prev) {
3033 if (ei->type == EXP_MMACRO) {
3034 break;
3037 if (ei == NULL) {
3038 error(ERR_NONFATAL, "`%%rotate' invoked outside a macro call");
3039 } else if (ei->nparam == 0) {
3040 error(ERR_NONFATAL,
3041 "`%%rotate' invoked within macro without parameters");
3042 } else {
3043 int rotate = ei->rotate + reloc_value(evalresult);
3045 rotate %= (int)ei->nparam;
3046 if (rotate < 0)
3047 rotate += ei->nparam;
3048 ei->rotate = rotate;
3050 return DIRECTIVE_FOUND;
3052 case PP_REP:
3053 if (defining != NULL) {
3054 if (defining->type == EXP_REP) {
3055 defining->def_depth ++;
3057 return NO_DIRECTIVE_FOUND;
3059 nolist = false;
3060 do {
3061 tline = tline->next;
3062 } while (tok_type_(tline, TOK_WHITESPACE));
3064 if (tok_type_(tline, TOK_ID) &&
3065 nasm_stricmp(tline->text, ".nolist") == 0) {
3066 nolist = true;
3067 do {
3068 tline = tline->next;
3069 } while (tok_type_(tline, TOK_WHITESPACE));
3072 if (tline) {
3073 t = expand_smacro(tline);
3074 tptr = &t;
3075 tokval.t_type = TOKEN_INVALID;
3076 evalresult =
3077 evaluate(ppscan, tptr, &tokval, NULL, pass, error, NULL);
3078 if (!evalresult) {
3079 free_tlist(origline);
3080 return DIRECTIVE_FOUND;
3082 if (tokval.t_type)
3083 error(ERR_WARNING|ERR_PASS1,
3084 "trailing garbage after expression ignored");
3085 if (!is_simple(evalresult)) {
3086 error(ERR_NONFATAL, "non-constant value given to `%%rep'");
3087 return DIRECTIVE_FOUND;
3089 count = reloc_value(evalresult);
3090 if (count >= REP_LIMIT) {
3091 error(ERR_NONFATAL, "`%%rep' value exceeds limit");
3092 count = 0;
3093 } else
3094 count++;
3095 } else {
3096 error(ERR_NONFATAL, "`%%rep' expects a repeat count");
3097 count = 0;
3099 free_tlist(origline);
3100 ed = new_ExpDef(EXP_REP);
3101 ed->nolist = nolist;
3102 ed->def_depth = 0;
3103 ed->cur_depth = 1;
3104 ed->max_depth = (count - 1);
3105 ed->ignoring = false;
3106 ed->prev = defining;
3107 defining = ed;
3108 return DIRECTIVE_FOUND;
3110 case PP_ENDREP:
3111 if (defining != NULL) {
3112 if (defining->type == EXP_REP) {
3113 if (defining->def_depth > 0) {
3114 defining->def_depth --;
3115 return NO_DIRECTIVE_FOUND;
3117 } else {
3118 return NO_DIRECTIVE_FOUND;
3121 if ((defining == NULL) || (defining->type != EXP_REP)) {
3122 error(ERR_NONFATAL, "`%%endrep': no matching `%%rep'");
3123 return DIRECTIVE_FOUND;
3127 * Now we have a "macro" defined - although it has no name
3128 * and we won't be entering it in the hash tables - we must
3129 * push a macro-end marker for it on to istk->expansion.
3130 * After that, it will take care of propagating itself (a
3131 * macro-end marker line for a macro which is really a %rep
3132 * block will cause the macro to be re-expanded, complete
3133 * with another macro-end marker to ensure the process
3134 * continues) until the whole expansion is forcibly removed
3135 * from istk->expansion by a %exitrep.
3137 ed = defining;
3138 defining = ed->prev;
3139 ed->prev = expansions;
3140 expansions = ed;
3141 ei = new_ExpInv(EXP_REP, ed);
3142 ei->current = ed->line;
3143 ei->emitting = ((ed->max_depth > 0) ? true : false);
3144 list->uplevel(ed->nolist ? LIST_MACRO_NOLIST : LIST_MACRO);
3145 ei->prev = istk->expansion;
3146 istk->expansion = ei;
3147 free_tlist(origline);
3148 return DIRECTIVE_FOUND;
3150 case PP_EXITREP:
3151 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3153 * We must search along istk->expansion until we hit a
3154 * rep invocation. Then we disable the emitting state(s)
3155 * between exitrep and endrep.
3157 for (ei = istk->expansion; ei != NULL; ei = ei->prev) {
3158 if (ei->type == EXP_REP) {
3159 break;
3163 if (ei != NULL) {
3165 * Set all invocations leading back to the rep
3166 * invocation to a non-emitting state.
3168 for (eei = istk->expansion; eei != ei; eei = eei->prev) {
3169 eei->emitting = false;
3171 eei->emitting = false;
3172 eei->current = NULL;
3173 eei->def->cur_depth = eei->def->max_depth;
3174 } else {
3175 error(ERR_NONFATAL, "`%%exitrep' not within `%%rep' block");
3177 free_tlist(origline);
3178 return DIRECTIVE_FOUND;
3180 case PP_XDEFINE:
3181 case PP_IXDEFINE:
3182 case PP_DEFINE:
3183 case PP_IDEFINE:
3184 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3185 casesense = (i == PP_DEFINE || i == PP_XDEFINE);
3187 tline = tline->next;
3188 skip_white_(tline);
3189 tline = expand_id(tline);
3190 if (!tline || (tline->type != TOK_ID &&
3191 (tline->type != TOK_PREPROC_ID ||
3192 tline->text[1] != '$'))) {
3193 error(ERR_NONFATAL, "`%s' expects a macro identifier",
3194 pp_directives[i]);
3195 free_tlist(origline);
3196 return DIRECTIVE_FOUND;
3199 ctx = get_ctx(tline->text, &mname, false);
3200 last = tline;
3201 param_start = tline = tline->next;
3202 nparam = 0;
3204 /* Expand the macro definition now for %xdefine and %ixdefine */
3205 if ((i == PP_XDEFINE) || (i == PP_IXDEFINE))
3206 tline = expand_smacro(tline);
3208 if (tok_is_(tline, "(")) {
3210 * This macro has parameters.
3213 tline = tline->next;
3214 while (1) {
3215 skip_white_(tline);
3216 if (!tline) {
3217 error(ERR_NONFATAL, "parameter identifier expected");
3218 free_tlist(origline);
3219 return DIRECTIVE_FOUND;
3221 if (tline->type != TOK_ID) {
3222 error(ERR_NONFATAL,
3223 "`%s': parameter identifier expected",
3224 tline->text);
3225 free_tlist(origline);
3226 return DIRECTIVE_FOUND;
3228 tline->type = TOK_SMAC_PARAM + nparam++;
3229 tline = tline->next;
3230 skip_white_(tline);
3231 if (tok_is_(tline, ",")) {
3232 tline = tline->next;
3233 } else {
3234 if (!tok_is_(tline, ")")) {
3235 error(ERR_NONFATAL,
3236 "`)' expected to terminate macro template");
3237 free_tlist(origline);
3238 return DIRECTIVE_FOUND;
3240 break;
3243 last = tline;
3244 tline = tline->next;
3246 if (tok_type_(tline, TOK_WHITESPACE))
3247 last = tline, tline = tline->next;
3248 macro_start = NULL;
3249 last->next = NULL;
3250 t = tline;
3251 while (t) {
3252 if (t->type == TOK_ID) {
3253 list_for_each(tt, param_start)
3254 if (tt->type >= TOK_SMAC_PARAM &&
3255 !strcmp(tt->text, t->text))
3256 t->type = tt->type;
3258 tt = t->next;
3259 t->next = macro_start;
3260 macro_start = t;
3261 t = tt;
3264 * Good. We now have a macro name, a parameter count, and a
3265 * token list (in reverse order) for an expansion. We ought
3266 * to be OK just to create an SMacro, store it, and let
3267 * free_tlist have the rest of the line (which we have
3268 * carefully re-terminated after chopping off the expansion
3269 * from the end).
3271 define_smacro(ctx, mname, casesense, nparam, macro_start);
3272 free_tlist(origline);
3273 return DIRECTIVE_FOUND;
3275 case PP_UNDEF:
3276 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3277 tline = tline->next;
3278 skip_white_(tline);
3279 tline = expand_id(tline);
3280 if (!tline || (tline->type != TOK_ID &&
3281 (tline->type != TOK_PREPROC_ID ||
3282 tline->text[1] != '$'))) {
3283 error(ERR_NONFATAL, "`%%undef' expects a macro identifier");
3284 free_tlist(origline);
3285 return DIRECTIVE_FOUND;
3287 if (tline->next) {
3288 error(ERR_WARNING|ERR_PASS1,
3289 "trailing garbage after macro name ignored");
3292 /* Find the context that symbol belongs to */
3293 ctx = get_ctx(tline->text, &mname, false);
3294 undef_smacro(ctx, mname);
3295 free_tlist(origline);
3296 return DIRECTIVE_FOUND;
3298 case PP_DEFSTR:
3299 case PP_IDEFSTR:
3300 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3301 casesense = (i == PP_DEFSTR);
3303 tline = tline->next;
3304 skip_white_(tline);
3305 tline = expand_id(tline);
3306 if (!tline || (tline->type != TOK_ID &&
3307 (tline->type != TOK_PREPROC_ID ||
3308 tline->text[1] != '$'))) {
3309 error(ERR_NONFATAL, "`%s' expects a macro identifier",
3310 pp_directives[i]);
3311 free_tlist(origline);
3312 return DIRECTIVE_FOUND;
3315 ctx = get_ctx(tline->text, &mname, false);
3316 last = tline;
3317 tline = expand_smacro(tline->next);
3318 last->next = NULL;
3320 while (tok_type_(tline, TOK_WHITESPACE))
3321 tline = delete_Token(tline);
3323 p = detoken(tline, false);
3324 macro_start = nasm_malloc(sizeof(*macro_start));
3325 macro_start->next = NULL;
3326 macro_start->text = nasm_quote(p, strlen(p));
3327 macro_start->type = TOK_STRING;
3328 macro_start->a.mac = NULL;
3329 nasm_free(p);
3332 * We now have a macro name, an implicit parameter count of
3333 * zero, and a string token to use as an expansion. Create
3334 * and store an SMacro.
3336 define_smacro(ctx, mname, casesense, 0, macro_start);
3337 free_tlist(origline);
3338 return DIRECTIVE_FOUND;
3340 case PP_DEFTOK:
3341 case PP_IDEFTOK:
3342 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3343 casesense = (i == PP_DEFTOK);
3345 tline = tline->next;
3346 skip_white_(tline);
3347 tline = expand_id(tline);
3348 if (!tline || (tline->type != TOK_ID &&
3349 (tline->type != TOK_PREPROC_ID ||
3350 tline->text[1] != '$'))) {
3351 error(ERR_NONFATAL,
3352 "`%s' expects a macro identifier as first parameter",
3353 pp_directives[i]);
3354 free_tlist(origline);
3355 return DIRECTIVE_FOUND;
3357 ctx = get_ctx(tline->text, &mname, false);
3358 last = tline;
3359 tline = expand_smacro(tline->next);
3360 last->next = NULL;
3362 t = tline;
3363 while (tok_type_(t, TOK_WHITESPACE))
3364 t = t->next;
3365 /* t should now point to the string */
3366 if (!tok_type_(t, TOK_STRING)) {
3367 error(ERR_NONFATAL,
3368 "`%s` requires string as second parameter",
3369 pp_directives[i]);
3370 free_tlist(tline);
3371 free_tlist(origline);
3372 return DIRECTIVE_FOUND;
3376 * Convert the string to a token stream. Note that smacros
3377 * are stored with the token stream reversed, so we have to
3378 * reverse the output of tokenize().
3380 nasm_unquote_cstr(t->text, i);
3381 macro_start = reverse_tokens(tokenize(t->text));
3384 * We now have a macro name, an implicit parameter count of
3385 * zero, and a numeric token to use as an expansion. Create
3386 * and store an SMacro.
3388 define_smacro(ctx, mname, casesense, 0, macro_start);
3389 free_tlist(tline);
3390 free_tlist(origline);
3391 return DIRECTIVE_FOUND;
3393 case PP_PATHSEARCH:
3394 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3396 FILE *fp;
3397 StrList *xsl = NULL;
3398 StrList **xst = &xsl;
3400 casesense = true;
3402 tline = tline->next;
3403 skip_white_(tline);
3404 tline = expand_id(tline);
3405 if (!tline || (tline->type != TOK_ID &&
3406 (tline->type != TOK_PREPROC_ID ||
3407 tline->text[1] != '$'))) {
3408 error(ERR_NONFATAL,
3409 "`%%pathsearch' expects a macro identifier as first parameter");
3410 free_tlist(origline);
3411 return DIRECTIVE_FOUND;
3413 ctx = get_ctx(tline->text, &mname, false);
3414 last = tline;
3415 tline = expand_smacro(tline->next);
3416 last->next = NULL;
3418 t = tline;
3419 while (tok_type_(t, TOK_WHITESPACE))
3420 t = t->next;
3422 if (!t || (t->type != TOK_STRING &&
3423 t->type != TOK_INTERNAL_STRING)) {
3424 error(ERR_NONFATAL, "`%%pathsearch' expects a file name");
3425 free_tlist(tline);
3426 free_tlist(origline);
3427 return DIRECTIVE_FOUND; /* but we did _something_ */
3429 if (t->next)
3430 error(ERR_WARNING|ERR_PASS1,
3431 "trailing garbage after `%%pathsearch' ignored");
3432 p = t->text;
3433 if (t->type != TOK_INTERNAL_STRING)
3434 nasm_unquote(p, NULL);
3436 fp = inc_fopen(p, &xsl, &xst, true);
3437 if (fp) {
3438 p = xsl->str;
3439 fclose(fp); /* Don't actually care about the file */
3441 macro_start = nasm_malloc(sizeof(*macro_start));
3442 macro_start->next = NULL;
3443 macro_start->text = nasm_quote(p, strlen(p));
3444 macro_start->type = TOK_STRING;
3445 macro_start->a.mac = NULL;
3446 if (xsl)
3447 nasm_free(xsl);
3450 * We now have a macro name, an implicit parameter count of
3451 * zero, and a string token to use as an expansion. Create
3452 * and store an SMacro.
3454 define_smacro(ctx, mname, casesense, 0, macro_start);
3455 free_tlist(tline);
3456 free_tlist(origline);
3457 return DIRECTIVE_FOUND;
3460 case PP_STRLEN:
3461 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3462 casesense = true;
3464 tline = tline->next;
3465 skip_white_(tline);
3466 tline = expand_id(tline);
3467 if (!tline || (tline->type != TOK_ID &&
3468 (tline->type != TOK_PREPROC_ID ||
3469 tline->text[1] != '$'))) {
3470 error(ERR_NONFATAL,
3471 "`%%strlen' expects a macro identifier as first parameter");
3472 free_tlist(origline);
3473 return DIRECTIVE_FOUND;
3475 ctx = get_ctx(tline->text, &mname, false);
3476 last = tline;
3477 tline = expand_smacro(tline->next);
3478 last->next = NULL;
3480 t = tline;
3481 while (tok_type_(t, TOK_WHITESPACE))
3482 t = t->next;
3483 /* t should now point to the string */
3484 if (!tok_type_(t, TOK_STRING)) {
3485 error(ERR_NONFATAL,
3486 "`%%strlen` requires string as second parameter");
3487 free_tlist(tline);
3488 free_tlist(origline);
3489 return DIRECTIVE_FOUND;
3492 macro_start = nasm_malloc(sizeof(*macro_start));
3493 macro_start->next = NULL;
3494 make_tok_num(macro_start, nasm_unquote(t->text, NULL));
3495 macro_start->a.mac = NULL;
3498 * We now have a macro name, an implicit parameter count of
3499 * zero, and a numeric token to use as an expansion. Create
3500 * and store an SMacro.
3502 define_smacro(ctx, mname, casesense, 0, macro_start);
3503 free_tlist(tline);
3504 free_tlist(origline);
3505 return DIRECTIVE_FOUND;
3507 case PP_STRCAT:
3508 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3509 casesense = true;
3511 tline = tline->next;
3512 skip_white_(tline);
3513 tline = expand_id(tline);
3514 if (!tline || (tline->type != TOK_ID &&
3515 (tline->type != TOK_PREPROC_ID ||
3516 tline->text[1] != '$'))) {
3517 error(ERR_NONFATAL,
3518 "`%%strcat' expects a macro identifier as first parameter");
3519 free_tlist(origline);
3520 return DIRECTIVE_FOUND;
3522 ctx = get_ctx(tline->text, &mname, false);
3523 last = tline;
3524 tline = expand_smacro(tline->next);
3525 last->next = NULL;
3527 len = 0;
3528 list_for_each(t, tline) {
3529 switch (t->type) {
3530 case TOK_WHITESPACE:
3531 break;
3532 case TOK_STRING:
3533 len += t->a.len = nasm_unquote(t->text, NULL);
3534 break;
3535 case TOK_OTHER:
3536 if (!strcmp(t->text, ",")) /* permit comma separators */
3537 break;
3538 /* else fall through */
3539 default:
3540 error(ERR_NONFATAL,
3541 "non-string passed to `%%strcat' (%d)", t->type);
3542 free_tlist(tline);
3543 free_tlist(origline);
3544 return DIRECTIVE_FOUND;
3548 p = pp = nasm_malloc(len);
3549 list_for_each(t, tline) {
3550 if (t->type == TOK_STRING) {
3551 memcpy(p, t->text, t->a.len);
3552 p += t->a.len;
3557 * We now have a macro name, an implicit parameter count of
3558 * zero, and a numeric token to use as an expansion. Create
3559 * and store an SMacro.
3561 macro_start = new_Token(NULL, TOK_STRING, NULL, 0);
3562 macro_start->text = nasm_quote(pp, len);
3563 nasm_free(pp);
3564 define_smacro(ctx, mname, casesense, 0, macro_start);
3565 free_tlist(tline);
3566 free_tlist(origline);
3567 return DIRECTIVE_FOUND;
3569 case PP_SUBSTR:
3570 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3572 int64_t start, count;
3573 size_t len;
3575 casesense = true;
3577 tline = tline->next;
3578 skip_white_(tline);
3579 tline = expand_id(tline);
3580 if (!tline || (tline->type != TOK_ID &&
3581 (tline->type != TOK_PREPROC_ID ||
3582 tline->text[1] != '$'))) {
3583 error(ERR_NONFATAL,
3584 "`%%substr' expects a macro identifier as first parameter");
3585 free_tlist(origline);
3586 return DIRECTIVE_FOUND;
3588 ctx = get_ctx(tline->text, &mname, false);
3589 last = tline;
3590 tline = expand_smacro(tline->next);
3591 last->next = NULL;
3593 if (tline) /* skip expanded id */
3594 t = tline->next;
3595 while (tok_type_(t, TOK_WHITESPACE))
3596 t = t->next;
3598 /* t should now point to the string */
3599 if (!tok_type_(t, TOK_STRING)) {
3600 error(ERR_NONFATAL,
3601 "`%%substr` requires string as second parameter");
3602 free_tlist(tline);
3603 free_tlist(origline);
3604 return DIRECTIVE_FOUND;
3607 tt = t->next;
3608 tptr = &tt;
3609 tokval.t_type = TOKEN_INVALID;
3610 evalresult = evaluate(ppscan, tptr, &tokval, NULL,
3611 pass, error, NULL);
3612 if (!evalresult) {
3613 free_tlist(tline);
3614 free_tlist(origline);
3615 return DIRECTIVE_FOUND;
3616 } else if (!is_simple(evalresult)) {
3617 error(ERR_NONFATAL, "non-constant value given to `%%substr`");
3618 free_tlist(tline);
3619 free_tlist(origline);
3620 return DIRECTIVE_FOUND;
3622 start = evalresult->value - 1;
3624 while (tok_type_(tt, TOK_WHITESPACE))
3625 tt = tt->next;
3626 if (!tt) {
3627 count = 1; /* Backwards compatibility: one character */
3628 } else {
3629 tokval.t_type = TOKEN_INVALID;
3630 evalresult = evaluate(ppscan, tptr, &tokval, NULL,
3631 pass, error, NULL);
3632 if (!evalresult) {
3633 free_tlist(tline);
3634 free_tlist(origline);
3635 return DIRECTIVE_FOUND;
3636 } else if (!is_simple(evalresult)) {
3637 error(ERR_NONFATAL, "non-constant value given to `%%substr`");
3638 free_tlist(tline);
3639 free_tlist(origline);
3640 return DIRECTIVE_FOUND;
3642 count = evalresult->value;
3645 len = nasm_unquote(t->text, NULL);
3646 /* make start and count being in range */
3647 if (start < 0)
3648 start = 0;
3649 if (count < 0)
3650 count = len + count + 1 - start;
3651 if (start + count > (int64_t)len)
3652 count = len - start;
3653 if (!len || count < 0 || start >=(int64_t)len)
3654 start = -1, count = 0; /* empty string */
3656 macro_start = nasm_malloc(sizeof(*macro_start));
3657 macro_start->next = NULL;
3658 macro_start->text = nasm_quote((start < 0) ? "" : t->text + start, count);
3659 macro_start->type = TOK_STRING;
3660 macro_start->a.mac = NULL;
3663 * We now have a macro name, an implicit parameter count of
3664 * zero, and a numeric token to use as an expansion. Create
3665 * and store an SMacro.
3667 define_smacro(ctx, mname, casesense, 0, macro_start);
3668 free_tlist(tline);
3669 free_tlist(origline);
3670 return DIRECTIVE_FOUND;
3673 case PP_ASSIGN:
3674 case PP_IASSIGN:
3675 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3676 casesense = (i == PP_ASSIGN);
3678 tline = tline->next;
3679 skip_white_(tline);
3680 tline = expand_id(tline);
3681 if (!tline || (tline->type != TOK_ID &&
3682 (tline->type != TOK_PREPROC_ID ||
3683 tline->text[1] != '$'))) {
3684 error(ERR_NONFATAL,
3685 "`%%%sassign' expects a macro identifier",
3686 (i == PP_IASSIGN ? "i" : ""));
3687 free_tlist(origline);
3688 return DIRECTIVE_FOUND;
3690 ctx = get_ctx(tline->text, &mname, false);
3691 last = tline;
3692 tline = expand_smacro(tline->next);
3693 last->next = NULL;
3695 t = tline;
3696 tptr = &t;
3697 tokval.t_type = TOKEN_INVALID;
3698 evalresult =
3699 evaluate(ppscan, tptr, &tokval, NULL, pass, error, NULL);
3700 free_tlist(tline);
3701 if (!evalresult) {
3702 free_tlist(origline);
3703 return DIRECTIVE_FOUND;
3706 if (tokval.t_type)
3707 error(ERR_WARNING|ERR_PASS1,
3708 "trailing garbage after expression ignored");
3710 if (!is_simple(evalresult)) {
3711 error(ERR_NONFATAL,
3712 "non-constant value given to `%%%sassign'",
3713 (i == PP_IASSIGN ? "i" : ""));
3714 free_tlist(origline);
3715 return DIRECTIVE_FOUND;
3718 macro_start = nasm_malloc(sizeof(*macro_start));
3719 macro_start->next = NULL;
3720 make_tok_num(macro_start, reloc_value(evalresult));
3721 macro_start->a.mac = NULL;
3724 * We now have a macro name, an implicit parameter count of
3725 * zero, and a numeric token to use as an expansion. Create
3726 * and store an SMacro.
3728 define_smacro(ctx, mname, casesense, 0, macro_start);
3729 free_tlist(origline);
3730 return DIRECTIVE_FOUND;
3732 case PP_LINE:
3733 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3735 * Syntax is `%line nnn[+mmm] [filename]'
3737 tline = tline->next;
3738 skip_white_(tline);
3739 if (!tok_type_(tline, TOK_NUMBER)) {
3740 error(ERR_NONFATAL, "`%%line' expects line number");
3741 free_tlist(origline);
3742 return DIRECTIVE_FOUND;
3744 k = readnum(tline->text, &err);
3745 m = 1;
3746 tline = tline->next;
3747 if (tok_is_(tline, "+")) {
3748 tline = tline->next;
3749 if (!tok_type_(tline, TOK_NUMBER)) {
3750 error(ERR_NONFATAL, "`%%line' expects line increment");
3751 free_tlist(origline);
3752 return DIRECTIVE_FOUND;
3754 m = readnum(tline->text, &err);
3755 tline = tline->next;
3757 skip_white_(tline);
3758 src_set_linnum(k);
3759 istk->lineinc = m;
3760 if (tline) {
3761 nasm_free(src_set_fname(detoken(tline, false)));
3763 free_tlist(origline);
3764 return DIRECTIVE_FOUND;
3766 case PP_WHILE:
3767 if (defining != NULL) {
3768 if (defining->type == EXP_WHILE) {
3769 defining->def_depth ++;
3771 return NO_DIRECTIVE_FOUND;
3773 l = NULL;
3774 if ((istk->expansion != NULL) &&
3775 (istk->expansion->emitting == false)) {
3776 j = COND_NEVER;
3777 } else {
3778 l = new_Line();
3779 l->first = copy_Token(tline->next);
3780 j = if_condition(tline->next, i);
3781 tline->next = NULL; /* it got freed */
3782 j = (((j < 0) ? COND_NEVER : j) ? COND_IF_TRUE : COND_IF_FALSE);
3784 ed = new_ExpDef(EXP_WHILE);
3785 ed->state = j;
3786 ed->cur_depth = 1;
3787 ed->max_depth = DEADMAN_LIMIT;
3788 ed->ignoring = ((ed->state == COND_IF_TRUE) ? false : true);
3789 if (ed->ignoring == false) {
3790 ed->line = l;
3791 ed->last = l;
3792 } else if (l != NULL) {
3793 delete_Token(l->first);
3794 nasm_free(l);
3795 l = NULL;
3797 ed->prev = defining;
3798 defining = ed;
3799 free_tlist(origline);
3800 return DIRECTIVE_FOUND;
3802 case PP_ENDWHILE:
3803 if (defining != NULL) {
3804 if (defining->type == EXP_WHILE) {
3805 if (defining->def_depth > 0) {
3806 defining->def_depth --;
3807 return NO_DIRECTIVE_FOUND;
3809 } else {
3810 return NO_DIRECTIVE_FOUND;
3813 if (tline->next != NULL) {
3814 error_precond(ERR_WARNING|ERR_PASS1,
3815 "trailing garbage after `%%endwhile' ignored");
3817 if ((defining == NULL) || (defining->type != EXP_WHILE)) {
3818 error(ERR_NONFATAL, "`%%endwhile': no matching `%%while'");
3819 return DIRECTIVE_FOUND;
3821 ed = defining;
3822 defining = ed->prev;
3823 if (ed->ignoring == false) {
3824 ed->prev = expansions;
3825 expansions = ed;
3826 ei = new_ExpInv(EXP_WHILE, ed);
3827 ei->current = ed->line->next;
3828 ei->emitting = true;
3829 ei->prev = istk->expansion;
3830 istk->expansion = ei;
3831 } else {
3832 nasm_free(ed);
3834 free_tlist(origline);
3835 return DIRECTIVE_FOUND;
3837 case PP_EXITWHILE:
3838 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3840 * We must search along istk->expansion until we hit a
3841 * while invocation. Then we disable the emitting state(s)
3842 * between exitwhile and endwhile.
3844 for (ei = istk->expansion; ei != NULL; ei = ei->prev) {
3845 if (ei->type == EXP_WHILE) {
3846 break;
3850 if (ei != NULL) {
3852 * Set all invocations leading back to the while
3853 * invocation to a non-emitting state.
3855 for (eei = istk->expansion; eei != ei; eei = eei->prev) {
3856 eei->emitting = false;
3858 eei->emitting = false;
3859 eei->current = NULL;
3860 eei->def->cur_depth = eei->def->max_depth;
3861 } else {
3862 error(ERR_NONFATAL, "`%%exitwhile' not within `%%while' block");
3864 free_tlist(origline);
3865 return DIRECTIVE_FOUND;
3867 case PP_COMMENT:
3868 if (defining != NULL) {
3869 if (defining->type == EXP_COMMENT) {
3870 defining->def_depth ++;
3872 return NO_DIRECTIVE_FOUND;
3874 ed = new_ExpDef(EXP_COMMENT);
3875 ed->ignoring = true;
3876 ed->prev = defining;
3877 defining = ed;
3878 free_tlist(origline);
3879 return DIRECTIVE_FOUND;
3881 case PP_ENDCOMMENT:
3882 if (defining != NULL) {
3883 if (defining->type == EXP_COMMENT) {
3884 if (defining->def_depth > 0) {
3885 defining->def_depth --;
3886 return NO_DIRECTIVE_FOUND;
3888 } else {
3889 return NO_DIRECTIVE_FOUND;
3892 if ((defining == NULL) || (defining->type != EXP_COMMENT)) {
3893 error(ERR_NONFATAL, "`%%endcomment': no matching `%%comment'");
3894 return DIRECTIVE_FOUND;
3896 ed = defining;
3897 defining = ed->prev;
3898 nasm_free(ed);
3899 free_tlist(origline);
3900 return DIRECTIVE_FOUND;
3902 case PP_FINAL:
3903 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3904 if (in_final != false) {
3905 error(ERR_FATAL, "`%%final' cannot be used recursively");
3907 tline = tline->next;
3908 skip_white_(tline);
3909 if (tline == NULL) {
3910 error(ERR_NONFATAL, "`%%final' expects at least one parameter");
3911 } else {
3912 l = new_Line();
3913 l->first = copy_Token(tline);
3914 l->next = finals;
3915 finals = l;
3917 free_tlist(origline);
3918 return DIRECTIVE_FOUND;
3920 default:
3921 error(ERR_FATAL,
3922 "preprocessor directive `%s' not yet implemented",
3923 pp_directives[i]);
3924 return DIRECTIVE_FOUND;
3929 * Ensure that a macro parameter contains a condition code and
3930 * nothing else. Return the condition code index if so, or -1
3931 * otherwise.
3933 static int find_cc(Token * t)
3935 Token *tt;
3936 int i, j, k, m;
3938 if (!t)
3939 return -1; /* Probably a %+ without a space */
3941 skip_white_(t);
3942 if (t->type != TOK_ID)
3943 return -1;
3944 tt = t->next;
3945 skip_white_(tt);
3946 if (tt && (tt->type != TOK_OTHER || strcmp(tt->text, ",")))
3947 return -1;
3949 i = -1;
3950 j = ARRAY_SIZE(conditions);
3951 while (j - i > 1) {
3952 k = (j + i) / 2;
3953 m = nasm_stricmp(t->text, conditions[k]);
3954 if (m == 0) {
3955 i = k;
3956 j = -2;
3957 break;
3958 } else if (m < 0) {
3959 j = k;
3960 } else
3961 i = k;
3963 if (j != -2)
3964 return -1;
3965 return i;
3968 static bool paste_tokens(Token **head, const struct tokseq_match *m,
3969 int mnum, bool handle_paste_tokens)
3971 Token **tail, *t, *tt;
3972 Token **paste_head;
3973 bool did_paste = false;
3974 char *tmp;
3975 int i;
3977 /* Now handle token pasting... */
3978 paste_head = NULL;
3979 tail = head;
3980 while ((t = *tail) && (tt = t->next)) {
3981 switch (t->type) {
3982 case TOK_WHITESPACE:
3983 if (tt->type == TOK_WHITESPACE) {
3984 /* Zap adjacent whitespace tokens */
3985 t->next = delete_Token(tt);
3986 } else {
3987 /* Do not advance paste_head here */
3988 tail = &t->next;
3990 break;
3991 case TOK_PASTE: /* %+ */
3992 if (handle_paste_tokens) {
3993 /* Zap %+ and whitespace tokens to the right */
3994 while (t && (t->type == TOK_WHITESPACE ||
3995 t->type == TOK_PASTE))
3996 t = *tail = delete_Token(t);
3997 if (!paste_head || !t)
3998 break; /* Nothing to paste with */
3999 tail = paste_head;
4000 t = *tail;
4001 tt = t->next;
4002 while (tok_type_(tt, TOK_WHITESPACE))
4003 tt = t->next = delete_Token(tt);
4004 if (tt) {
4005 tmp = nasm_strcat(t->text, tt->text);
4006 delete_Token(t);
4007 tt = delete_Token(tt);
4008 t = *tail = tokenize(tmp);
4009 nasm_free(tmp);
4010 while (t->next) {
4011 tail = &t->next;
4012 t = t->next;
4014 t->next = tt; /* Attach the remaining token chain */
4015 did_paste = true;
4017 paste_head = tail;
4018 tail = &t->next;
4019 break;
4021 /* else fall through */
4022 default:
4024 * Concatenation of tokens might look nontrivial
4025 * but in real it's pretty simple -- the caller
4026 * prepares the masks of token types to be concatenated
4027 * and we simply find matched sequences and slip
4028 * them together
4030 for (i = 0; i < mnum; i++) {
4031 if (PP_CONCAT_MASK(t->type) & m[i].mask_head) {
4032 size_t len = 0;
4033 char *tmp, *p;
4035 while (tt && (PP_CONCAT_MASK(tt->type) & m[i].mask_tail)) {
4036 len += strlen(tt->text);
4037 tt = tt->next;
4041 * Now tt points to the first token after
4042 * the potential paste area...
4044 if (tt != t->next) {
4045 /* We have at least two tokens... */
4046 len += strlen(t->text);
4047 p = tmp = nasm_malloc(len+1);
4048 while (t != tt) {
4049 strcpy(p, t->text);
4050 p = strchr(p, '\0');
4051 t = delete_Token(t);
4053 t = *tail = tokenize(tmp);
4054 nasm_free(tmp);
4055 while (t->next) {
4056 tail = &t->next;
4057 t = t->next;
4059 t->next = tt; /* Attach the remaining token chain */
4060 did_paste = true;
4062 paste_head = tail;
4063 tail = &t->next;
4064 break;
4067 if (i >= mnum) { /* no match */
4068 tail = &t->next;
4069 if (!tok_type_(t->next, TOK_WHITESPACE))
4070 paste_head = tail;
4072 break;
4075 return did_paste;
4079 * expands to a list of tokens from %{x:y}
4081 static Token *expand_mmac_params_range(ExpInv *ei, Token *tline, Token ***last)
4083 Token *t = tline, **tt, *tm, *head;
4084 char *pos;
4085 int fst, lst, j, i;
4087 pos = strchr(tline->text, ':');
4088 nasm_assert(pos);
4090 lst = atoi(pos + 1);
4091 fst = atoi(tline->text + 1);
4094 * only macros params are accounted so
4095 * if someone passes %0 -- we reject such
4096 * value(s)
4098 if (lst == 0 || fst == 0)
4099 goto err;
4101 /* the values should be sane */
4102 if ((fst > (int)ei->nparam || fst < (-(int)ei->nparam)) ||
4103 (lst > (int)ei->nparam || lst < (-(int)ei->nparam)))
4104 goto err;
4106 fst = fst < 0 ? fst + (int)ei->nparam + 1: fst;
4107 lst = lst < 0 ? lst + (int)ei->nparam + 1: lst;
4109 /* counted from zero */
4110 fst--, lst--;
4113 * it will be at least one token
4115 tm = ei->params[(fst + ei->rotate) % ei->nparam];
4116 t = new_Token(NULL, tm->type, tm->text, 0);
4117 head = t, tt = &t->next;
4118 if (fst < lst) {
4119 for (i = fst + 1; i <= lst; i++) {
4120 t = new_Token(NULL, TOK_OTHER, ",", 0);
4121 *tt = t, tt = &t->next;
4122 j = (i + ei->rotate) % ei->nparam;
4123 tm = ei->params[j];
4124 t = new_Token(NULL, tm->type, tm->text, 0);
4125 *tt = t, tt = &t->next;
4127 } else {
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;
4138 *last = tt;
4139 return head;
4141 err:
4142 error(ERR_NONFATAL, "`%%{%s}': macro parameters out of range",
4143 &tline->text[1]);
4144 return tline;
4148 * Expand MMacro-local things: parameter references (%0, %n, %+n,
4149 * %-n) and MMacro-local identifiers (%%foo) as well as
4150 * macro indirection (%[...]) and range (%{..:..}).
4152 static Token *expand_mmac_params(Token * tline)
4154 Token *t, *tt, **tail, *thead;
4155 bool changed = false;
4156 char *pos;
4158 tail = &thead;
4159 thead = NULL;
4161 while (tline) {
4162 if (tline->type == TOK_PREPROC_ID &&
4163 (((tline->text[1] == '+' || tline->text[1] == '-') && tline->text[2]) ||
4164 (tline->text[1] >= '0' && tline->text[1] <= '9') ||
4165 tline->text[1] == '%')) {
4166 char *text = NULL;
4167 int type = 0, cc; /* type = 0 to placate optimisers */
4168 char tmpbuf[30];
4169 unsigned int n;
4170 int i;
4171 ExpInv *ei;
4173 t = tline;
4174 tline = tline->next;
4176 for (ei = istk->expansion; ei != NULL; ei = ei->prev) {
4177 if (ei->type == EXP_MMACRO) {
4178 break;
4181 if (ei == NULL) {
4182 error(ERR_NONFATAL, "`%s': not in a macro call", t->text);
4183 } else {
4184 pos = strchr(t->text, ':');
4185 if (!pos) {
4186 switch (t->text[1]) {
4188 * We have to make a substitution of one of the
4189 * forms %1, %-1, %+1, %%foo, %0.
4191 case '0':
4192 if ((strlen(t->text) > 2) && (t->text[2] == '0')) {
4193 type = TOK_ID;
4194 text = nasm_strdup(ei->label_text);
4195 } else {
4196 type = TOK_NUMBER;
4197 snprintf(tmpbuf, sizeof(tmpbuf), "%d", ei->nparam);
4198 text = nasm_strdup(tmpbuf);
4200 break;
4201 case '%':
4202 type = TOK_ID;
4203 snprintf(tmpbuf, sizeof(tmpbuf), "..@%"PRIu64".",
4204 ei->unique);
4205 text = nasm_strcat(tmpbuf, t->text + 2);
4206 break;
4207 case '-':
4208 n = atoi(t->text + 2) - 1;
4209 if (n >= ei->nparam)
4210 tt = NULL;
4211 else {
4212 if (ei->nparam > 1)
4213 n = (n + ei->rotate) % ei->nparam;
4214 tt = ei->params[n];
4216 cc = find_cc(tt);
4217 if (cc == -1) {
4218 error(ERR_NONFATAL,
4219 "macro parameter %d is not a condition code",
4220 n + 1);
4221 text = NULL;
4222 } else {
4223 type = TOK_ID;
4224 if (inverse_ccs[cc] == -1) {
4225 error(ERR_NONFATAL,
4226 "condition code `%s' is not invertible",
4227 conditions[cc]);
4228 text = NULL;
4229 } else
4230 text = nasm_strdup(conditions[inverse_ccs[cc]]);
4232 break;
4233 case '+':
4234 n = atoi(t->text + 2) - 1;
4235 if (n >= ei->nparam)
4236 tt = NULL;
4237 else {
4238 if (ei->nparam > 1)
4239 n = (n + ei->rotate) % ei->nparam;
4240 tt = ei->params[n];
4242 cc = find_cc(tt);
4243 if (cc == -1) {
4244 error(ERR_NONFATAL,
4245 "macro parameter %d is not a condition code",
4246 n + 1);
4247 text = NULL;
4248 } else {
4249 type = TOK_ID;
4250 text = nasm_strdup(conditions[cc]);
4252 break;
4253 default:
4254 n = atoi(t->text + 1) - 1;
4255 if (n >= ei->nparam)
4256 tt = NULL;
4257 else {
4258 if (ei->nparam > 1)
4259 n = (n + ei->rotate) % ei->nparam;
4260 tt = ei->params[n];
4262 if (tt) {
4263 for (i = 0; i < ei->paramlen[n]; i++) {
4264 *tail = new_Token(NULL, tt->type, tt->text, 0);
4265 tail = &(*tail)->next;
4266 tt = tt->next;
4269 text = NULL; /* we've done it here */
4270 break;
4272 } else {
4274 * seems we have a parameters range here
4276 Token *head, **last;
4277 head = expand_mmac_params_range(ei, t, &last);
4278 if (head != t) {
4279 *tail = head;
4280 *last = tline;
4281 tline = head;
4282 text = NULL;
4286 if (!text) {
4287 delete_Token(t);
4288 } else {
4289 *tail = t;
4290 tail = &t->next;
4291 t->type = type;
4292 nasm_free(t->text);
4293 t->text = text;
4294 t->a.mac = NULL;
4296 changed = true;
4297 continue;
4298 } else if (tline->type == TOK_INDIRECT) {
4299 t = tline;
4300 tline = tline->next;
4301 tt = tokenize(t->text);
4302 tt = expand_mmac_params(tt);
4303 tt = expand_smacro(tt);
4304 *tail = tt;
4305 while (tt) {
4306 tt->a.mac = NULL; /* Necessary? */
4307 tail = &tt->next;
4308 tt = tt->next;
4310 delete_Token(t);
4311 changed = true;
4312 } else {
4313 t = *tail = tline;
4314 tline = tline->next;
4315 t->a.mac = NULL;
4316 tail = &t->next;
4319 *tail = NULL;
4321 if (changed) {
4322 const struct tokseq_match t[] = {
4324 PP_CONCAT_MASK(TOK_ID) |
4325 PP_CONCAT_MASK(TOK_FLOAT), /* head */
4326 PP_CONCAT_MASK(TOK_ID) |
4327 PP_CONCAT_MASK(TOK_NUMBER) |
4328 PP_CONCAT_MASK(TOK_FLOAT) |
4329 PP_CONCAT_MASK(TOK_OTHER) /* tail */
4332 PP_CONCAT_MASK(TOK_NUMBER), /* head */
4333 PP_CONCAT_MASK(TOK_NUMBER) /* tail */
4336 paste_tokens(&thead, t, ARRAY_SIZE(t), false);
4339 return thead;
4343 * Expand all single-line macro calls made in the given line.
4344 * Return the expanded version of the line. The original is deemed
4345 * to be destroyed in the process. (In reality we'll just move
4346 * Tokens from input to output a lot of the time, rather than
4347 * actually bothering to destroy and replicate.)
4350 static Token *expand_smacro(Token * tline)
4352 Token *t, *tt, *mstart, **tail, *thead;
4353 SMacro *head = NULL, *m;
4354 Token **params;
4355 int *paramsize;
4356 unsigned int nparam, sparam;
4357 int brackets;
4358 Token *org_tline = tline;
4359 Context *ctx;
4360 const char *mname;
4361 int deadman = DEADMAN_LIMIT;
4362 bool expanded;
4365 * Trick: we should avoid changing the start token pointer since it can
4366 * be contained in "next" field of other token. Because of this
4367 * we allocate a copy of first token and work with it; at the end of
4368 * routine we copy it back
4370 if (org_tline) {
4371 tline = new_Token(org_tline->next, org_tline->type,
4372 org_tline->text, 0);
4373 tline->a.mac = org_tline->a.mac;
4374 nasm_free(org_tline->text);
4375 org_tline->text = NULL;
4378 expanded = true; /* Always expand %+ at least once */
4380 again:
4381 thead = NULL;
4382 tail = &thead;
4384 while (tline) { /* main token loop */
4385 if (!--deadman) {
4386 error(ERR_NONFATAL, "interminable macro recursion");
4387 goto err;
4390 if ((mname = tline->text)) {
4391 /* if this token is a local macro, look in local context */
4392 if (tline->type == TOK_ID) {
4393 head = (SMacro *)hash_findix(&smacros, mname);
4394 } else if (tline->type == TOK_PREPROC_ID) {
4395 ctx = get_ctx(mname, &mname, false);
4396 head = ctx ? (SMacro *)hash_findix(&ctx->localmac, mname) : NULL;
4397 } else
4398 head = NULL;
4401 * We've hit an identifier. As in is_mmacro below, we first
4402 * check whether the identifier is a single-line macro at
4403 * all, then think about checking for parameters if
4404 * necessary.
4406 list_for_each(m, head)
4407 if (!mstrcmp(m->name, mname, m->casesense))
4408 break;
4409 if (m) {
4410 mstart = tline;
4411 params = NULL;
4412 paramsize = NULL;
4413 if (m->nparam == 0) {
4415 * Simple case: the macro is parameterless. Discard the
4416 * one token that the macro call took, and push the
4417 * expansion back on the to-do stack.
4419 if (!m->expansion) {
4420 if (!strcmp("__FILE__", m->name)) {
4421 int32_t num = 0;
4422 char *file = NULL;
4423 src_get(&num, &file);
4424 tline->text = nasm_quote(file, strlen(file));
4425 tline->type = TOK_STRING;
4426 nasm_free(file);
4427 continue;
4429 if (!strcmp("__LINE__", m->name)) {
4430 nasm_free(tline->text);
4431 make_tok_num(tline, src_get_linnum());
4432 continue;
4434 if (!strcmp("__BITS__", m->name)) {
4435 nasm_free(tline->text);
4436 make_tok_num(tline, globalbits);
4437 continue;
4439 tline = delete_Token(tline);
4440 continue;
4442 } else {
4444 * Complicated case: at least one macro with this name
4445 * exists and takes parameters. We must find the
4446 * parameters in the call, count them, find the SMacro
4447 * that corresponds to that form of the macro call, and
4448 * substitute for the parameters when we expand. What a
4449 * pain.
4451 /*tline = tline->next;
4452 skip_white_(tline); */
4453 do {
4454 t = tline->next;
4455 while (tok_type_(t, TOK_SMAC_END)) {
4456 t->a.mac->in_progress = false;
4457 t->text = NULL;
4458 t = tline->next = delete_Token(t);
4460 tline = t;
4461 } while (tok_type_(tline, TOK_WHITESPACE));
4462 if (!tok_is_(tline, "(")) {
4464 * This macro wasn't called with parameters: ignore
4465 * the call. (Behaviour borrowed from gnu cpp.)
4467 tline = mstart;
4468 m = NULL;
4469 } else {
4470 int paren = 0;
4471 int white = 0;
4472 brackets = 0;
4473 nparam = 0;
4474 sparam = PARAM_DELTA;
4475 params = nasm_malloc(sparam * sizeof(Token *));
4476 params[0] = tline->next;
4477 paramsize = nasm_malloc(sparam * sizeof(int));
4478 paramsize[0] = 0;
4479 while (true) { /* parameter loop */
4481 * For some unusual expansions
4482 * which concatenates function call
4484 t = tline->next;
4485 while (tok_type_(t, TOK_SMAC_END)) {
4486 t->a.mac->in_progress = false;
4487 t->text = NULL;
4488 t = tline->next = delete_Token(t);
4490 tline = t;
4492 if (!tline) {
4493 error(ERR_NONFATAL,
4494 "macro call expects terminating `)'");
4495 break;
4497 if (tline->type == TOK_WHITESPACE
4498 && brackets <= 0) {
4499 if (paramsize[nparam])
4500 white++;
4501 else
4502 params[nparam] = tline->next;
4503 continue; /* parameter loop */
4505 if (tline->type == TOK_OTHER
4506 && tline->text[1] == 0) {
4507 char ch = tline->text[0];
4508 if (ch == ',' && !paren && brackets <= 0) {
4509 if (++nparam >= sparam) {
4510 sparam += PARAM_DELTA;
4511 params = nasm_realloc(params,
4512 sparam * sizeof(Token *));
4513 paramsize = nasm_realloc(paramsize,
4514 sparam * sizeof(int));
4516 params[nparam] = tline->next;
4517 paramsize[nparam] = 0;
4518 white = 0;
4519 continue; /* parameter loop */
4521 if (ch == '{' &&
4522 (brackets > 0 || (brackets == 0 &&
4523 !paramsize[nparam])))
4525 if (!(brackets++)) {
4526 params[nparam] = tline->next;
4527 continue; /* parameter loop */
4530 if (ch == '}' && brackets > 0)
4531 if (--brackets == 0) {
4532 brackets = -1;
4533 continue; /* parameter loop */
4535 if (ch == '(' && !brackets)
4536 paren++;
4537 if (ch == ')' && brackets <= 0)
4538 if (--paren < 0)
4539 break;
4541 if (brackets < 0) {
4542 brackets = 0;
4543 error(ERR_NONFATAL, "braces do not "
4544 "enclose all of macro parameter");
4546 paramsize[nparam] += white + 1;
4547 white = 0;
4548 } /* parameter loop */
4549 nparam++;
4550 while (m && (m->nparam != nparam ||
4551 mstrcmp(m->name, mname,
4552 m->casesense)))
4553 m = m->next;
4554 if (!m)
4555 error(ERR_WARNING|ERR_PASS1|ERR_WARN_MNP,
4556 "macro `%s' exists, "
4557 "but not taking %d parameters",
4558 mstart->text, nparam);
4561 if (m && m->in_progress)
4562 m = NULL;
4563 if (!m) { /* in progess or didn't find '(' or wrong nparam */
4565 * Design question: should we handle !tline, which
4566 * indicates missing ')' here, or expand those
4567 * macros anyway, which requires the (t) test a few
4568 * lines down?
4570 nasm_free(params);
4571 nasm_free(paramsize);
4572 tline = mstart;
4573 } else {
4575 * Expand the macro: we are placed on the last token of the
4576 * call, so that we can easily split the call from the
4577 * following tokens. We also start by pushing an SMAC_END
4578 * token for the cycle removal.
4580 t = tline;
4581 if (t) {
4582 tline = t->next;
4583 t->next = NULL;
4585 tt = new_Token(tline, TOK_SMAC_END, NULL, 0);
4586 tt->a.mac = m;
4587 m->in_progress = true;
4588 tline = tt;
4589 list_for_each(t, m->expansion) {
4590 if (t->type >= TOK_SMAC_PARAM) {
4591 Token *pcopy = tline, **ptail = &pcopy;
4592 Token *ttt, *pt;
4593 int i;
4595 ttt = params[t->type - TOK_SMAC_PARAM];
4596 i = paramsize[t->type - TOK_SMAC_PARAM];
4597 while (--i >= 0) {
4598 pt = *ptail = new_Token(tline, ttt->type,
4599 ttt->text, 0);
4600 ptail = &pt->next;
4601 ttt = ttt->next;
4603 tline = pcopy;
4604 } else if (t->type == TOK_PREPROC_Q) {
4605 tt = new_Token(tline, TOK_ID, mname, 0);
4606 tline = tt;
4607 } else if (t->type == TOK_PREPROC_QQ) {
4608 tt = new_Token(tline, TOK_ID, m->name, 0);
4609 tline = tt;
4610 } else {
4611 tt = new_Token(tline, t->type, t->text, 0);
4612 tline = tt;
4617 * Having done that, get rid of the macro call, and clean
4618 * up the parameters.
4620 nasm_free(params);
4621 nasm_free(paramsize);
4622 free_tlist(mstart);
4623 expanded = true;
4624 continue; /* main token loop */
4629 if (tline->type == TOK_SMAC_END) {
4630 tline->a.mac->in_progress = false;
4631 tline = delete_Token(tline);
4632 } else {
4633 t = *tail = tline;
4634 tline = tline->next;
4635 t->a.mac = NULL;
4636 t->next = NULL;
4637 tail = &t->next;
4642 * Now scan the entire line and look for successive TOK_IDs that resulted
4643 * after expansion (they can't be produced by tokenize()). The successive
4644 * TOK_IDs should be concatenated.
4645 * Also we look for %+ tokens and concatenate the tokens before and after
4646 * them (without white spaces in between).
4648 if (expanded) {
4649 const struct tokseq_match t[] = {
4651 PP_CONCAT_MASK(TOK_ID) |
4652 PP_CONCAT_MASK(TOK_PREPROC_ID), /* head */
4653 PP_CONCAT_MASK(TOK_ID) |
4654 PP_CONCAT_MASK(TOK_PREPROC_ID) |
4655 PP_CONCAT_MASK(TOK_NUMBER) /* tail */
4658 if (paste_tokens(&thead, t, ARRAY_SIZE(t), true)) {
4660 * If we concatenated something, *and* we had previously expanded
4661 * an actual macro, scan the lines again for macros...
4663 tline = thead;
4664 expanded = false;
4665 goto again;
4669 err:
4670 if (org_tline) {
4671 if (thead) {
4672 *org_tline = *thead;
4673 /* since we just gave text to org_line, don't free it */
4674 thead->text = NULL;
4675 delete_Token(thead);
4676 } else {
4677 /* the expression expanded to empty line;
4678 we can't return NULL for some reasons
4679 we just set the line to a single WHITESPACE token. */
4680 memset(org_tline, 0, sizeof(*org_tline));
4681 org_tline->text = NULL;
4682 org_tline->type = TOK_WHITESPACE;
4684 thead = org_tline;
4687 return thead;
4691 * Similar to expand_smacro but used exclusively with macro identifiers
4692 * right before they are fetched in. The reason is that there can be
4693 * identifiers consisting of several subparts. We consider that if there
4694 * are more than one element forming the name, user wants a expansion,
4695 * otherwise it will be left as-is. Example:
4697 * %define %$abc cde
4699 * the identifier %$abc will be left as-is so that the handler for %define
4700 * will suck it and define the corresponding value. Other case:
4702 * %define _%$abc cde
4704 * In this case user wants name to be expanded *before* %define starts
4705 * working, so we'll expand %$abc into something (if it has a value;
4706 * otherwise it will be left as-is) then concatenate all successive
4707 * PP_IDs into one.
4709 static Token *expand_id(Token * tline)
4711 Token *cur, *oldnext = NULL;
4713 if (!tline || !tline->next)
4714 return tline;
4716 cur = tline;
4717 while (cur->next &&
4718 (cur->next->type == TOK_ID ||
4719 cur->next->type == TOK_PREPROC_ID
4720 || cur->next->type == TOK_NUMBER))
4721 cur = cur->next;
4723 /* If identifier consists of just one token, don't expand */
4724 if (cur == tline)
4725 return tline;
4727 if (cur) {
4728 oldnext = cur->next; /* Detach the tail past identifier */
4729 cur->next = NULL; /* so that expand_smacro stops here */
4732 tline = expand_smacro(tline);
4734 if (cur) {
4735 /* expand_smacro possibly changhed tline; re-scan for EOL */
4736 cur = tline;
4737 while (cur && cur->next)
4738 cur = cur->next;
4739 if (cur)
4740 cur->next = oldnext;
4743 return tline;
4747 * Determine whether the given line constitutes a multi-line macro
4748 * call, and return the ExpDef structure called if so. Doesn't have
4749 * to check for an initial label - that's taken care of in
4750 * expand_mmacro - but must check numbers of parameters. Guaranteed
4751 * to be called with tline->type == TOK_ID, so the putative macro
4752 * name is easy to find.
4754 static ExpDef *is_mmacro(Token * tline, Token *** params_array)
4756 ExpDef *head, *ed;
4757 Token **params;
4758 int nparam;
4760 head = (ExpDef *) hash_findix(&expdefs, tline->text);
4763 * Efficiency: first we see if any macro exists with the given
4764 * name. If not, we can return NULL immediately. _Then_ we
4765 * count the parameters, and then we look further along the
4766 * list if necessary to find the proper ExpDef.
4768 list_for_each(ed, head)
4769 if (!mstrcmp(ed->name, tline->text, ed->casesense))
4770 break;
4771 if (!ed)
4772 return NULL;
4775 * OK, we have a potential macro. Count and demarcate the
4776 * parameters.
4778 count_mmac_params(tline->next, &nparam, &params);
4781 * So we know how many parameters we've got. Find the ExpDef
4782 * structure that handles this number.
4784 while (ed) {
4785 if (ed->nparam_min <= nparam
4786 && (ed->plus || nparam <= ed->nparam_max)) {
4788 * It's right, and we can use it. Add its default
4789 * parameters to the end of our list if necessary.
4791 if (ed->defaults && nparam < ed->nparam_min + ed->ndefs) {
4792 params =
4793 nasm_realloc(params,
4794 ((ed->nparam_min + ed->ndefs +
4795 1) * sizeof(*params)));
4796 while (nparam < ed->nparam_min + ed->ndefs) {
4797 params[nparam] = ed->defaults[nparam - ed->nparam_min];
4798 nparam++;
4802 * If we've gone over the maximum parameter count (and
4803 * we're in Plus mode), ignore parameters beyond
4804 * nparam_max.
4806 if (ed->plus && nparam > ed->nparam_max)
4807 nparam = ed->nparam_max;
4809 * Then terminate the parameter list, and leave.
4811 if (!params) { /* need this special case */
4812 params = nasm_malloc(sizeof(*params));
4813 nparam = 0;
4815 params[nparam] = NULL;
4816 *params_array = params;
4817 return ed;
4820 * This one wasn't right: look for the next one with the
4821 * same name.
4823 list_for_each(ed, ed->next)
4824 if (!mstrcmp(ed->name, tline->text, ed->casesense))
4825 break;
4829 * After all that, we didn't find one with the right number of
4830 * parameters. Issue a warning, and fail to expand the macro.
4832 error(ERR_WARNING|ERR_PASS1|ERR_WARN_MNP,
4833 "macro `%s' exists, but not taking %d parameters",
4834 tline->text, nparam);
4835 nasm_free(params);
4836 return NULL;
4840 * Expand the multi-line macro call made by the given line, if
4841 * there is one to be expanded. If there is, push the expansion on
4842 * istk->expansion and return true. Otherwise return false.
4844 static bool expand_mmacro(Token * tline)
4846 Token *label = NULL;
4847 int dont_prepend = 0;
4848 Token **params, *t, *mtok;
4849 Line *l = NULL;
4850 ExpDef *ed;
4851 ExpInv *ei;
4852 int i, nparam, *paramlen;
4853 const char *mname;
4855 t = tline;
4856 skip_white_(t);
4857 /* if (!tok_type_(t, TOK_ID)) Lino 02/25/02 */
4858 if (!tok_type_(t, TOK_ID) && !tok_type_(t, TOK_PREPROC_ID))
4859 return false;
4860 mtok = t;
4861 ed = is_mmacro(t, &params);
4862 if (ed != NULL) {
4863 mname = t->text;
4864 } else {
4865 Token *last;
4867 * We have an id which isn't a macro call. We'll assume
4868 * it might be a label; we'll also check to see if a
4869 * colon follows it. Then, if there's another id after
4870 * that lot, we'll check it again for macro-hood.
4872 label = last = t;
4873 t = t->next;
4874 if (tok_type_(t, TOK_WHITESPACE))
4875 last = t, t = t->next;
4876 if (tok_is_(t, ":")) {
4877 dont_prepend = 1;
4878 last = t, t = t->next;
4879 if (tok_type_(t, TOK_WHITESPACE))
4880 last = t, t = t->next;
4882 if (!tok_type_(t, TOK_ID) || !(ed = is_mmacro(t, &params)))
4883 return false;
4884 last->next = NULL;
4885 mname = t->text;
4886 tline = t;
4890 * Fix up the parameters: this involves stripping leading and
4891 * trailing whitespace, then stripping braces if they are
4892 * present.
4894 for (nparam = 0; params[nparam]; nparam++) ;
4895 paramlen = nparam ? nasm_malloc(nparam * sizeof(*paramlen)) : NULL;
4897 for (i = 0; params[i]; i++) {
4898 int brace = false;
4899 int comma = (!ed->plus || i < nparam - 1);
4901 t = params[i];
4902 skip_white_(t);
4903 if (tok_is_(t, "{"))
4904 t = t->next, brace = true, comma = false;
4905 params[i] = t;
4906 paramlen[i] = 0;
4907 while (t) {
4908 if (comma && t->type == TOK_OTHER && !strcmp(t->text, ","))
4909 break; /* ... because we have hit a comma */
4910 if (comma && t->type == TOK_WHITESPACE
4911 && tok_is_(t->next, ","))
4912 break; /* ... or a space then a comma */
4913 if (brace && t->type == TOK_OTHER && !strcmp(t->text, "}"))
4914 break; /* ... or a brace */
4915 t = t->next;
4916 paramlen[i]++;
4920 if (ed->cur_depth >= ed->max_depth) {
4921 if (ed->max_depth > 1) {
4922 error(ERR_WARNING,
4923 "reached maximum macro recursion depth of %i for %s",
4924 ed->max_depth,ed->name);
4926 return false;
4927 } else {
4928 ed->cur_depth ++;
4932 * OK, we have found a ExpDef structure representing a
4933 * previously defined mmacro. Create an expansion invocation
4934 * and point it back to the expansion definition. Substitution of
4935 * parameter tokens and macro-local tokens doesn't get done
4936 * until the single-line macro substitution process; this is
4937 * because delaying them allows us to change the semantics
4938 * later through %rotate.
4940 ei = new_ExpInv(EXP_MMACRO, ed);
4941 ei->name = nasm_strdup(mname);
4942 //ei->label = label;
4943 //ei->label_text = detoken(label, false);
4944 ei->current = ed->line;
4945 ei->emitting = true;
4946 //ei->iline = tline;
4947 ei->params = params;
4948 ei->nparam = nparam;
4949 ei->rotate = 0;
4950 ei->paramlen = paramlen;
4951 ei->lineno = 0;
4953 ei->prev = istk->expansion;
4954 istk->expansion = ei;
4957 * Special case: detect %00 on first invocation; if found,
4958 * avoid emitting any labels that precede the mmacro call.
4959 * ed->prepend is set to -1 when %00 is detected, else 1.
4961 if (ed->prepend == 0) {
4962 for (l = ed->line; l != NULL; l = l->next) {
4963 for (t = l->first; t != NULL; t = t->next) {
4964 if ((t->type == TOK_PREPROC_ID) &&
4965 (strlen(t->text) == 3) &&
4966 (t->text[1] == '0') && (t->text[2] == '0')) {
4967 dont_prepend = -1;
4968 break;
4971 if (dont_prepend < 0) {
4972 break;
4975 ed->prepend = ((dont_prepend < 0) ? -1 : 1);
4979 * If we had a label, push it on as the first line of
4980 * the macro expansion.
4982 if (label != NULL) {
4983 if (ed->prepend < 0) {
4984 ei->label_text = detoken(label, false);
4985 } else {
4986 if (dont_prepend == 0) {
4987 t = label;
4988 while (t->next != NULL) {
4989 t = t->next;
4991 t->next = new_Token(NULL, TOK_OTHER, ":", 0);
4993 l = new_Line();
4994 l->first = copy_Token(label);
4995 l->next = ei->current;
4996 ei->current = l;
5000 list->uplevel(ed->nolist ? LIST_MACRO_NOLIST : LIST_MACRO);
5002 istk->mmac_depth++;
5003 return true;
5006 /* The function that actually does the error reporting */
5007 static void verror(int severity, const char *fmt, va_list arg)
5009 char buff[1024];
5011 vsnprintf(buff, sizeof(buff), fmt, arg);
5013 if (istk && istk->mmac_depth > 0) {
5014 ExpInv *ei = istk->expansion;
5015 int lineno = ei->lineno;
5016 while (ei) {
5017 if (ei->type == EXP_MMACRO)
5018 break;
5019 lineno += ei->relno;
5020 ei = ei->prev;
5022 nasm_error(severity, "(%s:%d) %s", ei->def->name,
5023 lineno, buff);
5024 } else
5025 nasm_error(severity, "%s", buff);
5029 * Since preprocessor always operate only on the line that didn't
5030 * arrived yet, we should always use ERR_OFFBY1.
5032 static void error(int severity, const char *fmt, ...)
5034 va_list arg;
5035 va_start(arg, fmt);
5036 verror(severity, fmt, arg);
5037 va_end(arg);
5041 * Because %else etc are evaluated in the state context
5042 * of the previous branch, errors might get lost with error():
5043 * %if 0 ... %else trailing garbage ... %endif
5044 * So %else etc should report errors with this function.
5046 static void error_precond(int severity, const char *fmt, ...)
5048 va_list arg;
5050 /* Only ignore the error if it's really in a dead branch */
5051 if ((istk != NULL) &&
5052 (istk->expansion != NULL) &&
5053 (istk->expansion->type == EXP_IF) &&
5054 (istk->expansion->def->state == COND_NEVER))
5055 return;
5057 va_start(arg, fmt);
5058 verror(severity, fmt, arg);
5059 va_end(arg);
5062 static void
5063 pp_reset(char *file, int apass, ListGen * listgen, StrList **deplist)
5065 Token *t;
5067 cstk = NULL;
5068 istk = nasm_malloc(sizeof(Include));
5069 istk->next = NULL;
5070 istk->expansion = NULL;
5071 istk->fp = fopen(file, "r");
5072 istk->fname = NULL;
5073 src_set_fname(nasm_strdup(file));
5074 src_set_linnum(0);
5075 istk->lineinc = 1;
5076 istk->mmac_depth = 0;
5077 if (!istk->fp)
5078 error(ERR_FATAL|ERR_NOFILE, "unable to open input file `%s'",
5079 file);
5080 defining = NULL;
5081 finals = NULL;
5082 in_final = false;
5083 nested_mac_count = 0;
5084 nested_rep_count = 0;
5085 init_macros();
5086 unique = 0;
5087 if (tasm_compatible_mode) {
5088 stdmacpos = nasm_stdmac;
5089 } else {
5090 stdmacpos = nasm_stdmac_after_tasm;
5092 any_extrastdmac = extrastdmac && *extrastdmac;
5093 do_predef = true;
5094 list = listgen;
5097 * 0 for dependencies, 1 for preparatory passes, 2 for final pass.
5098 * The caller, however, will also pass in 3 for preprocess-only so
5099 * we can set __PASS__ accordingly.
5101 pass = apass > 2 ? 2 : apass;
5103 dephead = deptail = deplist;
5104 if (deplist) {
5105 StrList *sl = nasm_malloc(strlen(file)+1+sizeof sl->next);
5106 sl->next = NULL;
5107 strcpy(sl->str, file);
5108 *deptail = sl;
5109 deptail = &sl->next;
5113 * Define the __PASS__ macro. This is defined here unlike
5114 * all the other builtins, because it is special -- it varies between
5115 * passes.
5117 t = nasm_malloc(sizeof(*t));
5118 t->next = NULL;
5119 make_tok_num(t, apass);
5120 t->a.mac = NULL;
5121 define_smacro(NULL, "__PASS__", true, 0, t);
5124 static char *pp_getline(void)
5126 char *line;
5127 Token *tline;
5128 ExpDef *ed;
5129 ExpInv *ei;
5130 Line *l;
5131 int j;
5133 while (1) {
5135 * Fetch a tokenized line, either from the expansion
5136 * buffer or from the input file.
5138 tline = NULL;
5140 while (1) { /* until we get a line we can use */
5142 * Fetch a tokenized line from the expansion buffer
5144 if (istk->expansion != NULL) {
5145 ei = istk->expansion;
5146 if (ei->current != NULL) {
5147 if (ei->emitting == false) {
5148 ei->current = NULL;
5149 continue;
5151 l = ei->current;
5152 ei->current = l->next;
5153 ei->lineno++;
5154 tline = copy_Token(l->first);
5155 if (((ei->type == EXP_REP) ||
5156 (ei->type == EXP_MMACRO) ||
5157 (ei->type == EXP_WHILE))
5158 && (ei->def->nolist == false)) {
5159 char *p = detoken(tline, false);
5160 list->line(LIST_MACRO, p);
5161 nasm_free(p);
5163 if (ei->linnum > -1) {
5164 src_set_linnum(src_get_linnum() + 1);
5166 break;
5167 } else if ((ei->type == EXP_REP) &&
5168 (ei->def->cur_depth < ei->def->max_depth)) {
5169 ei->def->cur_depth ++;
5170 ei->current = ei->def->line;
5171 ei->lineno = 0;
5172 continue;
5173 } else if ((ei->type == EXP_WHILE) &&
5174 (ei->def->cur_depth < ei->def->max_depth)) {
5175 ei->current = ei->def->line;
5176 ei->lineno = 0;
5177 tline = copy_Token(ei->current->first);
5178 j = if_condition(tline, PP_WHILE);
5179 tline = NULL;
5180 j = (((j < 0) ? COND_NEVER : j) ? COND_IF_TRUE : COND_IF_FALSE);
5181 if (j == COND_IF_TRUE) {
5182 ei->current = ei->current->next;
5183 ei->def->cur_depth ++;
5184 } else {
5185 ei->emitting = false;
5186 ei->current = NULL;
5187 ei->def->cur_depth = ei->def->max_depth;
5189 continue;
5190 } else {
5191 istk->expansion = ei->prev;
5192 ed = ei->def;
5193 if (ed != NULL) {
5194 if ((ei->emitting == true) &&
5195 (ed->max_depth == DEADMAN_LIMIT) &&
5196 (ed->cur_depth == DEADMAN_LIMIT)
5198 error(ERR_FATAL, "runaway expansion detected, aborting");
5200 if (ed->cur_depth > 0) {
5201 ed->cur_depth --;
5202 } else if (ed->type != EXP_MMACRO) {
5203 expansions = ed->prev;
5204 free_expdef(ed);
5206 if ((ei->type == EXP_REP) ||
5207 (ei->type == EXP_MMACRO) ||
5208 (ei->type == EXP_WHILE)) {
5209 list->downlevel(LIST_MACRO);
5210 if (ei->type == EXP_MMACRO) {
5211 istk->mmac_depth--;
5215 if (ei->linnum > -1) {
5216 src_set_linnum(ei->linnum);
5218 free_expinv(ei);
5219 continue;
5224 * Read in line from input and tokenize
5226 line = read_line();
5227 if (line) { /* from the current input file */
5228 line = prepreproc(line);
5229 tline = tokenize(line);
5230 nasm_free(line);
5231 break;
5235 * The current file has ended; work down the istk
5238 Include *i = istk;
5239 fclose(i->fp);
5240 if (i->expansion != NULL) {
5241 error(ERR_FATAL,
5242 "end of file while still in an expansion");
5244 /* only set line and file name if there's a next node */
5245 if (i->next) {
5246 src_set_linnum(i->lineno);
5247 nasm_free(src_set_fname(i->fname));
5249 if ((i->next == NULL) && (finals != NULL)) {
5250 in_final = true;
5251 ei = new_ExpInv(EXP_FINAL, NULL);
5252 ei->emitting = true;
5253 ei->current = finals;
5254 istk->expansion = ei;
5255 finals = NULL;
5256 continue;
5258 istk = i->next;
5259 list->downlevel(LIST_INCLUDE);
5260 nasm_free(i);
5261 if (istk == NULL) {
5262 if (finals != NULL) {
5263 in_final = true;
5264 } else {
5265 return NULL;
5268 continue;
5272 if (defining == NULL) {
5273 tline = expand_mmac_params(tline);
5277 * Check the line to see if it's a preprocessor directive.
5279 if (do_directive(tline) == DIRECTIVE_FOUND) {
5280 continue;
5281 } else if (defining != NULL) {
5283 * We're defining an expansion. We emit nothing at all,
5284 * and just shove the tokenized line on to the definition.
5286 if (defining->ignoring == false) {
5287 Line *l = new_Line();
5288 l->first = tline;
5289 if (defining->line == NULL) {
5290 defining->line = l;
5291 defining->last = l;
5292 } else {
5293 defining->last->next = l;
5294 defining->last = l;
5296 } else {
5297 free_tlist(tline);
5299 defining->linecount++;
5300 continue;
5301 } else if ((istk->expansion != NULL) &&
5302 (istk->expansion->emitting != true)) {
5304 * We're in a non-emitting branch of an expansion.
5305 * Emit nothing at all, not even a blank line: when we
5306 * emerge from the expansion we'll give a line-number
5307 * directive so we keep our place correctly.
5309 free_tlist(tline);
5310 continue;
5311 } else {
5312 tline = expand_smacro(tline);
5313 if (expand_mmacro(tline) != true) {
5315 * De-tokenize the line again, and emit it.
5317 line = detoken(tline, true);
5318 free_tlist(tline);
5319 break;
5320 } else {
5321 continue;
5325 return line;
5328 static void pp_cleanup(int pass)
5330 if (defining != NULL) {
5331 error(ERR_NONFATAL, "end of file while still defining an expansion");
5332 while (defining != NULL) {
5333 ExpDef *ed = defining;
5334 defining = ed->prev;
5335 free_expdef(ed);
5337 defining = NULL;
5339 while (cstk != NULL)
5340 ctx_pop();
5341 free_macros();
5342 while (istk != NULL) {
5343 Include *i = istk;
5344 istk = istk->next;
5345 fclose(i->fp);
5346 nasm_free(i->fname);
5347 nasm_free(i);
5348 while (i->expansion != NULL) {
5349 ExpInv *ei = i->expansion;
5350 i->expansion = ei->prev;
5351 free_expinv(ei);
5354 while (cstk)
5355 ctx_pop();
5356 nasm_free(src_set_fname(NULL));
5357 if (pass == 0) {
5358 IncPath *i;
5359 free_llist(predef);
5360 delete_Blocks();
5361 while ((i = ipath)) {
5362 ipath = i->next;
5363 if (i->path)
5364 nasm_free(i->path);
5365 nasm_free(i);
5370 void pp_include_path(char *path)
5372 IncPath *i;
5374 i = nasm_malloc(sizeof(IncPath));
5375 i->path = path ? nasm_strdup(path) : NULL;
5376 i->next = NULL;
5378 if (ipath) {
5379 IncPath *j = ipath;
5380 while (j->next)
5381 j = j->next;
5382 j->next = i;
5383 } else {
5384 ipath = i;
5388 void pp_pre_include(char *fname)
5390 Token *inc, *space, *name;
5391 Line *l;
5393 name = new_Token(NULL, TOK_INTERNAL_STRING, fname, 0);
5394 space = new_Token(name, TOK_WHITESPACE, NULL, 0);
5395 inc = new_Token(space, TOK_PREPROC_ID, "%include", 0);
5397 l = new_Line();
5398 l->next = predef;
5399 l->first = inc;
5400 predef = l;
5403 void pp_pre_define(char *definition)
5405 Token *def, *space;
5406 Line *l;
5407 char *equals;
5409 equals = strchr(definition, '=');
5410 space = new_Token(NULL, TOK_WHITESPACE, NULL, 0);
5411 def = new_Token(space, TOK_PREPROC_ID, "%define", 0);
5412 if (equals)
5413 *equals = ' ';
5414 space->next = tokenize(definition);
5415 if (equals)
5416 *equals = '=';
5418 l = new_Line();
5419 l->next = predef;
5420 l->first = def;
5421 predef = l;
5424 void pp_pre_undefine(char *definition)
5426 Token *def, *space;
5427 Line *l;
5429 space = new_Token(NULL, TOK_WHITESPACE, NULL, 0);
5430 def = new_Token(space, TOK_PREPROC_ID, "%undef", 0);
5431 space->next = tokenize(definition);
5433 l = new_Line();
5434 l->next = predef;
5435 l->first = def;
5436 predef = l;
5440 * This function is used to assist with "runtime" preprocessor
5441 * directives, e.g. pp_runtime("%define __BITS__ 64");
5443 * ERRORS ARE IGNORED HERE, SO MAKE COMPLETELY SURE THAT YOU
5444 * PASS A VALID STRING TO THIS FUNCTION!!!!!
5447 void pp_runtime(char *definition)
5449 Token *def;
5451 def = tokenize(definition);
5452 if (do_directive(def) == NO_DIRECTIVE_FOUND)
5453 free_tlist(def);
5457 void pp_extra_stdmac(macros_t *macros)
5459 extrastdmac = macros;
5462 static void make_tok_num(Token * tok, int64_t val)
5464 char numbuf[20];
5465 snprintf(numbuf, sizeof(numbuf), "%"PRId64"", val);
5466 tok->text = nasm_strdup(numbuf);
5467 tok->type = TOK_NUMBER;
5470 Preproc nasmpp = {
5471 pp_reset,
5472 pp_getline,
5473 pp_cleanup