Merge branch 'new-preproc'
[platform/upstream/nasm.git] / stdscan.c
1 /* ----------------------------------------------------------------------- *
2  *   
3  *   Copyright 1996-2009 The NASM Authors - All Rights Reserved
4  *   See the file AUTHORS included with the NASM distribution for
5  *   the specific copyright holders.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following
9  *   conditions are met:
10  *
11  *   * Redistributions of source code must retain the above copyright
12  *     notice, this list of conditions and the following disclaimer.
13  *   * Redistributions in binary form must reproduce the above
14  *     copyright notice, this list of conditions and the following
15  *     disclaimer in the documentation and/or other materials provided
16  *     with the distribution.
17  *     
18  *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19  *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20  *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21  *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23  *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26  *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  * ----------------------------------------------------------------------- */
33
34 #include "compiler.h"
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <ctype.h>
40 #include <inttypes.h>
41
42 #include "nasm.h"
43 #include "nasmlib.h"
44 #include "quote.h"
45 #include "stdscan.h"
46 #include "insns.h"
47
48 /*
49  * Standard scanner routine used by parser.c and some output
50  * formats. It keeps a succession of temporary-storage strings in
51  * stdscan_tempstorage, which can be cleared using stdscan_reset.
52  */
53 static char **stdscan_tempstorage = NULL;
54 static int stdscan_tempsize = 0, stdscan_templen = 0;
55 #define STDSCAN_TEMP_DELTA 256
56
57 static void stdscan_pop(void)
58 {
59     nasm_free(stdscan_tempstorage[--stdscan_templen]);
60 }
61
62 void stdscan_reset(void)
63 {
64     while (stdscan_templen > 0)
65         stdscan_pop();
66 }
67
68 /*
69  * Unimportant cleanup is done to avoid confusing people who are trying
70  * to debug real memory leaks
71  */
72 void stdscan_cleanup(void)
73 {
74     stdscan_reset();
75     nasm_free(stdscan_tempstorage);
76 }
77
78 static char *stdscan_copy(char *p, int len)
79 {
80     char *text;
81
82     text = nasm_malloc(len + 1);
83     memcpy(text, p, len);
84     text[len] = '\0';
85
86     if (stdscan_templen >= stdscan_tempsize) {
87         stdscan_tempsize += STDSCAN_TEMP_DELTA;
88         stdscan_tempstorage = nasm_realloc(stdscan_tempstorage,
89                                            stdscan_tempsize *
90                                            sizeof(char *));
91     }
92     stdscan_tempstorage[stdscan_templen++] = text;
93
94     return text;
95 }
96
97 char *stdscan_bufptr = NULL;
98 int stdscan(void *private_data, struct tokenval *tv)
99 {
100     char ourcopy[MAX_KEYWORD + 1], *r, *s;
101
102     (void)private_data;         /* Don't warn that this parameter is unused */
103
104     while (nasm_isspace(*stdscan_bufptr))
105         stdscan_bufptr++;
106     if (!*stdscan_bufptr)
107         return tv->t_type = 0;
108
109     /* we have a token; either an id, a number or a char */
110     if (isidstart(*stdscan_bufptr) ||
111         (*stdscan_bufptr == '$' && isidstart(stdscan_bufptr[1]))) {
112         /* now we've got an identifier */
113         bool is_sym = false;
114
115         if (*stdscan_bufptr == '$') {
116             is_sym = true;
117             stdscan_bufptr++;
118         }
119
120         r = stdscan_bufptr++;
121         /* read the entire buffer to advance the buffer pointer but... */
122         while (isidchar(*stdscan_bufptr))
123             stdscan_bufptr++;
124
125         /* ... copy only up to IDLEN_MAX-1 characters */
126         tv->t_charptr = stdscan_copy(r, stdscan_bufptr - r < IDLEN_MAX ?
127                                      stdscan_bufptr - r : IDLEN_MAX - 1);
128
129         if (is_sym || stdscan_bufptr - r > MAX_KEYWORD)
130             return tv->t_type = TOKEN_ID;       /* bypass all other checks */
131
132         for (s = tv->t_charptr, r = ourcopy; *s; s++)
133             *r++ = nasm_tolower(*s);
134         *r = '\0';
135         /* right, so we have an identifier sitting in temp storage. now,
136          * is it actually a register or instruction name, or what? */
137         return nasm_token_hash(ourcopy, tv);
138     } else if (*stdscan_bufptr == '$' && !isnumchar(stdscan_bufptr[1])) {
139         /*
140          * It's a $ sign with no following hex number; this must
141          * mean it's a Here token ($), evaluating to the current
142          * assembly location, or a Base token ($$), evaluating to
143          * the base of the current segment.
144          */
145         stdscan_bufptr++;
146         if (*stdscan_bufptr == '$') {
147             stdscan_bufptr++;
148             return tv->t_type = TOKEN_BASE;
149         }
150         return tv->t_type = TOKEN_HERE;
151     } else if (isnumstart(*stdscan_bufptr)) {   /* now we've got a number */
152         bool rn_error;
153         bool is_hex = false;
154         bool is_float = false;
155         bool has_e = false;
156         char c;
157
158         r = stdscan_bufptr;
159
160         if (*stdscan_bufptr == '$') {
161             stdscan_bufptr++;
162             is_hex = true;
163         }
164
165         for (;;) {
166             c = *stdscan_bufptr++;
167
168             if (!is_hex && (c == 'e' || c == 'E')) {
169                 has_e = true;
170                 if (*stdscan_bufptr == '+' || *stdscan_bufptr == '-') {
171                     /* e can only be followed by +/- if it is either a
172                        prefixed hex number or a floating-point number */
173                     is_float = true;
174                     stdscan_bufptr++;
175                 }
176             } else if (c == 'H' || c == 'h' || c == 'X' || c == 'x') {
177                 is_hex = true;
178             } else if (c == 'P' || c == 'p') {
179                 is_float = true;
180                 if (*stdscan_bufptr == '+' || *stdscan_bufptr == '-')
181                     stdscan_bufptr++;
182             } else if (isnumchar(c) || c == '_')
183                 ; /* just advance */
184             else if (c == '.')
185                 is_float = true;
186             else
187                 break;
188         }
189         stdscan_bufptr--;       /* Point to first character beyond number */
190
191         if (has_e && !is_hex) {
192             /* 1e13 is floating-point, but 1e13h is not */
193             is_float = true;
194         }
195
196         if (is_float) {
197             tv->t_charptr = stdscan_copy(r, stdscan_bufptr - r);
198             return tv->t_type = TOKEN_FLOAT;
199         } else {
200             r = stdscan_copy(r, stdscan_bufptr - r);
201             tv->t_integer = readnum(r, &rn_error);
202             stdscan_pop();
203             if (rn_error) {
204                 /* some malformation occurred */
205                 return tv->t_type = TOKEN_ERRNUM;
206             }
207             tv->t_charptr = NULL;
208             return tv->t_type = TOKEN_NUM;
209         }
210     } else if (*stdscan_bufptr == '\'' || *stdscan_bufptr == '"' ||
211                *stdscan_bufptr == '`') {
212         /* a quoted string */
213         char start_quote = *stdscan_bufptr;
214         tv->t_charptr = stdscan_bufptr;
215         tv->t_inttwo = nasm_unquote(tv->t_charptr, &stdscan_bufptr);
216         if (*stdscan_bufptr != start_quote)
217             return tv->t_type = TOKEN_ERRSTR;
218         stdscan_bufptr++;       /* Skip final quote */
219         return tv->t_type = TOKEN_STR;
220     } else if (*stdscan_bufptr == ';') {
221         /* a comment has happened - stay */
222         return tv->t_type = 0;
223     } else if (stdscan_bufptr[0] == '>' && stdscan_bufptr[1] == '>') {
224         stdscan_bufptr += 2;
225         return tv->t_type = TOKEN_SHR;
226     } else if (stdscan_bufptr[0] == '<' && stdscan_bufptr[1] == '<') {
227         stdscan_bufptr += 2;
228         return tv->t_type = TOKEN_SHL;
229     } else if (stdscan_bufptr[0] == '/' && stdscan_bufptr[1] == '/') {
230         stdscan_bufptr += 2;
231         return tv->t_type = TOKEN_SDIV;
232     } else if (stdscan_bufptr[0] == '%' && stdscan_bufptr[1] == '%') {
233         stdscan_bufptr += 2;
234         return tv->t_type = TOKEN_SMOD;
235     } else if (stdscan_bufptr[0] == '=' && stdscan_bufptr[1] == '=') {
236         stdscan_bufptr += 2;
237         return tv->t_type = TOKEN_EQ;
238     } else if (stdscan_bufptr[0] == '<' && stdscan_bufptr[1] == '>') {
239         stdscan_bufptr += 2;
240         return tv->t_type = TOKEN_NE;
241     } else if (stdscan_bufptr[0] == '!' && stdscan_bufptr[1] == '=') {
242         stdscan_bufptr += 2;
243         return tv->t_type = TOKEN_NE;
244     } else if (stdscan_bufptr[0] == '<' && stdscan_bufptr[1] == '=') {
245         stdscan_bufptr += 2;
246         return tv->t_type = TOKEN_LE;
247     } else if (stdscan_bufptr[0] == '>' && stdscan_bufptr[1] == '=') {
248         stdscan_bufptr += 2;
249         return tv->t_type = TOKEN_GE;
250     } else if (stdscan_bufptr[0] == '&' && stdscan_bufptr[1] == '&') {
251         stdscan_bufptr += 2;
252         return tv->t_type = TOKEN_DBL_AND;
253     } else if (stdscan_bufptr[0] == '^' && stdscan_bufptr[1] == '^') {
254         stdscan_bufptr += 2;
255         return tv->t_type = TOKEN_DBL_XOR;
256     } else if (stdscan_bufptr[0] == '|' && stdscan_bufptr[1] == '|') {
257         stdscan_bufptr += 2;
258         return tv->t_type = TOKEN_DBL_OR;
259     } else                      /* just an ordinary char */
260         return tv->t_type = (uint8_t)(*stdscan_bufptr++);
261 }