preproc: Use memset for stack allocated structure
[nasm/sigaren-mirror.git] / preproc.c
blob642c54f93f59b9ee4b7d1d81582e1dd2720881dd
1 /* ----------------------------------------------------------------------- *
3 * Copyright 1996-2010 The NASM Authors - All Rights Reserved
4 * See the file AUTHORS included with the NASM distribution for
5 * the specific copyright holders.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following
9 * conditions are met:
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 * ----------------------------------------------------------------------- */
35 * preproc.c macro preprocessor for the Netwide Assembler
38 /* Typical flow of text through preproc
40 * pp_getline gets tokenized lines, either
42 * from a macro expansion
44 * or
45 * {
46 * read_line gets raw text from stdmacpos, or predef, or current input file
47 * tokenize converts to tokens
48 * }
50 * expand_mmac_params is used to expand %1 etc., unless a macro is being
51 * defined or a false conditional is being processed
52 * (%0, %1, %+1, %-1, %%foo
54 * do_directive checks for directives
56 * expand_smacro is used to expand single line macros
58 * expand_mmacro is used to expand multi-line macros
60 * detoken is used to convert the line back to text
63 #include "compiler.h"
65 #include <stdio.h>
66 #include <stdarg.h>
67 #include <stdlib.h>
68 #include <stddef.h>
69 #include <string.h>
70 #include <ctype.h>
71 #include <limits.h>
72 #include <inttypes.h>
74 #include "nasm.h"
75 #include "nasmlib.h"
76 #include "preproc.h"
77 #include "hashtbl.h"
78 #include "quote.h"
79 #include "stdscan.h"
80 #include "eval.h"
81 #include "tokens.h"
82 #include "tables.h"
84 typedef struct SMacro SMacro;
85 typedef struct ExpDef ExpDef;
86 typedef struct ExpInv ExpInv;
87 typedef struct Context Context;
88 typedef struct Token Token;
89 typedef struct Blocks Blocks;
90 typedef struct Line Line;
91 typedef struct Include Include;
92 typedef struct Cond Cond;
93 typedef struct IncPath IncPath;
96 * Note on the storage of both SMacro and MMacros: the hash table
97 * indexes them case-insensitively, and we then have to go through a
98 * linked list of potential case aliases (and, for MMacros, parameter
99 * ranges); this is to preserve the matching semantics of the earlier
100 * code. If the number of case aliases for a specific macro is a
101 * performance issue, you may want to reconsider your coding style.
105 * Store the definition of a single-line macro.
107 struct SMacro {
108 SMacro *next;
109 char *name;
110 bool casesense;
111 bool in_progress;
112 unsigned int nparam;
113 Token *expansion;
117 * The context stack is composed of a linked list of these.
119 struct Context {
120 Context *next;
121 char *name;
122 struct hash_table localmac;
123 uint32_t number;
127 * This is the internal form which we break input lines up into.
128 * Typically stored in linked lists.
130 * Note that `type' serves a double meaning: TOK_SMAC_PARAM is not
131 * necessarily used as-is, but is intended to denote the number of
132 * the substituted parameter. So in the definition
134 * %define a(x,y) ( (x) & ~(y) )
136 * the token representing `x' will have its type changed to
137 * TOK_SMAC_PARAM, but the one representing `y' will be
138 * TOK_SMAC_PARAM+1.
140 * TOK_INTERNAL_STRING is a dirty hack: it's a single string token
141 * which doesn't need quotes around it. Used in the pre-include
142 * mechanism as an alternative to trying to find a sensible type of
143 * quote to use on the filename we were passed.
145 enum pp_token_type {
146 TOK_NONE = 0, TOK_WHITESPACE, TOK_COMMENT, TOK_ID,
147 TOK_PREPROC_ID, TOK_STRING,
148 TOK_NUMBER, TOK_FLOAT, TOK_SMAC_END, TOK_OTHER,
149 TOK_INTERNAL_STRING,
150 TOK_PREPROC_Q, TOK_PREPROC_QQ,
151 TOK_PASTE, /* %+ */
152 TOK_INDIRECT, /* %[...] */
153 TOK_SMAC_PARAM, /* MUST BE LAST IN THE LIST!!! */
154 TOK_MAX = INT_MAX /* Keep compiler from reducing the range */
157 #define PP_CONCAT_MASK(x) (1 << (x))
159 struct tokseq_match {
160 int mask_head;
161 int mask_tail;
164 struct Token {
165 Token *next;
166 char *text;
167 union {
168 SMacro *mac; /* associated macro for TOK_SMAC_END */
169 size_t len; /* scratch length field */
170 } a; /* Auxiliary data */
171 enum pp_token_type type;
175 * Expansion definitions are stored as a linked list of
176 * these, which is essentially a container to allow several linked
177 * lists of Tokens.
179 * Note that in this module, linked lists are treated as stacks
180 * wherever possible. For this reason, Lines are _pushed_ on to the
181 * `last' field in ExpDef structures, so that the linked list,
182 * if walked, would emit the expansion lines in the proper order.
184 struct Line {
185 Line *next;
186 Token *first;
190 * Expansion Types
192 enum pp_exp_type {
193 EXP_NONE = 0, EXP_PREDEF,
194 EXP_MMACRO, EXP_REP,
195 EXP_IF, EXP_WHILE,
196 EXP_COMMENT, EXP_FINAL,
197 EXP_MAX = INT_MAX /* Keep compiler from reducing the range */
201 * Store the definition of an expansion, in which is any
202 * preprocessor directive that has an ending pair.
204 * This design allows for arbitrary expansion/recursion depth,
205 * upto the DEADMAN_LIMIT.
207 * The `next' field is used for storing ExpDef in hash tables; the
208 * `prev' field is for the global `expansions` linked-list.
210 struct ExpDef {
211 ExpDef *prev; /* previous definition */
212 ExpDef *next; /* next in hash table */
213 enum pp_exp_type type; /* expansion type */
214 char *name; /* definition name */
215 int nparam_min, nparam_max;
216 bool casesense;
217 bool plus; /* is the last parameter greedy? */
218 bool nolist; /* is this expansion listing-inhibited? */
219 Token *dlist; /* all defaults as one list */
220 Token **defaults; /* parameter default pointers */
221 int ndefs; /* number of default parameters */
223 int prepend; /* label prepend state */
224 Line *label;
225 Line *line;
226 Line *last;
227 int linecount; /* number of lines within expansion */
229 int64_t def_depth; /* current number of definition pairs deep */
230 int64_t cur_depth; /* current number of expansions */
231 int64_t max_depth; /* maximum number of expansions allowed */
233 int state; /* condition state */
234 bool ignoring; /* ignoring definition lines */
238 * Store the invocation of an expansion.
240 * The `prev' field is for the `istk->expansion` linked-list.
242 * When an expansion is being expanded, `params', `iline', `nparam',
243 * `paramlen', `rotate' and `unique' are local to the invocation.
245 struct ExpInv {
246 ExpInv *prev; /* previous invocation */
247 enum pp_exp_type type; /* expansion type */
248 ExpDef *def; /* pointer to expansion definition */
249 char *name; /* invocation name */
250 Line *label; /* pointer to label */
251 char *label_text; /* pointer to label text */
252 Line *current; /* pointer to current line in invocation */
254 Token **params; /* actual parameters */
255 Token *iline; /* invocation line */
256 unsigned int nparam, rotate;
257 int *paramlen;
259 uint64_t unique;
260 bool emitting;
261 int lineno; /* current line number in expansion */
262 int linnum; /* line number at invocation */
263 int relno; /* relative line number at invocation */
267 * To handle an arbitrary level of file inclusion, we maintain a
268 * stack (ie linked list) of these things.
270 struct Include {
271 Include *next;
272 FILE *fp;
273 Cond *conds;
274 ExpInv *expansion;
275 char *fname;
276 int lineno, lineinc;
277 int mmac_depth;
281 * Include search path. This is simply a list of strings which get
282 * prepended, in turn, to the name of an include file, in an
283 * attempt to find the file if it's not in the current directory.
285 struct IncPath {
286 IncPath *next;
287 char *path;
291 * Conditional assembly: we maintain a separate stack of these for
292 * each level of file inclusion. (The only reason we keep the
293 * stacks separate is to ensure that a stray `%endif' in a file
294 * included from within the true branch of a `%if' won't terminate
295 * it and cause confusion: instead, rightly, it'll cause an error.)
297 enum {
299 * These states are for use just after %if or %elif: IF_TRUE
300 * means the condition has evaluated to truth so we are
301 * currently emitting, whereas IF_FALSE means we are not
302 * currently emitting but will start doing so if a %else comes
303 * up. In these states, all directives are admissible: %elif,
304 * %else and %endif. (And of course %if.)
306 COND_IF_TRUE, COND_IF_FALSE,
308 * These states come up after a %else: ELSE_TRUE means we're
309 * emitting, and ELSE_FALSE means we're not. In ELSE_* states,
310 * any %elif or %else will cause an error.
312 COND_ELSE_TRUE, COND_ELSE_FALSE,
314 * These states mean that we're not emitting now, and also that
315 * nothing until %endif will be emitted at all. COND_DONE is
316 * used when we've had our moment of emission
317 * and have now started seeing %elifs. COND_NEVER is used when
318 * the condition construct in question is contained within a
319 * non-emitting branch of a larger condition construct,
320 * or if there is an error.
322 COND_DONE, COND_NEVER
324 #define emitting(x) ( (x) == COND_IF_TRUE || (x) == COND_ELSE_TRUE )
327 * These defines are used as the possible return values for do_directive
329 #define NO_DIRECTIVE_FOUND 0
330 #define DIRECTIVE_FOUND 1
333 * This define sets the upper limit for smacro and expansions
335 #define DEADMAN_LIMIT (1 << 20)
337 /* max reps */
338 #define REP_LIMIT ((INT64_C(1) << 62))
341 * Condition codes. Note that we use c_ prefix not C_ because C_ is
342 * used in nasm.h for the "real" condition codes. At _this_ level,
343 * we treat CXZ and ECXZ as condition codes, albeit non-invertible
344 * ones, so we need a different enum...
346 static const char * const conditions[] = {
347 "a", "ae", "b", "be", "c", "cxz", "e", "ecxz", "g", "ge", "l", "le",
348 "na", "nae", "nb", "nbe", "nc", "ne", "ng", "nge", "nl", "nle", "no",
349 "np", "ns", "nz", "o", "p", "pe", "po", "rcxz", "s", "z"
351 enum pp_conds {
352 c_A, c_AE, c_B, c_BE, c_C, c_CXZ, c_E, c_ECXZ, c_G, c_GE, c_L, c_LE,
353 c_NA, c_NAE, c_NB, c_NBE, c_NC, c_NE, c_NG, c_NGE, c_NL, c_NLE, c_NO,
354 c_NP, c_NS, c_NZ, c_O, c_P, c_PE, c_PO, c_RCXZ, c_S, c_Z,
355 c_none = -1
357 static const enum pp_conds inverse_ccs[] = {
358 c_NA, c_NAE, c_NB, c_NBE, c_NC, -1, c_NE, -1, c_NG, c_NGE, c_NL, c_NLE,
359 c_A, c_AE, c_B, c_BE, c_C, c_E, c_G, c_GE, c_L, c_LE, c_O, c_P, c_S,
360 c_Z, c_NO, c_NP, c_PO, c_PE, -1, c_NS, c_NZ
363 /* For TASM compatibility we need to be able to recognise TASM compatible
364 * conditional compilation directives. Using the NASM pre-processor does
365 * not work, so we look for them specifically from the following list and
366 * then jam in the equivalent NASM directive into the input stream.
369 enum {
370 TM_ARG, TM_ELIF, TM_ELSE, TM_ENDIF, TM_IF, TM_IFDEF, TM_IFDIFI,
371 TM_IFNDEF, TM_INCLUDE, TM_LOCAL
374 static const char * const tasm_directives[] = {
375 "arg", "elif", "else", "endif", "if", "ifdef", "ifdifi",
376 "ifndef", "include", "local"
379 static int StackSize = 4;
380 static char *StackPointer = "ebp";
381 static int ArgOffset = 8;
382 static int LocalOffset = 0;
384 static Context *cstk;
385 static Include *istk;
386 static IncPath *ipath = NULL;
388 static int pass; /* HACK: pass 0 = generate dependencies only */
389 static StrList **dephead, **deptail; /* Dependency list */
391 static uint64_t unique; /* unique identifier numbers */
393 static Line *predef = NULL;
394 static bool do_predef;
396 static ListGen *list;
399 * The current set of expansion definitions we have defined.
401 static struct hash_table expdefs;
404 * The current set of single-line macros we have defined.
406 static struct hash_table smacros;
409 * Linked List of all active expansion definitions
411 struct ExpDef *expansions = NULL;
414 * The expansion we are currently defining
416 static ExpDef *defining = NULL;
418 static uint64_t nested_mac_count;
419 static uint64_t nested_rep_count;
422 * Linked-list of lines to preprocess, prior to cleanup
424 static Line *finals = NULL;
425 static bool in_final = false;
428 * The number of macro parameters to allocate space for at a time.
430 #define PARAM_DELTA 16
433 * The standard macro set: defined in macros.c in the array nasm_stdmac.
434 * This gives our position in the macro set, when we're processing it.
436 static macros_t *stdmacpos;
439 * The extra standard macros that come from the object format, if
440 * any.
442 static macros_t *extrastdmac = NULL;
443 static bool any_extrastdmac;
446 * Tokens are allocated in blocks to improve speed
448 #define TOKEN_BLOCKSIZE 4096
449 static Token *freeTokens = NULL;
450 struct Blocks {
451 Blocks *next;
452 void *chunk;
455 static Blocks blocks = { NULL, NULL };
458 * Forward declarations.
460 static Token *expand_mmac_params(Token * tline);
461 static Token *expand_smacro(Token * tline);
462 static Token *expand_id(Token * tline);
463 static Context *get_ctx(const char *name, const char **namep,
464 bool all_contexts);
465 static void make_tok_num(Token * tok, int64_t val);
466 static void error(int severity, const char *fmt, ...);
467 static void error_precond(int severity, const char *fmt, ...);
468 static void *new_Block(size_t size);
469 static void delete_Blocks(void);
470 static Token *new_Token(Token * next, enum pp_token_type type,
471 const char *text, int txtlen);
472 static Token *copy_Token(Token * tline);
473 static Token *delete_Token(Token * t);
474 static Line *new_Line(void);
475 static ExpDef *new_ExpDef(int exp_type);
476 static ExpInv *new_ExpInv(int exp_type, ExpDef *ed);
479 * Macros for safe checking of token pointers, avoid *(NULL)
481 #define tok_type_(x,t) ((x) && (x)->type == (t))
482 #define skip_white_(x) if (tok_type_((x), TOK_WHITESPACE)) (x)=(x)->next
483 #define tok_is_(x,v) (tok_type_((x), TOK_OTHER) && !strcmp((x)->text,(v)))
484 #define tok_isnt_(x,v) ((x) && ((x)->type!=TOK_OTHER || strcmp((x)->text,(v))))
487 * nasm_unquote with error if the string contains NUL characters.
488 * If the string contains NUL characters, issue an error and return
489 * the C len, i.e. truncate at the NUL.
491 static size_t nasm_unquote_cstr(char *qstr, enum preproc_token directive)
493 size_t len = nasm_unquote(qstr, NULL);
494 size_t clen = strlen(qstr);
496 if (len != clen)
497 error(ERR_NONFATAL, "NUL character in `%s' directive",
498 pp_directives[directive]);
500 return clen;
504 * In-place reverse a list of tokens.
506 static Token *reverse_tokens(Token *t)
508 Token *prev = NULL;
509 Token *next;
511 while (t) {
512 next = t->next;
513 t->next = prev;
514 prev = t;
515 t = next;
518 return prev;
522 * Handle TASM specific directives, which do not contain a % in
523 * front of them. We do it here because I could not find any other
524 * place to do it for the moment, and it is a hack (ideally it would
525 * be nice to be able to use the NASM pre-processor to do it).
527 static char *check_tasm_directive(char *line)
529 int32_t i, j, k, m, len;
530 char *p, *q, *oldline, oldchar;
532 p = nasm_skip_spaces(line);
534 /* Binary search for the directive name */
535 i = -1;
536 j = ARRAY_SIZE(tasm_directives);
537 q = nasm_skip_word(p);
538 len = q - p;
539 if (len) {
540 oldchar = p[len];
541 p[len] = 0;
542 while (j - i > 1) {
543 k = (j + i) / 2;
544 m = nasm_stricmp(p, tasm_directives[k]);
545 if (m == 0) {
546 /* We have found a directive, so jam a % in front of it
547 * so that NASM will then recognise it as one if it's own.
549 p[len] = oldchar;
550 len = strlen(p);
551 oldline = line;
552 line = nasm_malloc(len + 2);
553 line[0] = '%';
554 if (k == TM_IFDIFI) {
556 * NASM does not recognise IFDIFI, so we convert
557 * it to %if 0. This is not used in NASM
558 * compatible code, but does need to parse for the
559 * TASM macro package.
561 strcpy(line + 1, "if 0");
562 } else {
563 memcpy(line + 1, p, len + 1);
565 nasm_free(oldline);
566 return line;
567 } else if (m < 0) {
568 j = k;
569 } else
570 i = k;
572 p[len] = oldchar;
574 return line;
578 * The pre-preprocessing stage... This function translates line
579 * number indications as they emerge from GNU cpp (`# lineno "file"
580 * flags') into NASM preprocessor line number indications (`%line
581 * lineno file').
583 static char *prepreproc(char *line)
585 int lineno, fnlen;
586 char *fname, *oldline;
588 if (line[0] == '#' && line[1] == ' ') {
589 oldline = line;
590 fname = oldline + 2;
591 lineno = atoi(fname);
592 fname += strspn(fname, "0123456789 ");
593 if (*fname == '"')
594 fname++;
595 fnlen = strcspn(fname, "\"");
596 line = nasm_malloc(20 + fnlen);
597 snprintf(line, 20 + fnlen, "%%line %d %.*s", lineno, fnlen, fname);
598 nasm_free(oldline);
600 if (tasm_compatible_mode)
601 return check_tasm_directive(line);
602 return line;
606 * Free a linked list of tokens.
608 static void free_tlist(Token * list)
610 while (list)
611 list = delete_Token(list);
615 * Free a linked list of lines.
617 static void free_llist(Line * list)
619 Line *l, *tmp;
620 list_for_each_safe(l, tmp, list) {
621 free_tlist(l->first);
622 nasm_free(l);
627 * Free an ExpDef
629 static void free_expdef(ExpDef * ed)
631 nasm_free(ed->name);
632 free_tlist(ed->dlist);
633 nasm_free(ed->defaults);
634 free_llist(ed->line);
635 nasm_free(ed);
639 * Free an ExpInv
641 static void free_expinv(ExpInv * ei)
643 if (ei->name != NULL)
644 nasm_free(ei->name);
645 if (ei->label_text != NULL)
646 nasm_free(ei->label_text);
647 nasm_free(ei);
651 * Free all currently defined macros, and free the hash tables
653 static void free_smacro_table(struct hash_table *smt)
655 SMacro *s, *tmp;
656 const char *key;
657 struct hash_tbl_node *it = NULL;
659 while ((s = hash_iterate(smt, &it, &key)) != NULL) {
660 nasm_free((void *)key);
661 list_for_each_safe(s, tmp, s) {
662 nasm_free(s->name);
663 free_tlist(s->expansion);
664 nasm_free(s);
667 hash_free(smt);
670 static void free_expdef_table(struct hash_table *edt)
672 ExpDef *ed, *tmp;
673 const char *key;
674 struct hash_tbl_node *it = NULL;
676 it = NULL;
677 while ((ed = hash_iterate(edt, &it, &key)) != NULL) {
678 nasm_free((void *)key);
679 list_for_each_safe(ed ,tmp, ed)
680 free_expdef(ed);
682 hash_free(edt);
685 static void free_macros(void)
687 free_smacro_table(&smacros);
688 free_expdef_table(&expdefs);
692 * Initialize the hash tables
694 static void init_macros(void)
696 hash_init(&smacros, HASH_LARGE);
697 hash_init(&expdefs, HASH_LARGE);
701 * Pop the context stack.
703 static void ctx_pop(void)
705 Context *c = cstk;
707 cstk = cstk->next;
708 free_smacro_table(&c->localmac);
709 nasm_free(c->name);
710 nasm_free(c);
714 * Search for a key in the hash index; adding it if necessary
715 * (in which case we initialize the data pointer to NULL.)
717 static void **
718 hash_findi_add(struct hash_table *hash, const char *str)
720 struct hash_insert hi;
721 void **r;
722 char *strx;
724 r = hash_findi(hash, str, &hi);
725 if (r)
726 return r;
728 strx = nasm_strdup(str); /* Use a more efficient allocator here? */
729 return hash_add(&hi, strx, NULL);
733 * Like hash_findi, but returns the data element rather than a pointer
734 * to it. Used only when not adding a new element, hence no third
735 * argument.
737 static void *
738 hash_findix(struct hash_table *hash, const char *str)
740 void **p;
742 p = hash_findi(hash, str, NULL);
743 return p ? *p : NULL;
747 * read line from standard macros set,
748 * if there no more left -- return NULL
750 static char *line_from_stdmac(void)
752 unsigned char c;
753 const unsigned char *p = stdmacpos;
754 char *line, *q;
755 size_t len = 0;
757 if (!stdmacpos)
758 return NULL;
760 while ((c = *p++)) {
761 if (c >= 0x80)
762 len += pp_directives_len[c - 0x80] + 1;
763 else
764 len++;
767 line = nasm_malloc(len + 1);
768 q = line;
769 while ((c = *stdmacpos++)) {
770 if (c >= 0x80) {
771 memcpy(q, pp_directives[c - 0x80], pp_directives_len[c - 0x80]);
772 q += pp_directives_len[c - 0x80];
773 *q++ = ' ';
774 } else {
775 *q++ = c;
778 stdmacpos = p;
779 *q = '\0';
781 if (!*stdmacpos) {
782 /* This was the last of the standard macro chain... */
783 stdmacpos = NULL;
784 if (any_extrastdmac) {
785 stdmacpos = extrastdmac;
786 any_extrastdmac = false;
787 } else if (do_predef) {
788 ExpInv *ei;
789 Line *pd, *l;
790 Token *head, **tail, *t;
793 * Nasty hack: here we push the contents of
794 * `predef' on to the top-level expansion stack,
795 * since this is the most convenient way to
796 * implement the pre-include and pre-define
797 * features.
799 list_for_each(pd, predef) {
800 head = NULL;
801 tail = &head;
802 list_for_each(t, pd->first) {
803 *tail = new_Token(NULL, t->type, t->text, 0);
804 tail = &(*tail)->next;
807 l = new_Line();
808 l->first = head;
809 ei = new_ExpInv(EXP_PREDEF, NULL);
810 ei->current = l;
811 ei->emitting = true;
812 ei->prev = istk->expansion;
813 istk->expansion = ei;
815 do_predef = false;
819 return line;
822 #define BUF_DELTA 512
824 * Read a line from the top file in istk, handling multiple CR/LFs
825 * at the end of the line read, and handling spurious ^Zs. Will
826 * return lines from the standard macro set if this has not already
827 * been done.
829 static char *read_line(void)
831 char *buffer, *p, *q;
832 int bufsize, continued_count;
835 * standart macros set (predefined) goes first
837 p = line_from_stdmac();
838 if (p)
839 return p;
842 * regular read from a file
844 bufsize = BUF_DELTA;
845 buffer = nasm_malloc(BUF_DELTA);
846 p = buffer;
847 continued_count = 0;
848 while (1) {
849 q = fgets(p, bufsize - (p - buffer), istk->fp);
850 if (!q)
851 break;
852 p += strlen(p);
853 if (p > buffer && p[-1] == '\n') {
855 * Convert backslash-CRLF line continuation sequences into
856 * nothing at all (for DOS and Windows)
858 if (((p - 2) > buffer) && (p[-3] == '\\') && (p[-2] == '\r')) {
859 p -= 3;
860 *p = 0;
861 continued_count++;
864 * Also convert backslash-LF line continuation sequences into
865 * nothing at all (for Unix)
867 else if (((p - 1) > buffer) && (p[-2] == '\\')) {
868 p -= 2;
869 *p = 0;
870 continued_count++;
871 } else {
872 break;
875 if (p - buffer > bufsize - 10) {
876 int32_t offset = p - buffer;
877 bufsize += BUF_DELTA;
878 buffer = nasm_realloc(buffer, bufsize);
879 p = buffer + offset; /* prevent stale-pointer problems */
883 if (!q && p == buffer) {
884 nasm_free(buffer);
885 return NULL;
888 src_set_linnum(src_get_linnum() + istk->lineinc +
889 (continued_count * istk->lineinc));
892 * Play safe: remove CRs as well as LFs, if any of either are
893 * present at the end of the line.
895 while (--p >= buffer && (*p == '\n' || *p == '\r'))
896 *p = '\0';
899 * Handle spurious ^Z, which may be inserted into source files
900 * by some file transfer utilities.
902 buffer[strcspn(buffer, "\032")] = '\0';
904 list->line(LIST_READ, buffer);
906 return buffer;
910 * Tokenize a line of text. This is a very simple process since we
911 * don't need to parse the value out of e.g. numeric tokens: we
912 * simply split one string into many.
914 static Token *tokenize(char *line)
916 char c, *p = line;
917 enum pp_token_type type;
918 Token *list = NULL;
919 Token *t, **tail = &list;
921 while (*line) {
922 p = line;
923 if (*p == '%') {
924 p++;
925 if (*p == '+' && !nasm_isdigit(p[1])) {
926 p++;
927 type = TOK_PASTE;
928 } else if (nasm_isdigit(*p) ||
929 ((*p == '-' || *p == '+') && nasm_isdigit(p[1]))) {
930 do {
931 p++;
933 while (nasm_isdigit(*p));
934 type = TOK_PREPROC_ID;
935 } else if (*p == '{') {
936 p++;
937 while (*p && *p != '}') {
938 p[-1] = *p;
939 p++;
941 p[-1] = '\0';
942 if (*p)
943 p++;
944 type = TOK_PREPROC_ID;
945 } else if (*p == '[') {
946 int lvl = 1;
947 line += 2; /* Skip the leading %[ */
948 p++;
949 while (lvl && (c = *p++)) {
950 switch (c) {
951 case ']':
952 lvl--;
953 break;
954 case '%':
955 if (*p == '[')
956 lvl++;
957 break;
958 case '\'':
959 case '\"':
960 case '`':
961 p = nasm_skip_string(p - 1) + 1;
962 break;
963 default:
964 break;
967 p--;
968 if (*p)
969 *p++ = '\0';
970 if (lvl)
971 error(ERR_NONFATAL, "unterminated %[ construct");
972 type = TOK_INDIRECT;
973 } else if (*p == '?') {
974 type = TOK_PREPROC_Q; /* %? */
975 p++;
976 if (*p == '?') {
977 type = TOK_PREPROC_QQ; /* %?? */
978 p++;
980 } else if (*p == '!') {
981 type = TOK_PREPROC_ID;
982 p++;
983 if (isidchar(*p)) {
984 do {
985 p++;
986 } while (isidchar(*p));
987 } else if (*p == '\'' || *p == '\"' || *p == '`') {
988 p = nasm_skip_string(p);
989 if (*p)
990 p++;
991 else
992 error(ERR_NONFATAL|ERR_PASS1, "unterminated %! string");
993 } else {
994 /* %! without string or identifier */
995 type = TOK_OTHER; /* Legacy behavior... */
997 } else if (isidchar(*p) ||
998 ((*p == '!' || *p == '%' || *p == '$') &&
999 isidchar(p[1]))) {
1000 do {
1001 p++;
1003 while (isidchar(*p));
1004 type = TOK_PREPROC_ID;
1005 } else {
1006 type = TOK_OTHER;
1007 if (*p == '%')
1008 p++;
1010 } else if (isidstart(*p) || (*p == '$' && isidstart(p[1]))) {
1011 type = TOK_ID;
1012 p++;
1013 while (*p && isidchar(*p))
1014 p++;
1015 } else if (*p == '\'' || *p == '"' || *p == '`') {
1017 * A string token.
1019 type = TOK_STRING;
1020 p = nasm_skip_string(p);
1022 if (*p) {
1023 p++;
1024 } else {
1025 error(ERR_WARNING|ERR_PASS1, "unterminated string");
1026 /* Handling unterminated strings by UNV */
1027 /* type = -1; */
1029 } else if (p[0] == '$' && p[1] == '$') {
1030 type = TOK_OTHER; /* TOKEN_BASE */
1031 p += 2;
1032 } else if (isnumstart(*p)) {
1033 bool is_hex = false;
1034 bool is_float = false;
1035 bool has_e = false;
1036 char c, *r;
1039 * A numeric token.
1042 if (*p == '$') {
1043 p++;
1044 is_hex = true;
1047 for (;;) {
1048 c = *p++;
1050 if (!is_hex && (c == 'e' || c == 'E')) {
1051 has_e = true;
1052 if (*p == '+' || *p == '-') {
1054 * e can only be followed by +/- if it is either a
1055 * prefixed hex number or a floating-point number
1057 p++;
1058 is_float = true;
1060 } else if (c == 'H' || c == 'h' || c == 'X' || c == 'x') {
1061 is_hex = true;
1062 } else if (c == 'P' || c == 'p') {
1063 is_float = true;
1064 if (*p == '+' || *p == '-')
1065 p++;
1066 } else if (isnumchar(c) || c == '_')
1067 ; /* just advance */
1068 else if (c == '.') {
1070 * we need to deal with consequences of the legacy
1071 * parser, like "1.nolist" being two tokens
1072 * (TOK_NUMBER, TOK_ID) here; at least give it
1073 * a shot for now. In the future, we probably need
1074 * a flex-based scanner with proper pattern matching
1075 * to do it as well as it can be done. Nothing in
1076 * the world is going to help the person who wants
1077 * 0x123.p16 interpreted as two tokens, though.
1079 r = p;
1080 while (*r == '_')
1081 r++;
1083 if (nasm_isdigit(*r) || (is_hex && nasm_isxdigit(*r)) ||
1084 (!is_hex && (*r == 'e' || *r == 'E')) ||
1085 (*r == 'p' || *r == 'P')) {
1086 p = r;
1087 is_float = true;
1088 } else
1089 break; /* Terminate the token */
1090 } else
1091 break;
1093 p--; /* Point to first character beyond number */
1095 if (p == line+1 && *line == '$') {
1096 type = TOK_OTHER; /* TOKEN_HERE */
1097 } else {
1098 if (has_e && !is_hex) {
1099 /* 1e13 is floating-point, but 1e13h is not */
1100 is_float = true;
1103 type = is_float ? TOK_FLOAT : TOK_NUMBER;
1105 } else if (nasm_isspace(*p)) {
1106 type = TOK_WHITESPACE;
1107 p = nasm_skip_spaces(p);
1109 * Whitespace just before end-of-line is discarded by
1110 * pretending it's a comment; whitespace just before a
1111 * comment gets lumped into the comment.
1113 if (!*p || *p == ';') {
1114 type = TOK_COMMENT;
1115 while (*p)
1116 p++;
1118 } else if (*p == ';') {
1119 type = TOK_COMMENT;
1120 while (*p)
1121 p++;
1122 } else {
1124 * Anything else is an operator of some kind. We check
1125 * for all the double-character operators (>>, <<, //,
1126 * %%, <=, >=, ==, !=, <>, &&, ||, ^^), but anything
1127 * else is a single-character operator.
1129 type = TOK_OTHER;
1130 if ((p[0] == '>' && p[1] == '>') ||
1131 (p[0] == '<' && p[1] == '<') ||
1132 (p[0] == '/' && p[1] == '/') ||
1133 (p[0] == '<' && p[1] == '=') ||
1134 (p[0] == '>' && p[1] == '=') ||
1135 (p[0] == '=' && p[1] == '=') ||
1136 (p[0] == '!' && p[1] == '=') ||
1137 (p[0] == '<' && p[1] == '>') ||
1138 (p[0] == '&' && p[1] == '&') ||
1139 (p[0] == '|' && p[1] == '|') ||
1140 (p[0] == '^' && p[1] == '^')) {
1141 p++;
1143 p++;
1146 /* Handling unterminated string by UNV */
1147 /*if (type == -1)
1149 *tail = t = new_Token(NULL, TOK_STRING, line, p-line+1);
1150 t->text[p-line] = *line;
1151 tail = &t->next;
1153 else */
1154 if (type != TOK_COMMENT) {
1155 *tail = t = new_Token(NULL, type, line, p - line);
1156 tail = &t->next;
1158 line = p;
1160 return list;
1164 * this function allocates a new managed block of memory and
1165 * returns a pointer to the block. The managed blocks are
1166 * deleted only all at once by the delete_Blocks function.
1168 static void *new_Block(size_t size)
1170 Blocks *b = &blocks;
1172 /* first, get to the end of the linked list */
1173 while (b->next)
1174 b = b->next;
1175 /* now allocate the requested chunk */
1176 b->chunk = nasm_malloc(size);
1178 /* now allocate a new block for the next request */
1179 b->next = nasm_malloc(sizeof(Blocks));
1180 /* and initialize the contents of the new block */
1181 b->next->next = NULL;
1182 b->next->chunk = NULL;
1183 return b->chunk;
1187 * this function deletes all managed blocks of memory
1189 static void delete_Blocks(void)
1191 Blocks *a, *b = &blocks;
1194 * keep in mind that the first block, pointed to by blocks
1195 * is a static and not dynamically allocated, so we don't
1196 * free it.
1198 while (b) {
1199 if (b->chunk)
1200 nasm_free(b->chunk);
1201 a = b;
1202 b = b->next;
1203 if (a != &blocks)
1204 nasm_free(a);
1209 * this function creates a new Token and passes a pointer to it
1210 * back to the caller. It sets the type and text elements, and
1211 * also the a.mac and next elements to NULL.
1213 static Token *new_Token(Token * next, enum pp_token_type type,
1214 const char *text, int txtlen)
1216 Token *t;
1217 int i;
1219 if (!freeTokens) {
1220 freeTokens = (Token *) new_Block(TOKEN_BLOCKSIZE * sizeof(Token));
1221 for (i = 0; i < TOKEN_BLOCKSIZE - 1; i++)
1222 freeTokens[i].next = &freeTokens[i + 1];
1223 freeTokens[i].next = NULL;
1225 t = freeTokens;
1226 freeTokens = t->next;
1227 t->next = next;
1228 t->a.mac = NULL;
1229 t->type = type;
1230 if (type == TOK_WHITESPACE || !text) {
1231 t->text = NULL;
1232 } else {
1233 if (txtlen == 0)
1234 txtlen = strlen(text);
1235 t->text = nasm_malloc(txtlen+1);
1236 memcpy(t->text, text, txtlen);
1237 t->text[txtlen] = '\0';
1239 return t;
1242 static Token *copy_Token(Token * tline)
1244 Token *t, *tt, *first = NULL, *prev = NULL;
1245 int i;
1246 for (tt = tline; tt != NULL; tt = tt->next) {
1247 if (!freeTokens) {
1248 freeTokens = (Token *) new_Block(TOKEN_BLOCKSIZE * sizeof(Token));
1249 for (i = 0; i < TOKEN_BLOCKSIZE - 1; i++)
1250 freeTokens[i].next = &freeTokens[i + 1];
1251 freeTokens[i].next = NULL;
1253 t = freeTokens;
1254 freeTokens = t->next;
1255 t->next = NULL;
1256 t->text = tt->text ? nasm_strdup(tt->text) : NULL;
1257 t->a.mac = tt->a.mac;
1258 t->a.len = tt->a.len;
1259 t->type = tt->type;
1260 if (prev != NULL) {
1261 prev->next = t;
1262 } else {
1263 first = t;
1265 prev = t;
1267 return first;
1270 static Token *delete_Token(Token * t)
1272 Token *next = t->next;
1273 nasm_free(t->text);
1274 t->next = freeTokens;
1275 freeTokens = t;
1276 return next;
1280 * Convert a line of tokens back into text.
1281 * If expand_locals is not zero, identifiers of the form "%$*xxx"
1282 * will be transformed into ..@ctxnum.xxx
1284 static char *detoken(Token * tlist, bool expand_locals)
1286 Token *t;
1287 char *line, *p;
1288 const char *q;
1289 int len = 0;
1291 list_for_each(t, tlist) {
1292 if (t->type == TOK_PREPROC_ID && t->text[1] == '!') {
1293 char *v;
1294 char *q = t->text;
1296 v = t->text + 2;
1297 if (*v == '\'' || *v == '\"' || *v == '`') {
1298 size_t len = nasm_unquote(v, NULL);
1299 size_t clen = strlen(v);
1301 if (len != clen) {
1302 error(ERR_NONFATAL | ERR_PASS1,
1303 "NUL character in %! string");
1304 v = NULL;
1308 if (v) {
1309 char *p = getenv(v);
1310 if (!p) {
1311 error(ERR_NONFATAL | ERR_PASS1,
1312 "nonexistent environment variable `%s'", v);
1313 p = "";
1315 t->text = nasm_strdup(p);
1317 nasm_free(q);
1320 /* Expand local macros here and not during preprocessing */
1321 if (expand_locals &&
1322 t->type == TOK_PREPROC_ID && t->text &&
1323 t->text[0] == '%' && t->text[1] == '$') {
1324 const char *q;
1325 char *p;
1326 Context *ctx = get_ctx(t->text, &q, false);
1327 if (ctx) {
1328 char buffer[40];
1329 snprintf(buffer, sizeof(buffer), "..@%"PRIu32".", ctx->number);
1330 p = nasm_strcat(buffer, q);
1331 nasm_free(t->text);
1332 t->text = p;
1336 /* Expand %? and %?? directives */
1337 if (expand_locals && (istk->expansion != NULL) &&
1338 ((t->type == TOK_PREPROC_Q) ||
1339 (t->type == TOK_PREPROC_QQ))) {
1340 ExpInv *ei;
1341 for (ei = istk->expansion; ei != NULL; ei = ei->prev){
1342 if (ei->type == EXP_MMACRO) {
1343 nasm_free(t->text);
1344 if (t->type == TOK_PREPROC_Q) {
1345 t->text = nasm_strdup(ei->name);
1346 } else {
1347 t->text = nasm_strdup(ei->def->name);
1349 break;
1354 if (t->type == TOK_WHITESPACE)
1355 len++;
1356 else if (t->text)
1357 len += strlen(t->text);
1360 p = line = nasm_malloc(len + 1);
1362 list_for_each(t, tlist) {
1363 if (t->type == TOK_WHITESPACE) {
1364 *p++ = ' ';
1365 } else if (t->text) {
1366 q = t->text;
1367 while (*q)
1368 *p++ = *q++;
1371 *p = '\0';
1373 return line;
1377 * Initialize a new Line
1379 static inline Line *new_Line(void)
1381 return (Line *)nasm_zalloc(sizeof(Line));
1386 * Initialize a new Expansion Definition
1388 static ExpDef *new_ExpDef(int exp_type)
1390 ExpDef *ed = (ExpDef*)nasm_zalloc(sizeof(ExpDef));
1391 ed->type = exp_type;
1392 ed->casesense = true;
1393 ed->state = COND_NEVER;
1395 return ed;
1400 * Initialize a new Expansion Instance
1402 static ExpInv *new_ExpInv(int exp_type, ExpDef *ed)
1404 ExpInv *ei = (ExpInv*)nasm_zalloc(sizeof(ExpInv));
1405 ei->type = exp_type;
1406 ei->def = ed;
1407 ei->unique = ++unique;
1409 if ((istk->mmac_depth < 1) &&
1410 (istk->expansion == NULL) &&
1411 (ed != NULL) &&
1412 (ed->type != EXP_MMACRO) &&
1413 (ed->type != EXP_REP) &&
1414 (ed->type != EXP_WHILE)) {
1415 ei->linnum = src_get_linnum();
1416 src_set_linnum(ei->linnum - ed->linecount - 1);
1417 } else {
1418 ei->linnum = -1;
1420 if ((istk->expansion == NULL) ||
1421 (ei->type == EXP_MMACRO)) {
1422 ei->relno = 0;
1423 } else {
1424 ei->relno = istk->expansion->lineno;
1425 if (ed != NULL) {
1426 ei->relno -= (ed->linecount + 1);
1429 return ei;
1433 * A scanner, suitable for use by the expression evaluator, which
1434 * operates on a line of Tokens. Expects a pointer to a pointer to
1435 * the first token in the line to be passed in as its private_data
1436 * field.
1438 * FIX: This really needs to be unified with stdscan.
1440 static int ppscan(void *private_data, struct tokenval *tokval)
1442 Token **tlineptr = private_data;
1443 Token *tline;
1444 char ourcopy[MAX_KEYWORD+1], *p, *r, *s;
1446 do {
1447 tline = *tlineptr;
1448 *tlineptr = tline ? tline->next : NULL;
1449 } while (tline && (tline->type == TOK_WHITESPACE ||
1450 tline->type == TOK_COMMENT));
1452 if (!tline)
1453 return tokval->t_type = TOKEN_EOS;
1455 tokval->t_charptr = tline->text;
1457 if (tline->text[0] == '$' && !tline->text[1])
1458 return tokval->t_type = TOKEN_HERE;
1459 if (tline->text[0] == '$' && tline->text[1] == '$' && !tline->text[2])
1460 return tokval->t_type = TOKEN_BASE;
1462 if (tline->type == TOK_ID) {
1463 p = tokval->t_charptr = tline->text;
1464 if (p[0] == '$') {
1465 tokval->t_charptr++;
1466 return tokval->t_type = TOKEN_ID;
1469 for (r = p, s = ourcopy; *r; r++) {
1470 if (r >= p+MAX_KEYWORD)
1471 return tokval->t_type = TOKEN_ID; /* Not a keyword */
1472 *s++ = nasm_tolower(*r);
1474 *s = '\0';
1475 /* right, so we have an identifier sitting in temp storage. now,
1476 * is it actually a register or instruction name, or what? */
1477 return nasm_token_hash(ourcopy, tokval);
1480 if (tline->type == TOK_NUMBER) {
1481 bool rn_error;
1482 tokval->t_integer = readnum(tline->text, &rn_error);
1483 tokval->t_charptr = tline->text;
1484 if (rn_error)
1485 return tokval->t_type = TOKEN_ERRNUM;
1486 else
1487 return tokval->t_type = TOKEN_NUM;
1490 if (tline->type == TOK_FLOAT) {
1491 return tokval->t_type = TOKEN_FLOAT;
1494 if (tline->type == TOK_STRING) {
1495 char bq, *ep;
1497 bq = tline->text[0];
1498 tokval->t_charptr = tline->text;
1499 tokval->t_inttwo = nasm_unquote(tline->text, &ep);
1501 if (ep[0] != bq || ep[1] != '\0')
1502 return tokval->t_type = TOKEN_ERRSTR;
1503 else
1504 return tokval->t_type = TOKEN_STR;
1507 if (tline->type == TOK_OTHER) {
1508 if (!strcmp(tline->text, "<<"))
1509 return tokval->t_type = TOKEN_SHL;
1510 if (!strcmp(tline->text, ">>"))
1511 return tokval->t_type = TOKEN_SHR;
1512 if (!strcmp(tline->text, "//"))
1513 return tokval->t_type = TOKEN_SDIV;
1514 if (!strcmp(tline->text, "%%"))
1515 return tokval->t_type = TOKEN_SMOD;
1516 if (!strcmp(tline->text, "=="))
1517 return tokval->t_type = TOKEN_EQ;
1518 if (!strcmp(tline->text, "<>"))
1519 return tokval->t_type = TOKEN_NE;
1520 if (!strcmp(tline->text, "!="))
1521 return tokval->t_type = TOKEN_NE;
1522 if (!strcmp(tline->text, "<="))
1523 return tokval->t_type = TOKEN_LE;
1524 if (!strcmp(tline->text, ">="))
1525 return tokval->t_type = TOKEN_GE;
1526 if (!strcmp(tline->text, "&&"))
1527 return tokval->t_type = TOKEN_DBL_AND;
1528 if (!strcmp(tline->text, "^^"))
1529 return tokval->t_type = TOKEN_DBL_XOR;
1530 if (!strcmp(tline->text, "||"))
1531 return tokval->t_type = TOKEN_DBL_OR;
1535 * We have no other options: just return the first character of
1536 * the token text.
1538 return tokval->t_type = tline->text[0];
1542 * Compare a string to the name of an existing macro; this is a
1543 * simple wrapper which calls either strcmp or nasm_stricmp
1544 * depending on the value of the `casesense' parameter.
1546 static int mstrcmp(const char *p, const char *q, bool casesense)
1548 return casesense ? strcmp(p, q) : nasm_stricmp(p, q);
1552 * Compare a string to the name of an existing macro; this is a
1553 * simple wrapper which calls either strcmp or nasm_stricmp
1554 * depending on the value of the `casesense' parameter.
1556 static int mmemcmp(const char *p, const char *q, size_t l, bool casesense)
1558 return casesense ? memcmp(p, q, l) : nasm_memicmp(p, q, l);
1562 * Return the Context structure associated with a %$ token. Return
1563 * NULL, having _already_ reported an error condition, if the
1564 * context stack isn't deep enough for the supplied number of $
1565 * signs.
1566 * If all_contexts == true, contexts that enclose current are
1567 * also scanned for such smacro, until it is found; if not -
1568 * only the context that directly results from the number of $'s
1569 * in variable's name.
1571 * If "namep" is non-NULL, set it to the pointer to the macro name
1572 * tail, i.e. the part beyond %$...
1574 static Context *get_ctx(const char *name, const char **namep,
1575 bool all_contexts)
1577 Context *ctx;
1578 SMacro *m;
1579 int i;
1581 if (namep)
1582 *namep = name;
1584 if (!name || name[0] != '%' || name[1] != '$')
1585 return NULL;
1587 if (!cstk) {
1588 error(ERR_NONFATAL, "`%s': context stack is empty", name);
1589 return NULL;
1592 name += 2;
1593 ctx = cstk;
1594 i = 0;
1595 while (ctx && *name == '$') {
1596 name++;
1597 i++;
1598 ctx = ctx->next;
1600 if (!ctx) {
1601 error(ERR_NONFATAL, "`%s': context stack is only"
1602 " %d level%s deep", name, i, (i == 1 ? "" : "s"));
1603 return NULL;
1606 if (namep)
1607 *namep = name;
1609 if (!all_contexts)
1610 return ctx;
1612 do {
1613 /* Search for this smacro in found context */
1614 m = hash_findix(&ctx->localmac, name);
1615 while (m) {
1616 if (!mstrcmp(m->name, name, m->casesense))
1617 return ctx;
1618 m = m->next;
1620 ctx = ctx->next;
1622 while (ctx);
1623 return NULL;
1627 * Check to see if a file is already in a string list
1629 static bool in_list(const StrList *list, const char *str)
1631 while (list) {
1632 if (!strcmp(list->str, str))
1633 return true;
1634 list = list->next;
1636 return false;
1640 * Open an include file. This routine must always return a valid
1641 * file pointer if it returns - it's responsible for throwing an
1642 * ERR_FATAL and bombing out completely if not. It should also try
1643 * the include path one by one until it finds the file or reaches
1644 * the end of the path.
1646 static FILE *inc_fopen(const char *file, StrList **dhead, StrList ***dtail,
1647 bool missing_ok)
1649 FILE *fp;
1650 char *prefix = "";
1651 IncPath *ip = ipath;
1652 int len = strlen(file);
1653 size_t prefix_len = 0;
1654 StrList *sl;
1656 while (1) {
1657 sl = nasm_malloc(prefix_len+len+1+sizeof sl->next);
1658 sl->next = NULL;
1659 memcpy(sl->str, prefix, prefix_len);
1660 memcpy(sl->str+prefix_len, file, len+1);
1661 fp = fopen(sl->str, "r");
1662 if (fp && dhead && !in_list(*dhead, sl->str)) {
1663 **dtail = sl;
1664 *dtail = &sl->next;
1665 } else {
1666 nasm_free(sl);
1668 if (fp)
1669 return fp;
1670 if (!ip) {
1671 if (!missing_ok)
1672 break;
1673 prefix = NULL;
1674 } else {
1675 prefix = ip->path;
1676 ip = ip->next;
1678 if (prefix) {
1679 prefix_len = strlen(prefix);
1680 } else {
1681 /* -MG given and file not found */
1682 if (dhead && !in_list(*dhead, file)) {
1683 sl = nasm_malloc(len+1+sizeof sl->next);
1684 sl->next = NULL;
1685 strcpy(sl->str, file);
1686 **dtail = sl;
1687 *dtail = &sl->next;
1689 return NULL;
1693 error(ERR_FATAL, "unable to open include file `%s'", file);
1694 return NULL;
1698 * Determine if we should warn on defining a single-line macro of
1699 * name `name', with `nparam' parameters. If nparam is 0 or -1, will
1700 * return true if _any_ single-line macro of that name is defined.
1701 * Otherwise, will return true if a single-line macro with either
1702 * `nparam' or no parameters is defined.
1704 * If a macro with precisely the right number of parameters is
1705 * defined, or nparam is -1, the address of the definition structure
1706 * will be returned in `defn'; otherwise NULL will be returned. If `defn'
1707 * is NULL, no action will be taken regarding its contents, and no
1708 * error will occur.
1710 * Note that this is also called with nparam zero to resolve
1711 * `ifdef'.
1713 * If you already know which context macro belongs to, you can pass
1714 * the context pointer as first parameter; if you won't but name begins
1715 * with %$ the context will be automatically computed. If all_contexts
1716 * is true, macro will be searched in outer contexts as well.
1718 static bool
1719 smacro_defined(Context * ctx, const char *name, int nparam, SMacro ** defn,
1720 bool nocase)
1722 struct hash_table *smtbl;
1723 SMacro *m;
1725 if (ctx) {
1726 smtbl = &ctx->localmac;
1727 } else if (name[0] == '%' && name[1] == '$') {
1728 if (cstk)
1729 ctx = get_ctx(name, &name, false);
1730 if (!ctx)
1731 return false; /* got to return _something_ */
1732 smtbl = &ctx->localmac;
1733 } else {
1734 smtbl = &smacros;
1736 m = (SMacro *) hash_findix(smtbl, name);
1738 while (m) {
1739 if (!mstrcmp(m->name, name, m->casesense && nocase) &&
1740 (nparam <= 0 || m->nparam == 0 || nparam == (int) m->nparam)) {
1741 if (defn) {
1742 if (nparam == (int) m->nparam || nparam == -1)
1743 *defn = m;
1744 else
1745 *defn = NULL;
1747 return true;
1749 m = m->next;
1752 return false;
1756 * Count and mark off the parameters in a multi-line macro call.
1757 * This is called both from within the multi-line macro expansion
1758 * code, and also to mark off the default parameters when provided
1759 * in a %macro definition line.
1761 static void count_mmac_params(Token * t, int *nparam, Token *** params)
1763 int paramsize, brace;
1765 *nparam = paramsize = 0;
1766 *params = NULL;
1767 while (t) {
1768 /* +1: we need space for the final NULL */
1769 if (*nparam+1 >= paramsize) {
1770 paramsize += PARAM_DELTA;
1771 *params = nasm_realloc(*params, sizeof(**params) * paramsize);
1773 skip_white_(t);
1774 brace = false;
1775 if (tok_is_(t, "{"))
1776 brace = true;
1777 (*params)[(*nparam)++] = t;
1778 while (tok_isnt_(t, brace ? "}" : ","))
1779 t = t->next;
1780 if (t) { /* got a comma/brace */
1781 t = t->next;
1782 if (brace) {
1784 * Now we've found the closing brace, look further
1785 * for the comma.
1787 skip_white_(t);
1788 if (tok_isnt_(t, ",")) {
1789 error(ERR_NONFATAL,
1790 "braces do not enclose all of macro parameter");
1791 while (tok_isnt_(t, ","))
1792 t = t->next;
1794 if (t)
1795 t = t->next; /* eat the comma */
1802 * Determine whether one of the various `if' conditions is true or
1803 * not.
1805 * We must free the tline we get passed.
1807 static bool if_condition(Token * tline, enum preproc_token ct)
1809 enum pp_conditional i = PP_COND(ct);
1810 bool j;
1811 Token *t, *tt, **tptr, *origline;
1812 struct tokenval tokval;
1813 expr *evalresult;
1814 enum pp_token_type needtype;
1815 char *p;
1817 origline = tline;
1819 switch (i) {
1820 case PPC_IFCTX:
1821 j = false; /* have we matched yet? */
1822 while (true) {
1823 skip_white_(tline);
1824 if (!tline)
1825 break;
1826 if (tline->type != TOK_ID) {
1827 error(ERR_NONFATAL,
1828 "`%s' expects context identifiers", pp_directives[ct]);
1829 free_tlist(origline);
1830 return -1;
1832 if (cstk && cstk->name && !nasm_stricmp(tline->text, cstk->name))
1833 j = true;
1834 tline = tline->next;
1836 break;
1838 case PPC_IFDEF:
1839 j = false; /* have we matched yet? */
1840 while (tline) {
1841 skip_white_(tline);
1842 if (!tline || (tline->type != TOK_ID &&
1843 (tline->type != TOK_PREPROC_ID ||
1844 tline->text[1] != '$'))) {
1845 error(ERR_NONFATAL,
1846 "`%s' expects macro identifiers", pp_directives[ct]);
1847 goto fail;
1849 if (smacro_defined(NULL, tline->text, 0, NULL, true))
1850 j = true;
1851 tline = tline->next;
1853 break;
1855 case PPC_IFENV:
1856 tline = expand_smacro(tline);
1857 j = false; /* have we matched yet? */
1858 while (tline) {
1859 skip_white_(tline);
1860 if (!tline || (tline->type != TOK_ID &&
1861 tline->type != TOK_STRING &&
1862 (tline->type != TOK_PREPROC_ID ||
1863 tline->text[1] != '!'))) {
1864 error(ERR_NONFATAL,
1865 "`%s' expects environment variable names",
1866 pp_directives[ct]);
1867 goto fail;
1869 p = tline->text;
1870 if (tline->type == TOK_PREPROC_ID)
1871 p += 2; /* Skip leading %! */
1872 if (*p == '\'' || *p == '\"' || *p == '`')
1873 nasm_unquote_cstr(p, ct);
1874 if (getenv(p))
1875 j = true;
1876 tline = tline->next;
1878 break;
1880 case PPC_IFIDN:
1881 case PPC_IFIDNI:
1882 tline = expand_smacro(tline);
1883 t = tt = tline;
1884 while (tok_isnt_(tt, ","))
1885 tt = tt->next;
1886 if (!tt) {
1887 error(ERR_NONFATAL,
1888 "`%s' expects two comma-separated arguments",
1889 pp_directives[ct]);
1890 goto fail;
1892 tt = tt->next;
1893 j = true; /* assume equality unless proved not */
1894 while ((t->type != TOK_OTHER || strcmp(t->text, ",")) && tt) {
1895 if (tt->type == TOK_OTHER && !strcmp(tt->text, ",")) {
1896 error(ERR_NONFATAL, "`%s': more than one comma on line",
1897 pp_directives[ct]);
1898 goto fail;
1900 if (t->type == TOK_WHITESPACE) {
1901 t = t->next;
1902 continue;
1904 if (tt->type == TOK_WHITESPACE) {
1905 tt = tt->next;
1906 continue;
1908 if (tt->type != t->type) {
1909 j = false; /* found mismatching tokens */
1910 break;
1912 /* When comparing strings, need to unquote them first */
1913 if (t->type == TOK_STRING) {
1914 size_t l1 = nasm_unquote(t->text, NULL);
1915 size_t l2 = nasm_unquote(tt->text, NULL);
1917 if (l1 != l2) {
1918 j = false;
1919 break;
1921 if (mmemcmp(t->text, tt->text, l1, i == PPC_IFIDN)) {
1922 j = false;
1923 break;
1925 } else if (mstrcmp(tt->text, t->text, i == PPC_IFIDN) != 0) {
1926 j = false; /* found mismatching tokens */
1927 break;
1930 t = t->next;
1931 tt = tt->next;
1933 if ((t->type != TOK_OTHER || strcmp(t->text, ",")) || tt)
1934 j = false; /* trailing gunk on one end or other */
1935 break;
1937 case PPC_IFMACRO:
1939 bool found = false;
1940 ExpDef searching, *ed;
1942 skip_white_(tline);
1943 tline = expand_id(tline);
1944 if (!tok_type_(tline, TOK_ID)) {
1945 error(ERR_NONFATAL,
1946 "`%s' expects a macro name", pp_directives[ct]);
1947 goto fail;
1949 memset(&searching, 0, sizeof(searching));
1950 searching.name = nasm_strdup(tline->text);
1951 searching.casesense = true;
1952 searching.nparam_max = INT_MAX;
1953 tline = expand_smacro(tline->next);
1954 skip_white_(tline);
1955 if (!tline) {
1956 } else if (!tok_type_(tline, TOK_NUMBER)) {
1957 error(ERR_NONFATAL,
1958 "`%s' expects a parameter count or nothing",
1959 pp_directives[ct]);
1960 } else {
1961 searching.nparam_min = searching.nparam_max =
1962 readnum(tline->text, &j);
1963 if (j)
1964 error(ERR_NONFATAL,
1965 "unable to parse parameter count `%s'",
1966 tline->text);
1968 if (tline && tok_is_(tline->next, "-")) {
1969 tline = tline->next->next;
1970 if (tok_is_(tline, "*"))
1971 searching.nparam_max = INT_MAX;
1972 else if (!tok_type_(tline, TOK_NUMBER))
1973 error(ERR_NONFATAL,
1974 "`%s' expects a parameter count after `-'",
1975 pp_directives[ct]);
1976 else {
1977 searching.nparam_max = readnum(tline->text, &j);
1978 if (j)
1979 error(ERR_NONFATAL,
1980 "unable to parse parameter count `%s'",
1981 tline->text);
1982 if (searching.nparam_min > searching.nparam_max)
1983 error(ERR_NONFATAL,
1984 "minimum parameter count exceeds maximum");
1987 if (tline && tok_is_(tline->next, "+")) {
1988 tline = tline->next;
1989 searching.plus = true;
1991 ed = (ExpDef *) hash_findix(&expdefs, searching.name);
1992 while (ed != NULL) {
1993 if (!strcmp(ed->name, searching.name) &&
1994 (ed->nparam_min <= searching.nparam_max || searching.plus) &&
1995 (searching.nparam_min <= ed->nparam_max || ed->plus)) {
1996 found = true;
1997 break;
1999 ed = ed->next;
2001 if (tline && tline->next)
2002 error(ERR_WARNING|ERR_PASS1,
2003 "trailing garbage after %%ifmacro ignored");
2004 nasm_free(searching.name);
2005 j = found;
2006 break;
2009 case PPC_IFID:
2010 needtype = TOK_ID;
2011 goto iftype;
2012 case PPC_IFNUM:
2013 needtype = TOK_NUMBER;
2014 goto iftype;
2015 case PPC_IFSTR:
2016 needtype = TOK_STRING;
2017 goto iftype;
2019 iftype:
2020 t = tline = expand_smacro(tline);
2022 while (tok_type_(t, TOK_WHITESPACE) ||
2023 (needtype == TOK_NUMBER &&
2024 tok_type_(t, TOK_OTHER) &&
2025 (t->text[0] == '-' || t->text[0] == '+') &&
2026 !t->text[1]))
2027 t = t->next;
2029 j = tok_type_(t, needtype);
2030 break;
2032 case PPC_IFTOKEN:
2033 t = tline = expand_smacro(tline);
2034 while (tok_type_(t, TOK_WHITESPACE))
2035 t = t->next;
2037 j = false;
2038 if (t) {
2039 t = t->next; /* Skip the actual token */
2040 while (tok_type_(t, TOK_WHITESPACE))
2041 t = t->next;
2042 j = !t; /* Should be nothing left */
2044 break;
2046 case PPC_IFEMPTY:
2047 t = tline = expand_smacro(tline);
2048 while (tok_type_(t, TOK_WHITESPACE))
2049 t = t->next;
2051 j = !t; /* Should be empty */
2052 break;
2054 case PPC_IF:
2055 t = tline = expand_smacro(tline);
2056 tptr = &t;
2057 tokval.t_type = TOKEN_INVALID;
2058 evalresult = evaluate(ppscan, tptr, &tokval,
2059 NULL, pass | CRITICAL, error, NULL);
2060 if (!evalresult)
2061 return -1;
2062 if (tokval.t_type)
2063 error(ERR_WARNING|ERR_PASS1,
2064 "trailing garbage after expression ignored");
2065 if (!is_simple(evalresult)) {
2066 error(ERR_NONFATAL,
2067 "non-constant value given to `%s'", pp_directives[ct]);
2068 goto fail;
2070 j = reloc_value(evalresult) != 0;
2071 break;
2073 default:
2074 error(ERR_FATAL,
2075 "preprocessor directive `%s' not yet implemented",
2076 pp_directives[ct]);
2077 goto fail;
2080 free_tlist(origline);
2081 return j ^ PP_NEGATIVE(ct);
2083 fail:
2084 free_tlist(origline);
2085 return -1;
2089 * Common code for defining an smacro
2091 static bool define_smacro(Context *ctx, const char *mname, bool casesense,
2092 int nparam, Token *expansion)
2094 SMacro *smac, **smhead;
2095 struct hash_table *smtbl;
2097 if (smacro_defined(ctx, mname, nparam, &smac, casesense)) {
2098 if (!smac) {
2099 error(ERR_WARNING|ERR_PASS1,
2100 "single-line macro `%s' defined both with and"
2101 " without parameters", mname);
2103 * Some instances of the old code considered this a failure,
2104 * some others didn't. What is the right thing to do here?
2106 free_tlist(expansion);
2107 return false; /* Failure */
2108 } else {
2110 * We're redefining, so we have to take over an
2111 * existing SMacro structure. This means freeing
2112 * what was already in it.
2114 nasm_free(smac->name);
2115 free_tlist(smac->expansion);
2117 } else {
2118 smtbl = ctx ? &ctx->localmac : &smacros;
2119 smhead = (SMacro **) hash_findi_add(smtbl, mname);
2120 smac = nasm_malloc(sizeof(SMacro));
2121 smac->next = *smhead;
2122 *smhead = smac;
2124 smac->name = nasm_strdup(mname);
2125 smac->casesense = casesense;
2126 smac->nparam = nparam;
2127 smac->expansion = expansion;
2128 smac->in_progress = false;
2129 return true; /* Success */
2133 * Undefine an smacro
2135 static void undef_smacro(Context *ctx, const char *mname)
2137 SMacro **smhead, *s, **sp;
2138 struct hash_table *smtbl;
2140 smtbl = ctx ? &ctx->localmac : &smacros;
2141 smhead = (SMacro **)hash_findi(smtbl, mname, NULL);
2143 if (smhead) {
2145 * We now have a macro name... go hunt for it.
2147 sp = smhead;
2148 while ((s = *sp) != NULL) {
2149 if (!mstrcmp(s->name, mname, s->casesense)) {
2150 *sp = s->next;
2151 nasm_free(s->name);
2152 free_tlist(s->expansion);
2153 nasm_free(s);
2154 } else {
2155 sp = &s->next;
2162 * Parse a mmacro specification.
2164 static bool parse_mmacro_spec(Token *tline, ExpDef *def, const char *directive)
2166 bool err;
2168 tline = tline->next;
2169 skip_white_(tline);
2170 tline = expand_id(tline);
2171 if (!tok_type_(tline, TOK_ID)) {
2172 error(ERR_NONFATAL, "`%s' expects a macro name", directive);
2173 return false;
2176 def->name = nasm_strdup(tline->text);
2177 def->plus = false;
2178 def->nolist = false;
2179 // def->in_progress = 0;
2180 // def->rep_nest = NULL;
2181 def->nparam_min = 0;
2182 def->nparam_max = 0;
2184 tline = expand_smacro(tline->next);
2185 skip_white_(tline);
2186 if (!tok_type_(tline, TOK_NUMBER)) {
2187 error(ERR_NONFATAL, "`%s' expects a parameter count", directive);
2188 } else {
2189 def->nparam_min = def->nparam_max =
2190 readnum(tline->text, &err);
2191 if (err)
2192 error(ERR_NONFATAL,
2193 "unable to parse parameter count `%s'", tline->text);
2195 if (tline && tok_is_(tline->next, "-")) {
2196 tline = tline->next->next;
2197 if (tok_is_(tline, "*")) {
2198 def->nparam_max = INT_MAX;
2199 } else if (!tok_type_(tline, TOK_NUMBER)) {
2200 error(ERR_NONFATAL,
2201 "`%s' expects a parameter count after `-'", directive);
2202 } else {
2203 def->nparam_max = readnum(tline->text, &err);
2204 if (err) {
2205 error(ERR_NONFATAL, "unable to parse parameter count `%s'",
2206 tline->text);
2208 if (def->nparam_min > def->nparam_max) {
2209 error(ERR_NONFATAL, "minimum parameter count exceeds maximum");
2213 if (tline && tok_is_(tline->next, "+")) {
2214 tline = tline->next;
2215 def->plus = true;
2217 if (tline && tok_type_(tline->next, TOK_ID) &&
2218 !nasm_stricmp(tline->next->text, ".nolist")) {
2219 tline = tline->next;
2220 def->nolist = true;
2224 * Handle default parameters.
2226 if (tline && tline->next) {
2227 def->dlist = tline->next;
2228 tline->next = NULL;
2229 count_mmac_params(def->dlist, &def->ndefs, &def->defaults);
2230 } else {
2231 def->dlist = NULL;
2232 def->defaults = NULL;
2234 def->line = NULL;
2236 if (def->defaults && def->ndefs > def->nparam_max - def->nparam_min &&
2237 !def->plus)
2238 error(ERR_WARNING|ERR_PASS1|ERR_WARN_MDP,
2239 "too many default macro parameters");
2241 return true;
2246 * Decode a size directive
2248 static int parse_size(const char *str) {
2249 static const char *size_names[] =
2250 { "byte", "dword", "oword", "qword", "tword", "word", "yword" };
2251 static const int sizes[] =
2252 { 0, 1, 4, 16, 8, 10, 2, 32 };
2254 return sizes[bsii(str, size_names, ARRAY_SIZE(size_names))+1];
2258 * find and process preprocessor directive in passed line
2259 * Find out if a line contains a preprocessor directive, and deal
2260 * with it if so.
2262 * If a directive _is_ found, it is the responsibility of this routine
2263 * (and not the caller) to free_tlist() the line.
2265 * @param tline a pointer to the current tokeninzed line linked list
2266 * @return DIRECTIVE_FOUND or NO_DIRECTIVE_FOUND
2269 static int do_directive(Token * tline)
2271 enum preproc_token i;
2272 int j;
2273 bool err;
2274 int nparam;
2275 bool nolist;
2276 bool casesense;
2277 int k, m;
2278 int offset;
2279 char *p, *pp;
2280 const char *mname;
2281 Include *inc;
2282 Context *ctx;
2283 Line *l;
2284 Token *t, *tt, *param_start, *macro_start, *last, **tptr, *origline;
2285 struct tokenval tokval;
2286 expr *evalresult;
2287 ExpDef *ed, *eed, **edhead;
2288 ExpInv *ei, *eei;
2289 int64_t count;
2290 size_t len;
2291 int severity;
2293 origline = tline;
2295 skip_white_(tline);
2296 if (!tline || !tok_type_(tline, TOK_PREPROC_ID) ||
2297 (tline->text[1] == '%' || tline->text[1] == '$'
2298 || tline->text[1] == '!'))
2299 return NO_DIRECTIVE_FOUND;
2301 i = pp_token_hash(tline->text);
2303 switch (i) {
2304 case PP_INVALID:
2305 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2306 error(ERR_NONFATAL, "unknown preprocessor directive `%s'",
2307 tline->text);
2308 return NO_DIRECTIVE_FOUND; /* didn't get it */
2310 case PP_STACKSIZE:
2311 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2312 /* Directive to tell NASM what the default stack size is. The
2313 * default is for a 16-bit stack, and this can be overriden with
2314 * %stacksize large.
2316 tline = tline->next;
2317 if (tline && tline->type == TOK_WHITESPACE)
2318 tline = tline->next;
2319 if (!tline || tline->type != TOK_ID) {
2320 error(ERR_NONFATAL, "`%%stacksize' missing size parameter");
2321 free_tlist(origline);
2322 return DIRECTIVE_FOUND;
2324 if (nasm_stricmp(tline->text, "flat") == 0) {
2325 /* All subsequent ARG directives are for a 32-bit stack */
2326 StackSize = 4;
2327 StackPointer = "ebp";
2328 ArgOffset = 8;
2329 LocalOffset = 0;
2330 } else if (nasm_stricmp(tline->text, "flat64") == 0) {
2331 /* All subsequent ARG directives are for a 64-bit stack */
2332 StackSize = 8;
2333 StackPointer = "rbp";
2334 ArgOffset = 16;
2335 LocalOffset = 0;
2336 } else if (nasm_stricmp(tline->text, "large") == 0) {
2337 /* All subsequent ARG directives are for a 16-bit stack,
2338 * far function call.
2340 StackSize = 2;
2341 StackPointer = "bp";
2342 ArgOffset = 4;
2343 LocalOffset = 0;
2344 } else if (nasm_stricmp(tline->text, "small") == 0) {
2345 /* All subsequent ARG directives are for a 16-bit stack,
2346 * far function call. We don't support near functions.
2348 StackSize = 2;
2349 StackPointer = "bp";
2350 ArgOffset = 6;
2351 LocalOffset = 0;
2352 } else {
2353 error(ERR_NONFATAL, "`%%stacksize' invalid size type");
2354 free_tlist(origline);
2355 return DIRECTIVE_FOUND;
2357 free_tlist(origline);
2358 return DIRECTIVE_FOUND;
2360 case PP_ARG:
2361 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2362 /* TASM like ARG directive to define arguments to functions, in
2363 * the following form:
2365 * ARG arg1:WORD, arg2:DWORD, arg4:QWORD
2367 offset = ArgOffset;
2368 do {
2369 char *arg, directive[256];
2370 int size = StackSize;
2372 /* Find the argument name */
2373 tline = tline->next;
2374 if (tline && tline->type == TOK_WHITESPACE)
2375 tline = tline->next;
2376 if (!tline || tline->type != TOK_ID) {
2377 error(ERR_NONFATAL, "`%%arg' missing argument parameter");
2378 free_tlist(origline);
2379 return DIRECTIVE_FOUND;
2381 arg = tline->text;
2383 /* Find the argument size type */
2384 tline = tline->next;
2385 if (!tline || tline->type != TOK_OTHER
2386 || tline->text[0] != ':') {
2387 error(ERR_NONFATAL,
2388 "Syntax error processing `%%arg' directive");
2389 free_tlist(origline);
2390 return DIRECTIVE_FOUND;
2392 tline = tline->next;
2393 if (!tline || tline->type != TOK_ID) {
2394 error(ERR_NONFATAL, "`%%arg' missing size type parameter");
2395 free_tlist(origline);
2396 return DIRECTIVE_FOUND;
2399 /* Allow macro expansion of type parameter */
2400 tt = tokenize(tline->text);
2401 tt = expand_smacro(tt);
2402 size = parse_size(tt->text);
2403 if (!size) {
2404 error(ERR_NONFATAL,
2405 "Invalid size type for `%%arg' missing directive");
2406 free_tlist(tt);
2407 free_tlist(origline);
2408 return DIRECTIVE_FOUND;
2410 free_tlist(tt);
2412 /* Round up to even stack slots */
2413 size = ALIGN(size, StackSize);
2415 /* Now define the macro for the argument */
2416 snprintf(directive, sizeof(directive), "%%define %s (%s+%d)",
2417 arg, StackPointer, offset);
2418 do_directive(tokenize(directive));
2419 offset += size;
2421 /* Move to the next argument in the list */
2422 tline = tline->next;
2423 if (tline && tline->type == TOK_WHITESPACE)
2424 tline = tline->next;
2425 } while (tline && tline->type == TOK_OTHER && tline->text[0] == ',');
2426 ArgOffset = offset;
2427 free_tlist(origline);
2428 return DIRECTIVE_FOUND;
2430 case PP_LOCAL:
2431 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2432 /* TASM like LOCAL directive to define local variables for a
2433 * function, in the following form:
2435 * LOCAL local1:WORD, local2:DWORD, local4:QWORD = LocalSize
2437 * The '= LocalSize' at the end is ignored by NASM, but is
2438 * required by TASM to define the local parameter size (and used
2439 * by the TASM macro package).
2441 offset = LocalOffset;
2442 do {
2443 char *local, directive[256];
2444 int size = StackSize;
2446 /* Find the argument name */
2447 tline = tline->next;
2448 if (tline && tline->type == TOK_WHITESPACE)
2449 tline = tline->next;
2450 if (!tline || tline->type != TOK_ID) {
2451 error(ERR_NONFATAL,
2452 "`%%local' missing argument parameter");
2453 free_tlist(origline);
2454 return DIRECTIVE_FOUND;
2456 local = tline->text;
2458 /* Find the argument size type */
2459 tline = tline->next;
2460 if (!tline || tline->type != TOK_OTHER
2461 || tline->text[0] != ':') {
2462 error(ERR_NONFATAL,
2463 "Syntax error processing `%%local' directive");
2464 free_tlist(origline);
2465 return DIRECTIVE_FOUND;
2467 tline = tline->next;
2468 if (!tline || tline->type != TOK_ID) {
2469 error(ERR_NONFATAL,
2470 "`%%local' missing size type parameter");
2471 free_tlist(origline);
2472 return DIRECTIVE_FOUND;
2475 /* Allow macro expansion of type parameter */
2476 tt = tokenize(tline->text);
2477 tt = expand_smacro(tt);
2478 size = parse_size(tt->text);
2479 if (!size) {
2480 error(ERR_NONFATAL,
2481 "Invalid size type for `%%local' missing directive");
2482 free_tlist(tt);
2483 free_tlist(origline);
2484 return DIRECTIVE_FOUND;
2486 free_tlist(tt);
2488 /* Round up to even stack slots */
2489 size = ALIGN(size, StackSize);
2491 offset += size; /* Negative offset, increment before */
2493 /* Now define the macro for the argument */
2494 snprintf(directive, sizeof(directive), "%%define %s (%s-%d)",
2495 local, StackPointer, offset);
2496 do_directive(tokenize(directive));
2498 /* Now define the assign to setup the enter_c macro correctly */
2499 snprintf(directive, sizeof(directive),
2500 "%%assign %%$localsize %%$localsize+%d", size);
2501 do_directive(tokenize(directive));
2503 /* Move to the next argument in the list */
2504 tline = tline->next;
2505 if (tline && tline->type == TOK_WHITESPACE)
2506 tline = tline->next;
2507 } while (tline && tline->type == TOK_OTHER && tline->text[0] == ',');
2508 LocalOffset = offset;
2509 free_tlist(origline);
2510 return DIRECTIVE_FOUND;
2512 case PP_CLEAR:
2513 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2514 if (tline->next)
2515 error(ERR_WARNING|ERR_PASS1,
2516 "trailing garbage after `%%clear' ignored");
2517 free_macros();
2518 init_macros();
2519 free_tlist(origline);
2520 return DIRECTIVE_FOUND;
2522 case PP_DEPEND:
2523 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2524 t = tline->next = expand_smacro(tline->next);
2525 skip_white_(t);
2526 if (!t || (t->type != TOK_STRING &&
2527 t->type != TOK_INTERNAL_STRING)) {
2528 error(ERR_NONFATAL, "`%%depend' expects a file name");
2529 free_tlist(origline);
2530 return DIRECTIVE_FOUND; /* but we did _something_ */
2532 if (t->next)
2533 error(ERR_WARNING|ERR_PASS1,
2534 "trailing garbage after `%%depend' ignored");
2535 p = t->text;
2536 if (t->type != TOK_INTERNAL_STRING)
2537 nasm_unquote_cstr(p, i);
2538 if (dephead && !in_list(*dephead, p)) {
2539 StrList *sl = nasm_malloc(strlen(p)+1+sizeof sl->next);
2540 sl->next = NULL;
2541 strcpy(sl->str, p);
2542 *deptail = sl;
2543 deptail = &sl->next;
2545 free_tlist(origline);
2546 return DIRECTIVE_FOUND;
2548 case PP_INCLUDE:
2549 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2550 t = tline->next = expand_smacro(tline->next);
2551 skip_white_(t);
2553 if (!t || (t->type != TOK_STRING &&
2554 t->type != TOK_INTERNAL_STRING)) {
2555 error(ERR_NONFATAL, "`%%include' expects a file name");
2556 free_tlist(origline);
2557 return DIRECTIVE_FOUND; /* but we did _something_ */
2559 if (t->next)
2560 error(ERR_WARNING|ERR_PASS1,
2561 "trailing garbage after `%%include' ignored");
2562 p = t->text;
2563 if (t->type != TOK_INTERNAL_STRING)
2564 nasm_unquote_cstr(p, i);
2565 inc = nasm_zalloc(sizeof(Include));
2566 inc->next = istk;
2567 inc->fp = inc_fopen(p, dephead, &deptail, pass == 0);
2568 if (!inc->fp) {
2569 /* -MG given but file not found */
2570 nasm_free(inc);
2571 } else {
2572 inc->fname = src_set_fname(nasm_strdup(p));
2573 inc->lineno = src_set_linnum(0);
2574 inc->lineinc = 1;
2575 inc->expansion = NULL;
2576 istk = inc;
2577 list->uplevel(LIST_INCLUDE);
2579 free_tlist(origline);
2580 return DIRECTIVE_FOUND;
2582 case PP_USE:
2583 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2585 static macros_t *use_pkg;
2586 const char *pkg_macro = NULL;
2588 tline = tline->next;
2589 skip_white_(tline);
2590 tline = expand_id(tline);
2592 if (!tline || (tline->type != TOK_STRING &&
2593 tline->type != TOK_INTERNAL_STRING &&
2594 tline->type != TOK_ID)) {
2595 error(ERR_NONFATAL, "`%%use' expects a package name");
2596 free_tlist(origline);
2597 return DIRECTIVE_FOUND; /* but we did _something_ */
2599 if (tline->next)
2600 error(ERR_WARNING|ERR_PASS1,
2601 "trailing garbage after `%%use' ignored");
2602 if (tline->type == TOK_STRING)
2603 nasm_unquote_cstr(tline->text, i);
2604 use_pkg = nasm_stdmac_find_package(tline->text);
2605 if (!use_pkg)
2606 error(ERR_NONFATAL, "unknown `%%use' package: %s", tline->text);
2607 else
2608 pkg_macro = (char *)use_pkg + 1; /* The first string will be <%define>__USE_*__ */
2609 if (use_pkg && ! smacro_defined(NULL, pkg_macro, 0, NULL, true)) {
2610 /* Not already included, go ahead and include it */
2611 stdmacpos = use_pkg;
2613 free_tlist(origline);
2614 return DIRECTIVE_FOUND;
2616 case PP_PUSH:
2617 case PP_REPL:
2618 case PP_POP:
2619 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2620 tline = tline->next;
2621 skip_white_(tline);
2622 tline = expand_id(tline);
2623 if (tline) {
2624 if (!tok_type_(tline, TOK_ID)) {
2625 error(ERR_NONFATAL, "`%s' expects a context identifier",
2626 pp_directives[i]);
2627 free_tlist(origline);
2628 return DIRECTIVE_FOUND; /* but we did _something_ */
2630 if (tline->next)
2631 error(ERR_WARNING|ERR_PASS1,
2632 "trailing garbage after `%s' ignored",
2633 pp_directives[i]);
2634 p = nasm_strdup(tline->text);
2635 } else {
2636 p = NULL; /* Anonymous */
2639 if (i == PP_PUSH) {
2640 ctx = nasm_malloc(sizeof(Context));
2641 ctx->next = cstk;
2642 hash_init(&ctx->localmac, HASH_SMALL);
2643 ctx->name = p;
2644 ctx->number = unique++;
2645 cstk = ctx;
2646 } else {
2647 /* %pop or %repl */
2648 if (!cstk) {
2649 error(ERR_NONFATAL, "`%s': context stack is empty",
2650 pp_directives[i]);
2651 } else if (i == PP_POP) {
2652 if (p && (!cstk->name || nasm_stricmp(p, cstk->name)))
2653 error(ERR_NONFATAL, "`%%pop' in wrong context: %s, "
2654 "expected %s",
2655 cstk->name ? cstk->name : "anonymous", p);
2656 else
2657 ctx_pop();
2658 } else {
2659 /* i == PP_REPL */
2660 nasm_free(cstk->name);
2661 cstk->name = p;
2662 p = NULL;
2664 nasm_free(p);
2666 free_tlist(origline);
2667 return DIRECTIVE_FOUND;
2668 case PP_FATAL:
2669 severity = ERR_FATAL;
2670 goto issue_error;
2671 case PP_ERROR:
2672 severity = ERR_NONFATAL;
2673 goto issue_error;
2674 case PP_WARNING:
2675 severity = ERR_WARNING|ERR_WARN_USER;
2676 goto issue_error;
2678 issue_error:
2679 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2681 /* Only error out if this is the final pass */
2682 if (pass != 2 && i != PP_FATAL)
2683 return DIRECTIVE_FOUND;
2685 tline->next = expand_smacro(tline->next);
2686 tline = tline->next;
2687 skip_white_(tline);
2688 t = tline ? tline->next : NULL;
2689 skip_white_(t);
2690 if (tok_type_(tline, TOK_STRING) && !t) {
2691 /* The line contains only a quoted string */
2692 p = tline->text;
2693 nasm_unquote(p, NULL); /* Ignore NUL character truncation */
2694 error(severity, "%s", p);
2695 } else {
2696 /* Not a quoted string, or more than a quoted string */
2697 p = detoken(tline, false);
2698 error(severity, "%s", p);
2699 nasm_free(p);
2701 free_tlist(origline);
2702 return DIRECTIVE_FOUND;
2705 CASE_PP_IF:
2706 if (defining != NULL) {
2707 if (defining->type == EXP_IF) {
2708 defining->def_depth ++;
2710 return NO_DIRECTIVE_FOUND;
2712 if ((istk->expansion != NULL) &&
2713 (istk->expansion->emitting == false)) {
2714 j = COND_NEVER;
2715 } else {
2716 j = if_condition(tline->next, i);
2717 tline->next = NULL; /* it got freed */
2718 j = (((j < 0) ? COND_NEVER : j) ? COND_IF_TRUE : COND_IF_FALSE);
2720 ed = new_ExpDef(EXP_IF);
2721 ed->state = j;
2722 ed->nolist = NULL;
2723 ed->def_depth = 0;
2724 ed->cur_depth = 0;
2725 ed->max_depth = 0;
2726 ed->ignoring = ((ed->state == COND_IF_TRUE) ? false : true);
2727 ed->prev = defining;
2728 defining = ed;
2729 free_tlist(origline);
2730 return DIRECTIVE_FOUND;
2732 CASE_PP_ELIF:
2733 if (defining != NULL) {
2734 if ((defining->type != EXP_IF) || (defining->def_depth > 0)) {
2735 return NO_DIRECTIVE_FOUND;
2738 if ((defining == NULL) || (defining->type != EXP_IF)) {
2739 error(ERR_FATAL, "`%s': no matching `%%if'", pp_directives[i]);
2741 switch (defining->state) {
2742 case COND_IF_TRUE:
2743 defining->state = COND_DONE;
2744 defining->ignoring = true;
2745 break;
2747 case COND_DONE:
2748 case COND_NEVER:
2749 defining->ignoring = true;
2750 break;
2752 case COND_ELSE_TRUE:
2753 case COND_ELSE_FALSE:
2754 error_precond(ERR_WARNING|ERR_PASS1,
2755 "`%%elif' after `%%else' ignored");
2756 defining->state = COND_NEVER;
2757 defining->ignoring = true;
2758 break;
2760 case COND_IF_FALSE:
2762 * IMPORTANT: In the case of %if, we will already have
2763 * called expand_mmac_params(); however, if we're
2764 * processing an %elif we must have been in a
2765 * non-emitting mode, which would have inhibited
2766 * the normal invocation of expand_mmac_params().
2767 * Therefore, we have to do it explicitly here.
2769 j = if_condition(expand_mmac_params(tline->next), i);
2770 tline->next = NULL; /* it got freed */
2771 defining->state =
2772 j < 0 ? COND_NEVER : j ? COND_IF_TRUE : COND_IF_FALSE;
2773 defining->ignoring = ((defining->state == COND_IF_TRUE) ? false : true);
2774 break;
2776 free_tlist(origline);
2777 return DIRECTIVE_FOUND;
2779 case PP_ELSE:
2780 if (defining != NULL) {
2781 if ((defining->type != EXP_IF) || (defining->def_depth > 0)) {
2782 return NO_DIRECTIVE_FOUND;
2785 if (tline->next)
2786 error_precond(ERR_WARNING|ERR_PASS1,
2787 "trailing garbage after `%%else' ignored");
2788 if ((defining == NULL) || (defining->type != EXP_IF)) {
2789 error(ERR_FATAL, "`%s': no matching `%%if'", pp_directives[i]);
2791 switch (defining->state) {
2792 case COND_IF_TRUE:
2793 case COND_DONE:
2794 defining->state = COND_ELSE_FALSE;
2795 defining->ignoring = true;
2796 break;
2798 case COND_NEVER:
2799 defining->ignoring = true;
2800 break;
2802 case COND_IF_FALSE:
2803 defining->state = COND_ELSE_TRUE;
2804 defining->ignoring = false;
2805 break;
2807 case COND_ELSE_TRUE:
2808 case COND_ELSE_FALSE:
2809 error_precond(ERR_WARNING|ERR_PASS1,
2810 "`%%else' after `%%else' ignored.");
2811 defining->state = COND_NEVER;
2812 defining->ignoring = true;
2813 break;
2815 free_tlist(origline);
2816 return DIRECTIVE_FOUND;
2818 case PP_ENDIF:
2819 if (defining != NULL) {
2820 if (defining->type == EXP_IF) {
2821 if (defining->def_depth > 0) {
2822 defining->def_depth --;
2823 return NO_DIRECTIVE_FOUND;
2825 } else {
2826 return NO_DIRECTIVE_FOUND;
2829 if (tline->next)
2830 error_precond(ERR_WARNING|ERR_PASS1,
2831 "trailing garbage after `%%endif' ignored");
2832 if ((defining == NULL) || (defining->type != EXP_IF)) {
2833 error(ERR_NONFATAL, "`%%endif': no matching `%%if'");
2834 return DIRECTIVE_FOUND;
2836 ed = defining;
2837 defining = ed->prev;
2838 ed->prev = expansions;
2839 expansions = ed;
2840 ei = new_ExpInv(EXP_IF, ed);
2841 ei->current = ed->line;
2842 ei->emitting = true;
2843 ei->prev = istk->expansion;
2844 istk->expansion = ei;
2845 free_tlist(origline);
2846 return DIRECTIVE_FOUND;
2848 case PP_RMACRO:
2849 case PP_IRMACRO:
2850 case PP_MACRO:
2851 case PP_IMACRO:
2852 if (defining != NULL) {
2853 if (defining->type == EXP_MMACRO) {
2854 defining->def_depth ++;
2856 return NO_DIRECTIVE_FOUND;
2858 ed = new_ExpDef(EXP_MMACRO);
2859 ed->max_depth =
2860 (i == PP_RMACRO) || (i == PP_IRMACRO) ? DEADMAN_LIMIT : 0;
2861 ed->casesense = (i == PP_MACRO) || (i == PP_RMACRO);
2862 if (!parse_mmacro_spec(tline, ed, pp_directives[i])) {
2863 nasm_free(ed);
2864 ed = NULL;
2865 return DIRECTIVE_FOUND;
2867 ed->def_depth = 0;
2868 ed->cur_depth = 0;
2869 ed->max_depth = (ed->max_depth + 1);
2870 ed->ignoring = false;
2871 ed->prev = defining;
2872 defining = ed;
2874 eed = (ExpDef *) hash_findix(&expdefs, ed->name);
2875 while (eed) {
2876 if (!strcmp(eed->name, ed->name) &&
2877 (eed->nparam_min <= ed->nparam_max
2878 || ed->plus)
2879 && (ed->nparam_min <= eed->nparam_max
2880 || eed->plus)) {
2881 error(ERR_WARNING|ERR_PASS1,
2882 "redefining multi-line macro `%s'", ed->name);
2883 return DIRECTIVE_FOUND;
2885 eed = eed->next;
2887 free_tlist(origline);
2888 return DIRECTIVE_FOUND;
2890 case PP_ENDM:
2891 case PP_ENDMACRO:
2892 if (defining != NULL) {
2893 if (defining->type == EXP_MMACRO) {
2894 if (defining->def_depth > 0) {
2895 defining->def_depth --;
2896 return NO_DIRECTIVE_FOUND;
2898 } else {
2899 return NO_DIRECTIVE_FOUND;
2902 if (!(defining) || (defining->type != EXP_MMACRO)) {
2903 error(ERR_NONFATAL, "`%s': not defining a macro", tline->text);
2904 return DIRECTIVE_FOUND;
2906 edhead = (ExpDef **) hash_findi_add(&expdefs, defining->name);
2907 defining->next = *edhead;
2908 *edhead = defining;
2909 ed = defining;
2910 defining = ed->prev;
2911 ed->prev = expansions;
2912 expansions = ed;
2913 ed = NULL;
2914 free_tlist(origline);
2915 return DIRECTIVE_FOUND;
2917 case PP_EXITMACRO:
2918 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2920 * We must search along istk->expansion until we hit a
2921 * macro invocation. Then we disable the emitting state(s)
2922 * between exitmacro and endmacro.
2924 for (ei = istk->expansion; ei != NULL; ei = ei->prev) {
2925 if(ei->type == EXP_MMACRO) {
2926 break;
2930 if (ei != NULL) {
2932 * Set all invocations leading back to the macro
2933 * invocation to a non-emitting state.
2935 for (eei = istk->expansion; eei != ei; eei = eei->prev) {
2936 eei->emitting = false;
2938 eei->emitting = false;
2939 } else {
2940 error(ERR_NONFATAL, "`%%exitmacro' not within `%%macro' block");
2942 free_tlist(origline);
2943 return DIRECTIVE_FOUND;
2945 case PP_UNMACRO:
2946 case PP_UNIMACRO:
2947 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2949 ExpDef **ed_p;
2950 ExpDef spec;
2952 spec.casesense = (i == PP_UNMACRO);
2953 if (!parse_mmacro_spec(tline, &spec, pp_directives[i])) {
2954 return DIRECTIVE_FOUND;
2956 ed_p = (ExpDef **) hash_findi(&expdefs, spec.name, NULL);
2957 while (ed_p && *ed_p) {
2958 ed = *ed_p;
2959 if (ed->casesense == spec.casesense &&
2960 !mstrcmp(ed->name, spec.name, spec.casesense) &&
2961 ed->nparam_min == spec.nparam_min &&
2962 ed->nparam_max == spec.nparam_max &&
2963 ed->plus == spec.plus) {
2964 *ed_p = ed->next;
2965 free_expdef(ed);
2966 } else {
2967 ed_p = &ed->next;
2970 free_tlist(origline);
2971 free_tlist(spec.dlist);
2972 return DIRECTIVE_FOUND;
2975 case PP_ROTATE:
2976 if (defining != NULL) return NO_DIRECTIVE_FOUND;
2977 if (tline->next && tline->next->type == TOK_WHITESPACE)
2978 tline = tline->next;
2979 if (!tline->next) {
2980 free_tlist(origline);
2981 error(ERR_NONFATAL, "`%%rotate' missing rotate count");
2982 return DIRECTIVE_FOUND;
2984 t = expand_smacro(tline->next);
2985 tline->next = NULL;
2986 free_tlist(origline);
2987 tline = t;
2988 tptr = &t;
2989 tokval.t_type = TOKEN_INVALID;
2990 evalresult =
2991 evaluate(ppscan, tptr, &tokval, NULL, pass, error, NULL);
2992 free_tlist(tline);
2993 if (!evalresult)
2994 return DIRECTIVE_FOUND;
2995 if (tokval.t_type)
2996 error(ERR_WARNING|ERR_PASS1,
2997 "trailing garbage after expression ignored");
2998 if (!is_simple(evalresult)) {
2999 error(ERR_NONFATAL, "non-constant value given to `%%rotate'");
3000 return DIRECTIVE_FOUND;
3002 for (ei = istk->expansion; ei != NULL; ei = ei->prev) {
3003 if (ei->type == EXP_MMACRO) {
3004 break;
3007 if (ei == NULL) {
3008 error(ERR_NONFATAL, "`%%rotate' invoked outside a macro call");
3009 } else if (ei->nparam == 0) {
3010 error(ERR_NONFATAL,
3011 "`%%rotate' invoked within macro without parameters");
3012 } else {
3013 int rotate = ei->rotate + reloc_value(evalresult);
3015 rotate %= (int)ei->nparam;
3016 if (rotate < 0)
3017 rotate += ei->nparam;
3018 ei->rotate = rotate;
3020 return DIRECTIVE_FOUND;
3022 case PP_REP:
3023 if (defining != NULL) {
3024 if (defining->type == EXP_REP) {
3025 defining->def_depth ++;
3027 return NO_DIRECTIVE_FOUND;
3029 nolist = false;
3030 do {
3031 tline = tline->next;
3032 } while (tok_type_(tline, TOK_WHITESPACE));
3034 if (tok_type_(tline, TOK_ID) &&
3035 nasm_stricmp(tline->text, ".nolist") == 0) {
3036 nolist = true;
3037 do {
3038 tline = tline->next;
3039 } while (tok_type_(tline, TOK_WHITESPACE));
3042 if (tline) {
3043 t = expand_smacro(tline);
3044 tptr = &t;
3045 tokval.t_type = TOKEN_INVALID;
3046 evalresult =
3047 evaluate(ppscan, tptr, &tokval, NULL, pass, error, NULL);
3048 if (!evalresult) {
3049 free_tlist(origline);
3050 return DIRECTIVE_FOUND;
3052 if (tokval.t_type)
3053 error(ERR_WARNING|ERR_PASS1,
3054 "trailing garbage after expression ignored");
3055 if (!is_simple(evalresult)) {
3056 error(ERR_NONFATAL, "non-constant value given to `%%rep'");
3057 return DIRECTIVE_FOUND;
3059 count = reloc_value(evalresult);
3060 if (count >= REP_LIMIT) {
3061 error(ERR_NONFATAL, "`%%rep' value exceeds limit");
3062 count = 0;
3063 } else
3064 count++;
3065 } else {
3066 error(ERR_NONFATAL, "`%%rep' expects a repeat count");
3067 count = 0;
3069 free_tlist(origline);
3070 ed = new_ExpDef(EXP_REP);
3071 ed->nolist = nolist;
3072 ed->def_depth = 0;
3073 ed->cur_depth = 1;
3074 ed->max_depth = (count - 1);
3075 ed->ignoring = false;
3076 ed->prev = defining;
3077 defining = ed;
3078 return DIRECTIVE_FOUND;
3080 case PP_ENDREP:
3081 if (defining != NULL) {
3082 if (defining->type == EXP_REP) {
3083 if (defining->def_depth > 0) {
3084 defining->def_depth --;
3085 return NO_DIRECTIVE_FOUND;
3087 } else {
3088 return NO_DIRECTIVE_FOUND;
3091 if ((defining == NULL) || (defining->type != EXP_REP)) {
3092 error(ERR_NONFATAL, "`%%endrep': no matching `%%rep'");
3093 return DIRECTIVE_FOUND;
3097 * Now we have a "macro" defined - although it has no name
3098 * and we won't be entering it in the hash tables - we must
3099 * push a macro-end marker for it on to istk->expansion.
3100 * After that, it will take care of propagating itself (a
3101 * macro-end marker line for a macro which is really a %rep
3102 * block will cause the macro to be re-expanded, complete
3103 * with another macro-end marker to ensure the process
3104 * continues) until the whole expansion is forcibly removed
3105 * from istk->expansion by a %exitrep.
3107 ed = defining;
3108 defining = ed->prev;
3109 ed->prev = expansions;
3110 expansions = ed;
3111 ei = new_ExpInv(EXP_REP, ed);
3112 ei->current = ed->line;
3113 ei->emitting = ((ed->max_depth > 0) ? true : false);
3114 list->uplevel(ed->nolist ? LIST_MACRO_NOLIST : LIST_MACRO);
3115 ei->prev = istk->expansion;
3116 istk->expansion = ei;
3117 free_tlist(origline);
3118 return DIRECTIVE_FOUND;
3120 case PP_EXITREP:
3121 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3123 * We must search along istk->expansion until we hit a
3124 * rep invocation. Then we disable the emitting state(s)
3125 * between exitrep and endrep.
3127 for (ei = istk->expansion; ei != NULL; ei = ei->prev) {
3128 if (ei->type == EXP_REP) {
3129 break;
3133 if (ei != NULL) {
3135 * Set all invocations leading back to the rep
3136 * invocation to a non-emitting state.
3138 for (eei = istk->expansion; eei != ei; eei = eei->prev) {
3139 eei->emitting = false;
3141 eei->emitting = false;
3142 eei->current = NULL;
3143 eei->def->cur_depth = eei->def->max_depth;
3144 } else {
3145 error(ERR_NONFATAL, "`%%exitrep' not within `%%rep' block");
3147 free_tlist(origline);
3148 return DIRECTIVE_FOUND;
3150 case PP_XDEFINE:
3151 case PP_IXDEFINE:
3152 case PP_DEFINE:
3153 case PP_IDEFINE:
3154 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3155 casesense = (i == PP_DEFINE || i == PP_XDEFINE);
3157 tline = tline->next;
3158 skip_white_(tline);
3159 tline = expand_id(tline);
3160 if (!tline || (tline->type != TOK_ID &&
3161 (tline->type != TOK_PREPROC_ID ||
3162 tline->text[1] != '$'))) {
3163 error(ERR_NONFATAL, "`%s' expects a macro identifier",
3164 pp_directives[i]);
3165 free_tlist(origline);
3166 return DIRECTIVE_FOUND;
3169 ctx = get_ctx(tline->text, &mname, false);
3170 last = tline;
3171 param_start = tline = tline->next;
3172 nparam = 0;
3174 /* Expand the macro definition now for %xdefine and %ixdefine */
3175 if ((i == PP_XDEFINE) || (i == PP_IXDEFINE))
3176 tline = expand_smacro(tline);
3178 if (tok_is_(tline, "(")) {
3180 * This macro has parameters.
3183 tline = tline->next;
3184 while (1) {
3185 skip_white_(tline);
3186 if (!tline) {
3187 error(ERR_NONFATAL, "parameter identifier expected");
3188 free_tlist(origline);
3189 return DIRECTIVE_FOUND;
3191 if (tline->type != TOK_ID) {
3192 error(ERR_NONFATAL,
3193 "`%s': parameter identifier expected",
3194 tline->text);
3195 free_tlist(origline);
3196 return DIRECTIVE_FOUND;
3198 tline->type = TOK_SMAC_PARAM + nparam++;
3199 tline = tline->next;
3200 skip_white_(tline);
3201 if (tok_is_(tline, ",")) {
3202 tline = tline->next;
3203 } else {
3204 if (!tok_is_(tline, ")")) {
3205 error(ERR_NONFATAL,
3206 "`)' expected to terminate macro template");
3207 free_tlist(origline);
3208 return DIRECTIVE_FOUND;
3210 break;
3213 last = tline;
3214 tline = tline->next;
3216 if (tok_type_(tline, TOK_WHITESPACE))
3217 last = tline, tline = tline->next;
3218 macro_start = NULL;
3219 last->next = NULL;
3220 t = tline;
3221 while (t) {
3222 if (t->type == TOK_ID) {
3223 list_for_each(tt, param_start)
3224 if (tt->type >= TOK_SMAC_PARAM &&
3225 !strcmp(tt->text, t->text))
3226 t->type = tt->type;
3228 tt = t->next;
3229 t->next = macro_start;
3230 macro_start = t;
3231 t = tt;
3234 * Good. We now have a macro name, a parameter count, and a
3235 * token list (in reverse order) for an expansion. We ought
3236 * to be OK just to create an SMacro, store it, and let
3237 * free_tlist have the rest of the line (which we have
3238 * carefully re-terminated after chopping off the expansion
3239 * from the end).
3241 define_smacro(ctx, mname, casesense, nparam, macro_start);
3242 free_tlist(origline);
3243 return DIRECTIVE_FOUND;
3245 case PP_UNDEF:
3246 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3247 tline = tline->next;
3248 skip_white_(tline);
3249 tline = expand_id(tline);
3250 if (!tline || (tline->type != TOK_ID &&
3251 (tline->type != TOK_PREPROC_ID ||
3252 tline->text[1] != '$'))) {
3253 error(ERR_NONFATAL, "`%%undef' expects a macro identifier");
3254 free_tlist(origline);
3255 return DIRECTIVE_FOUND;
3257 if (tline->next) {
3258 error(ERR_WARNING|ERR_PASS1,
3259 "trailing garbage after macro name ignored");
3262 /* Find the context that symbol belongs to */
3263 ctx = get_ctx(tline->text, &mname, false);
3264 undef_smacro(ctx, mname);
3265 free_tlist(origline);
3266 return DIRECTIVE_FOUND;
3268 case PP_DEFSTR:
3269 case PP_IDEFSTR:
3270 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3271 casesense = (i == PP_DEFSTR);
3273 tline = tline->next;
3274 skip_white_(tline);
3275 tline = expand_id(tline);
3276 if (!tline || (tline->type != TOK_ID &&
3277 (tline->type != TOK_PREPROC_ID ||
3278 tline->text[1] != '$'))) {
3279 error(ERR_NONFATAL, "`%s' expects a macro identifier",
3280 pp_directives[i]);
3281 free_tlist(origline);
3282 return DIRECTIVE_FOUND;
3285 ctx = get_ctx(tline->text, &mname, false);
3286 last = tline;
3287 tline = expand_smacro(tline->next);
3288 last->next = NULL;
3290 while (tok_type_(tline, TOK_WHITESPACE))
3291 tline = delete_Token(tline);
3293 p = detoken(tline, false);
3294 macro_start = nasm_malloc(sizeof(*macro_start));
3295 macro_start->next = NULL;
3296 macro_start->text = nasm_quote(p, strlen(p));
3297 macro_start->type = TOK_STRING;
3298 macro_start->a.mac = NULL;
3299 nasm_free(p);
3302 * We now have a macro name, an implicit parameter count of
3303 * zero, and a string token to use as an expansion. Create
3304 * and store an SMacro.
3306 define_smacro(ctx, mname, casesense, 0, macro_start);
3307 free_tlist(origline);
3308 return DIRECTIVE_FOUND;
3310 case PP_DEFTOK:
3311 case PP_IDEFTOK:
3312 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3313 casesense = (i == PP_DEFTOK);
3315 tline = tline->next;
3316 skip_white_(tline);
3317 tline = expand_id(tline);
3318 if (!tline || (tline->type != TOK_ID &&
3319 (tline->type != TOK_PREPROC_ID ||
3320 tline->text[1] != '$'))) {
3321 error(ERR_NONFATAL,
3322 "`%s' expects a macro identifier as first parameter",
3323 pp_directives[i]);
3324 free_tlist(origline);
3325 return DIRECTIVE_FOUND;
3327 ctx = get_ctx(tline->text, &mname, false);
3328 last = tline;
3329 tline = expand_smacro(tline->next);
3330 last->next = NULL;
3332 t = tline;
3333 while (tok_type_(t, TOK_WHITESPACE))
3334 t = t->next;
3335 /* t should now point to the string */
3336 if (!tok_type_(t, TOK_STRING)) {
3337 error(ERR_NONFATAL,
3338 "`%s` requires string as second parameter",
3339 pp_directives[i]);
3340 free_tlist(tline);
3341 free_tlist(origline);
3342 return DIRECTIVE_FOUND;
3346 * Convert the string to a token stream. Note that smacros
3347 * are stored with the token stream reversed, so we have to
3348 * reverse the output of tokenize().
3350 nasm_unquote_cstr(t->text, i);
3351 macro_start = reverse_tokens(tokenize(t->text));
3354 * We now have a macro name, an implicit parameter count of
3355 * zero, and a numeric token to use as an expansion. Create
3356 * and store an SMacro.
3358 define_smacro(ctx, mname, casesense, 0, macro_start);
3359 free_tlist(tline);
3360 free_tlist(origline);
3361 return DIRECTIVE_FOUND;
3363 case PP_PATHSEARCH:
3364 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3366 FILE *fp;
3367 StrList *xsl = NULL;
3368 StrList **xst = &xsl;
3370 casesense = true;
3372 tline = tline->next;
3373 skip_white_(tline);
3374 tline = expand_id(tline);
3375 if (!tline || (tline->type != TOK_ID &&
3376 (tline->type != TOK_PREPROC_ID ||
3377 tline->text[1] != '$'))) {
3378 error(ERR_NONFATAL,
3379 "`%%pathsearch' expects a macro identifier as first parameter");
3380 free_tlist(origline);
3381 return DIRECTIVE_FOUND;
3383 ctx = get_ctx(tline->text, &mname, false);
3384 last = tline;
3385 tline = expand_smacro(tline->next);
3386 last->next = NULL;
3388 t = tline;
3389 while (tok_type_(t, TOK_WHITESPACE))
3390 t = t->next;
3392 if (!t || (t->type != TOK_STRING &&
3393 t->type != TOK_INTERNAL_STRING)) {
3394 error(ERR_NONFATAL, "`%%pathsearch' expects a file name");
3395 free_tlist(tline);
3396 free_tlist(origline);
3397 return DIRECTIVE_FOUND; /* but we did _something_ */
3399 if (t->next)
3400 error(ERR_WARNING|ERR_PASS1,
3401 "trailing garbage after `%%pathsearch' ignored");
3402 p = t->text;
3403 if (t->type != TOK_INTERNAL_STRING)
3404 nasm_unquote(p, NULL);
3406 fp = inc_fopen(p, &xsl, &xst, true);
3407 if (fp) {
3408 p = xsl->str;
3409 fclose(fp); /* Don't actually care about the file */
3411 macro_start = nasm_malloc(sizeof(*macro_start));
3412 macro_start->next = NULL;
3413 macro_start->text = nasm_quote(p, strlen(p));
3414 macro_start->type = TOK_STRING;
3415 macro_start->a.mac = NULL;
3416 if (xsl)
3417 nasm_free(xsl);
3420 * We now have a macro name, an implicit parameter count of
3421 * zero, and a string token to use as an expansion. Create
3422 * and store an SMacro.
3424 define_smacro(ctx, mname, casesense, 0, macro_start);
3425 free_tlist(tline);
3426 free_tlist(origline);
3427 return DIRECTIVE_FOUND;
3430 case PP_STRLEN:
3431 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3432 casesense = true;
3434 tline = tline->next;
3435 skip_white_(tline);
3436 tline = expand_id(tline);
3437 if (!tline || (tline->type != TOK_ID &&
3438 (tline->type != TOK_PREPROC_ID ||
3439 tline->text[1] != '$'))) {
3440 error(ERR_NONFATAL,
3441 "`%%strlen' expects a macro identifier as first parameter");
3442 free_tlist(origline);
3443 return DIRECTIVE_FOUND;
3445 ctx = get_ctx(tline->text, &mname, false);
3446 last = tline;
3447 tline = expand_smacro(tline->next);
3448 last->next = NULL;
3450 t = tline;
3451 while (tok_type_(t, TOK_WHITESPACE))
3452 t = t->next;
3453 /* t should now point to the string */
3454 if (!tok_type_(t, TOK_STRING)) {
3455 error(ERR_NONFATAL,
3456 "`%%strlen` requires string as second parameter");
3457 free_tlist(tline);
3458 free_tlist(origline);
3459 return DIRECTIVE_FOUND;
3462 macro_start = nasm_malloc(sizeof(*macro_start));
3463 macro_start->next = NULL;
3464 make_tok_num(macro_start, nasm_unquote(t->text, NULL));
3465 macro_start->a.mac = NULL;
3468 * We now have a macro name, an implicit parameter count of
3469 * zero, and a numeric token to use as an expansion. Create
3470 * and store an SMacro.
3472 define_smacro(ctx, mname, casesense, 0, macro_start);
3473 free_tlist(tline);
3474 free_tlist(origline);
3475 return DIRECTIVE_FOUND;
3477 case PP_STRCAT:
3478 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3479 casesense = true;
3481 tline = tline->next;
3482 skip_white_(tline);
3483 tline = expand_id(tline);
3484 if (!tline || (tline->type != TOK_ID &&
3485 (tline->type != TOK_PREPROC_ID ||
3486 tline->text[1] != '$'))) {
3487 error(ERR_NONFATAL,
3488 "`%%strcat' expects a macro identifier as first parameter");
3489 free_tlist(origline);
3490 return DIRECTIVE_FOUND;
3492 ctx = get_ctx(tline->text, &mname, false);
3493 last = tline;
3494 tline = expand_smacro(tline->next);
3495 last->next = NULL;
3497 len = 0;
3498 list_for_each(t, tline) {
3499 switch (t->type) {
3500 case TOK_WHITESPACE:
3501 break;
3502 case TOK_STRING:
3503 len += t->a.len = nasm_unquote(t->text, NULL);
3504 break;
3505 case TOK_OTHER:
3506 if (!strcmp(t->text, ",")) /* permit comma separators */
3507 break;
3508 /* else fall through */
3509 default:
3510 error(ERR_NONFATAL,
3511 "non-string passed to `%%strcat' (%d)", t->type);
3512 free_tlist(tline);
3513 free_tlist(origline);
3514 return DIRECTIVE_FOUND;
3518 p = pp = nasm_malloc(len);
3519 list_for_each(t, tline) {
3520 if (t->type == TOK_STRING) {
3521 memcpy(p, t->text, t->a.len);
3522 p += t->a.len;
3527 * We now have a macro name, an implicit parameter count of
3528 * zero, and a numeric token to use as an expansion. Create
3529 * and store an SMacro.
3531 macro_start = new_Token(NULL, TOK_STRING, NULL, 0);
3532 macro_start->text = nasm_quote(pp, len);
3533 nasm_free(pp);
3534 define_smacro(ctx, mname, casesense, 0, macro_start);
3535 free_tlist(tline);
3536 free_tlist(origline);
3537 return DIRECTIVE_FOUND;
3539 case PP_SUBSTR:
3540 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3542 int64_t start, count;
3543 size_t len;
3545 casesense = true;
3547 tline = tline->next;
3548 skip_white_(tline);
3549 tline = expand_id(tline);
3550 if (!tline || (tline->type != TOK_ID &&
3551 (tline->type != TOK_PREPROC_ID ||
3552 tline->text[1] != '$'))) {
3553 error(ERR_NONFATAL,
3554 "`%%substr' expects a macro identifier as first parameter");
3555 free_tlist(origline);
3556 return DIRECTIVE_FOUND;
3558 ctx = get_ctx(tline->text, &mname, false);
3559 last = tline;
3560 tline = expand_smacro(tline->next);
3561 last->next = NULL;
3563 if (tline) /* skip expanded id */
3564 t = tline->next;
3565 while (tok_type_(t, TOK_WHITESPACE))
3566 t = t->next;
3568 /* t should now point to the string */
3569 if (!tok_type_(t, TOK_STRING)) {
3570 error(ERR_NONFATAL,
3571 "`%%substr` requires string as second parameter");
3572 free_tlist(tline);
3573 free_tlist(origline);
3574 return DIRECTIVE_FOUND;
3577 tt = t->next;
3578 tptr = &tt;
3579 tokval.t_type = TOKEN_INVALID;
3580 evalresult = evaluate(ppscan, tptr, &tokval, NULL,
3581 pass, error, NULL);
3582 if (!evalresult) {
3583 free_tlist(tline);
3584 free_tlist(origline);
3585 return DIRECTIVE_FOUND;
3586 } else if (!is_simple(evalresult)) {
3587 error(ERR_NONFATAL, "non-constant value given to `%%substr`");
3588 free_tlist(tline);
3589 free_tlist(origline);
3590 return DIRECTIVE_FOUND;
3592 start = evalresult->value - 1;
3594 while (tok_type_(tt, TOK_WHITESPACE))
3595 tt = tt->next;
3596 if (!tt) {
3597 count = 1; /* Backwards compatibility: one character */
3598 } else {
3599 tokval.t_type = TOKEN_INVALID;
3600 evalresult = evaluate(ppscan, tptr, &tokval, NULL,
3601 pass, error, NULL);
3602 if (!evalresult) {
3603 free_tlist(tline);
3604 free_tlist(origline);
3605 return DIRECTIVE_FOUND;
3606 } else if (!is_simple(evalresult)) {
3607 error(ERR_NONFATAL, "non-constant value given to `%%substr`");
3608 free_tlist(tline);
3609 free_tlist(origline);
3610 return DIRECTIVE_FOUND;
3612 count = evalresult->value;
3615 len = nasm_unquote(t->text, NULL);
3616 /* make start and count being in range */
3617 if (start < 0)
3618 start = 0;
3619 if (count < 0)
3620 count = len + count + 1 - start;
3621 if (start + count > (int64_t)len)
3622 count = len - start;
3623 if (!len || count < 0 || start >=(int64_t)len)
3624 start = -1, count = 0; /* empty string */
3626 macro_start = nasm_malloc(sizeof(*macro_start));
3627 macro_start->next = NULL;
3628 macro_start->text = nasm_quote((start < 0) ? "" : t->text + start, count);
3629 macro_start->type = TOK_STRING;
3630 macro_start->a.mac = NULL;
3633 * We now have a macro name, an implicit parameter count of
3634 * zero, and a numeric token to use as an expansion. Create
3635 * and store an SMacro.
3637 define_smacro(ctx, mname, casesense, 0, macro_start);
3638 free_tlist(tline);
3639 free_tlist(origline);
3640 return DIRECTIVE_FOUND;
3643 case PP_ASSIGN:
3644 case PP_IASSIGN:
3645 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3646 casesense = (i == PP_ASSIGN);
3648 tline = tline->next;
3649 skip_white_(tline);
3650 tline = expand_id(tline);
3651 if (!tline || (tline->type != TOK_ID &&
3652 (tline->type != TOK_PREPROC_ID ||
3653 tline->text[1] != '$'))) {
3654 error(ERR_NONFATAL,
3655 "`%%%sassign' expects a macro identifier",
3656 (i == PP_IASSIGN ? "i" : ""));
3657 free_tlist(origline);
3658 return DIRECTIVE_FOUND;
3660 ctx = get_ctx(tline->text, &mname, false);
3661 last = tline;
3662 tline = expand_smacro(tline->next);
3663 last->next = NULL;
3665 t = tline;
3666 tptr = &t;
3667 tokval.t_type = TOKEN_INVALID;
3668 evalresult =
3669 evaluate(ppscan, tptr, &tokval, NULL, pass, error, NULL);
3670 free_tlist(tline);
3671 if (!evalresult) {
3672 free_tlist(origline);
3673 return DIRECTIVE_FOUND;
3676 if (tokval.t_type)
3677 error(ERR_WARNING|ERR_PASS1,
3678 "trailing garbage after expression ignored");
3680 if (!is_simple(evalresult)) {
3681 error(ERR_NONFATAL,
3682 "non-constant value given to `%%%sassign'",
3683 (i == PP_IASSIGN ? "i" : ""));
3684 free_tlist(origline);
3685 return DIRECTIVE_FOUND;
3688 macro_start = nasm_malloc(sizeof(*macro_start));
3689 macro_start->next = NULL;
3690 make_tok_num(macro_start, reloc_value(evalresult));
3691 macro_start->a.mac = NULL;
3694 * We now have a macro name, an implicit parameter count of
3695 * zero, and a numeric token to use as an expansion. Create
3696 * and store an SMacro.
3698 define_smacro(ctx, mname, casesense, 0, macro_start);
3699 free_tlist(origline);
3700 return DIRECTIVE_FOUND;
3702 case PP_LINE:
3703 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3705 * Syntax is `%line nnn[+mmm] [filename]'
3707 tline = tline->next;
3708 skip_white_(tline);
3709 if (!tok_type_(tline, TOK_NUMBER)) {
3710 error(ERR_NONFATAL, "`%%line' expects line number");
3711 free_tlist(origline);
3712 return DIRECTIVE_FOUND;
3714 k = readnum(tline->text, &err);
3715 m = 1;
3716 tline = tline->next;
3717 if (tok_is_(tline, "+")) {
3718 tline = tline->next;
3719 if (!tok_type_(tline, TOK_NUMBER)) {
3720 error(ERR_NONFATAL, "`%%line' expects line increment");
3721 free_tlist(origline);
3722 return DIRECTIVE_FOUND;
3724 m = readnum(tline->text, &err);
3725 tline = tline->next;
3727 skip_white_(tline);
3728 src_set_linnum(k);
3729 istk->lineinc = m;
3730 if (tline) {
3731 nasm_free(src_set_fname(detoken(tline, false)));
3733 free_tlist(origline);
3734 return DIRECTIVE_FOUND;
3736 case PP_WHILE:
3737 if (defining != NULL) {
3738 if (defining->type == EXP_WHILE) {
3739 defining->def_depth ++;
3741 return NO_DIRECTIVE_FOUND;
3743 l = NULL;
3744 if ((istk->expansion != NULL) &&
3745 (istk->expansion->emitting == false)) {
3746 j = COND_NEVER;
3747 } else {
3748 l = new_Line();
3749 l->first = copy_Token(tline->next);
3750 j = if_condition(tline->next, i);
3751 tline->next = NULL; /* it got freed */
3752 j = (((j < 0) ? COND_NEVER : j) ? COND_IF_TRUE : COND_IF_FALSE);
3754 ed = new_ExpDef(EXP_WHILE);
3755 ed->state = j;
3756 ed->cur_depth = 1;
3757 ed->max_depth = DEADMAN_LIMIT;
3758 ed->ignoring = ((ed->state == COND_IF_TRUE) ? false : true);
3759 if (ed->ignoring == false) {
3760 ed->line = l;
3761 ed->last = l;
3762 } else if (l != NULL) {
3763 delete_Token(l->first);
3764 nasm_free(l);
3765 l = NULL;
3767 ed->prev = defining;
3768 defining = ed;
3769 free_tlist(origline);
3770 return DIRECTIVE_FOUND;
3772 case PP_ENDWHILE:
3773 if (defining != NULL) {
3774 if (defining->type == EXP_WHILE) {
3775 if (defining->def_depth > 0) {
3776 defining->def_depth --;
3777 return NO_DIRECTIVE_FOUND;
3779 } else {
3780 return NO_DIRECTIVE_FOUND;
3783 if (tline->next != NULL) {
3784 error_precond(ERR_WARNING|ERR_PASS1,
3785 "trailing garbage after `%%endwhile' ignored");
3787 if ((defining == NULL) || (defining->type != EXP_WHILE)) {
3788 error(ERR_NONFATAL, "`%%endwhile': no matching `%%while'");
3789 return DIRECTIVE_FOUND;
3791 ed = defining;
3792 defining = ed->prev;
3793 if (ed->ignoring == false) {
3794 ed->prev = expansions;
3795 expansions = ed;
3796 ei = new_ExpInv(EXP_WHILE, ed);
3797 ei->current = ed->line->next;
3798 ei->emitting = true;
3799 ei->prev = istk->expansion;
3800 istk->expansion = ei;
3801 } else {
3802 nasm_free(ed);
3804 free_tlist(origline);
3805 return DIRECTIVE_FOUND;
3807 case PP_EXITWHILE:
3808 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3810 * We must search along istk->expansion until we hit a
3811 * while invocation. Then we disable the emitting state(s)
3812 * between exitwhile and endwhile.
3814 for (ei = istk->expansion; ei != NULL; ei = ei->prev) {
3815 if (ei->type == EXP_WHILE) {
3816 break;
3820 if (ei != NULL) {
3822 * Set all invocations leading back to the while
3823 * invocation to a non-emitting state.
3825 for (eei = istk->expansion; eei != ei; eei = eei->prev) {
3826 eei->emitting = false;
3828 eei->emitting = false;
3829 eei->current = NULL;
3830 eei->def->cur_depth = eei->def->max_depth;
3831 } else {
3832 error(ERR_NONFATAL, "`%%exitwhile' not within `%%while' block");
3834 free_tlist(origline);
3835 return DIRECTIVE_FOUND;
3837 case PP_COMMENT:
3838 if (defining != NULL) {
3839 if (defining->type == EXP_COMMENT) {
3840 defining->def_depth ++;
3842 return NO_DIRECTIVE_FOUND;
3844 ed = new_ExpDef(EXP_COMMENT);
3845 ed->ignoring = true;
3846 ed->prev = defining;
3847 defining = ed;
3848 free_tlist(origline);
3849 return DIRECTIVE_FOUND;
3851 case PP_ENDCOMMENT:
3852 if (defining != NULL) {
3853 if (defining->type == EXP_COMMENT) {
3854 if (defining->def_depth > 0) {
3855 defining->def_depth --;
3856 return NO_DIRECTIVE_FOUND;
3858 } else {
3859 return NO_DIRECTIVE_FOUND;
3862 if ((defining == NULL) || (defining->type != EXP_COMMENT)) {
3863 error(ERR_NONFATAL, "`%%endcomment': no matching `%%comment'");
3864 return DIRECTIVE_FOUND;
3866 ed = defining;
3867 defining = ed->prev;
3868 nasm_free(ed);
3869 free_tlist(origline);
3870 return DIRECTIVE_FOUND;
3872 case PP_FINAL:
3873 if (defining != NULL) return NO_DIRECTIVE_FOUND;
3874 if (in_final != false) {
3875 error(ERR_FATAL, "`%%final' cannot be used recursively");
3877 tline = tline->next;
3878 skip_white_(tline);
3879 if (tline == NULL) {
3880 error(ERR_NONFATAL, "`%%final' expects at least one parameter");
3881 } else {
3882 l = new_Line();
3883 l->first = copy_Token(tline);
3884 l->next = finals;
3885 finals = l;
3887 free_tlist(origline);
3888 return DIRECTIVE_FOUND;
3890 default:
3891 error(ERR_FATAL,
3892 "preprocessor directive `%s' not yet implemented",
3893 pp_directives[i]);
3894 return DIRECTIVE_FOUND;
3899 * Ensure that a macro parameter contains a condition code and
3900 * nothing else. Return the condition code index if so, or -1
3901 * otherwise.
3903 static int find_cc(Token * t)
3905 Token *tt;
3906 int i, j, k, m;
3908 if (!t)
3909 return -1; /* Probably a %+ without a space */
3911 skip_white_(t);
3912 if (t->type != TOK_ID)
3913 return -1;
3914 tt = t->next;
3915 skip_white_(tt);
3916 if (tt && (tt->type != TOK_OTHER || strcmp(tt->text, ",")))
3917 return -1;
3919 i = -1;
3920 j = ARRAY_SIZE(conditions);
3921 while (j - i > 1) {
3922 k = (j + i) / 2;
3923 m = nasm_stricmp(t->text, conditions[k]);
3924 if (m == 0) {
3925 i = k;
3926 j = -2;
3927 break;
3928 } else if (m < 0) {
3929 j = k;
3930 } else
3931 i = k;
3933 if (j != -2)
3934 return -1;
3935 return i;
3938 static bool paste_tokens(Token **head, const struct tokseq_match *m,
3939 int mnum, bool handle_paste_tokens)
3941 Token **tail, *t, *tt;
3942 Token **paste_head;
3943 bool did_paste = false;
3944 char *tmp;
3945 int i;
3947 /* Now handle token pasting... */
3948 paste_head = NULL;
3949 tail = head;
3950 while ((t = *tail) && (tt = t->next)) {
3951 switch (t->type) {
3952 case TOK_WHITESPACE:
3953 if (tt->type == TOK_WHITESPACE) {
3954 /* Zap adjacent whitespace tokens */
3955 t->next = delete_Token(tt);
3956 } else {
3957 /* Do not advance paste_head here */
3958 tail = &t->next;
3960 break;
3961 case TOK_PASTE: /* %+ */
3962 if (handle_paste_tokens) {
3963 /* Zap %+ and whitespace tokens to the right */
3964 while (t && (t->type == TOK_WHITESPACE ||
3965 t->type == TOK_PASTE))
3966 t = *tail = delete_Token(t);
3967 if (!paste_head || !t)
3968 break; /* Nothing to paste with */
3969 tail = paste_head;
3970 t = *tail;
3971 tt = t->next;
3972 while (tok_type_(tt, TOK_WHITESPACE))
3973 tt = t->next = delete_Token(tt);
3974 if (tt) {
3975 tmp = nasm_strcat(t->text, tt->text);
3976 delete_Token(t);
3977 tt = delete_Token(tt);
3978 t = *tail = tokenize(tmp);
3979 nasm_free(tmp);
3980 while (t->next) {
3981 tail = &t->next;
3982 t = t->next;
3984 t->next = tt; /* Attach the remaining token chain */
3985 did_paste = true;
3987 paste_head = tail;
3988 tail = &t->next;
3989 break;
3991 /* else fall through */
3992 default:
3994 * Concatenation of tokens might look nontrivial
3995 * but in real it's pretty simple -- the caller
3996 * prepares the masks of token types to be concatenated
3997 * and we simply find matched sequences and slip
3998 * them together
4000 for (i = 0; i < mnum; i++) {
4001 if (PP_CONCAT_MASK(t->type) & m[i].mask_head) {
4002 size_t len = 0;
4003 char *tmp, *p;
4005 while (tt && (PP_CONCAT_MASK(tt->type) & m[i].mask_tail)) {
4006 len += strlen(tt->text);
4007 tt = tt->next;
4011 * Now tt points to the first token after
4012 * the potential paste area...
4014 if (tt != t->next) {
4015 /* We have at least two tokens... */
4016 len += strlen(t->text);
4017 p = tmp = nasm_malloc(len+1);
4018 while (t != tt) {
4019 strcpy(p, t->text);
4020 p = strchr(p, '\0');
4021 t = delete_Token(t);
4023 t = *tail = tokenize(tmp);
4024 nasm_free(tmp);
4025 while (t->next) {
4026 tail = &t->next;
4027 t = t->next;
4029 t->next = tt; /* Attach the remaining token chain */
4030 did_paste = true;
4032 paste_head = tail;
4033 tail = &t->next;
4034 break;
4037 if (i >= mnum) { /* no match */
4038 tail = &t->next;
4039 if (!tok_type_(t->next, TOK_WHITESPACE))
4040 paste_head = tail;
4042 break;
4045 return did_paste;
4049 * expands to a list of tokens from %{x:y}
4051 static Token *expand_mmac_params_range(ExpInv *ei, Token *tline, Token ***last)
4053 Token *t = tline, **tt, *tm, *head;
4054 char *pos;
4055 int fst, lst, j, i;
4057 pos = strchr(tline->text, ':');
4058 nasm_assert(pos);
4060 lst = atoi(pos + 1);
4061 fst = atoi(tline->text + 1);
4064 * only macros params are accounted so
4065 * if someone passes %0 -- we reject such
4066 * value(s)
4068 if (lst == 0 || fst == 0)
4069 goto err;
4071 /* the values should be sane */
4072 if ((fst > (int)ei->nparam || fst < (-(int)ei->nparam)) ||
4073 (lst > (int)ei->nparam || lst < (-(int)ei->nparam)))
4074 goto err;
4076 fst = fst < 0 ? fst + (int)ei->nparam + 1: fst;
4077 lst = lst < 0 ? lst + (int)ei->nparam + 1: lst;
4079 /* counted from zero */
4080 fst--, lst--;
4083 * it will be at least one token
4085 tm = ei->params[(fst + ei->rotate) % ei->nparam];
4086 t = new_Token(NULL, tm->type, tm->text, 0);
4087 head = t, tt = &t->next;
4088 if (fst < lst) {
4089 for (i = fst + 1; i <= lst; i++) {
4090 t = new_Token(NULL, TOK_OTHER, ",", 0);
4091 *tt = t, tt = &t->next;
4092 j = (i + ei->rotate) % ei->nparam;
4093 tm = ei->params[j];
4094 t = new_Token(NULL, tm->type, tm->text, 0);
4095 *tt = t, tt = &t->next;
4097 } else {
4098 for (i = fst - 1; i >= lst; i--) {
4099 t = new_Token(NULL, TOK_OTHER, ",", 0);
4100 *tt = t, tt = &t->next;
4101 j = (i + ei->rotate) % ei->nparam;
4102 tm = ei->params[j];
4103 t = new_Token(NULL, tm->type, tm->text, 0);
4104 *tt = t, tt = &t->next;
4108 *last = tt;
4109 return head;
4111 err:
4112 error(ERR_NONFATAL, "`%%{%s}': macro parameters out of range",
4113 &tline->text[1]);
4114 return tline;
4118 * Expand MMacro-local things: parameter references (%0, %n, %+n,
4119 * %-n) and MMacro-local identifiers (%%foo) as well as
4120 * macro indirection (%[...]) and range (%{..:..}).
4122 static Token *expand_mmac_params(Token * tline)
4124 Token *t, *tt, **tail, *thead;
4125 bool changed = false;
4126 char *pos;
4128 tail = &thead;
4129 thead = NULL;
4131 while (tline) {
4132 if (tline->type == TOK_PREPROC_ID &&
4133 (((tline->text[1] == '+' || tline->text[1] == '-') && tline->text[2]) ||
4134 (tline->text[1] >= '0' && tline->text[1] <= '9') ||
4135 tline->text[1] == '%')) {
4136 char *text = NULL;
4137 int type = 0, cc; /* type = 0 to placate optimisers */
4138 char tmpbuf[30];
4139 unsigned int n;
4140 int i;
4141 ExpInv *ei;
4143 t = tline;
4144 tline = tline->next;
4146 for (ei = istk->expansion; ei != NULL; ei = ei->prev) {
4147 if (ei->type == EXP_MMACRO) {
4148 break;
4151 if (ei == NULL) {
4152 error(ERR_NONFATAL, "`%s': not in a macro call", t->text);
4153 } else {
4154 pos = strchr(t->text, ':');
4155 if (!pos) {
4156 switch (t->text[1]) {
4158 * We have to make a substitution of one of the
4159 * forms %1, %-1, %+1, %%foo, %0.
4161 case '0':
4162 if ((strlen(t->text) > 2) && (t->text[2] == '0')) {
4163 type = TOK_ID;
4164 text = nasm_strdup(ei->label_text);
4165 } else {
4166 type = TOK_NUMBER;
4167 snprintf(tmpbuf, sizeof(tmpbuf), "%d", ei->nparam);
4168 text = nasm_strdup(tmpbuf);
4170 break;
4171 case '%':
4172 type = TOK_ID;
4173 snprintf(tmpbuf, sizeof(tmpbuf), "..@%"PRIu64".",
4174 ei->unique);
4175 text = nasm_strcat(tmpbuf, t->text + 2);
4176 break;
4177 case '-':
4178 n = atoi(t->text + 2) - 1;
4179 if (n >= ei->nparam)
4180 tt = NULL;
4181 else {
4182 if (ei->nparam > 1)
4183 n = (n + ei->rotate) % ei->nparam;
4184 tt = ei->params[n];
4186 cc = find_cc(tt);
4187 if (cc == -1) {
4188 error(ERR_NONFATAL,
4189 "macro parameter %d is not a condition code",
4190 n + 1);
4191 text = NULL;
4192 } else {
4193 type = TOK_ID;
4194 if (inverse_ccs[cc] == -1) {
4195 error(ERR_NONFATAL,
4196 "condition code `%s' is not invertible",
4197 conditions[cc]);
4198 text = NULL;
4199 } else
4200 text = nasm_strdup(conditions[inverse_ccs[cc]]);
4202 break;
4203 case '+':
4204 n = atoi(t->text + 2) - 1;
4205 if (n >= ei->nparam)
4206 tt = NULL;
4207 else {
4208 if (ei->nparam > 1)
4209 n = (n + ei->rotate) % ei->nparam;
4210 tt = ei->params[n];
4212 cc = find_cc(tt);
4213 if (cc == -1) {
4214 error(ERR_NONFATAL,
4215 "macro parameter %d is not a condition code",
4216 n + 1);
4217 text = NULL;
4218 } else {
4219 type = TOK_ID;
4220 text = nasm_strdup(conditions[cc]);
4222 break;
4223 default:
4224 n = atoi(t->text + 1) - 1;
4225 if (n >= ei->nparam)
4226 tt = NULL;
4227 else {
4228 if (ei->nparam > 1)
4229 n = (n + ei->rotate) % ei->nparam;
4230 tt = ei->params[n];
4232 if (tt) {
4233 for (i = 0; i < ei->paramlen[n]; i++) {
4234 *tail = new_Token(NULL, tt->type, tt->text, 0);
4235 tail = &(*tail)->next;
4236 tt = tt->next;
4239 text = NULL; /* we've done it here */
4240 break;
4242 } else {
4244 * seems we have a parameters range here
4246 Token *head, **last;
4247 head = expand_mmac_params_range(ei, t, &last);
4248 if (head != t) {
4249 *tail = head;
4250 *last = tline;
4251 tline = head;
4252 text = NULL;
4256 if (!text) {
4257 delete_Token(t);
4258 } else {
4259 *tail = t;
4260 tail = &t->next;
4261 t->type = type;
4262 nasm_free(t->text);
4263 t->text = text;
4264 t->a.mac = NULL;
4266 changed = true;
4267 continue;
4268 } else if (tline->type == TOK_INDIRECT) {
4269 t = tline;
4270 tline = tline->next;
4271 tt = tokenize(t->text);
4272 tt = expand_mmac_params(tt);
4273 tt = expand_smacro(tt);
4274 *tail = tt;
4275 while (tt) {
4276 tt->a.mac = NULL; /* Necessary? */
4277 tail = &tt->next;
4278 tt = tt->next;
4280 delete_Token(t);
4281 changed = true;
4282 } else {
4283 t = *tail = tline;
4284 tline = tline->next;
4285 t->a.mac = NULL;
4286 tail = &t->next;
4289 *tail = NULL;
4291 if (changed) {
4292 const struct tokseq_match t[] = {
4294 PP_CONCAT_MASK(TOK_ID) |
4295 PP_CONCAT_MASK(TOK_FLOAT), /* head */
4296 PP_CONCAT_MASK(TOK_ID) |
4297 PP_CONCAT_MASK(TOK_NUMBER) |
4298 PP_CONCAT_MASK(TOK_FLOAT) |
4299 PP_CONCAT_MASK(TOK_OTHER) /* tail */
4302 PP_CONCAT_MASK(TOK_NUMBER), /* head */
4303 PP_CONCAT_MASK(TOK_NUMBER) /* tail */
4306 paste_tokens(&thead, t, ARRAY_SIZE(t), false);
4309 return thead;
4313 * Expand all single-line macro calls made in the given line.
4314 * Return the expanded version of the line. The original is deemed
4315 * to be destroyed in the process. (In reality we'll just move
4316 * Tokens from input to output a lot of the time, rather than
4317 * actually bothering to destroy and replicate.)
4320 static Token *expand_smacro(Token * tline)
4322 Token *t, *tt, *mstart, **tail, *thead;
4323 SMacro *head = NULL, *m;
4324 Token **params;
4325 int *paramsize;
4326 unsigned int nparam, sparam;
4327 int brackets;
4328 Token *org_tline = tline;
4329 Context *ctx;
4330 const char *mname;
4331 int deadman = DEADMAN_LIMIT;
4332 bool expanded;
4335 * Trick: we should avoid changing the start token pointer since it can
4336 * be contained in "next" field of other token. Because of this
4337 * we allocate a copy of first token and work with it; at the end of
4338 * routine we copy it back
4340 if (org_tline) {
4341 tline = new_Token(org_tline->next, org_tline->type,
4342 org_tline->text, 0);
4343 tline->a.mac = org_tline->a.mac;
4344 nasm_free(org_tline->text);
4345 org_tline->text = NULL;
4348 expanded = true; /* Always expand %+ at least once */
4350 again:
4351 thead = NULL;
4352 tail = &thead;
4354 while (tline) { /* main token loop */
4355 if (!--deadman) {
4356 error(ERR_NONFATAL, "interminable macro recursion");
4357 goto err;
4360 if ((mname = tline->text)) {
4361 /* if this token is a local macro, look in local context */
4362 if (tline->type == TOK_ID) {
4363 head = (SMacro *)hash_findix(&smacros, mname);
4364 } else if (tline->type == TOK_PREPROC_ID) {
4365 ctx = get_ctx(mname, &mname, false);
4366 head = ctx ? (SMacro *)hash_findix(&ctx->localmac, mname) : NULL;
4367 } else
4368 head = NULL;
4371 * We've hit an identifier. As in is_mmacro below, we first
4372 * check whether the identifier is a single-line macro at
4373 * all, then think about checking for parameters if
4374 * necessary.
4376 list_for_each(m, head)
4377 if (!mstrcmp(m->name, mname, m->casesense))
4378 break;
4379 if (m) {
4380 mstart = tline;
4381 params = NULL;
4382 paramsize = NULL;
4383 if (m->nparam == 0) {
4385 * Simple case: the macro is parameterless. Discard the
4386 * one token that the macro call took, and push the
4387 * expansion back on the to-do stack.
4389 if (!m->expansion) {
4390 if (!strcmp("__FILE__", m->name)) {
4391 int32_t num = 0;
4392 char *file = NULL;
4393 src_get(&num, &file);
4394 tline->text = nasm_quote(file, strlen(file));
4395 tline->type = TOK_STRING;
4396 nasm_free(file);
4397 continue;
4399 if (!strcmp("__LINE__", m->name)) {
4400 nasm_free(tline->text);
4401 make_tok_num(tline, src_get_linnum());
4402 continue;
4404 if (!strcmp("__BITS__", m->name)) {
4405 nasm_free(tline->text);
4406 make_tok_num(tline, globalbits);
4407 continue;
4409 tline = delete_Token(tline);
4410 continue;
4412 } else {
4414 * Complicated case: at least one macro with this name
4415 * exists and takes parameters. We must find the
4416 * parameters in the call, count them, find the SMacro
4417 * that corresponds to that form of the macro call, and
4418 * substitute for the parameters when we expand. What a
4419 * pain.
4421 /*tline = tline->next;
4422 skip_white_(tline); */
4423 do {
4424 t = tline->next;
4425 while (tok_type_(t, TOK_SMAC_END)) {
4426 t->a.mac->in_progress = false;
4427 t->text = NULL;
4428 t = tline->next = delete_Token(t);
4430 tline = t;
4431 } while (tok_type_(tline, TOK_WHITESPACE));
4432 if (!tok_is_(tline, "(")) {
4434 * This macro wasn't called with parameters: ignore
4435 * the call. (Behaviour borrowed from gnu cpp.)
4437 tline = mstart;
4438 m = NULL;
4439 } else {
4440 int paren = 0;
4441 int white = 0;
4442 brackets = 0;
4443 nparam = 0;
4444 sparam = PARAM_DELTA;
4445 params = nasm_malloc(sparam * sizeof(Token *));
4446 params[0] = tline->next;
4447 paramsize = nasm_malloc(sparam * sizeof(int));
4448 paramsize[0] = 0;
4449 while (true) { /* parameter loop */
4451 * For some unusual expansions
4452 * which concatenates function call
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;
4462 if (!tline) {
4463 error(ERR_NONFATAL,
4464 "macro call expects terminating `)'");
4465 break;
4467 if (tline->type == TOK_WHITESPACE
4468 && brackets <= 0) {
4469 if (paramsize[nparam])
4470 white++;
4471 else
4472 params[nparam] = tline->next;
4473 continue; /* parameter loop */
4475 if (tline->type == TOK_OTHER
4476 && tline->text[1] == 0) {
4477 char ch = tline->text[0];
4478 if (ch == ',' && !paren && brackets <= 0) {
4479 if (++nparam >= sparam) {
4480 sparam += PARAM_DELTA;
4481 params = nasm_realloc(params,
4482 sparam * sizeof(Token *));
4483 paramsize = nasm_realloc(paramsize,
4484 sparam * sizeof(int));
4486 params[nparam] = tline->next;
4487 paramsize[nparam] = 0;
4488 white = 0;
4489 continue; /* parameter loop */
4491 if (ch == '{' &&
4492 (brackets > 0 || (brackets == 0 &&
4493 !paramsize[nparam])))
4495 if (!(brackets++)) {
4496 params[nparam] = tline->next;
4497 continue; /* parameter loop */
4500 if (ch == '}' && brackets > 0)
4501 if (--brackets == 0) {
4502 brackets = -1;
4503 continue; /* parameter loop */
4505 if (ch == '(' && !brackets)
4506 paren++;
4507 if (ch == ')' && brackets <= 0)
4508 if (--paren < 0)
4509 break;
4511 if (brackets < 0) {
4512 brackets = 0;
4513 error(ERR_NONFATAL, "braces do not "
4514 "enclose all of macro parameter");
4516 paramsize[nparam] += white + 1;
4517 white = 0;
4518 } /* parameter loop */
4519 nparam++;
4520 while (m && (m->nparam != nparam ||
4521 mstrcmp(m->name, mname,
4522 m->casesense)))
4523 m = m->next;
4524 if (!m)
4525 error(ERR_WARNING|ERR_PASS1|ERR_WARN_MNP,
4526 "macro `%s' exists, "
4527 "but not taking %d parameters",
4528 mstart->text, nparam);
4531 if (m && m->in_progress)
4532 m = NULL;
4533 if (!m) { /* in progess or didn't find '(' or wrong nparam */
4535 * Design question: should we handle !tline, which
4536 * indicates missing ')' here, or expand those
4537 * macros anyway, which requires the (t) test a few
4538 * lines down?
4540 nasm_free(params);
4541 nasm_free(paramsize);
4542 tline = mstart;
4543 } else {
4545 * Expand the macro: we are placed on the last token of the
4546 * call, so that we can easily split the call from the
4547 * following tokens. We also start by pushing an SMAC_END
4548 * token for the cycle removal.
4550 t = tline;
4551 if (t) {
4552 tline = t->next;
4553 t->next = NULL;
4555 tt = new_Token(tline, TOK_SMAC_END, NULL, 0);
4556 tt->a.mac = m;
4557 m->in_progress = true;
4558 tline = tt;
4559 list_for_each(t, m->expansion) {
4560 if (t->type >= TOK_SMAC_PARAM) {
4561 Token *pcopy = tline, **ptail = &pcopy;
4562 Token *ttt, *pt;
4563 int i;
4565 ttt = params[t->type - TOK_SMAC_PARAM];
4566 i = paramsize[t->type - TOK_SMAC_PARAM];
4567 while (--i >= 0) {
4568 pt = *ptail = new_Token(tline, ttt->type,
4569 ttt->text, 0);
4570 ptail = &pt->next;
4571 ttt = ttt->next;
4573 tline = pcopy;
4574 } else if (t->type == TOK_PREPROC_Q) {
4575 tt = new_Token(tline, TOK_ID, mname, 0);
4576 tline = tt;
4577 } else if (t->type == TOK_PREPROC_QQ) {
4578 tt = new_Token(tline, TOK_ID, m->name, 0);
4579 tline = tt;
4580 } else {
4581 tt = new_Token(tline, t->type, t->text, 0);
4582 tline = tt;
4587 * Having done that, get rid of the macro call, and clean
4588 * up the parameters.
4590 nasm_free(params);
4591 nasm_free(paramsize);
4592 free_tlist(mstart);
4593 expanded = true;
4594 continue; /* main token loop */
4599 if (tline->type == TOK_SMAC_END) {
4600 tline->a.mac->in_progress = false;
4601 tline = delete_Token(tline);
4602 } else {
4603 t = *tail = tline;
4604 tline = tline->next;
4605 t->a.mac = NULL;
4606 t->next = NULL;
4607 tail = &t->next;
4612 * Now scan the entire line and look for successive TOK_IDs that resulted
4613 * after expansion (they can't be produced by tokenize()). The successive
4614 * TOK_IDs should be concatenated.
4615 * Also we look for %+ tokens and concatenate the tokens before and after
4616 * them (without white spaces in between).
4618 if (expanded) {
4619 const struct tokseq_match t[] = {
4621 PP_CONCAT_MASK(TOK_ID) |
4622 PP_CONCAT_MASK(TOK_PREPROC_ID), /* head */
4623 PP_CONCAT_MASK(TOK_ID) |
4624 PP_CONCAT_MASK(TOK_PREPROC_ID) |
4625 PP_CONCAT_MASK(TOK_NUMBER) /* tail */
4628 if (paste_tokens(&thead, t, ARRAY_SIZE(t), true)) {
4630 * If we concatenated something, *and* we had previously expanded
4631 * an actual macro, scan the lines again for macros...
4633 tline = thead;
4634 expanded = false;
4635 goto again;
4639 err:
4640 if (org_tline) {
4641 if (thead) {
4642 *org_tline = *thead;
4643 /* since we just gave text to org_line, don't free it */
4644 thead->text = NULL;
4645 delete_Token(thead);
4646 } else {
4647 /* the expression expanded to empty line;
4648 we can't return NULL for some reasons
4649 we just set the line to a single WHITESPACE token. */
4650 memset(org_tline, 0, sizeof(*org_tline));
4651 org_tline->text = NULL;
4652 org_tline->type = TOK_WHITESPACE;
4654 thead = org_tline;
4657 return thead;
4661 * Similar to expand_smacro but used exclusively with macro identifiers
4662 * right before they are fetched in. The reason is that there can be
4663 * identifiers consisting of several subparts. We consider that if there
4664 * are more than one element forming the name, user wants a expansion,
4665 * otherwise it will be left as-is. Example:
4667 * %define %$abc cde
4669 * the identifier %$abc will be left as-is so that the handler for %define
4670 * will suck it and define the corresponding value. Other case:
4672 * %define _%$abc cde
4674 * In this case user wants name to be expanded *before* %define starts
4675 * working, so we'll expand %$abc into something (if it has a value;
4676 * otherwise it will be left as-is) then concatenate all successive
4677 * PP_IDs into one.
4679 static Token *expand_id(Token * tline)
4681 Token *cur, *oldnext = NULL;
4683 if (!tline || !tline->next)
4684 return tline;
4686 cur = tline;
4687 while (cur->next &&
4688 (cur->next->type == TOK_ID ||
4689 cur->next->type == TOK_PREPROC_ID
4690 || cur->next->type == TOK_NUMBER))
4691 cur = cur->next;
4693 /* If identifier consists of just one token, don't expand */
4694 if (cur == tline)
4695 return tline;
4697 if (cur) {
4698 oldnext = cur->next; /* Detach the tail past identifier */
4699 cur->next = NULL; /* so that expand_smacro stops here */
4702 tline = expand_smacro(tline);
4704 if (cur) {
4705 /* expand_smacro possibly changhed tline; re-scan for EOL */
4706 cur = tline;
4707 while (cur && cur->next)
4708 cur = cur->next;
4709 if (cur)
4710 cur->next = oldnext;
4713 return tline;
4717 * Determine whether the given line constitutes a multi-line macro
4718 * call, and return the ExpDef structure called if so. Doesn't have
4719 * to check for an initial label - that's taken care of in
4720 * expand_mmacro - but must check numbers of parameters. Guaranteed
4721 * to be called with tline->type == TOK_ID, so the putative macro
4722 * name is easy to find.
4724 static ExpDef *is_mmacro(Token * tline, Token *** params_array)
4726 ExpDef *head, *ed;
4727 Token **params;
4728 int nparam;
4730 head = (ExpDef *) hash_findix(&expdefs, tline->text);
4733 * Efficiency: first we see if any macro exists with the given
4734 * name. If not, we can return NULL immediately. _Then_ we
4735 * count the parameters, and then we look further along the
4736 * list if necessary to find the proper ExpDef.
4738 list_for_each(ed, head)
4739 if (!mstrcmp(ed->name, tline->text, ed->casesense))
4740 break;
4741 if (!ed)
4742 return NULL;
4745 * OK, we have a potential macro. Count and demarcate the
4746 * parameters.
4748 count_mmac_params(tline->next, &nparam, &params);
4751 * So we know how many parameters we've got. Find the ExpDef
4752 * structure that handles this number.
4754 while (ed) {
4755 if (ed->nparam_min <= nparam
4756 && (ed->plus || nparam <= ed->nparam_max)) {
4758 * It's right, and we can use it. Add its default
4759 * parameters to the end of our list if necessary.
4761 if (ed->defaults && nparam < ed->nparam_min + ed->ndefs) {
4762 params =
4763 nasm_realloc(params,
4764 ((ed->nparam_min + ed->ndefs +
4765 1) * sizeof(*params)));
4766 while (nparam < ed->nparam_min + ed->ndefs) {
4767 params[nparam] = ed->defaults[nparam - ed->nparam_min];
4768 nparam++;
4772 * If we've gone over the maximum parameter count (and
4773 * we're in Plus mode), ignore parameters beyond
4774 * nparam_max.
4776 if (ed->plus && nparam > ed->nparam_max)
4777 nparam = ed->nparam_max;
4779 * Then terminate the parameter list, and leave.
4781 if (!params) { /* need this special case */
4782 params = nasm_malloc(sizeof(*params));
4783 nparam = 0;
4785 params[nparam] = NULL;
4786 *params_array = params;
4787 return ed;
4790 * This one wasn't right: look for the next one with the
4791 * same name.
4793 list_for_each(ed, ed->next)
4794 if (!mstrcmp(ed->name, tline->text, ed->casesense))
4795 break;
4799 * After all that, we didn't find one with the right number of
4800 * parameters. Issue a warning, and fail to expand the macro.
4802 error(ERR_WARNING|ERR_PASS1|ERR_WARN_MNP,
4803 "macro `%s' exists, but not taking %d parameters",
4804 tline->text, nparam);
4805 nasm_free(params);
4806 return NULL;
4810 * Expand the multi-line macro call made by the given line, if
4811 * there is one to be expanded. If there is, push the expansion on
4812 * istk->expansion and return true. Otherwise return false.
4814 static bool expand_mmacro(Token * tline)
4816 Token *label = NULL;
4817 int dont_prepend = 0;
4818 Token **params, *t, *mtok;
4819 Line *l = NULL;
4820 ExpDef *ed;
4821 ExpInv *ei;
4822 int i, nparam, *paramlen;
4823 const char *mname;
4825 t = tline;
4826 skip_white_(t);
4827 /* if (!tok_type_(t, TOK_ID)) Lino 02/25/02 */
4828 if (!tok_type_(t, TOK_ID) && !tok_type_(t, TOK_PREPROC_ID))
4829 return false;
4830 mtok = t;
4831 ed = is_mmacro(t, &params);
4832 if (ed != NULL) {
4833 mname = t->text;
4834 } else {
4835 Token *last;
4837 * We have an id which isn't a macro call. We'll assume
4838 * it might be a label; we'll also check to see if a
4839 * colon follows it. Then, if there's another id after
4840 * that lot, we'll check it again for macro-hood.
4842 label = last = t;
4843 t = t->next;
4844 if (tok_type_(t, TOK_WHITESPACE))
4845 last = t, t = t->next;
4846 if (tok_is_(t, ":")) {
4847 dont_prepend = 1;
4848 last = t, t = t->next;
4849 if (tok_type_(t, TOK_WHITESPACE))
4850 last = t, t = t->next;
4852 if (!tok_type_(t, TOK_ID) || !(ed = is_mmacro(t, &params)))
4853 return false;
4854 last->next = NULL;
4855 mname = t->text;
4856 tline = t;
4860 * Fix up the parameters: this involves stripping leading and
4861 * trailing whitespace, then stripping braces if they are
4862 * present.
4864 for (nparam = 0; params[nparam]; nparam++) ;
4865 paramlen = nparam ? nasm_malloc(nparam * sizeof(*paramlen)) : NULL;
4867 for (i = 0; params[i]; i++) {
4868 int brace = false;
4869 int comma = (!ed->plus || i < nparam - 1);
4871 t = params[i];
4872 skip_white_(t);
4873 if (tok_is_(t, "{"))
4874 t = t->next, brace = true, comma = false;
4875 params[i] = t;
4876 paramlen[i] = 0;
4877 while (t) {
4878 if (comma && t->type == TOK_OTHER && !strcmp(t->text, ","))
4879 break; /* ... because we have hit a comma */
4880 if (comma && t->type == TOK_WHITESPACE
4881 && tok_is_(t->next, ","))
4882 break; /* ... or a space then a comma */
4883 if (brace && t->type == TOK_OTHER && !strcmp(t->text, "}"))
4884 break; /* ... or a brace */
4885 t = t->next;
4886 paramlen[i]++;
4890 if (ed->cur_depth >= ed->max_depth) {
4891 if (ed->max_depth > 1) {
4892 error(ERR_WARNING,
4893 "reached maximum macro recursion depth of %i for %s",
4894 ed->max_depth,ed->name);
4896 return false;
4897 } else {
4898 ed->cur_depth ++;
4902 * OK, we have found a ExpDef structure representing a
4903 * previously defined mmacro. Create an expansion invocation
4904 * and point it back to the expansion definition. Substitution of
4905 * parameter tokens and macro-local tokens doesn't get done
4906 * until the single-line macro substitution process; this is
4907 * because delaying them allows us to change the semantics
4908 * later through %rotate.
4910 ei = new_ExpInv(EXP_MMACRO, ed);
4911 ei->name = nasm_strdup(mname);
4912 //ei->label = label;
4913 //ei->label_text = detoken(label, false);
4914 ei->current = ed->line;
4915 ei->emitting = true;
4916 //ei->iline = tline;
4917 ei->params = params;
4918 ei->nparam = nparam;
4919 ei->rotate = 0;
4920 ei->paramlen = paramlen;
4921 ei->lineno = 0;
4923 ei->prev = istk->expansion;
4924 istk->expansion = ei;
4927 * Special case: detect %00 on first invocation; if found,
4928 * avoid emitting any labels that precede the mmacro call.
4929 * ed->prepend is set to -1 when %00 is detected, else 1.
4931 if (ed->prepend == 0) {
4932 for (l = ed->line; l != NULL; l = l->next) {
4933 for (t = l->first; t != NULL; t = t->next) {
4934 if ((t->type == TOK_PREPROC_ID) &&
4935 (strlen(t->text) == 3) &&
4936 (t->text[1] == '0') && (t->text[2] == '0')) {
4937 dont_prepend = -1;
4938 break;
4941 if (dont_prepend < 0) {
4942 break;
4945 ed->prepend = ((dont_prepend < 0) ? -1 : 1);
4949 * If we had a label, push it on as the first line of
4950 * the macro expansion.
4952 if (label != NULL) {
4953 if (ed->prepend < 0) {
4954 ei->label_text = detoken(label, false);
4955 } else {
4956 if (dont_prepend == 0) {
4957 t = label;
4958 while (t->next != NULL) {
4959 t = t->next;
4961 t->next = new_Token(NULL, TOK_OTHER, ":", 0);
4963 l = new_Line();
4964 l->first = copy_Token(label);
4965 l->next = ei->current;
4966 ei->current = l;
4970 list->uplevel(ed->nolist ? LIST_MACRO_NOLIST : LIST_MACRO);
4972 istk->mmac_depth++;
4973 return true;
4976 /* The function that actually does the error reporting */
4977 static void verror(int severity, const char *fmt, va_list arg)
4979 char buff[1024];
4981 vsnprintf(buff, sizeof(buff), fmt, arg);
4983 if (istk && istk->mmac_depth > 0) {
4984 ExpInv *ei = istk->expansion;
4985 int lineno = ei->lineno;
4986 while (ei) {
4987 if (ei->type == EXP_MMACRO)
4988 break;
4989 lineno += ei->relno;
4990 ei = ei->prev;
4992 nasm_error(severity, "(%s:%d) %s", ei->def->name,
4993 lineno, buff);
4994 } else
4995 nasm_error(severity, "%s", buff);
4999 * Since preprocessor always operate only on the line that didn't
5000 * arrived yet, we should always use ERR_OFFBY1.
5002 static void error(int severity, const char *fmt, ...)
5004 va_list arg;
5005 va_start(arg, fmt);
5006 verror(severity, fmt, arg);
5007 va_end(arg);
5011 * Because %else etc are evaluated in the state context
5012 * of the previous branch, errors might get lost with error():
5013 * %if 0 ... %else trailing garbage ... %endif
5014 * So %else etc should report errors with this function.
5016 static void error_precond(int severity, const char *fmt, ...)
5018 va_list arg;
5020 /* Only ignore the error if it's really in a dead branch */
5021 if ((istk != NULL) &&
5022 (istk->expansion != NULL) &&
5023 (istk->expansion->type == EXP_IF) &&
5024 (istk->expansion->def->state == COND_NEVER))
5025 return;
5027 va_start(arg, fmt);
5028 verror(severity, fmt, arg);
5029 va_end(arg);
5032 static void
5033 pp_reset(char *file, int apass, ListGen * listgen, StrList **deplist)
5035 Token *t;
5037 cstk = NULL;
5038 istk = nasm_malloc(sizeof(Include));
5039 istk->next = NULL;
5040 istk->expansion = NULL;
5041 istk->fp = fopen(file, "r");
5042 istk->fname = NULL;
5043 src_set_fname(nasm_strdup(file));
5044 src_set_linnum(0);
5045 istk->lineinc = 1;
5046 istk->mmac_depth = 0;
5047 if (!istk->fp)
5048 error(ERR_FATAL|ERR_NOFILE, "unable to open input file `%s'",
5049 file);
5050 defining = NULL;
5051 finals = NULL;
5052 in_final = false;
5053 nested_mac_count = 0;
5054 nested_rep_count = 0;
5055 init_macros();
5056 unique = 0;
5057 if (tasm_compatible_mode) {
5058 stdmacpos = nasm_stdmac;
5059 } else {
5060 stdmacpos = nasm_stdmac_after_tasm;
5062 any_extrastdmac = extrastdmac && *extrastdmac;
5063 do_predef = true;
5064 list = listgen;
5067 * 0 for dependencies, 1 for preparatory passes, 2 for final pass.
5068 * The caller, however, will also pass in 3 for preprocess-only so
5069 * we can set __PASS__ accordingly.
5071 pass = apass > 2 ? 2 : apass;
5073 dephead = deptail = deplist;
5074 if (deplist) {
5075 StrList *sl = nasm_malloc(strlen(file)+1+sizeof sl->next);
5076 sl->next = NULL;
5077 strcpy(sl->str, file);
5078 *deptail = sl;
5079 deptail = &sl->next;
5083 * Define the __PASS__ macro. This is defined here unlike
5084 * all the other builtins, because it is special -- it varies between
5085 * passes.
5087 t = nasm_malloc(sizeof(*t));
5088 t->next = NULL;
5089 make_tok_num(t, apass);
5090 t->a.mac = NULL;
5091 define_smacro(NULL, "__PASS__", true, 0, t);
5094 static char *pp_getline(void)
5096 char *line;
5097 Token *tline;
5098 ExpDef *ed;
5099 ExpInv *ei;
5100 Line *l;
5101 int j;
5103 while (1) {
5105 * Fetch a tokenized line, either from the expansion
5106 * buffer or from the input file.
5108 tline = NULL;
5110 while (1) { /* until we get a line we can use */
5112 * Fetch a tokenized line from the expansion buffer
5114 if (istk->expansion != NULL) {
5115 ei = istk->expansion;
5116 if (ei->current != NULL) {
5117 if (ei->emitting == false) {
5118 ei->current = NULL;
5119 continue;
5121 l = ei->current;
5122 ei->current = l->next;
5123 ei->lineno++;
5124 tline = copy_Token(l->first);
5125 if (((ei->type == EXP_REP) ||
5126 (ei->type == EXP_MMACRO) ||
5127 (ei->type == EXP_WHILE))
5128 && (ei->def->nolist == false)) {
5129 char *p = detoken(tline, false);
5130 list->line(LIST_MACRO, p);
5131 nasm_free(p);
5133 if (ei->linnum > -1) {
5134 src_set_linnum(src_get_linnum() + 1);
5136 break;
5137 } else if ((ei->type == EXP_REP) &&
5138 (ei->def->cur_depth < ei->def->max_depth)) {
5139 ei->def->cur_depth ++;
5140 ei->current = ei->def->line;
5141 ei->lineno = 0;
5142 continue;
5143 } else if ((ei->type == EXP_WHILE) &&
5144 (ei->def->cur_depth < ei->def->max_depth)) {
5145 ei->current = ei->def->line;
5146 ei->lineno = 0;
5147 tline = copy_Token(ei->current->first);
5148 j = if_condition(tline, PP_WHILE);
5149 tline = NULL;
5150 j = (((j < 0) ? COND_NEVER : j) ? COND_IF_TRUE : COND_IF_FALSE);
5151 if (j == COND_IF_TRUE) {
5152 ei->current = ei->current->next;
5153 ei->def->cur_depth ++;
5154 } else {
5155 ei->emitting = false;
5156 ei->current = NULL;
5157 ei->def->cur_depth = ei->def->max_depth;
5159 continue;
5160 } else {
5161 istk->expansion = ei->prev;
5162 ed = ei->def;
5163 if (ed != NULL) {
5164 if ((ei->emitting == true) &&
5165 (ed->max_depth == DEADMAN_LIMIT) &&
5166 (ed->cur_depth == DEADMAN_LIMIT)
5168 error(ERR_FATAL, "runaway expansion detected, aborting");
5170 if (ed->cur_depth > 0) {
5171 ed->cur_depth --;
5172 } else if ((ed->type != EXP_MMACRO) && (ed->type != EXP_IF)) {
5173 /***** should this really be right here??? *****/
5175 Line *l = NULL, *ll = NULL;
5176 for (l = ed->line; l != NULL;) {
5177 if (l->first != NULL) {
5178 free_tlist(l->first);
5179 l->first = NULL;
5181 ll = l;
5182 l = l->next;
5183 nasm_free(ll);
5185 expansions = ed->prev;
5186 nasm_free(ed);
5189 if ((ei->type == EXP_REP) ||
5190 (ei->type == EXP_MMACRO) ||
5191 (ei->type == EXP_WHILE)) {
5192 list->downlevel(LIST_MACRO);
5193 if (ei->type == EXP_MMACRO) {
5194 istk->mmac_depth--;
5198 if (ei->linnum > -1) {
5199 src_set_linnum(ei->linnum);
5201 free_expinv(ei);
5202 continue;
5207 * Read in line from input and tokenize
5209 line = read_line();
5210 if (line) { /* from the current input file */
5211 line = prepreproc(line);
5212 tline = tokenize(line);
5213 nasm_free(line);
5214 break;
5218 * The current file has ended; work down the istk
5221 Include *i = istk;
5222 fclose(i->fp);
5223 if (i->expansion != NULL) {
5224 error(ERR_FATAL,
5225 "end of file while still in an expansion");
5227 /* only set line and file name if there's a next node */
5228 if (i->next) {
5229 src_set_linnum(i->lineno);
5230 nasm_free(src_set_fname(i->fname));
5232 if ((i->next == NULL) && (finals != NULL)) {
5233 in_final = true;
5234 ei = new_ExpInv(EXP_FINAL, NULL);
5235 ei->emitting = true;
5236 ei->current = finals;
5237 istk->expansion = ei;
5238 finals = NULL;
5239 continue;
5241 istk = i->next;
5242 list->downlevel(LIST_INCLUDE);
5243 nasm_free(i);
5244 if (istk == NULL) {
5245 if (finals != NULL) {
5246 in_final = true;
5247 } else {
5248 return NULL;
5251 continue;
5255 if (defining == NULL) {
5256 tline = expand_mmac_params(tline);
5260 * Check the line to see if it's a preprocessor directive.
5262 if (do_directive(tline) == DIRECTIVE_FOUND) {
5263 continue;
5264 } else if (defining != NULL) {
5266 * We're defining an expansion. We emit nothing at all,
5267 * and just shove the tokenized line on to the definition.
5269 if (defining->ignoring == false) {
5270 Line *l = new_Line();
5271 l->first = tline;
5272 if (defining->line == NULL) {
5273 defining->line = l;
5274 defining->last = l;
5275 } else {
5276 defining->last->next = l;
5277 defining->last = l;
5279 } else {
5280 //free_tlist(tline); /***** sanity check: is this supposed to be here? *****/
5282 defining->linecount++;
5283 continue;
5284 } else if ((istk->expansion != NULL) &&
5285 (istk->expansion->emitting != true)) {
5287 * We're in a non-emitting branch of an expansion.
5288 * Emit nothing at all, not even a blank line: when we
5289 * emerge from the expansion we'll give a line-number
5290 * directive so we keep our place correctly.
5292 free_tlist(tline);
5293 continue;
5294 } else {
5295 tline = expand_smacro(tline);
5296 if (expand_mmacro(tline) != true) {
5298 * De-tokenize the line again, and emit it.
5300 line = detoken(tline, true);
5301 free_tlist(tline);
5302 break;
5303 } else {
5304 continue;
5308 return line;
5311 static void pp_cleanup(int pass)
5313 if (defining != NULL) {
5314 error(ERR_NONFATAL, "end of file while still defining an expansion");
5315 while (defining != NULL) {
5316 ExpDef *ed = defining;
5317 defining = ed->prev;
5318 free_expdef(ed);
5320 defining = NULL;
5322 while (cstk != NULL)
5323 ctx_pop();
5324 free_macros();
5325 while (istk != NULL) {
5326 Include *i = istk;
5327 istk = istk->next;
5328 fclose(i->fp);
5329 nasm_free(i->fname);
5330 nasm_free(i);
5331 while (i->expansion != NULL) {
5332 ExpInv *ei = i->expansion;
5333 i->expansion = ei->prev;
5334 free_expinv(ei);
5337 while (cstk)
5338 ctx_pop();
5339 nasm_free(src_set_fname(NULL));
5340 if (pass == 0) {
5341 IncPath *i;
5342 free_llist(predef);
5343 delete_Blocks();
5344 while ((i = ipath)) {
5345 ipath = i->next;
5346 if (i->path)
5347 nasm_free(i->path);
5348 nasm_free(i);
5353 void pp_include_path(char *path)
5355 IncPath *i;
5357 i = nasm_malloc(sizeof(IncPath));
5358 i->path = path ? nasm_strdup(path) : NULL;
5359 i->next = NULL;
5361 if (ipath) {
5362 IncPath *j = ipath;
5363 while (j->next)
5364 j = j->next;
5365 j->next = i;
5366 } else {
5367 ipath = i;
5371 void pp_pre_include(char *fname)
5373 Token *inc, *space, *name;
5374 Line *l;
5376 name = new_Token(NULL, TOK_INTERNAL_STRING, fname, 0);
5377 space = new_Token(name, TOK_WHITESPACE, NULL, 0);
5378 inc = new_Token(space, TOK_PREPROC_ID, "%include", 0);
5380 l = new_Line();
5381 l->next = predef;
5382 l->first = inc;
5383 predef = l;
5386 void pp_pre_define(char *definition)
5388 Token *def, *space;
5389 Line *l;
5390 char *equals;
5392 equals = strchr(definition, '=');
5393 space = new_Token(NULL, TOK_WHITESPACE, NULL, 0);
5394 def = new_Token(space, TOK_PREPROC_ID, "%define", 0);
5395 if (equals)
5396 *equals = ' ';
5397 space->next = tokenize(definition);
5398 if (equals)
5399 *equals = '=';
5401 l = new_Line();
5402 l->next = predef;
5403 l->first = def;
5404 predef = l;
5407 void pp_pre_undefine(char *definition)
5409 Token *def, *space;
5410 Line *l;
5412 space = new_Token(NULL, TOK_WHITESPACE, NULL, 0);
5413 def = new_Token(space, TOK_PREPROC_ID, "%undef", 0);
5414 space->next = tokenize(definition);
5416 l = new_Line();
5417 l->next = predef;
5418 l->first = def;
5419 predef = l;
5423 * This function is used to assist with "runtime" preprocessor
5424 * directives, e.g. pp_runtime("%define __BITS__ 64");
5426 * ERRORS ARE IGNORED HERE, SO MAKE COMPLETELY SURE THAT YOU
5427 * PASS A VALID STRING TO THIS FUNCTION!!!!!
5430 void pp_runtime(char *definition)
5432 Token *def;
5434 def = tokenize(definition);
5435 if (do_directive(def) == NO_DIRECTIVE_FOUND)
5436 free_tlist(def);
5440 void pp_extra_stdmac(macros_t *macros)
5442 extrastdmac = macros;
5445 static void make_tok_num(Token * tok, int64_t val)
5447 char numbuf[20];
5448 snprintf(numbuf, sizeof(numbuf), "%"PRId64"", val);
5449 tok->text = nasm_strdup(numbuf);
5450 tok->type = TOK_NUMBER;
5453 Preproc nasmpp = {
5454 pp_reset,
5455 pp_getline,
5456 pp_cleanup