24 |
#include "m4.h" |
#include "m4.h" |
25 |
#include "m4private.h" |
#include "m4private.h" |
26 |
|
|
27 |
static void expand_macro (const char *name, m4_symbol *); |
static void collect_arguments (m4 *context, const char *name, |
28 |
static void expand_token (struct obstack *, m4__token_type, m4_token *); |
m4_symbol *symbol, struct obstack *argptr, |
29 |
|
struct obstack *arguments); |
30 |
|
static void expand_macro (m4 *context, const char *name, |
31 |
|
m4_symbol *symbol); |
32 |
|
static void expand_token (m4 *context, struct obstack *obs, |
33 |
|
m4__token_type type, m4_token *token); |
34 |
|
static boolean expand_argument (m4 *context, struct obstack *obs, |
35 |
|
m4_token *argp); |
36 |
|
|
37 |
/* Current recursion level in expand_macro (). */ |
/* Current recursion level in expand_macro (). */ |
38 |
int m4_expansion_level = 0; |
int m4_expansion_level = 0; |
42 |
|
|
43 |
/* This function reads all input, and expands each token, one at a time. */ |
/* This function reads all input, and expands each token, one at a time. */ |
44 |
void |
void |
45 |
m4_expand_input (void) |
m4_expand_input (m4 *context) |
46 |
{ |
{ |
47 |
m4__token_type type; |
m4__token_type type; |
48 |
m4_token token; |
m4_token token; |
49 |
|
|
50 |
while ((type = m4_next_token (&token)) != M4_TOKEN_EOF) |
while ((type = m4_next_token (&token)) != M4_TOKEN_EOF) |
51 |
expand_token ((struct obstack *) NULL, type, &token); |
expand_token (context, (struct obstack *) NULL, type, &token); |
52 |
} |
} |
53 |
|
|
54 |
|
|
57 |
macro definition. If they have, they are expanded as macros, otherwise |
macro definition. If they have, they are expanded as macros, otherwise |
58 |
the text are just copied to the output. */ |
the text are just copied to the output. */ |
59 |
static void |
static void |
60 |
expand_token (struct obstack *obs, m4__token_type type, m4_token *token) |
expand_token (m4 *context, struct obstack *obs, |
61 |
|
m4__token_type type, m4_token *token) |
62 |
{ |
{ |
63 |
m4_symbol *symbol; |
m4_symbol *symbol; |
64 |
char *text = xstrdup (TOKEN_TEXT (token)); |
char *text = xstrdup (TOKEN_TEXT (token)); |
82 |
if (M4_IS_ESCAPE(*textp)) |
if (M4_IS_ESCAPE(*textp)) |
83 |
++textp; |
++textp; |
84 |
|
|
85 |
symbol = m4_symbol_lookup (textp); |
symbol = m4_symbol_lookup (M4SYMTAB, textp); |
86 |
if (symbol == NULL |
if (symbol == NULL |
87 |
|| SYMBOL_TYPE (symbol) == M4_TOKEN_VOID |
|| SYMBOL_TYPE (symbol) == M4_TOKEN_VOID |
88 |
|| (SYMBOL_TYPE (symbol) == M4_TOKEN_FUNC |
|| (SYMBOL_TYPE (symbol) == M4_TOKEN_FUNC |
92 |
m4_shipout_text (obs, text, strlen (text)); |
m4_shipout_text (obs, text, strlen (text)); |
93 |
} |
} |
94 |
else |
else |
95 |
expand_macro (textp, symbol); |
expand_macro (context, textp, symbol); |
96 |
} |
} |
97 |
break; |
break; |
98 |
|
|
114 |
the last for the active macro call. The arguments are build on the |
the last for the active macro call. The arguments are build on the |
115 |
obstack OBS, indirectly through expand_token (). */ |
obstack OBS, indirectly through expand_token (). */ |
116 |
static boolean |
static boolean |
117 |
expand_argument (struct obstack *obs, m4_token *argp) |
expand_argument (m4 *context, struct obstack *obs, m4_token *argp) |
118 |
{ |
{ |
119 |
m4__token_type type; |
m4__token_type type; |
120 |
m4_token token; |
m4_token token; |
157 |
paren_level++; |
paren_level++; |
158 |
else if (M4_IS_CLOSE (*text)) |
else if (M4_IS_CLOSE (*text)) |
159 |
paren_level--; |
paren_level--; |
160 |
expand_token (obs, type, &token); |
expand_token (context, obs, type, &token); |
161 |
break; |
break; |
162 |
|
|
163 |
case M4_TOKEN_EOF: |
case M4_TOKEN_EOF: |
168 |
case M4_TOKEN_WORD: |
case M4_TOKEN_WORD: |
169 |
case M4_TOKEN_SPACE: |
case M4_TOKEN_SPACE: |
170 |
case M4_TOKEN_STRING: |
case M4_TOKEN_STRING: |
171 |
expand_token (obs, type, &token); |
expand_token (context, obs, type, &token); |
172 |
break; |
break; |
173 |
|
|
174 |
case M4_TOKEN_MACDEF: |
case M4_TOKEN_MACDEF: |
186 |
} |
} |
187 |
} |
} |
188 |
|
|
189 |
|
|
190 |
|
/* The macro expansion is handled by expand_macro (). It parses the |
191 |
|
arguments, using collect_arguments (), and builds a table of pointers to |
192 |
|
the arguments. The arguments themselves are stored on a local obstack. |
193 |
|
Expand_macro () uses call_macro () to do the call of the macro. |
194 |
|
|
195 |
|
Expand_macro () is potentially recursive, since it calls expand_argument |
196 |
|
(), which might call expand_token (), which might call expand_macro (). */ |
197 |
|
static void |
198 |
|
expand_macro (m4 *context, const char *name, m4_symbol *symbol) |
199 |
|
{ |
200 |
|
struct obstack arguments; |
201 |
|
struct obstack argptr; |
202 |
|
m4_token **argv; |
203 |
|
int argc; |
204 |
|
struct obstack *expansion; |
205 |
|
const char *expanded; |
206 |
|
boolean traced; |
207 |
|
int my_call_id; |
208 |
|
|
209 |
|
m4_expansion_level++; |
210 |
|
if (m4_expansion_level > nesting_limit) |
211 |
|
M4ERROR ((EXIT_FAILURE, 0, _("\ |
212 |
|
ERROR: Recursion limit of %d exceeded, use -L<N> to change it"), |
213 |
|
nesting_limit)); |
214 |
|
|
215 |
|
macro_call_id++; |
216 |
|
my_call_id = macro_call_id; |
217 |
|
|
218 |
|
traced = (boolean) ((debug_level & M4_DEBUG_TRACE_ALL) || SYMBOL_TRACED (symbol)); |
219 |
|
|
220 |
|
obstack_init (&argptr); |
221 |
|
obstack_init (&arguments); |
222 |
|
|
223 |
|
if (traced && (debug_level & M4_DEBUG_TRACE_CALL)) |
224 |
|
m4_trace_prepre (name, my_call_id); |
225 |
|
|
226 |
|
collect_arguments (context, name, symbol, &argptr, &arguments); |
227 |
|
|
228 |
|
argc = obstack_object_size (&argptr) / sizeof (m4_token *); |
229 |
|
argv = (m4_token **) obstack_finish (&argptr); |
230 |
|
|
231 |
|
if (traced) |
232 |
|
m4_trace_pre (name, my_call_id, argc, argv); |
233 |
|
|
234 |
|
expansion = m4_push_string_init (); |
235 |
|
if (!m4_bad_argc (argc, argv, |
236 |
|
SYMBOL_MIN_ARGS (symbol), SYMBOL_MAX_ARGS (symbol))) |
237 |
|
m4_call_macro (symbol, context, expansion, argc, argv); |
238 |
|
expanded = m4_push_string_finish (); |
239 |
|
|
240 |
|
if (traced) |
241 |
|
m4_trace_post (name, my_call_id, argc, argv, expanded); |
242 |
|
|
243 |
|
--m4_expansion_level; |
244 |
|
|
245 |
|
obstack_free (&arguments, NULL); |
246 |
|
obstack_free (&argptr, NULL); |
247 |
|
} |
248 |
|
|
249 |
/* Collect all the arguments to a call of the macro SYMBOL (called NAME). |
/* Collect all the arguments to a call of the macro SYMBOL (called NAME). |
250 |
The arguments are stored on the obstack ARGUMENTS and a table of pointers |
The arguments are stored on the obstack ARGUMENTS and a table of pointers |
251 |
to the arguments on the obstack ARGPTR. */ |
to the arguments on the obstack ARGPTR. */ |
252 |
static void |
static void |
253 |
collect_arguments (const char *name, m4_symbol *symbol, |
collect_arguments (m4 *context, const char *name, m4_symbol *symbol, |
254 |
struct obstack *argptr, struct obstack *arguments) |
struct obstack *argptr, struct obstack *arguments) |
255 |
{ |
{ |
256 |
int ch; /* lookahead for ( */ |
int ch; /* lookahead for ( */ |
273 |
m4_next_token (&token); /* gobble parenthesis */ |
m4_next_token (&token); /* gobble parenthesis */ |
274 |
do |
do |
275 |
{ |
{ |
276 |
more_args = expand_argument (arguments, &token); |
more_args = expand_argument (context, arguments, &token); |
277 |
|
|
278 |
if (!groks_macro_args && TOKEN_TYPE (&token) == M4_TOKEN_FUNC) |
if (!groks_macro_args && TOKEN_TYPE (&token) == M4_TOKEN_FUNC) |
279 |
{ |
{ |
287 |
while (more_args); |
while (more_args); |
288 |
} |
} |
289 |
} |
} |
|
|
|
290 |
|
|
291 |
|
|
292 |
/* The actual call of a macro is handled by m4_call_macro (). |
/* The actual call of a macro is handled by m4_call_macro (). |
296 |
the call, stored in the ARGV table. The expansion is left on |
the call, stored in the ARGV table. The expansion is left on |
297 |
the obstack EXPANSION. Macro tracing is also handled here. */ |
the obstack EXPANSION. Macro tracing is also handled here. */ |
298 |
void |
void |
299 |
m4_call_macro (m4_symbol *symbol, int argc, m4_token **argv, |
m4_call_macro (m4_symbol *symbol, m4 *context, struct obstack *expansion, |
300 |
struct obstack *expansion) |
int argc, m4_token **argv) |
301 |
{ |
{ |
302 |
switch (SYMBOL_TYPE (symbol)) |
switch (SYMBOL_TYPE (symbol)) |
303 |
{ |
{ |
304 |
case M4_TOKEN_FUNC: |
case M4_TOKEN_FUNC: |
305 |
(*SYMBOL_FUNC (symbol)) (expansion, argc, argv); |
(*SYMBOL_FUNC (symbol)) (context, expansion, argc, argv); |
306 |
break; |
break; |
307 |
|
|
308 |
case M4_TOKEN_TEXT: |
case M4_TOKEN_TEXT: |
309 |
m4_process_macro (expansion, symbol, argc, argv); |
m4_process_macro (symbol, context, expansion, argc, argv); |
310 |
break; |
break; |
311 |
|
|
312 |
case M4_TOKEN_VOID: |
case M4_TOKEN_VOID: |
316 |
} |
} |
317 |
} |
} |
318 |
|
|
|
/* The macro expansion is handled by expand_macro (). It parses the |
|
|
arguments, using collect_arguments (), and builds a table of pointers to |
|
|
the arguments. The arguments themselves are stored on a local obstack. |
|
|
Expand_macro () uses call_macro () to do the call of the macro. |
|
|
|
|
|
Expand_macro () is potentially recursive, since it calls expand_argument |
|
|
(), which might call expand_token (), which might call expand_macro (). */ |
|
|
static void |
|
|
expand_macro (const char *name, m4_symbol *symbol) |
|
|
{ |
|
|
struct obstack arguments; |
|
|
struct obstack argptr; |
|
|
m4_token **argv; |
|
|
int argc; |
|
|
struct obstack *expansion; |
|
|
const char *expanded; |
|
|
boolean traced; |
|
|
int my_call_id; |
|
|
|
|
|
m4_expansion_level++; |
|
|
if (m4_expansion_level > nesting_limit) |
|
|
M4ERROR ((EXIT_FAILURE, 0, _("\ |
|
|
ERROR: Recursion limit of %d exceeded, use -L<N> to change it"), |
|
|
nesting_limit)); |
|
|
|
|
|
macro_call_id++; |
|
|
my_call_id = macro_call_id; |
|
|
|
|
|
traced = (boolean) ((debug_level & M4_DEBUG_TRACE_ALL) || SYMBOL_TRACED (symbol)); |
|
|
|
|
|
obstack_init (&argptr); |
|
|
obstack_init (&arguments); |
|
|
|
|
|
if (traced && (debug_level & M4_DEBUG_TRACE_CALL)) |
|
|
m4_trace_prepre (name, my_call_id); |
|
|
|
|
|
collect_arguments (name, symbol, &argptr, &arguments); |
|
|
|
|
|
argc = obstack_object_size (&argptr) / sizeof (m4_token *); |
|
|
argv = (m4_token **) obstack_finish (&argptr); |
|
|
|
|
|
if (traced) |
|
|
m4_trace_pre (name, my_call_id, argc, argv); |
|
|
|
|
|
expansion = m4_push_string_init (); |
|
|
if (!m4_bad_argc (argc, argv, |
|
|
SYMBOL_MIN_ARGS (symbol), SYMBOL_MAX_ARGS (symbol))) |
|
|
m4_call_macro (symbol, argc, argv, expansion); |
|
|
expanded = m4_push_string_finish (); |
|
|
|
|
|
if (traced) |
|
|
m4_trace_post (name, my_call_id, argc, argv, expanded); |
|
|
|
|
|
--m4_expansion_level; |
|
|
|
|
|
obstack_free (&arguments, NULL); |
|
|
obstack_free (&argptr, NULL); |
|
|
} |
|
|
|
|
319 |
/* This function handles all expansion of user defined and predefined |
/* This function handles all expansion of user defined and predefined |
320 |
macros. It is called with an obstack OBS, where the macros expansion |
macros. It is called with an obstack OBS, where the macros expansion |
321 |
will be placed, as an unfinished object. SYMBOL points to the macro |
will be placed, as an unfinished object. SYMBOL points to the macro |
322 |
definition, giving the expansion text. ARGC and ARGV are the arguments, |
definition, giving the expansion text. ARGC and ARGV are the arguments, |
323 |
as usual. */ |
as usual. */ |
324 |
void |
void |
325 |
m4_process_macro (struct obstack *obs, m4_symbol *symbol, int argc, |
m4_process_macro (m4_symbol *symbol, m4 *context, struct obstack *obs, |
326 |
m4_token **argv) |
int argc, m4_token **argv) |
327 |
{ |
{ |
328 |
const unsigned char *text; |
const unsigned char *text; |
329 |
int i; |
int i; |