12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310 |
- /* CPP Library - traditional lexical analysis and macro expansion.
- Copyright (C) 2002-2015 Free Software Foundation, Inc.
- Contributed by Neil Booth, May 2002
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 3, or (at your option) any
- later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING3. If not see
- <http://www.gnu.org/licenses/>. */
- #include "config.h"
- #include "system.h"
- #include "cpplib.h"
- #include "internal.h"
- /* The replacement text of a function-like macro is stored as a
- contiguous sequence of aligned blocks, each representing the text
- between subsequent parameters.
- Each block comprises the text between its surrounding parameters,
- the length of that text, and the one-based index of the following
- parameter. The final block in the replacement text is easily
- recognizable as it has an argument index of zero. */
- struct block
- {
- unsigned int text_len;
- unsigned short arg_index;
- uchar text[1];
- };
- #define BLOCK_HEADER_LEN offsetof (struct block, text)
- #define BLOCK_LEN(TEXT_LEN) CPP_ALIGN (BLOCK_HEADER_LEN + (TEXT_LEN))
- /* Structure holding information about a function-like macro
- invocation. */
- struct fun_macro
- {
- /* Memory buffer holding the trad_arg array. */
- _cpp_buff *buff;
- /* An array of size the number of macro parameters + 1, containing
- the offsets of the start of each macro argument in the output
- buffer. The argument continues until the character before the
- start of the next one. */
- size_t *args;
- /* The hashnode of the macro. */
- cpp_hashnode *node;
- /* The offset of the macro name in the output buffer. */
- size_t offset;
- /* The line the macro name appeared on. */
- source_location line;
- /* Number of parameters. */
- unsigned int paramc;
- /* Zero-based index of argument being currently lexed. */
- unsigned int argc;
- };
- /* Lexing state. It is mostly used to prevent macro expansion. */
- enum ls {ls_none = 0, /* Normal state. */
- ls_fun_open, /* When looking for '('. */
- ls_fun_close, /* When looking for ')'. */
- ls_defined, /* After defined. */
- ls_defined_close, /* Looking for ')' of defined(). */
- ls_hash, /* After # in preprocessor conditional. */
- ls_predicate, /* After the predicate, maybe paren? */
- ls_answer, /* In answer to predicate. */
- ls_has_include, /* After __has_include__. */
- ls_has_include_close}; /* Looking for ')' of __has_include__. */
- /* Lexing TODO: Maybe handle space in escaped newlines. Stop lex.c
- from recognizing comments and directives during its lexing pass. */
- static const uchar *skip_whitespace (cpp_reader *, const uchar *, int);
- static cpp_hashnode *lex_identifier (cpp_reader *, const uchar *);
- static const uchar *copy_comment (cpp_reader *, const uchar *, int);
- static void check_output_buffer (cpp_reader *, size_t);
- static void push_replacement_text (cpp_reader *, cpp_hashnode *);
- static bool scan_parameters (cpp_reader *, cpp_macro *);
- static bool recursive_macro (cpp_reader *, cpp_hashnode *);
- static void save_replacement_text (cpp_reader *, cpp_macro *, unsigned int);
- static void maybe_start_funlike (cpp_reader *, cpp_hashnode *, const uchar *,
- struct fun_macro *);
- static void save_argument (struct fun_macro *, size_t);
- static void replace_args_and_push (cpp_reader *, struct fun_macro *);
- static size_t canonicalize_text (uchar *, const uchar *, size_t, uchar *);
- /* Ensures we have N bytes' space in the output buffer, and
- reallocates it if not. */
- static void
- check_output_buffer (cpp_reader *pfile, size_t n)
- {
- /* We might need two bytes to terminate an unterminated comment, and
- one more to terminate the line with a NUL. */
- n += 2 + 1;
- if (n > (size_t) (pfile->out.limit - pfile->out.cur))
- {
- size_t size = pfile->out.cur - pfile->out.base;
- size_t new_size = (size + n) * 3 / 2;
- pfile->out.base = XRESIZEVEC (unsigned char, pfile->out.base, new_size);
- pfile->out.limit = pfile->out.base + new_size;
- pfile->out.cur = pfile->out.base + size;
- }
- }
- /* Skip a C-style block comment in a macro as a result of -CC.
- Buffer->cur points to the initial asterisk of the comment. */
- static void
- skip_macro_block_comment (cpp_reader *pfile)
- {
- const uchar *cur = pfile->buffer->cur;
- cur++;
- if (*cur == '/')
- cur++;
- /* People like decorating comments with '*', so check for '/'
- instead for efficiency. */
- while(! (*cur++ == '/' && cur[-2] == '*') )
- ;
- pfile->buffer->cur = cur;
- }
- /* CUR points to the asterisk introducing a comment in the current
- context. IN_DEFINE is true if we are in the replacement text of a
- macro.
- The asterisk and following comment is copied to the buffer pointed
- to by pfile->out.cur, which must be of sufficient size.
- Unterminated comments are diagnosed, and correctly terminated in
- the output. pfile->out.cur is updated depending upon IN_DEFINE,
- -C, -CC and pfile->state.in_directive.
- Returns a pointer to the first character after the comment in the
- input buffer. */
- static const uchar *
- copy_comment (cpp_reader *pfile, const uchar *cur, int in_define)
- {
- bool unterminated, copy = false;
- source_location src_loc = pfile->line_table->highest_line;
- cpp_buffer *buffer = pfile->buffer;
- buffer->cur = cur;
- if (pfile->context->prev)
- unterminated = false, skip_macro_block_comment (pfile);
- else
- unterminated = _cpp_skip_block_comment (pfile);
-
- if (unterminated)
- cpp_error_with_line (pfile, CPP_DL_ERROR, src_loc, 0,
- "unterminated comment");
- /* Comments in directives become spaces so that tokens are properly
- separated when the ISO preprocessor re-lexes the line. The
- exception is #define. */
- if (pfile->state.in_directive)
- {
- if (in_define)
- {
- if (CPP_OPTION (pfile, discard_comments_in_macro_exp))
- pfile->out.cur--;
- else
- copy = true;
- }
- else
- pfile->out.cur[-1] = ' ';
- }
- else if (CPP_OPTION (pfile, discard_comments))
- pfile->out.cur--;
- else
- copy = true;
- if (copy)
- {
- size_t len = (size_t) (buffer->cur - cur);
- memcpy (pfile->out.cur, cur, len);
- pfile->out.cur += len;
- if (unterminated)
- {
- *pfile->out.cur++ = '*';
- *pfile->out.cur++ = '/';
- }
- }
- return buffer->cur;
- }
- /* CUR points to any character in the input buffer. Skips over all
- contiguous horizontal white space and NULs, including comments if
- SKIP_COMMENTS, until reaching the first non-horizontal-whitespace
- character or the end of the current context. Escaped newlines are
- removed.
- The whitespace is copied verbatim to the output buffer, except that
- comments are handled as described in copy_comment().
- pfile->out.cur is updated.
- Returns a pointer to the first character after the whitespace in
- the input buffer. */
- static const uchar *
- skip_whitespace (cpp_reader *pfile, const uchar *cur, int skip_comments)
- {
- uchar *out = pfile->out.cur;
- for (;;)
- {
- unsigned int c = *cur++;
- *out++ = c;
- if (is_nvspace (c))
- continue;
- if (c == '/' && *cur == '*' && skip_comments)
- {
- pfile->out.cur = out;
- cur = copy_comment (pfile, cur, false /* in_define */);
- out = pfile->out.cur;
- continue;
- }
- out--;
- break;
- }
- pfile->out.cur = out;
- return cur - 1;
- }
- /* Lexes and outputs an identifier starting at CUR, which is assumed
- to point to a valid first character of an identifier. Returns
- the hashnode, and updates out.cur. */
- static cpp_hashnode *
- lex_identifier (cpp_reader *pfile, const uchar *cur)
- {
- size_t len;
- uchar *out = pfile->out.cur;
- cpp_hashnode *result;
- do
- *out++ = *cur++;
- while (is_numchar (*cur));
- CUR (pfile->context) = cur;
- len = out - pfile->out.cur;
- result = CPP_HASHNODE (ht_lookup (pfile->hash_table, pfile->out.cur,
- len, HT_ALLOC));
- pfile->out.cur = out;
- return result;
- }
- /* Overlays the true file buffer temporarily with text of length LEN
- starting at START. The true buffer is restored upon calling
- restore_buff(). */
- void
- _cpp_overlay_buffer (cpp_reader *pfile, const uchar *start, size_t len)
- {
- cpp_buffer *buffer = pfile->buffer;
- pfile->overlaid_buffer = buffer;
- pfile->saved_cur = buffer->cur;
- pfile->saved_rlimit = buffer->rlimit;
- pfile->saved_line_base = buffer->next_line;
- buffer->need_line = false;
- buffer->cur = start;
- buffer->line_base = start;
- buffer->rlimit = start + len;
- }
- /* Restores a buffer overlaid by _cpp_overlay_buffer(). */
- void
- _cpp_remove_overlay (cpp_reader *pfile)
- {
- cpp_buffer *buffer = pfile->overlaid_buffer;
- buffer->cur = pfile->saved_cur;
- buffer->rlimit = pfile->saved_rlimit;
- buffer->line_base = pfile->saved_line_base;
- buffer->need_line = true;
- pfile->overlaid_buffer = NULL;
- }
- /* Reads a logical line into the output buffer. Returns TRUE if there
- is more text left in the buffer. */
- bool
- _cpp_read_logical_line_trad (cpp_reader *pfile)
- {
- do
- {
- if (pfile->buffer->need_line && !_cpp_get_fresh_line (pfile))
- return false;
- }
- while (!_cpp_scan_out_logical_line (pfile, NULL, false)
- || pfile->state.skipping);
- return pfile->buffer != NULL;
- }
- /* Return true if NODE is a fun_like macro. */
- static inline bool
- fun_like_macro (cpp_hashnode *node)
- {
- if (node->flags & NODE_BUILTIN)
- return node->value.builtin == BT_HAS_ATTRIBUTE;
- else
- return node->value.macro->fun_like;
- }
- /* Set up state for finding the opening '(' of a function-like
- macro. */
- static void
- maybe_start_funlike (cpp_reader *pfile, cpp_hashnode *node, const uchar *start,
- struct fun_macro *macro)
- {
- unsigned int n;
- if (node->flags & NODE_BUILTIN)
- n = 1;
- else
- n = node->value.macro->paramc;
- if (macro->buff)
- _cpp_release_buff (pfile, macro->buff);
- macro->buff = _cpp_get_buff (pfile, (n + 1) * sizeof (size_t));
- macro->args = (size_t *) BUFF_FRONT (macro->buff);
- macro->node = node;
- macro->offset = start - pfile->out.base;
- macro->paramc = n;
- macro->argc = 0;
- }
- /* Save the OFFSET of the start of the next argument to MACRO. */
- static void
- save_argument (struct fun_macro *macro, size_t offset)
- {
- macro->argc++;
- if (macro->argc <= macro->paramc)
- macro->args[macro->argc] = offset;
- }
- /* Copies the next logical line in the current buffer (starting at
- buffer->cur) to the output buffer. The output is guaranteed to
- terminate with a NUL character. buffer->cur is updated.
- If MACRO is non-NULL, then we are scanning the replacement list of
- MACRO, and we call save_replacement_text() every time we meet an
- argument.
- If BUILTIN_MACRO_ARG is true, this is called to macro expand
- arguments of builtin function-like macros. */
- bool
- _cpp_scan_out_logical_line (cpp_reader *pfile, cpp_macro *macro,
- bool builtin_macro_arg)
- {
- bool result = true;
- cpp_context *context;
- const uchar *cur;
- uchar *out;
- struct fun_macro fmacro;
- unsigned int c, paren_depth = 0, quote;
- enum ls lex_state = ls_none;
- bool header_ok;
- const uchar *start_of_input_line;
- fmacro.buff = NULL;
- fmacro.args = NULL;
- fmacro.node = NULL;
- fmacro.offset = 0;
- fmacro.line = 0;
- fmacro.paramc = 0;
- fmacro.argc = 0;
- quote = 0;
- header_ok = pfile->state.angled_headers;
- CUR (pfile->context) = pfile->buffer->cur;
- RLIMIT (pfile->context) = pfile->buffer->rlimit;
- if (!builtin_macro_arg)
- {
- pfile->out.cur = pfile->out.base;
- pfile->out.first_line = pfile->line_table->highest_line;
- }
- /* start_of_input_line is needed to make sure that directives really,
- really start at the first character of the line. */
- start_of_input_line = pfile->buffer->cur;
- new_context:
- context = pfile->context;
- cur = CUR (context);
- check_output_buffer (pfile, RLIMIT (context) - cur);
- out = pfile->out.cur;
- for (;;)
- {
- if (!context->prev
- && !builtin_macro_arg
- && cur >= pfile->buffer->notes[pfile->buffer->cur_note].pos)
- {
- pfile->buffer->cur = cur;
- _cpp_process_line_notes (pfile, false);
- }
- c = *cur++;
- *out++ = c;
- /* Whitespace should "continue" out of the switch,
- non-whitespace should "break" out of it. */
- switch (c)
- {
- case ' ':
- case '\t':
- case '\f':
- case '\v':
- case '\0':
- continue;
- case '\n':
- /* If this is a macro's expansion, pop it. */
- if (context->prev)
- {
- pfile->out.cur = out - 1;
- _cpp_pop_context (pfile);
- goto new_context;
- }
- /* Omit the newline from the output buffer. */
- pfile->out.cur = out - 1;
- pfile->buffer->cur = cur;
- if (builtin_macro_arg)
- goto done;
- pfile->buffer->need_line = true;
- CPP_INCREMENT_LINE (pfile, 0);
- if ((lex_state == ls_fun_open || lex_state == ls_fun_close)
- && !pfile->state.in_directive
- && _cpp_get_fresh_line (pfile))
- {
- /* Newlines in arguments become a space, but we don't
- clear any in-progress quote. */
- if (lex_state == ls_fun_close)
- out[-1] = ' ';
- cur = pfile->buffer->cur;
- continue;
- }
- goto done;
- case '<':
- if (header_ok)
- quote = '>';
- break;
- case '>':
- if (c == quote)
- quote = 0;
- break;
- case '"':
- case '\'':
- if (c == quote)
- quote = 0;
- else if (!quote)
- quote = c;
- break;
- case '\\':
- /* Skip escaped quotes here, it's easier than above. */
- if (*cur == '\\' || *cur == '"' || *cur == '\'')
- *out++ = *cur++;
- break;
- case '/':
- /* Traditional CPP does not recognize comments within
- literals. */
- if (!quote && *cur == '*')
- {
- pfile->out.cur = out;
- cur = copy_comment (pfile, cur, macro != 0);
- out = pfile->out.cur;
- continue;
- }
- break;
- case '_':
- case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
- case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
- case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
- case 's': case 't': case 'u': case 'v': case 'w': case 'x':
- case 'y': case 'z':
- case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
- case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
- case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
- case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
- case 'Y': case 'Z':
- if (!pfile->state.skipping && (quote == 0 || macro))
- {
- cpp_hashnode *node;
- uchar *out_start = out - 1;
- pfile->out.cur = out_start;
- node = lex_identifier (pfile, cur - 1);
- out = pfile->out.cur;
- cur = CUR (context);
- if (node->type == NT_MACRO
- /* Should we expand for ls_answer? */
- && (lex_state == ls_none || lex_state == ls_fun_open)
- && !pfile->state.prevent_expansion)
- {
- /* Macros invalidate MI optimization. */
- pfile->mi_valid = false;
- if (fun_like_macro (node))
- {
- maybe_start_funlike (pfile, node, out_start, &fmacro);
- lex_state = ls_fun_open;
- fmacro.line = pfile->line_table->highest_line;
- continue;
- }
- else if (!recursive_macro (pfile, node))
- {
- /* Remove the object-like macro's name from the
- output, and push its replacement text. */
- pfile->out.cur = out_start;
- push_replacement_text (pfile, node);
- lex_state = ls_none;
- goto new_context;
- }
- }
- else if (macro && (node->flags & NODE_MACRO_ARG) != 0)
- {
- /* Found a parameter in the replacement text of a
- #define. Remove its name from the output. */
- pfile->out.cur = out_start;
- save_replacement_text (pfile, macro, node->value.arg_index);
- out = pfile->out.base;
- }
- else if (lex_state == ls_hash)
- {
- lex_state = ls_predicate;
- continue;
- }
- else if (pfile->state.in_expression
- && node == pfile->spec_nodes.n_defined)
- {
- lex_state = ls_defined;
- continue;
- }
- else if (pfile->state.in_expression
- && (node == pfile->spec_nodes.n__has_include__
- || node == pfile->spec_nodes.n__has_include_next__))
- {
- lex_state = ls_has_include;
- continue;
- }
- }
- break;
- case '(':
- if (quote == 0)
- {
- paren_depth++;
- if (lex_state == ls_fun_open)
- {
- if (recursive_macro (pfile, fmacro.node))
- lex_state = ls_none;
- else
- {
- lex_state = ls_fun_close;
- paren_depth = 1;
- out = pfile->out.base + fmacro.offset;
- fmacro.args[0] = fmacro.offset;
- }
- }
- else if (lex_state == ls_predicate)
- lex_state = ls_answer;
- else if (lex_state == ls_defined)
- lex_state = ls_defined_close;
- else if (lex_state == ls_has_include)
- lex_state = ls_has_include_close;
- }
- break;
- case ',':
- if (quote == 0 && lex_state == ls_fun_close && paren_depth == 1)
- save_argument (&fmacro, out - pfile->out.base);
- break;
- case ')':
- if (quote == 0)
- {
- paren_depth--;
- if (lex_state == ls_fun_close && paren_depth == 0)
- {
- if (fmacro.node->flags & NODE_BUILTIN)
- {
- /* Handle builtin function-like macros like
- __has_attribute. The already parsed arguments
- are put into a buffer, which is then preprocessed
- and the result is fed to _cpp_push_text_context
- with disabled expansion, where the ISO preprocessor
- parses it. While in traditional preprocessing
- macro arguments aren't immediately expanded, they in
- the end are because the macro with replaced arguments
- is preprocessed again. For the builtin function-like
- macros we need the argument immediately though,
- if we don't preprocess them, they would behave
- very differently from ISO preprocessor handling
- of those builtin macros. So, this handling is
- more similar to traditional preprocessing of
- #if directives, where we also keep preprocessing
- until everything is expanded, and then feed the
- result with disabled expansion to ISO preprocessor
- for handling the directives. */
- lex_state = ls_none;
- save_argument (&fmacro, out - pfile->out.base);
- cpp_macro m;
- memset (&m, '\0', sizeof (m));
- m.paramc = fmacro.paramc;
- if (_cpp_arguments_ok (pfile, &m, fmacro.node,
- fmacro.argc))
- {
- size_t len = fmacro.args[1] - fmacro.args[0];
- uchar *buf;
- /* Remove the macro's invocation from the
- output, and push its replacement text. */
- pfile->out.cur = pfile->out.base + fmacro.offset;
- CUR (context) = cur;
- buf = _cpp_unaligned_alloc (pfile, len + 2);
- buf[0] = '(';
- memcpy (buf + 1, pfile->out.base + fmacro.args[0],
- len);
- buf[len + 1] = '\n';
- const unsigned char *ctx_rlimit = RLIMIT (context);
- const unsigned char *saved_cur = pfile->buffer->cur;
- const unsigned char *saved_rlimit
- = pfile->buffer->rlimit;
- const unsigned char *saved_line_base
- = pfile->buffer->line_base;
- bool saved_need_line = pfile->buffer->need_line;
- cpp_buffer *saved_overlaid_buffer
- = pfile->overlaid_buffer;
- pfile->buffer->cur = buf;
- pfile->buffer->line_base = buf;
- pfile->buffer->rlimit = buf + len + 1;
- pfile->buffer->need_line = false;
- pfile->overlaid_buffer = pfile->buffer;
- bool saved_in_directive = pfile->state.in_directive;
- pfile->state.in_directive = true;
- cpp_context *saved_prev_context = context->prev;
- context->prev = NULL;
- _cpp_scan_out_logical_line (pfile, NULL, true);
- pfile->state.in_directive = saved_in_directive;
- check_output_buffer (pfile, 1);
- *pfile->out.cur = '\n';
- pfile->buffer->cur = pfile->out.base + fmacro.offset;
- pfile->buffer->line_base = pfile->buffer->cur;
- pfile->buffer->rlimit = pfile->out.cur;
- CUR (context) = pfile->buffer->cur;
- RLIMIT (context) = pfile->buffer->rlimit;
- pfile->state.prevent_expansion++;
- const uchar *text
- = _cpp_builtin_macro_text (pfile, fmacro.node);
- pfile->state.prevent_expansion--;
- context->prev = saved_prev_context;
- pfile->buffer->cur = saved_cur;
- pfile->buffer->rlimit = saved_rlimit;
- pfile->buffer->line_base = saved_line_base;
- pfile->buffer->need_line = saved_need_line;
- pfile->overlaid_buffer = saved_overlaid_buffer;
- pfile->out.cur = pfile->out.base + fmacro.offset;
- CUR (context) = cur;
- RLIMIT (context) = ctx_rlimit;
- len = ustrlen (text);
- buf = _cpp_unaligned_alloc (pfile, len + 1);
- memcpy (buf, text, len);
- buf[len] = '\n';
- text = buf;
- _cpp_push_text_context (pfile, fmacro.node,
- text, len);
- goto new_context;
- }
- break;
- }
- cpp_macro *m = fmacro.node->value.macro;
- m->used = 1;
- lex_state = ls_none;
- save_argument (&fmacro, out - pfile->out.base);
- /* A single zero-length argument is no argument. */
- if (fmacro.argc == 1
- && m->paramc == 0
- && out == pfile->out.base + fmacro.offset + 1)
- fmacro.argc = 0;
- if (_cpp_arguments_ok (pfile, m, fmacro.node, fmacro.argc))
- {
- /* Remove the macro's invocation from the
- output, and push its replacement text. */
- pfile->out.cur = pfile->out.base + fmacro.offset;
- CUR (context) = cur;
- replace_args_and_push (pfile, &fmacro);
- goto new_context;
- }
- }
- else if (lex_state == ls_answer || lex_state == ls_defined_close
- || lex_state == ls_has_include_close)
- lex_state = ls_none;
- }
- break;
- case '#':
- if (cur - 1 == start_of_input_line
- /* A '#' from a macro doesn't start a directive. */
- && !pfile->context->prev
- && !pfile->state.in_directive)
- {
- /* A directive. With the way _cpp_handle_directive
- currently works, we only want to call it if either we
- know the directive is OK, or we want it to fail and
- be removed from the output. If we want it to be
- passed through (the assembler case) then we must not
- call _cpp_handle_directive. */
- pfile->out.cur = out;
- cur = skip_whitespace (pfile, cur, true /* skip_comments */);
- out = pfile->out.cur;
- if (*cur == '\n')
- {
- /* Null directive. Ignore it and don't invalidate
- the MI optimization. */
- pfile->buffer->need_line = true;
- CPP_INCREMENT_LINE (pfile, 0);
- result = false;
- goto done;
- }
- else
- {
- bool do_it = false;
- if (is_numstart (*cur)
- && CPP_OPTION (pfile, lang) != CLK_ASM)
- do_it = true;
- else if (is_idstart (*cur))
- /* Check whether we know this directive, but don't
- advance. */
- do_it = lex_identifier (pfile, cur)->is_directive;
- if (do_it || CPP_OPTION (pfile, lang) != CLK_ASM)
- {
- /* This is a kludge. We want to have the ISO
- preprocessor lex the next token. */
- pfile->buffer->cur = cur;
- _cpp_handle_directive (pfile, false /* indented */);
- result = false;
- goto done;
- }
- }
- }
- if (pfile->state.in_expression)
- {
- lex_state = ls_hash;
- continue;
- }
- break;
- default:
- break;
- }
- /* Non-whitespace disables MI optimization and stops treating
- '<' as a quote in #include. */
- header_ok = false;
- if (!pfile->state.in_directive)
- pfile->mi_valid = false;
- if (lex_state == ls_none)
- continue;
- /* Some of these transitions of state are syntax errors. The
- ISO preprocessor will issue errors later. */
- if (lex_state == ls_fun_open)
- /* Missing '('. */
- lex_state = ls_none;
- else if (lex_state == ls_hash
- || lex_state == ls_predicate
- || lex_state == ls_defined
- || lex_state == ls_has_include)
- lex_state = ls_none;
- /* ls_answer and ls_defined_close keep going until ')'. */
- }
- done:
- if (fmacro.buff)
- _cpp_release_buff (pfile, fmacro.buff);
- if (lex_state == ls_fun_close)
- cpp_error_with_line (pfile, CPP_DL_ERROR, fmacro.line, 0,
- "unterminated argument list invoking macro \"%s\"",
- NODE_NAME (fmacro.node));
- return result;
- }
- /* Push a context holding the replacement text of the macro NODE on
- the context stack. NODE is either object-like, or a function-like
- macro with no arguments. */
- static void
- push_replacement_text (cpp_reader *pfile, cpp_hashnode *node)
- {
- size_t len;
- const uchar *text;
- uchar *buf;
- if (node->flags & NODE_BUILTIN)
- {
- text = _cpp_builtin_macro_text (pfile, node);
- len = ustrlen (text);
- buf = _cpp_unaligned_alloc (pfile, len + 1);
- memcpy (buf, text, len);
- buf[len] = '\n';
- text = buf;
- }
- else
- {
- cpp_macro *macro = node->value.macro;
- macro->used = 1;
- text = macro->exp.text;
- macro->traditional = 1;
- len = macro->count;
- }
- _cpp_push_text_context (pfile, node, text, len);
- }
- /* Returns TRUE if traditional macro recursion is detected. */
- static bool
- recursive_macro (cpp_reader *pfile, cpp_hashnode *node)
- {
- bool recursing = !!(node->flags & NODE_DISABLED);
- /* Object-like macros that are already expanding are necessarily
- recursive.
- However, it is possible to have traditional function-like macros
- that are not infinitely recursive but recurse to any given depth.
- Further, it is easy to construct examples that get ever longer
- until the point they stop recursing. So there is no easy way to
- detect true recursion; instead we assume any expansion more than
- 20 deep since the first invocation of this macro must be
- recursing. */
- if (recursing && fun_like_macro (node))
- {
- size_t depth = 0;
- cpp_context *context = pfile->context;
- do
- {
- depth++;
- if (context->c.macro == node && depth > 20)
- break;
- context = context->prev;
- }
- while (context);
- recursing = context != NULL;
- }
- if (recursing)
- cpp_error (pfile, CPP_DL_ERROR,
- "detected recursion whilst expanding macro \"%s\"",
- NODE_NAME (node));
- return recursing;
- }
- /* Return the length of the replacement text of a function-like or
- object-like non-builtin macro. */
- size_t
- _cpp_replacement_text_len (const cpp_macro *macro)
- {
- size_t len;
- if (macro->fun_like && (macro->paramc != 0))
- {
- const uchar *exp;
- len = 0;
- for (exp = macro->exp.text;;)
- {
- struct block *b = (struct block *) exp;
- len += b->text_len;
- if (b->arg_index == 0)
- break;
- len += NODE_LEN (macro->params[b->arg_index - 1]);
- exp += BLOCK_LEN (b->text_len);
- }
- }
- else
- len = macro->count;
-
- return len;
- }
- /* Copy the replacement text of MACRO to DEST, which must be of
- sufficient size. It is not NUL-terminated. The next character is
- returned. */
- uchar *
- _cpp_copy_replacement_text (const cpp_macro *macro, uchar *dest)
- {
- if (macro->fun_like && (macro->paramc != 0))
- {
- const uchar *exp;
- for (exp = macro->exp.text;;)
- {
- struct block *b = (struct block *) exp;
- cpp_hashnode *param;
- memcpy (dest, b->text, b->text_len);
- dest += b->text_len;
- if (b->arg_index == 0)
- break;
- param = macro->params[b->arg_index - 1];
- memcpy (dest, NODE_NAME (param), NODE_LEN (param));
- dest += NODE_LEN (param);
- exp += BLOCK_LEN (b->text_len);
- }
- }
- else
- {
- memcpy (dest, macro->exp.text, macro->count);
- dest += macro->count;
- }
- return dest;
- }
- /* Push a context holding the replacement text of the macro NODE on
- the context stack. NODE is either object-like, or a function-like
- macro with no arguments. */
- static void
- replace_args_and_push (cpp_reader *pfile, struct fun_macro *fmacro)
- {
- cpp_macro *macro = fmacro->node->value.macro;
- if (macro->paramc == 0)
- push_replacement_text (pfile, fmacro->node);
- else
- {
- const uchar *exp;
- uchar *p;
- _cpp_buff *buff;
- size_t len = 0;
- int cxtquote = 0;
- /* Get an estimate of the length of the argument-replaced text.
- This is a worst case estimate, assuming that every replacement
- text character needs quoting. */
- for (exp = macro->exp.text;;)
- {
- struct block *b = (struct block *) exp;
- len += b->text_len;
- if (b->arg_index == 0)
- break;
- len += 2 * (fmacro->args[b->arg_index]
- - fmacro->args[b->arg_index - 1] - 1);
- exp += BLOCK_LEN (b->text_len);
- }
- /* Allocate room for the expansion plus \n. */
- buff = _cpp_get_buff (pfile, len + 1);
- /* Copy the expansion and replace arguments. */
- /* Accumulate actual length, including quoting as necessary */
- p = BUFF_FRONT (buff);
- len = 0;
- for (exp = macro->exp.text;;)
- {
- struct block *b = (struct block *) exp;
- size_t arglen;
- int argquote;
- uchar *base;
- uchar *in;
- len += b->text_len;
- /* Copy the non-argument text literally, keeping
- track of whether matching quotes have been seen. */
- for (arglen = b->text_len, in = b->text; arglen > 0; arglen--)
- {
- if (*in == '"')
- cxtquote = ! cxtquote;
- *p++ = *in++;
- }
- /* Done if no more arguments */
- if (b->arg_index == 0)
- break;
- arglen = (fmacro->args[b->arg_index]
- - fmacro->args[b->arg_index - 1] - 1);
- base = pfile->out.base + fmacro->args[b->arg_index - 1];
- in = base;
- #if 0
- /* Skip leading whitespace in the text for the argument to
- be substituted. To be compatible with gcc 2.95, we would
- also need to trim trailing whitespace. Gcc 2.95 trims
- leading and trailing whitespace, which may be a bug. The
- current gcc testsuite explicitly checks that this leading
- and trailing whitespace in actual arguments is
- preserved. */
- while (arglen > 0 && is_space (*in))
- {
- in++;
- arglen--;
- }
- #endif
- for (argquote = 0; arglen > 0; arglen--)
- {
- if (cxtquote && *in == '"')
- {
- if (in > base && *(in-1) != '\\')
- argquote = ! argquote;
- /* Always add backslash before double quote if argument
- is expanded in a quoted context */
- *p++ = '\\';
- len++;
- }
- else if (cxtquote && argquote && *in == '\\')
- {
- /* Always add backslash before a backslash in an argument
- that is expanded in a quoted context and also in the
- range of a quoted context in the argument itself. */
- *p++ = '\\';
- len++;
- }
- *p++ = *in++;
- len++;
- }
- exp += BLOCK_LEN (b->text_len);
- }
- /* \n-terminate. */
- *p = '\n';
- _cpp_push_text_context (pfile, fmacro->node, BUFF_FRONT (buff), len);
- /* So we free buffer allocation when macro is left. */
- pfile->context->buff = buff;
- }
- }
- /* Read and record the parameters, if any, of a function-like macro
- definition. Destroys pfile->out.cur.
- Returns true on success, false on failure (syntax error or a
- duplicate parameter). On success, CUR (pfile->context) is just
- past the closing parenthesis. */
- static bool
- scan_parameters (cpp_reader *pfile, cpp_macro *macro)
- {
- const uchar *cur = CUR (pfile->context) + 1;
- bool ok;
- for (;;)
- {
- cur = skip_whitespace (pfile, cur, true /* skip_comments */);
- if (is_idstart (*cur))
- {
- struct cpp_hashnode *id = lex_identifier (pfile, cur);
- ok = false;
- if (_cpp_save_parameter (pfile, macro, id, id))
- break;
- cur = skip_whitespace (pfile, CUR (pfile->context),
- true /* skip_comments */);
- if (*cur == ',')
- {
- cur++;
- continue;
- }
- ok = (*cur == ')');
- break;
- }
- ok = (*cur == ')' && macro->paramc == 0);
- break;
- }
- if (!ok)
- cpp_error (pfile, CPP_DL_ERROR, "syntax error in macro parameter list");
- CUR (pfile->context) = cur + (*cur == ')');
- return ok;
- }
- /* Save the text from pfile->out.base to pfile->out.cur as
- the replacement text for the current macro, followed by argument
- ARG_INDEX, with zero indicating the end of the replacement
- text. */
- static void
- save_replacement_text (cpp_reader *pfile, cpp_macro *macro,
- unsigned int arg_index)
- {
- size_t len = pfile->out.cur - pfile->out.base;
- uchar *exp;
- if (macro->paramc == 0)
- {
- /* Object-like and function-like macros without parameters
- simply store their \n-terminated replacement text. */
- exp = _cpp_unaligned_alloc (pfile, len + 1);
- memcpy (exp, pfile->out.base, len);
- exp[len] = '\n';
- macro->exp.text = exp;
- macro->traditional = 1;
- macro->count = len;
- }
- else
- {
- /* Store the text's length (unsigned int), the argument index
- (unsigned short, base 1) and then the text. */
- size_t blen = BLOCK_LEN (len);
- struct block *block;
- if (macro->count + blen > BUFF_ROOM (pfile->a_buff))
- _cpp_extend_buff (pfile, &pfile->a_buff, macro->count + blen);
- exp = BUFF_FRONT (pfile->a_buff);
- block = (struct block *) (exp + macro->count);
- macro->exp.text = exp;
- macro->traditional = 1;
- /* Write out the block information. */
- block->text_len = len;
- block->arg_index = arg_index;
- memcpy (block->text, pfile->out.base, len);
- /* Lex the rest into the start of the output buffer. */
- pfile->out.cur = pfile->out.base;
- macro->count += blen;
- /* If we've finished, commit the memory. */
- if (arg_index == 0)
- BUFF_FRONT (pfile->a_buff) += macro->count;
- }
- }
- /* Analyze and save the replacement text of a macro. Returns true on
- success. */
- bool
- _cpp_create_trad_definition (cpp_reader *pfile, cpp_macro *macro)
- {
- const uchar *cur;
- uchar *limit;
- cpp_context *context = pfile->context;
- /* The context has not been set up for command line defines, and CUR
- has not been updated for the macro name for in-file defines. */
- pfile->out.cur = pfile->out.base;
- CUR (context) = pfile->buffer->cur;
- RLIMIT (context) = pfile->buffer->rlimit;
- check_output_buffer (pfile, RLIMIT (context) - CUR (context));
- /* Is this a function-like macro? */
- if (* CUR (context) == '(')
- {
- bool ok = scan_parameters (pfile, macro);
- /* Remember the params so we can clear NODE_MACRO_ARG flags. */
- macro->params = (cpp_hashnode **) BUFF_FRONT (pfile->a_buff);
- /* Setting macro to NULL indicates an error occurred, and
- prevents unnecessary work in _cpp_scan_out_logical_line. */
- if (!ok)
- macro = NULL;
- else
- {
- BUFF_FRONT (pfile->a_buff) = (uchar *) ¯o->params[macro->paramc];
- macro->fun_like = 1;
- }
- }
- /* Skip leading whitespace in the replacement text. */
- pfile->buffer->cur
- = skip_whitespace (pfile, CUR (context),
- CPP_OPTION (pfile, discard_comments_in_macro_exp));
- pfile->state.prevent_expansion++;
- _cpp_scan_out_logical_line (pfile, macro, false);
- pfile->state.prevent_expansion--;
- if (!macro)
- return false;
- /* Skip trailing white space. */
- cur = pfile->out.base;
- limit = pfile->out.cur;
- while (limit > cur && is_space (limit[-1]))
- limit--;
- pfile->out.cur = limit;
- save_replacement_text (pfile, macro, 0);
- return true;
- }
- /* Copy SRC of length LEN to DEST, but convert all contiguous
- whitespace to a single space, provided it is not in quotes. The
- quote currently in effect is pointed to by PQUOTE, and is updated
- by the function. Returns the number of bytes copied. */
- static size_t
- canonicalize_text (uchar *dest, const uchar *src, size_t len, uchar *pquote)
- {
- uchar *orig_dest = dest;
- uchar quote = *pquote;
- while (len)
- {
- if (is_space (*src) && !quote)
- {
- do
- src++, len--;
- while (len && is_space (*src));
- *dest++ = ' ';
- }
- else
- {
- if (*src == '\'' || *src == '"')
- {
- if (!quote)
- quote = *src;
- else if (quote == *src)
- quote = 0;
- }
- *dest++ = *src++, len--;
- }
- }
- *pquote = quote;
- return dest - orig_dest;
- }
- /* Returns true if MACRO1 and MACRO2 have expansions different other
- than in the form of their whitespace. */
- bool
- _cpp_expansions_different_trad (const cpp_macro *macro1,
- const cpp_macro *macro2)
- {
- uchar *p1 = XNEWVEC (uchar, macro1->count + macro2->count);
- uchar *p2 = p1 + macro1->count;
- uchar quote1 = 0, quote2 = 0;
- bool mismatch;
- size_t len1, len2;
- if (macro1->paramc > 0)
- {
- const uchar *exp1 = macro1->exp.text, *exp2 = macro2->exp.text;
- mismatch = true;
- for (;;)
- {
- struct block *b1 = (struct block *) exp1;
- struct block *b2 = (struct block *) exp2;
- if (b1->arg_index != b2->arg_index)
- break;
- len1 = canonicalize_text (p1, b1->text, b1->text_len, "e1);
- len2 = canonicalize_text (p2, b2->text, b2->text_len, "e2);
- if (len1 != len2 || memcmp (p1, p2, len1))
- break;
- if (b1->arg_index == 0)
- {
- mismatch = false;
- break;
- }
- exp1 += BLOCK_LEN (b1->text_len);
- exp2 += BLOCK_LEN (b2->text_len);
- }
- }
- else
- {
- len1 = canonicalize_text (p1, macro1->exp.text, macro1->count, "e1);
- len2 = canonicalize_text (p2, macro2->exp.text, macro2->count, "e2);
- mismatch = (len1 != len2 || memcmp (p1, p2, len1));
- }
- free (p1);
- return mismatch;
- }
|