]>
Commit | Line | Data |
---|---|---|
004cb263 NB |
1 | /* CPP Library - traditional lexical analysis and macro expansion. |
2 | Copyright (C) 2002 Free Software Foundation, Inc. | |
3 | Contributed by Neil Booth, May 2002 | |
4 | ||
5 | This program is free software; you can redistribute it and/or modify it | |
6 | under the terms of the GNU General Public License as published by the | |
7 | Free Software Foundation; either version 2, or (at your option) any | |
8 | later version. | |
9 | ||
10 | This program is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | GNU General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU General Public License | |
16 | along with this program; if not, write to the Free Software | |
17 | Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |
18 | ||
19 | #include "config.h" | |
20 | #include "system.h" | |
21 | #include "cpplib.h" | |
22 | #include "cpphash.h" | |
23 | ||
c70f6ed3 NB |
24 | /* The replacement text of a function-like macro is stored as a |
25 | contiguous sequence of aligned blocks. Each block represents the | |
26 | portion of text from the start of the previous block (or the start | |
27 | of the macro replacement text in the case of the first block) to | |
28 | the next parameter, or the end of the replacement list if there | |
29 | are none left. | |
30 | ||
31 | Each block consists of an unsigned int, which is the length of text | |
32 | contained in the third part, an unsigned short, which is the | |
33 | one-based index of the argument that immediately follows that text, | |
34 | and the text itself. The final block in the macro expansion is | |
35 | recognizable as it has an argument index of zero. */ | |
36 | ||
37 | struct block | |
38 | { | |
39 | unsigned int text_len; | |
40 | unsigned short arg_index; | |
41 | uchar text[1]; | |
42 | }; | |
43 | ||
44 | #define BLOCK_HEADER_LEN offsetof (struct block, text) | |
45 | #define BLOCK_LEN(TEXT_LEN) CPP_ALIGN (BLOCK_HEADER_LEN + TEXT_LEN) | |
46 | ||
1ce676a0 NB |
47 | /* Structure holding information about a function-like macro |
48 | invocation. */ | |
49 | struct fun_macro | |
50 | { | |
51 | /* Memory buffer holding the trad_arg array. */ | |
52 | _cpp_buff *buff; | |
53 | ||
54 | /* An array of size the number of macro parameters + 1, containing | |
55 | the offsets of the start of each macro argument in the output | |
56 | buffer. The argument continues until the character before the | |
57 | start of the next one. */ | |
58 | size_t *args; | |
59 | ||
60 | /* The hashnode of the macro. */ | |
61 | cpp_hashnode *node; | |
62 | ||
63 | /* The offset of the macro name in the output buffer. */ | |
64 | size_t offset; | |
65 | ||
66 | /* Zero-based index of argument being currently lexed. */ | |
67 | unsigned int argc; | |
68 | }; | |
69 | ||
43612ffb NB |
70 | /* Lexing TODO: Handle -C, maybe -CC, and space in escaped newlines. |
71 | Stop cpplex.c from recognizing comments and directives during its | |
cbc69f84 NB |
72 | lexing pass. Get rid of line_base usage - seems pointless? Do we |
73 | get escaped newline at EOF correct? */ | |
004cb263 NB |
74 | |
75 | static const uchar *handle_newline PARAMS ((cpp_reader *, const uchar *)); | |
76 | static const uchar *skip_escaped_newlines PARAMS ((cpp_reader *, | |
77 | const uchar *)); | |
cbc69f84 | 78 | static const uchar *skip_whitespace PARAMS ((cpp_reader *, const uchar *)); |
004cb263 NB |
79 | static cpp_hashnode *lex_identifier PARAMS ((cpp_reader *, const uchar *)); |
80 | static const uchar *skip_comment PARAMS ((cpp_reader *, const uchar *)); | |
c70f6ed3 | 81 | static void scan_out_logical_line PARAMS ((cpp_reader *pfile, cpp_macro *)); |
004cb263 | 82 | static void check_output_buffer PARAMS ((cpp_reader *, size_t)); |
cbc69f84 | 83 | static void push_replacement_text PARAMS ((cpp_reader *, cpp_hashnode *)); |
c70f6ed3 | 84 | static bool scan_parameters PARAMS ((cpp_reader *, cpp_macro *)); |
974c43f1 | 85 | static bool recursive_macro PARAMS ((cpp_reader *, cpp_hashnode *)); |
c70f6ed3 NB |
86 | static void save_replacement_text PARAMS ((cpp_reader *, cpp_macro *, |
87 | unsigned int)); | |
1ce676a0 NB |
88 | static void maybe_start_funlike PARAMS ((cpp_reader *, cpp_hashnode *, |
89 | const uchar *, struct fun_macro *)); | |
90 | static void save_argument PARAMS ((struct fun_macro *, size_t)); | |
91 | static void replace_args_and_push PARAMS ((cpp_reader *, struct fun_macro *)); | |
6618c5d4 NB |
92 | static size_t canonicalize_text PARAMS ((uchar *, const uchar *, size_t, |
93 | uchar *)); | |
004cb263 NB |
94 | |
95 | /* Ensures we have N bytes' space in the output buffer, and | |
96 | reallocates it if not. */ | |
97 | static void | |
98 | check_output_buffer (pfile, n) | |
99 | cpp_reader *pfile; | |
100 | size_t n; | |
101 | { | |
1a76916c | 102 | if (n > (size_t) (pfile->out.limit - pfile->out.cur)) |
004cb263 | 103 | { |
1a76916c | 104 | size_t size = pfile->out.cur - pfile->out.base; |
004cb263 NB |
105 | size_t new_size = (size + n) * 3 / 2; |
106 | ||
1a76916c NB |
107 | pfile->out.base |
108 | = (uchar *) xrealloc (pfile->out.base, new_size); | |
109 | pfile->out.limit = pfile->out.base + new_size; | |
110 | pfile->out.cur = pfile->out.base + size; | |
004cb263 NB |
111 | } |
112 | } | |
113 | ||
114 | /* To be called whenever a newline character is encountered in the | |
115 | input file, at CUR. Handles DOS, MAC and Unix ends of line, and | |
116 | returns the character after the newline sequence. */ | |
117 | static const uchar * | |
118 | handle_newline (pfile, cur) | |
119 | cpp_reader *pfile; | |
120 | const uchar *cur; | |
121 | { | |
122 | pfile->line++; | |
123 | if (cur[0] + cur[1] == '\r' + '\n') | |
124 | cur++; | |
43612ffb | 125 | pfile->buffer->line_base = cur + 1; |
004cb263 NB |
126 | return cur + 1; |
127 | } | |
128 | ||
129 | /* CUR points to any character in the buffer, not necessarily a | |
130 | backslash. Advances CUR until all escaped newlines are skipped, | |
131 | and returns the new position. */ | |
132 | static const uchar * | |
133 | skip_escaped_newlines (pfile, cur) | |
134 | cpp_reader *pfile; | |
135 | const uchar *cur; | |
136 | { | |
137 | while (*cur == '\\' && is_vspace (cur[1])) | |
138 | cur = handle_newline (pfile, cur + 1); | |
139 | ||
140 | return cur; | |
141 | } | |
142 | ||
143 | /* CUR points to the character after the asterisk introducing a | |
144 | comment. Returns the position after the comment. */ | |
145 | static const uchar * | |
146 | skip_comment (pfile, cur) | |
147 | cpp_reader *pfile; | |
148 | const uchar *cur; | |
149 | { | |
150 | unsigned int from_line = pfile->line; | |
82eda77e NB |
151 | unsigned int c = 0, prevc = 0; |
152 | const uchar *limit = RLIMIT (pfile->context); | |
004cb263 | 153 | |
43612ffb | 154 | while (cur < limit) |
004cb263 | 155 | { |
43612ffb NB |
156 | prevc = c; |
157 | c = *cur++; | |
158 | ||
159 | if (c == '/') | |
004cb263 | 160 | { |
43612ffb NB |
161 | if (prevc == '*') |
162 | break; | |
163 | if (*cur == '*' && cur[1] != '/' | |
164 | && CPP_OPTION (pfile, warn_comments)) | |
165 | cpp_error_with_line (pfile, DL_WARNING, pfile->line, 0, | |
166 | "\"/*\" within comment"); | |
004cb263 NB |
167 | } |
168 | else if (is_vspace (c)) | |
169 | cur = handle_newline (pfile, cur - 1); | |
004cb263 NB |
170 | } |
171 | ||
43612ffb NB |
172 | if (c != '/' || prevc != '*') |
173 | cpp_error_with_line (pfile, DL_ERROR, from_line, 0, | |
174 | "unterminated comment"); | |
175 | ||
004cb263 NB |
176 | return cur; |
177 | } | |
178 | ||
cbc69f84 NB |
179 | /* Skip any horizontal whitespace and comments beginning at CUR, |
180 | returning the following character. */ | |
181 | static const uchar * | |
182 | skip_whitespace (pfile, cur) | |
183 | cpp_reader *pfile; | |
184 | const uchar *cur; | |
185 | { | |
186 | const uchar *tmp; | |
187 | ||
188 | for (;;) | |
189 | { | |
190 | while (is_nvspace (*cur) && *cur != 0) | |
191 | cur++; | |
192 | ||
193 | if (*cur == '\0' && cur != RLIMIT (pfile->context)) | |
194 | continue; | |
195 | ||
196 | if (*cur == '\\') | |
197 | { | |
198 | tmp = cur; | |
199 | cur = skip_escaped_newlines (pfile, cur); | |
200 | if (tmp != cur) | |
201 | continue; | |
202 | } | |
203 | ||
204 | if (*cur == '/') | |
205 | { | |
206 | tmp = skip_escaped_newlines (pfile, cur + 1); | |
207 | if (*tmp == '*') | |
208 | { | |
209 | cur = skip_comment (pfile, tmp + 1); | |
210 | continue; | |
211 | } | |
212 | } | |
213 | ||
214 | break; | |
215 | } | |
216 | ||
217 | return cur; | |
218 | } | |
219 | ||
004cb263 NB |
220 | /* Lexes and outputs an identifier starting at CUR, which is assumed |
221 | to point to a valid first character of an identifier. Returns | |
1a76916c | 222 | the hashnode, and updates out.cur. */ |
004cb263 NB |
223 | static cpp_hashnode * |
224 | lex_identifier (pfile, cur) | |
225 | cpp_reader *pfile; | |
226 | const uchar *cur; | |
227 | { | |
228 | size_t len; | |
1a76916c | 229 | uchar *out = pfile->out.cur; |
cbc69f84 | 230 | cpp_hashnode *result; |
004cb263 NB |
231 | |
232 | do | |
233 | { | |
234 | do | |
235 | *out++ = *cur++; | |
1ce676a0 | 236 | while (is_numchar (*cur)); |
004cb263 NB |
237 | cur = skip_escaped_newlines (pfile, cur); |
238 | } | |
1ce676a0 | 239 | while (is_numchar (*cur)); |
004cb263 | 240 | |
82eda77e | 241 | CUR (pfile->context) = cur; |
1a76916c NB |
242 | len = out - pfile->out.cur; |
243 | result = (cpp_hashnode *) ht_lookup (pfile->hash_table, pfile->out.cur, | |
cbc69f84 | 244 | len, HT_ALLOC); |
1a76916c | 245 | pfile->out.cur = out; |
cbc69f84 NB |
246 | return result; |
247 | } | |
248 | ||
249 | /* Reads an identifier, returning its hashnode. If the next token is | |
250 | not an identifier, returns NULL. */ | |
251 | cpp_hashnode * | |
252 | _cpp_lex_identifier_trad (pfile) | |
253 | cpp_reader *pfile; | |
254 | { | |
255 | const uchar *cur = skip_whitespace (pfile, CUR (pfile->context)); | |
256 | ||
1ce676a0 | 257 | if (!is_idstart (*cur)) |
cbc69f84 NB |
258 | { |
259 | CUR (pfile->context) = cur; | |
260 | return NULL; | |
261 | } | |
262 | ||
263 | return lex_identifier (pfile, cur); | |
004cb263 NB |
264 | } |
265 | ||
266 | /* Overlays the true file buffer temporarily with text of length LEN | |
267 | starting at START. The true buffer is restored upon calling | |
268 | restore_buff(). */ | |
269 | void | |
270 | _cpp_overlay_buffer (pfile, start, len) | |
271 | cpp_reader *pfile; | |
272 | const uchar *start; | |
273 | size_t len; | |
274 | { | |
275 | cpp_buffer *buffer = pfile->buffer; | |
276 | ||
277 | buffer->saved_cur = buffer->cur; | |
278 | buffer->saved_rlimit = buffer->rlimit; | |
279 | buffer->saved_line_base = buffer->line_base; | |
280 | ||
281 | buffer->cur = start; | |
282 | buffer->line_base = start; | |
283 | buffer->rlimit = start + len; | |
1a76916c NB |
284 | |
285 | pfile->saved_line = pfile->line; | |
004cb263 NB |
286 | } |
287 | ||
288 | /* Restores a buffer overlaid by _cpp_overlay_buffer(). */ | |
1a76916c NB |
289 | void |
290 | _cpp_remove_overlay (pfile) | |
004cb263 NB |
291 | cpp_reader *pfile; |
292 | { | |
293 | cpp_buffer *buffer = pfile->buffer; | |
294 | ||
295 | buffer->cur = buffer->saved_cur; | |
296 | buffer->rlimit = buffer->saved_rlimit; | |
297 | buffer->line_base = buffer->saved_line_base; | |
1a76916c NB |
298 | |
299 | pfile->line = pfile->saved_line; | |
004cb263 NB |
300 | } |
301 | ||
302 | /* Reads a logical line into the output buffer. Returns TRUE if there | |
303 | is more text left in the buffer. */ | |
304 | bool | |
1a76916c | 305 | _cpp_read_logical_line_trad (pfile) |
004cb263 NB |
306 | cpp_reader *pfile; |
307 | { | |
974c43f1 | 308 | cpp_buffer *buffer = pfile->buffer; |
004cb263 | 309 | |
974c43f1 | 310 | do |
004cb263 | 311 | { |
974c43f1 | 312 | if (buffer->cur == buffer->rlimit) |
004cb263 | 313 | { |
974c43f1 NB |
314 | bool stop = true; |
315 | ||
316 | /* Don't pop the last buffer. */ | |
317 | if (buffer->prev) | |
318 | { | |
319 | stop = buffer->return_at_eof; | |
320 | _cpp_pop_buffer (pfile); | |
321 | } | |
322 | ||
323 | if (stop) | |
324 | return false; | |
004cb263 NB |
325 | } |
326 | ||
974c43f1 NB |
327 | CUR (pfile->context) = buffer->cur; |
328 | RLIMIT (pfile->context) = buffer->rlimit; | |
329 | scan_out_logical_line (pfile, NULL); | |
330 | buffer->cur = CUR (pfile->context); | |
004cb263 | 331 | } |
974c43f1 | 332 | while (pfile->state.skipping); |
82eda77e | 333 | |
004cb263 NB |
334 | return true; |
335 | } | |
336 | ||
1ce676a0 NB |
337 | /* Set up state for finding the opening '(' of a function-like |
338 | macro. */ | |
339 | static void | |
340 | maybe_start_funlike (pfile, node, start, macro) | |
341 | cpp_reader *pfile; | |
342 | cpp_hashnode *node; | |
343 | const uchar *start; | |
344 | struct fun_macro *macro; | |
345 | { | |
346 | unsigned int n = node->value.macro->paramc + 1; | |
347 | ||
348 | if (macro->buff) | |
349 | _cpp_release_buff (pfile, macro->buff); | |
350 | macro->buff = _cpp_get_buff (pfile, n * sizeof (size_t)); | |
351 | macro->args = (size_t *) BUFF_FRONT (macro->buff); | |
352 | macro->node = node; | |
1a76916c | 353 | macro->offset = start - pfile->out.base; |
1ce676a0 NB |
354 | macro->argc = 0; |
355 | ||
356 | pfile->state.parsing_args = 1; | |
357 | } | |
358 | ||
359 | /* Save the OFFSET of the start of the next argument to MACRO. */ | |
360 | static void | |
361 | save_argument (macro, offset) | |
362 | struct fun_macro *macro; | |
363 | size_t offset; | |
364 | { | |
365 | macro->argc++; | |
366 | if (macro->argc <= macro->node->value.macro->paramc) | |
367 | macro->args[macro->argc] = offset; | |
368 | } | |
369 | ||
004cb263 NB |
370 | /* Copies the next logical line in the current buffer to the output |
371 | buffer. The output is guaranteed to terminate with a NUL | |
c70f6ed3 NB |
372 | character. |
373 | ||
374 | If MACRO is non-NULL, then we are scanning the replacement list of | |
1ce676a0 | 375 | MACRO, and we call save_replacement_text() every time we meet an |
c70f6ed3 | 376 | argument. */ |
004cb263 | 377 | static void |
c70f6ed3 | 378 | scan_out_logical_line (pfile, macro) |
004cb263 | 379 | cpp_reader *pfile; |
c70f6ed3 | 380 | cpp_macro *macro; |
004cb263 | 381 | { |
cbc69f84 NB |
382 | cpp_context *context; |
383 | const uchar *cur; | |
1ce676a0 | 384 | unsigned int c, paren_depth, quote = 0; |
004cb263 | 385 | uchar *out; |
1ce676a0 | 386 | struct fun_macro fmacro; |
004cb263 | 387 | |
1ce676a0 | 388 | fmacro.buff = NULL; |
974c43f1 NB |
389 | |
390 | start_logical_line: | |
391 | pfile->out.cur = pfile->out.base; | |
392 | pfile->out.first_line = pfile->line; | |
cbc69f84 NB |
393 | new_context: |
394 | context = pfile->context; | |
395 | cur = CUR (context); | |
82eda77e | 396 | check_output_buffer (pfile, RLIMIT (context) - cur); |
1a76916c | 397 | out = pfile->out.cur; |
004cb263 NB |
398 | |
399 | for (;;) | |
400 | { | |
401 | c = *cur++; | |
402 | *out++ = c; | |
403 | ||
404 | /* There are only a few entities we need to catch: comments, | |
405 | identifiers, newlines, escaped newlines, # and '\0'. */ | |
406 | switch (c) | |
407 | { | |
408 | case '\0': | |
82eda77e | 409 | if (cur - 1 != RLIMIT (context)) |
004cb263 | 410 | break; |
cbc69f84 NB |
411 | |
412 | /* If this is a macro's expansion, pop it. */ | |
413 | if (context->prev) | |
414 | { | |
1a76916c | 415 | pfile->out.cur = out - 1; |
cbc69f84 NB |
416 | _cpp_pop_context (pfile); |
417 | goto new_context; | |
418 | } | |
419 | ||
420 | /* Premature end of file. Fake a new line. */ | |
004cb263 | 421 | cur--; |
82eda77e | 422 | if (!pfile->buffer->from_stage3) |
004cb263 | 423 | cpp_error (pfile, DL_PEDWARN, "no newline at end of file"); |
1ce676a0 NB |
424 | if (pfile->state.parsing_args == 2) |
425 | cpp_error (pfile, DL_ERROR, | |
426 | "unterminated argument list invoking macro \"%s\"", | |
427 | NODE_NAME (fmacro.node)); | |
004cb263 | 428 | pfile->line++; |
1ce676a0 | 429 | goto done; |
82eda77e NB |
430 | |
431 | case '\r': case '\n': | |
432 | cur = handle_newline (pfile, cur - 1); | |
1ce676a0 NB |
433 | if (pfile->state.parsing_args == 2) |
434 | { | |
435 | /* Newlines in arguments become a space. */ | |
436 | out[-1] = ' '; | |
437 | continue; | |
438 | } | |
439 | goto done; | |
004cb263 NB |
440 | |
441 | case '"': | |
442 | case '\'': | |
443 | if (c == quote) | |
444 | quote = 0; | |
445 | else if (!quote) | |
446 | quote = c; | |
447 | break; | |
448 | ||
449 | case '\\': | |
450 | if (is_vspace (*cur)) | |
451 | out--, cur = skip_escaped_newlines (pfile, cur - 1); | |
452 | else | |
453 | { | |
454 | /* Skip escaped quotes here, it's easier than above, but | |
455 | take care to first skip escaped newlines. */ | |
456 | cur = skip_escaped_newlines (pfile, cur); | |
457 | if (*cur == '\\' || *cur == '"' || *cur == '\'') | |
458 | *out++ = *cur++; | |
459 | } | |
460 | break; | |
461 | ||
462 | case '/': | |
463 | /* Traditional CPP does not recognize comments within | |
464 | literals. */ | |
465 | if (!quote) | |
466 | { | |
467 | cur = skip_escaped_newlines (pfile, cur); | |
468 | if (*cur == '*') | |
469 | out--, cur = skip_comment (pfile, cur + 1); | |
470 | } | |
471 | break; | |
472 | ||
473 | case '_': | |
474 | case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': | |
475 | case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': | |
476 | case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': | |
477 | case 's': case 't': case 'u': case 'v': case 'w': case 'x': | |
478 | case 'y': case 'z': | |
479 | case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': | |
480 | case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': | |
481 | case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': | |
482 | case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': | |
483 | case 'Y': case 'Z': | |
c70f6ed3 NB |
484 | if (quote == 0 || macro) |
485 | { | |
486 | cpp_hashnode *node; | |
487 | ||
1a76916c | 488 | pfile->out.cur = --out; |
c70f6ed3 NB |
489 | node = lex_identifier (pfile, cur - 1); |
490 | ||
1ce676a0 | 491 | if (node->type == NT_MACRO |
974c43f1 | 492 | && !pfile->state.skipping |
1ce676a0 | 493 | && pfile->state.parsing_args != 2 |
974c43f1 NB |
494 | && !pfile->state.prevent_expansion |
495 | && !recursive_macro (pfile, node)) | |
c70f6ed3 | 496 | { |
1ce676a0 NB |
497 | if (node->value.macro->fun_like) |
498 | maybe_start_funlike (pfile, node, out, &fmacro); | |
499 | else | |
500 | { | |
501 | /* Remove the object-like macro's name from the | |
502 | output, and push its replacement text. */ | |
1a76916c | 503 | pfile->out.cur = out; |
1ce676a0 NB |
504 | push_replacement_text (pfile, node); |
505 | goto new_context; | |
506 | } | |
c70f6ed3 NB |
507 | } |
508 | else if (macro && node->arg_index) | |
509 | { | |
1ce676a0 NB |
510 | /* Found a parameter in the replacement text of a |
511 | #define. Remove its name from the output. */ | |
1a76916c | 512 | pfile->out.cur = out; |
c70f6ed3 NB |
513 | save_replacement_text (pfile, macro, node->arg_index); |
514 | } | |
515 | ||
1a76916c | 516 | out = pfile->out.cur; |
c70f6ed3 NB |
517 | cur = CUR (context); |
518 | } | |
004cb263 NB |
519 | break; |
520 | ||
1ce676a0 NB |
521 | case '(': |
522 | if (quote == 0) | |
523 | { | |
524 | paren_depth++; | |
525 | if (pfile->state.parsing_args == 1) | |
526 | { | |
1a76916c | 527 | const uchar *p = pfile->out.base + fmacro.offset; |
1ce676a0 NB |
528 | |
529 | /* Invoke a prior function-like macro if there is only | |
530 | white space in-between. */ | |
531 | while (is_numchar (*p)) | |
532 | p++; | |
533 | while (is_space (*p)) | |
534 | p++; | |
535 | ||
536 | if (p == out - 1) | |
537 | { | |
538 | pfile->state.parsing_args = 2; | |
539 | paren_depth = 1; | |
1a76916c | 540 | out = pfile->out.base + fmacro.offset; |
1ce676a0 NB |
541 | fmacro.args[0] = fmacro.offset; |
542 | } | |
543 | else | |
544 | pfile->state.parsing_args = 0; | |
545 | } | |
546 | } | |
547 | break; | |
548 | ||
549 | case ',': | |
550 | if (quote == 0 && pfile->state.parsing_args == 2 && paren_depth == 1) | |
1a76916c | 551 | save_argument (&fmacro, out - pfile->out.base); |
1ce676a0 NB |
552 | break; |
553 | ||
554 | case ')': | |
555 | if (quote == 0) | |
556 | { | |
557 | paren_depth--; | |
558 | if (pfile->state.parsing_args == 2 && paren_depth == 0) | |
559 | { | |
560 | cpp_macro *m = fmacro.node->value.macro; | |
561 | ||
562 | pfile->state.parsing_args = 0; | |
1a76916c | 563 | save_argument (&fmacro, out - pfile->out.base); |
1ce676a0 | 564 | |
6618c5d4 NB |
565 | /* A single zero-length argument is no argument. */ |
566 | if (fmacro.argc == 1 | |
567 | && m->paramc == 0 | |
1a76916c | 568 | && out == pfile->out.base + 1) |
6618c5d4 | 569 | fmacro.argc = 0; |
1ce676a0 NB |
570 | |
571 | if (_cpp_arguments_ok (pfile, m, fmacro.node, fmacro.argc)) | |
572 | { | |
573 | /* Remove the macro's invocation from the | |
574 | output, and push its replacement text. */ | |
1a76916c | 575 | pfile->out.cur = (pfile->out.base |
1ce676a0 NB |
576 | + fmacro.offset); |
577 | CUR (context) = cur; | |
578 | replace_args_and_push (pfile, &fmacro); | |
579 | goto new_context; | |
580 | } | |
581 | } | |
582 | } | |
583 | break; | |
584 | ||
1a76916c NB |
585 | case '#': |
586 | /* At start of a line it's a directive. */ | |
587 | if (out - 1 == pfile->out.base && !pfile->state.in_directive) | |
588 | { | |
589 | /* This is a kludge. We want to have the ISO | |
590 | preprocessor lex the next token. */ | |
591 | pfile->buffer->cur = cur; | |
592 | if (_cpp_handle_directive (pfile, false /* indented */)) | |
974c43f1 | 593 | goto start_logical_line; |
1a76916c NB |
594 | } |
595 | break; | |
596 | ||
004cb263 NB |
597 | default: |
598 | break; | |
599 | } | |
600 | } | |
1ce676a0 NB |
601 | |
602 | done: | |
603 | out[-1] = '\0'; | |
604 | CUR (context) = cur; | |
1a76916c | 605 | pfile->out.cur = out - 1; |
1ce676a0 NB |
606 | if (fmacro.buff) |
607 | _cpp_release_buff (pfile, fmacro.buff); | |
004cb263 | 608 | } |
cbc69f84 NB |
609 | |
610 | /* Push a context holding the replacement text of the macro NODE on | |
1ce676a0 NB |
611 | the context stack. NODE is either object-like, or a function-like |
612 | macro with no arguments. */ | |
cbc69f84 NB |
613 | static void |
614 | push_replacement_text (pfile, node) | |
615 | cpp_reader *pfile; | |
616 | cpp_hashnode *node; | |
617 | { | |
618 | cpp_macro *macro = node->value.macro; | |
619 | ||
1ce676a0 NB |
620 | _cpp_push_text_context (pfile, node, macro->exp.text, macro->count); |
621 | } | |
622 | ||
974c43f1 NB |
623 | /* Returns TRUE if traditional macro recursion is detected. */ |
624 | static bool | |
625 | recursive_macro (pfile, node) | |
626 | cpp_reader *pfile; | |
627 | cpp_hashnode *node; | |
628 | { | |
629 | bool recursing = node->flags & NODE_DISABLED; | |
630 | ||
631 | /* Object-like macros that are already expanding are necessarily | |
632 | recursive. | |
633 | ||
634 | However, it is possible to have traditional function-like macros | |
635 | that are not infinitely recursive but recurse to any given depth. | |
636 | Further, it is easy to construct examples that get ever longer | |
637 | until the point they stop recursing. So there is no easy way to | |
638 | detect true recursion; instead we assume any expansion more than | |
639 | 20 deep since the first invocation of this macro must be | |
640 | recursing. */ | |
641 | if (recursing && node->value.macro->fun_like) | |
642 | { | |
643 | size_t depth = 0; | |
644 | cpp_context *context = pfile->context; | |
645 | ||
646 | do | |
647 | { | |
648 | depth++; | |
649 | if (context->macro == node && depth > 20) | |
650 | break; | |
651 | context = context->prev; | |
652 | } | |
653 | while (context); | |
654 | recursing = context != NULL; | |
655 | } | |
656 | ||
657 | if (recursing) | |
658 | cpp_error (pfile, DL_ERROR, | |
659 | "detected recursion whilst expanding macro \"%s\"", | |
660 | NODE_NAME (node)); | |
661 | ||
662 | return recursing; | |
663 | } | |
664 | ||
1ce676a0 NB |
665 | /* Push a context holding the replacement text of the macro NODE on |
666 | the context stack. NODE is either object-like, or a function-like | |
667 | macro with no arguments. */ | |
668 | static void | |
669 | replace_args_and_push (pfile, fmacro) | |
670 | cpp_reader *pfile; | |
671 | struct fun_macro *fmacro; | |
672 | { | |
673 | cpp_macro *macro = fmacro->node->value.macro; | |
674 | ||
675 | if (macro->paramc == 0) | |
676 | push_replacement_text (pfile, fmacro->node); | |
677 | else | |
678 | { | |
679 | const uchar *exp; | |
680 | uchar *p; | |
681 | _cpp_buff *buff; | |
682 | size_t len = 0; | |
683 | ||
684 | /* Calculate the length of the argument-replaced text. */ | |
685 | for (exp = macro->exp.text;;) | |
686 | { | |
687 | struct block *b = (struct block *) exp; | |
688 | ||
689 | len += b->text_len; | |
690 | if (b->arg_index == 0) | |
691 | break; | |
692 | len += (fmacro->args[b->arg_index] | |
693 | - fmacro->args[b->arg_index - 1] - 1); | |
694 | exp += BLOCK_LEN (b->text_len); | |
695 | } | |
696 | ||
697 | /* Allocate room for the expansion plus NUL. */ | |
698 | buff = _cpp_get_buff (pfile, len + 1); | |
699 | ||
700 | /* Copy the expansion and replace arguments. */ | |
701 | p = BUFF_FRONT (buff); | |
702 | for (exp = macro->exp.text;;) | |
703 | { | |
704 | struct block *b = (struct block *) exp; | |
705 | size_t arglen; | |
706 | ||
707 | memcpy (p, b->text, b->text_len); | |
708 | p += b->text_len; | |
709 | if (b->arg_index == 0) | |
710 | break; | |
711 | arglen = (fmacro->args[b->arg_index] | |
712 | - fmacro->args[b->arg_index - 1] - 1); | |
1a76916c | 713 | memcpy (p, pfile->out.base + fmacro->args[b->arg_index - 1], |
1ce676a0 NB |
714 | arglen); |
715 | p += arglen; | |
716 | exp += BLOCK_LEN (b->text_len); | |
717 | } | |
718 | ||
719 | /* NUL-terminate. */ | |
720 | *p = '\0'; | |
721 | _cpp_push_text_context (pfile, fmacro->node, BUFF_FRONT (buff), len); | |
722 | ||
723 | /* So we free buffer allocation when macro is left. */ | |
724 | pfile->context->buff = buff; | |
725 | } | |
cbc69f84 NB |
726 | } |
727 | ||
c70f6ed3 | 728 | /* Read and record the parameters, if any, of a function-like macro |
1a76916c | 729 | definition. Destroys pfile->out.cur. |
c70f6ed3 NB |
730 | |
731 | Returns true on success, false on failure (syntax error or a | |
732 | duplicate parameter). On success, CUR (pfile->context) is just | |
733 | past the closing parenthesis. */ | |
734 | static bool | |
735 | scan_parameters (pfile, macro) | |
736 | cpp_reader *pfile; | |
737 | cpp_macro *macro; | |
738 | { | |
739 | const uchar *cur = CUR (pfile->context) + 1; | |
740 | bool ok; | |
741 | ||
742 | for (;;) | |
743 | { | |
744 | cur = skip_whitespace (pfile, cur); | |
745 | ||
1ce676a0 | 746 | if (is_idstart (*cur)) |
c70f6ed3 NB |
747 | { |
748 | ok = false; | |
749 | if (_cpp_save_parameter (pfile, macro, lex_identifier (pfile, cur))) | |
750 | break; | |
751 | cur = skip_whitespace (pfile, CUR (pfile->context)); | |
752 | if (*cur == ',') | |
753 | { | |
754 | cur++; | |
755 | continue; | |
756 | } | |
757 | ok = (*cur == ')'); | |
758 | break; | |
759 | } | |
760 | ||
761 | ok = (*cur == ')' && macro->paramc == 0); | |
762 | break; | |
763 | } | |
764 | ||
765 | CUR (pfile->context) = cur + (*cur == ')'); | |
766 | ||
767 | return ok; | |
768 | } | |
769 | ||
1a76916c | 770 | /* Save the text from pfile->out.base to pfile->out.cur as |
c70f6ed3 NB |
771 | the replacement text for the current macro, followed by argument |
772 | ARG_INDEX, with zero indicating the end of the replacement | |
773 | text. */ | |
774 | static void | |
775 | save_replacement_text (pfile, macro, arg_index) | |
776 | cpp_reader *pfile; | |
777 | cpp_macro *macro; | |
778 | unsigned int arg_index; | |
779 | { | |
1a76916c | 780 | size_t len = pfile->out.cur - pfile->out.base; |
c70f6ed3 NB |
781 | uchar *exp; |
782 | ||
783 | if (macro->paramc == 0) | |
784 | { | |
785 | /* Object-like and function-like macros without parameters | |
786 | simply store their NUL-terminated replacement text. */ | |
787 | exp = _cpp_unaligned_alloc (pfile, len + 1); | |
1a76916c | 788 | memcpy (exp, pfile->out.base, len); |
c70f6ed3 NB |
789 | exp[len] = '\0'; |
790 | macro->exp.text = exp; | |
791 | macro->count = len; | |
792 | } | |
793 | else | |
794 | { | |
795 | /* Store the text's length (unsigned int), the argument index | |
796 | (unsigned short, base 1) and then the text. */ | |
797 | size_t blen = BLOCK_LEN (len); | |
798 | struct block *block; | |
799 | ||
800 | if (macro->count + blen > BUFF_ROOM (pfile->a_buff)) | |
801 | _cpp_extend_buff (pfile, &pfile->a_buff, macro->count + blen); | |
802 | ||
803 | exp = BUFF_FRONT (pfile->a_buff); | |
804 | block = (struct block *) (exp + macro->count); | |
805 | macro->exp.text = exp; | |
806 | ||
807 | /* Write out the block information. */ | |
808 | block->text_len = len; | |
809 | block->arg_index = arg_index; | |
1a76916c | 810 | memcpy (block->text, pfile->out.base, len); |
c70f6ed3 NB |
811 | |
812 | /* Lex the rest into the start of the output buffer. */ | |
1a76916c | 813 | pfile->out.cur = pfile->out.base; |
c70f6ed3 | 814 | |
1ce676a0 | 815 | macro->count += blen; |
6618c5d4 NB |
816 | |
817 | /* If we've finished, commit the memory. */ | |
818 | if (arg_index == 0) | |
819 | BUFF_FRONT (pfile->a_buff) += macro->count; | |
c70f6ed3 NB |
820 | } |
821 | } | |
822 | ||
823 | /* Analyze and save the replacement text of a macro. Returns true on | |
824 | success. */ | |
cbc69f84 NB |
825 | bool |
826 | _cpp_create_trad_definition (pfile, macro) | |
827 | cpp_reader *pfile; | |
828 | cpp_macro *macro; | |
829 | { | |
c70f6ed3 NB |
830 | const uchar *cur; |
831 | uchar *limit; | |
cbc69f84 | 832 | |
1a76916c NB |
833 | CUR (pfile->context) = pfile->buffer->cur; |
834 | ||
c70f6ed3 NB |
835 | /* Is this a function-like macro? */ |
836 | if (* CUR (pfile->context) == '(') | |
837 | { | |
1ce676a0 NB |
838 | /* Setting macro to NULL indicates an error occurred, and |
839 | prevents unnecessary work in scan_out_logical_line. */ | |
c70f6ed3 NB |
840 | if (!scan_parameters (pfile, macro)) |
841 | macro = NULL; | |
842 | else | |
843 | { | |
844 | /* Success. Commit the parameter array. */ | |
845 | macro->params = (cpp_hashnode **) BUFF_FRONT (pfile->a_buff); | |
846 | BUFF_FRONT (pfile->a_buff) = (uchar *) ¯o->params[macro->paramc]; | |
847 | macro->fun_like = 1; | |
848 | } | |
c70f6ed3 NB |
849 | } |
850 | ||
1ce676a0 NB |
851 | /* Skip leading whitespace in the replacement text. */ |
852 | CUR (pfile->context) = skip_whitespace (pfile, CUR (pfile->context)); | |
853 | ||
c70f6ed3 NB |
854 | pfile->state.prevent_expansion++; |
855 | scan_out_logical_line (pfile, macro); | |
856 | pfile->state.prevent_expansion--; | |
857 | ||
858 | if (!macro) | |
859 | return false; | |
cbc69f84 NB |
860 | |
861 | /* Skip trailing white space. */ | |
1a76916c NB |
862 | cur = pfile->out.base; |
863 | limit = pfile->out.cur; | |
cbc69f84 NB |
864 | while (limit > cur && is_space (limit[-1])) |
865 | limit--; | |
1a76916c | 866 | pfile->out.cur = limit; |
c70f6ed3 | 867 | save_replacement_text (pfile, macro, 0); |
cbc69f84 NB |
868 | |
869 | return true; | |
870 | } | |
871 | ||
6618c5d4 NB |
872 | /* Copy SRC of length LEN to DEST, but convert all contiguous |
873 | whitespace to a single space, provided it is not in quotes. The | |
874 | quote currently in effect is pointed to by PQUOTE, and is updated | |
875 | by the function. Returns the number of bytes copied. */ | |
876 | static size_t | |
877 | canonicalize_text (dest, src, len, pquote) | |
878 | uchar *dest; | |
879 | const uchar *src; | |
880 | size_t len; | |
881 | uchar *pquote; | |
882 | { | |
883 | uchar *orig_dest = dest; | |
884 | uchar quote = *pquote; | |
885 | ||
886 | while (len) | |
887 | { | |
888 | if (is_space (*src) && !quote) | |
889 | { | |
890 | do | |
891 | src++, len--; | |
892 | while (len && is_space (*src)); | |
893 | *dest++ = ' '; | |
894 | } | |
895 | else | |
896 | { | |
897 | if (*src == '\'' || *src == '"') | |
898 | { | |
899 | if (!quote) | |
900 | quote = *src; | |
901 | else if (quote == *src) | |
902 | quote = 0; | |
903 | } | |
904 | *dest++ = *src++, len--; | |
905 | } | |
906 | } | |
907 | ||
908 | *pquote = quote; | |
909 | return dest - orig_dest; | |
910 | } | |
911 | ||
912 | /* Returns true if MACRO1 and MACRO2 have expansions different other | |
913 | than in the form of their whitespace. */ | |
914 | bool | |
915 | _cpp_expansions_different_trad (macro1, macro2) | |
afb03408 | 916 | const cpp_macro *macro1, *macro2; |
6618c5d4 NB |
917 | { |
918 | uchar *p1 = xmalloc (macro1->count + macro2->count); | |
919 | uchar *p2 = p1 + macro1->count; | |
920 | uchar quote1 = 0, quote2; | |
921 | bool mismatch; | |
922 | size_t len1, len2; | |
923 | ||
924 | if (macro1->paramc > 0) | |
925 | { | |
926 | const uchar *exp1 = macro1->exp.text, *exp2 = macro2->exp.text; | |
927 | ||
928 | mismatch = true; | |
929 | for (;;) | |
930 | { | |
931 | struct block *b1 = (struct block *) exp1; | |
932 | struct block *b2 = (struct block *) exp2; | |
933 | ||
934 | if (b1->arg_index != b2->arg_index) | |
935 | break; | |
936 | ||
937 | len1 = canonicalize_text (p1, b1->text, b1->text_len, "e1); | |
938 | len2 = canonicalize_text (p2, b2->text, b2->text_len, "e2); | |
939 | if (len1 != len2 || memcmp (p1, p2, len1)) | |
940 | break; | |
941 | if (b1->arg_index == 0) | |
942 | { | |
943 | mismatch = false; | |
944 | break; | |
945 | } | |
946 | exp1 += BLOCK_LEN (b1->text_len); | |
947 | exp2 += BLOCK_LEN (b2->text_len); | |
948 | } | |
949 | } | |
950 | else | |
951 | { | |
952 | len1 = canonicalize_text (p1, macro1->exp.text, macro1->count, "e1); | |
953 | len2 = canonicalize_text (p2, macro2->exp.text, macro2->count, "e2); | |
954 | mismatch = (len1 != len2 || memcmp (p1, p2, len1)); | |
955 | } | |
956 | ||
957 | free (p1); | |
958 | return mismatch; | |
959 | } | |
960 | ||
cbc69f84 NB |
961 | /* Prepare to be able to scan the current buffer. */ |
962 | void | |
963 | _cpp_set_trad_context (pfile) | |
964 | cpp_reader *pfile; | |
965 | { | |
966 | cpp_buffer *buffer = pfile->buffer; | |
967 | cpp_context *context = pfile->context; | |
968 | ||
969 | if (pfile->context->prev) | |
970 | abort (); | |
971 | ||
1a76916c | 972 | pfile->out.cur = pfile->out.base; |
cbc69f84 NB |
973 | CUR (context) = buffer->cur; |
974 | RLIMIT (context) = buffer->rlimit; | |
975 | check_output_buffer (pfile, RLIMIT (context) - CUR (context)); | |
976 | } |