Commit 1ce676a0 by Neil Booth Committed by Neil Booth

cpphash.h (_cpp_push_text_context): Update.

	* cpphash.h (_cpp_push_text_context): Update.
	(_cpp_arguments_ok): New.
	* cppmacro.c (_cpp_arguments_ok): New, split out from...
	(collect_args): ...here.
	(_cpp_push_text_context): Change inputs.
	* cpptrad.c (struct fun_macro, maybe_start_funlike, save_argument,
	replace_args_and_push): New.
	(lex_identifier, _cpp_lex_identifier_trad, scan_parameters):
	Don't use IS macros directly.
	(scan_out_logical_line): Handle function-like macro argument
	collection.
	(push_replacement_text): Update.
	(replacement_length): Remove.
	(_cpp_create_trad_definition): Don't skip whitespace before
	checking for '('.

From-SVN: r54412
parent 25f2e176
2002-06-09 Neil Booth <neil@daikokuya.demon.co.uk>
* cpphash.h (_cpp_push_text_context): Update.
(_cpp_arguments_ok): New.
* cppmacro.c (_cpp_arguments_ok): New, split out from...
(collect_args): ...here.
(_cpp_push_text_context): Change inputs.
* cpptrad.c (struct fun_macro, maybe_start_funlike, save_argument,
replace_args_and_push): New.
(lex_identifier, _cpp_lex_identifier_trad, scan_parameters):
Don't use IS macros directly.
(scan_out_logical_line): Handle function-like macro argument
collection.
(push_replacement_text): Update.
(replacement_length): Remove.
(_cpp_create_trad_definition): Don't skip whitespace before
checking for '('.
2002-06-09 Marek Michalkiewicz <marekm@amelek.gda.pl> 2002-06-09 Marek Michalkiewicz <marekm@amelek.gda.pl>
* config/avr/avr.c (avr_mcu_types): Update for new devices. * config/avr/avr.c (avr_mcu_types): Update for new devices.
......
...@@ -438,9 +438,12 @@ extern void _cpp_free_definition PARAMS ((cpp_hashnode *)); ...@@ -438,9 +438,12 @@ extern void _cpp_free_definition PARAMS ((cpp_hashnode *));
extern bool _cpp_create_definition PARAMS ((cpp_reader *, cpp_hashnode *)); extern bool _cpp_create_definition PARAMS ((cpp_reader *, cpp_hashnode *));
extern void _cpp_pop_context PARAMS ((cpp_reader *)); extern void _cpp_pop_context PARAMS ((cpp_reader *));
extern void _cpp_push_text_context PARAMS ((cpp_reader *, cpp_hashnode *, extern void _cpp_push_text_context PARAMS ((cpp_reader *, cpp_hashnode *,
const uchar *, const uchar*)); const uchar *, size_t));
extern bool _cpp_save_parameter PARAMS ((cpp_reader *, cpp_macro *, extern bool _cpp_save_parameter PARAMS ((cpp_reader *, cpp_macro *,
cpp_hashnode *)); cpp_hashnode *));
extern bool _cpp_arguments_ok PARAMS ((cpp_reader *, cpp_macro *,
const cpp_hashnode *,
unsigned int));
/* In cpphash.c */ /* In cpphash.c */
extern void _cpp_init_hashtable PARAMS ((cpp_reader *, hash_table *)); extern void _cpp_init_hashtable PARAMS ((cpp_reader *, hash_table *));
......
...@@ -451,6 +451,52 @@ paste_all_tokens (pfile, lhs) ...@@ -451,6 +451,52 @@ paste_all_tokens (pfile, lhs)
push_token_context (pfile, NULL, lhs, 1); push_token_context (pfile, NULL, lhs, 1);
} }
/* Returns TRUE if the number of arguments ARGC supplied in an
invocation of the MACRO referenced by NODE is valid. An empty
invocation to a macro with no parameters should pass ARGC as zero.
Note that MACRO cannot necessarily be deduced from NODE, in case
NODE was redefined whilst collecting arguments. */
bool
_cpp_arguments_ok (pfile, macro, node, argc)
cpp_reader *pfile;
cpp_macro *macro;
const cpp_hashnode *node;
unsigned int argc;
{
if (argc == macro->paramc)
return true;
if (argc < macro->paramc)
{
/* As an extension, a rest argument is allowed to not appear in
the invocation at all.
e.g. #define debug(format, args...) something
debug("string");
This is exactly the same as if there had been an empty rest
argument - debug("string", ). */
if (argc + 1 == macro->paramc && macro->variadic)
{
if (CPP_PEDANTIC (pfile) && ! macro->syshdr)
cpp_error (pfile, DL_PEDWARN,
"ISO C99 requires rest arguments to be used");
return true;
}
cpp_error (pfile, DL_ERROR,
"macro \"%s\" requires %u arguments, but only %u given",
NODE_NAME (node), macro->paramc, argc);
}
else
cpp_error (pfile, DL_ERROR,
"macro \"%s\" passed %u arguments, but takes just %u",
NODE_NAME (node), argc, macro->paramc);
return false;
}
/* Reads and returns the arguments to a function-like macro /* Reads and returns the arguments to a function-like macro
invocation. Assumes the opening parenthesis has been processed. invocation. Assumes the opening parenthesis has been processed.
If there is an error, emits an appropriate diagnostic and returns If there is an error, emits an appropriate diagnostic and returns
...@@ -466,7 +512,6 @@ collect_args (pfile, node) ...@@ -466,7 +512,6 @@ collect_args (pfile, node)
macro_arg *args, *arg; macro_arg *args, *arg;
const cpp_token *token; const cpp_token *token;
unsigned int argc; unsigned int argc;
bool error = false;
macro = node->value.macro; macro = node->value.macro;
if (macro->paramc) if (macro->paramc)
...@@ -561,47 +606,17 @@ collect_args (pfile, node) ...@@ -561,47 +606,17 @@ collect_args (pfile, node)
cpp_error (pfile, DL_ERROR, cpp_error (pfile, DL_ERROR,
"unterminated argument list invoking macro \"%s\"", "unterminated argument list invoking macro \"%s\"",
NODE_NAME (node)); NODE_NAME (node));
error = true;
}
else if (argc < macro->paramc)
{
/* As an extension, a rest argument is allowed to not appear in
the invocation at all.
e.g. #define debug(format, args...) something
debug("string");
This is exactly the same as if there had been an empty rest
argument - debug("string", ). */
if (argc + 1 == macro->paramc && macro->variadic)
{
if (CPP_PEDANTIC (pfile) && ! macro->syshdr)
cpp_error (pfile, DL_PEDWARN,
"ISO C99 requires rest arguments to be used");
} }
else else
{ {
cpp_error (pfile, DL_ERROR, /* A single empty argument is counted as no argument. */
"macro \"%s\" requires %u arguments, but only %u given", if (argc == 1 && macro->paramc == 0 && args[0].count == 0)
NODE_NAME (node), macro->paramc, argc); argc = 0;
error = true; if (_cpp_arguments_ok (pfile, macro, node, argc))
}
}
else if (argc > macro->paramc)
{
/* Empty argument to a macro taking no arguments is OK. */
if (argc != 1 || arg->count)
{
cpp_error (pfile, DL_ERROR,
"macro \"%s\" passed %u arguments, but takes just %u",
NODE_NAME (node), argc, macro->paramc);
error = true;
}
}
if (!error)
return base_buff; return base_buff;
}
/* An error occurred. */
_cpp_release_buff (pfile, base_buff); _cpp_release_buff (pfile, base_buff);
return NULL; return NULL;
} }
...@@ -919,10 +934,11 @@ push_token_context (pfile, macro, first, count) ...@@ -919,10 +934,11 @@ push_token_context (pfile, macro, first, count)
/* Push a traditional macro's replacement text. */ /* Push a traditional macro's replacement text. */
void void
_cpp_push_text_context (pfile, macro, start, end) _cpp_push_text_context (pfile, macro, start, len)
cpp_reader *pfile; cpp_reader *pfile;
cpp_hashnode *macro; cpp_hashnode *macro;
const uchar *start, *end; const uchar *start;
size_t len;
{ {
cpp_context *context = next_context (pfile); cpp_context *context = next_context (pfile);
...@@ -930,7 +946,7 @@ _cpp_push_text_context (pfile, macro, start, end) ...@@ -930,7 +946,7 @@ _cpp_push_text_context (pfile, macro, start, end)
context->macro = macro; context->macro = macro;
context->buff = NULL; context->buff = NULL;
CUR (context) = start; CUR (context) = start;
RLIMIT (context) = end; RLIMIT (context) = start + len;
} }
/* Expand an argument ARG before replacing parameters in a /* Expand an argument ARG before replacing parameters in a
......
...@@ -44,6 +44,29 @@ struct block ...@@ -44,6 +44,29 @@ struct block
#define BLOCK_HEADER_LEN offsetof (struct block, text) #define BLOCK_HEADER_LEN offsetof (struct block, text)
#define BLOCK_LEN(TEXT_LEN) CPP_ALIGN (BLOCK_HEADER_LEN + TEXT_LEN) #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;
/* Zero-based index of argument being currently lexed. */
unsigned int argc;
};
/* Lexing TODO: Handle -C, maybe -CC, and space in escaped newlines. /* Lexing TODO: Handle -C, maybe -CC, and space in escaped newlines.
Stop cpplex.c from recognizing comments and directives during its Stop cpplex.c from recognizing comments and directives during its
lexing pass. Get rid of line_base usage - seems pointless? Do we lexing pass. Get rid of line_base usage - seems pointless? Do we
...@@ -62,7 +85,10 @@ static void push_replacement_text PARAMS ((cpp_reader *, cpp_hashnode *)); ...@@ -62,7 +85,10 @@ static void push_replacement_text PARAMS ((cpp_reader *, cpp_hashnode *));
static bool scan_parameters PARAMS ((cpp_reader *, cpp_macro *)); static bool scan_parameters PARAMS ((cpp_reader *, cpp_macro *));
static void save_replacement_text PARAMS ((cpp_reader *, cpp_macro *, static void save_replacement_text PARAMS ((cpp_reader *, cpp_macro *,
unsigned int)); unsigned int));
static unsigned int replacement_length PARAMS ((cpp_macro *)); static void maybe_start_funlike PARAMS ((cpp_reader *, cpp_hashnode *,
const uchar *, struct fun_macro *));
static void save_argument PARAMS ((struct fun_macro *, size_t));
static void replace_args_and_push PARAMS ((cpp_reader *, struct fun_macro *));
/* Ensures we have N bytes' space in the output buffer, and /* Ensures we have N bytes' space in the output buffer, and
reallocates it if not. */ reallocates it if not. */
...@@ -205,10 +231,10 @@ lex_identifier (pfile, cur) ...@@ -205,10 +231,10 @@ lex_identifier (pfile, cur)
{ {
do do
*out++ = *cur++; *out++ = *cur++;
while (ISIDNUM (*cur)); while (is_numchar (*cur));
cur = skip_escaped_newlines (pfile, cur); cur = skip_escaped_newlines (pfile, cur);
} }
while (ISIDNUM (*cur)); while (is_numchar (*cur));
CUR (pfile->context) = cur; CUR (pfile->context) = cur;
len = out - pfile->trad_out_cur; len = out - pfile->trad_out_cur;
...@@ -226,7 +252,7 @@ _cpp_lex_identifier_trad (pfile) ...@@ -226,7 +252,7 @@ _cpp_lex_identifier_trad (pfile)
{ {
const uchar *cur = skip_whitespace (pfile, CUR (pfile->context)); const uchar *cur = skip_whitespace (pfile, CUR (pfile->context));
if (!ISIDST (*cur)) if (!is_idstart (*cur))
{ {
CUR (pfile->context) = cur; CUR (pfile->context) = cur;
return NULL; return NULL;
...@@ -309,12 +335,45 @@ _cpp_read_logical_line_trad (pfile) ...@@ -309,12 +335,45 @@ _cpp_read_logical_line_trad (pfile)
return true; return true;
} }
/* Set up state for finding the opening '(' of a function-like
macro. */
static void
maybe_start_funlike (pfile, node, start, macro)
cpp_reader *pfile;
cpp_hashnode *node;
const uchar *start;
struct fun_macro *macro;
{
unsigned int n = node->value.macro->paramc + 1;
if (macro->buff)
_cpp_release_buff (pfile, macro->buff);
macro->buff = _cpp_get_buff (pfile, n * sizeof (size_t));
macro->args = (size_t *) BUFF_FRONT (macro->buff);
macro->node = node;
macro->offset = start - pfile->trad_out_base;
macro->argc = 0;
pfile->state.parsing_args = 1;
}
/* Save the OFFSET of the start of the next argument to MACRO. */
static void
save_argument (macro, offset)
struct fun_macro *macro;
size_t offset;
{
macro->argc++;
if (macro->argc <= macro->node->value.macro->paramc)
macro->args[macro->argc] = offset;
}
/* Copies the next logical line in the current buffer to the output /* Copies the next logical line in the current buffer to the output
buffer. The output is guaranteed to terminate with a NUL buffer. The output is guaranteed to terminate with a NUL
character. character.
If MACRO is non-NULL, then we are scanning the replacement list of 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 MACRO, and we call save_replacement_text() every time we meet an
argument. */ argument. */
static void static void
scan_out_logical_line (pfile, macro) scan_out_logical_line (pfile, macro)
...@@ -323,9 +382,11 @@ scan_out_logical_line (pfile, macro) ...@@ -323,9 +382,11 @@ scan_out_logical_line (pfile, macro)
{ {
cpp_context *context; cpp_context *context;
const uchar *cur; const uchar *cur;
unsigned int c, quote = 0; unsigned int c, paren_depth, quote = 0;
uchar *out; uchar *out;
struct fun_macro fmacro;
fmacro.buff = NULL;
new_context: new_context:
context = pfile->context; context = pfile->context;
cur = CUR (context); cur = CUR (context);
...@@ -357,16 +418,22 @@ scan_out_logical_line (pfile, macro) ...@@ -357,16 +418,22 @@ scan_out_logical_line (pfile, macro)
cur--; cur--;
if (!pfile->buffer->from_stage3) if (!pfile->buffer->from_stage3)
cpp_error (pfile, DL_PEDWARN, "no newline at end of file"); cpp_error (pfile, DL_PEDWARN, "no newline at end of file");
if (pfile->state.parsing_args == 2)
cpp_error (pfile, DL_ERROR,
"unterminated argument list invoking macro \"%s\"",
NODE_NAME (fmacro.node));
pfile->line++; pfile->line++;
goto finish_output; goto done;
case '\r': case '\n': case '\r': case '\n':
cur = handle_newline (pfile, cur - 1); cur = handle_newline (pfile, cur - 1);
out[-1] = '\0'; if (pfile->state.parsing_args == 2)
finish_output: {
CUR (context) = cur; /* Newlines in arguments become a space. */
pfile->trad_out_cur = out - 1; out[-1] = ' ';
return; continue;
}
goto done;
case '"': case '"':
case '\'': case '\'':
...@@ -418,16 +485,25 @@ scan_out_logical_line (pfile, macro) ...@@ -418,16 +485,25 @@ scan_out_logical_line (pfile, macro)
pfile->trad_out_cur = --out; pfile->trad_out_cur = --out;
node = lex_identifier (pfile, cur - 1); node = lex_identifier (pfile, cur - 1);
if (node->type == NT_MACRO && !pfile->state.prevent_expansion) if (node->type == NT_MACRO
&& pfile->state.parsing_args != 2
&& !pfile->state.prevent_expansion)
{
if (node->value.macro->fun_like)
maybe_start_funlike (pfile, node, out, &fmacro);
else
{ {
/* Remove the macro name from the output. */ /* Remove the object-like macro's name from the
output, and push its replacement text. */
pfile->trad_out_cur = out; pfile->trad_out_cur = out;
push_replacement_text (pfile, node); push_replacement_text (pfile, node);
goto new_context; goto new_context;
} }
}
else if (macro && node->arg_index) else if (macro && node->arg_index)
{ {
/* Remove the macro name from the output. */ /* Found a parameter in the replacement text of a
#define. Remove its name from the output. */
pfile->trad_out_cur = out; pfile->trad_out_cur = out;
save_replacement_text (pfile, macro, node->arg_index); save_replacement_text (pfile, macro, node->arg_index);
} }
...@@ -437,15 +513,91 @@ scan_out_logical_line (pfile, macro) ...@@ -437,15 +513,91 @@ scan_out_logical_line (pfile, macro)
} }
break; break;
case '(':
if (quote == 0)
{
paren_depth++;
if (pfile->state.parsing_args == 1)
{
const uchar *p = pfile->trad_out_base + fmacro.offset;
/* Invoke a prior function-like macro if there is only
white space in-between. */
while (is_numchar (*p))
p++;
while (is_space (*p))
p++;
if (p == out - 1)
{
pfile->state.parsing_args = 2;
paren_depth = 1;
out = pfile->trad_out_base + fmacro.offset;
fmacro.args[0] = fmacro.offset;
}
else
pfile->state.parsing_args = 0;
}
}
break;
case ',':
if (quote == 0 && pfile->state.parsing_args == 2 && paren_depth == 1)
save_argument (&fmacro, out - pfile->trad_out_base);
break;
case ')':
if (quote == 0)
{
paren_depth--;
if (pfile->state.parsing_args == 2 && paren_depth == 0)
{
cpp_macro *m = fmacro.node->value.macro;
pfile->state.parsing_args = 0;
save_argument (&fmacro, out - pfile->trad_out_base);
/* A single whitespace argument is no argument. */
if (fmacro.argc == 1 && m->paramc == 0)
{
const uchar *p = pfile->trad_out_base;
p += fmacro.args[0];
while (is_space (*p))
p++;
if (p == pfile->trad_out_base + fmacro.args[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->trad_out_cur = (pfile->trad_out_base
+ fmacro.offset);
CUR (context) = cur;
replace_args_and_push (pfile, &fmacro);
goto new_context;
}
}
}
break;
default: default:
break; break;
} }
} }
done:
out[-1] = '\0';
CUR (context) = cur;
pfile->trad_out_cur = out - 1;
if (fmacro.buff)
_cpp_release_buff (pfile, fmacro.buff);
} }
/* Push a context holding the replacement text of the macro NODE on /* Push a context holding the replacement text of the macro NODE on
the context stack. Doesn't yet handle special built-ins or the context stack. NODE is either object-like, or a function-like
function-like macros. */ macro with no arguments. */
static void static void
push_replacement_text (pfile, node) push_replacement_text (pfile, node)
cpp_reader *pfile; cpp_reader *pfile;
...@@ -453,9 +605,70 @@ push_replacement_text (pfile, node) ...@@ -453,9 +605,70 @@ push_replacement_text (pfile, node)
{ {
cpp_macro *macro = node->value.macro; cpp_macro *macro = node->value.macro;
_cpp_push_text_context (pfile, node, _cpp_push_text_context (pfile, node, macro->exp.text, macro->count);
macro->exp.text, }
macro->exp.text + macro->count);
/* 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 (pfile, fmacro)
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;
/* Calculate the length of the argument-replaced text. */
for (exp = macro->exp.text;;)
{
struct block *b = (struct block *) exp;
len += b->text_len;
if (b->arg_index == 0)
break;
len += (fmacro->args[b->arg_index]
- fmacro->args[b->arg_index - 1] - 1);
exp += BLOCK_LEN (b->text_len);
}
/* Allocate room for the expansion plus NUL. */
buff = _cpp_get_buff (pfile, len + 1);
/* Copy the expansion and replace arguments. */
p = BUFF_FRONT (buff);
for (exp = macro->exp.text;;)
{
struct block *b = (struct block *) exp;
size_t arglen;
memcpy (p, b->text, b->text_len);
p += b->text_len;
if (b->arg_index == 0)
break;
arglen = (fmacro->args[b->arg_index]
- fmacro->args[b->arg_index - 1] - 1);
memcpy (p, pfile->trad_out_base + fmacro->args[b->arg_index - 1],
arglen);
p += arglen;
exp += BLOCK_LEN (b->text_len);
}
/* NUL-terminate. */
*p = '\0';
_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 /* Read and record the parameters, if any, of a function-like macro
...@@ -476,7 +689,7 @@ scan_parameters (pfile, macro) ...@@ -476,7 +689,7 @@ scan_parameters (pfile, macro)
{ {
cur = skip_whitespace (pfile, cur); cur = skip_whitespace (pfile, cur);
if (ISIDST (*cur)) if (is_idstart (*cur))
{ {
ok = false; ok = false;
if (_cpp_save_parameter (pfile, macro, lex_identifier (pfile, cur))) if (_cpp_save_parameter (pfile, macro, lex_identifier (pfile, cur)))
...@@ -500,25 +713,6 @@ scan_parameters (pfile, macro) ...@@ -500,25 +713,6 @@ scan_parameters (pfile, macro)
return ok; return ok;
} }
/* Calculate the length of the replacement text of MACRO. */
static unsigned int
replacement_length (macro)
cpp_macro *macro;
{
unsigned int result = 0;
const uchar *exp = macro->exp.text;
for (;;)
{
struct block *block = (struct block *) exp;
result += block->text_len;
if (block->arg_index == 0)
return result;
exp += BLOCK_LEN (block->text_len);
}
}
/* Save the text from pfile->trad_out_base to pfile->trad_out_cur as /* Save the text from pfile->trad_out_base to pfile->trad_out_cur as
the replacement text for the current macro, followed by argument the replacement text for the current macro, followed by argument
ARG_INDEX, with zero indicating the end of the replacement ARG_INDEX, with zero indicating the end of the replacement
...@@ -568,9 +762,6 @@ save_replacement_text (pfile, macro, arg_index) ...@@ -568,9 +762,6 @@ save_replacement_text (pfile, macro, arg_index)
in the replacement list, excluding the parameter names, and in the replacement list, excluding the parameter names, and
save this in macro->count, else store the total bytes in the save this in macro->count, else store the total bytes in the
replacement text so far (including block headers). */ replacement text so far (including block headers). */
if (arg_index == 0)
macro->count = replacement_length (macro);
else
macro->count += blen; macro->count += blen;
} }
} }
...@@ -585,13 +776,11 @@ _cpp_create_trad_definition (pfile, macro) ...@@ -585,13 +776,11 @@ _cpp_create_trad_definition (pfile, macro)
const uchar *cur; const uchar *cur;
uchar *limit; uchar *limit;
/* Skip leading whitespace now. */
CUR (pfile->context) = skip_whitespace (pfile, CUR (pfile->context));
/* Is this a function-like macro? */ /* Is this a function-like macro? */
if (* CUR (pfile->context) == '(') if (* CUR (pfile->context) == '(')
{ {
/* Setting macro to NULL indicates an error occurred. */ /* Setting macro to NULL indicates an error occurred, and
prevents unnecessary work in scan_out_logical_line. */
if (!scan_parameters (pfile, macro)) if (!scan_parameters (pfile, macro))
macro = NULL; macro = NULL;
else else
...@@ -601,9 +790,10 @@ _cpp_create_trad_definition (pfile, macro) ...@@ -601,9 +790,10 @@ _cpp_create_trad_definition (pfile, macro)
BUFF_FRONT (pfile->a_buff) = (uchar *) &macro->params[macro->paramc]; BUFF_FRONT (pfile->a_buff) = (uchar *) &macro->params[macro->paramc];
macro->fun_like = 1; macro->fun_like = 1;
} }
}
/* Skip leading whitespace in the replacement text. */
CUR (pfile->context) = skip_whitespace (pfile, CUR (pfile->context)); CUR (pfile->context) = skip_whitespace (pfile, CUR (pfile->context));
}
pfile->trad_out_cur = pfile->trad_out_base; pfile->trad_out_cur = pfile->trad_out_base;
pfile->state.prevent_expansion++; pfile->state.prevent_expansion++;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment