home *** CD-ROM | disk | FTP | other *** search
- /*
- * GNU m4 -- A simple macro processor
- * Copyright (C) 1989-1992 Free Software Foundation, Inc.
- *
- * 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 2, 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; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
- /*
- * This file contains the functions, that performs the basic argument
- * parsing and macro expansion.
- */
-
- #include "m4.h"
-
- static void expand_token ();
- static void expand_macro ();
-
- /* Current recursion level in expand_macro (). */
- int expansion_level = 0;
-
- /* The number of the current call of expand_macro (). */
- static int macro_call_id = 0;
-
- /*
- * This function read all input, and expands each token, one at a time.
- */
- void
- expand_input (void)
- {
- token_type t;
- token_data td;
-
- while ((t = next_token (&td)) != TOKEN_EOF)
- expand_token ((struct obstack *) NULL, t, &td);
- }
-
-
- /*
- * Expand one token, according to its type. Potential macro names
- * (TOKEN_WORD) are looked up in the symbol table, to see if they have a
- * macro definition. If they have, they are expanded as macroes,
- * otherwise the text are just copied to the output.
- */
- static void
- expand_token (struct obstack *obs, token_type t, token_data *td)
- {
- symbol *sym;
-
- switch (t)
- { /* TOKSW */
- case TOKEN_EOF:
- case TOKEN_MACDEF:
- break;
- case TOKEN_SIMPLE:
- case TOKEN_STRING:
- shipout_text (obs, TOKEN_DATA_TEXT (td));
- break;
- case TOKEN_WORD:
- sym = lookup_symbol (TOKEN_DATA_TEXT (td), SYMBOL_LOOKUP);
- if (sym == NULL || SYMBOL_TYPE (sym) == TOKEN_VOID)
- shipout_text (obs, TOKEN_DATA_TEXT (td));
- else
- expand_macro (sym);
- break;
- default:
- internal_error ("Bad token type in expand_token ()");
- break;
- }
- }
-
-
- /*
- * This function parses one argument to a macro call. It expects the
- * first left parenthesis, or the separating comma to have been read by
- * the caller. It skips leading whitespace, and reads and expands
- * tokens, until it finds a comma or an right parenthesis at the same
- * level of parentheses. It returns a flag indicating whether the
- * argument read are the last for the active macro call. The argument
- * are build on the obstack OBS, indirectly through expand_token ().
- */
- static boolean
- expand_argument (struct obstack *obs, token_data *argp)
- {
- token_type t;
- token_data td;
- char *text;
- int paren_level;
-
- TOKEN_DATA_TYPE (argp) = TOKEN_VOID;
-
- /* Skip leading white space. */
- do
- {
- t = next_token (&td);
- }
- while (t == TOKEN_SIMPLE && isspace (*TOKEN_DATA_TEXT (&td)));
-
- paren_level = 0;
-
- while (1)
- {
-
- switch (t)
- { /* TOKSW */
- case TOKEN_SIMPLE:
- text = TOKEN_DATA_TEXT (&td);
- if ((*text == ',' || *text == ')') && paren_level == 0)
- {
-
- /* The argument MUST be finished, whether we want it or not. */
- obstack_1grow (obs, '\0');
- text = obstack_finish (obs);
-
- if (TOKEN_DATA_TYPE (argp) == TOKEN_VOID)
- {
- TOKEN_DATA_TYPE (argp) = TOKEN_TEXT;
- TOKEN_DATA_TEXT (argp) = text;
- }
- return (boolean) (*TOKEN_DATA_TEXT (&td) == ',');
- }
-
- if (*text == '(')
- paren_level++;
- else if (*text == ')')
- paren_level--;
- expand_token (obs, t, &td);
- break;
- case TOKEN_EOF:
- fatal ("EOF in argument list");
- break;
- case TOKEN_WORD:
- case TOKEN_STRING:
- expand_token (obs, t, &td);
- break;
- case TOKEN_MACDEF:
- if (obstack_object_size (obs) == 0)
- {
- TOKEN_DATA_TYPE (argp) = TOKEN_FUNC;
- TOKEN_DATA_FUNC (argp) = TOKEN_DATA_FUNC (&td);
- TOKEN_DATA_FUNC_TRACED (argp) = TOKEN_DATA_FUNC_TRACED (&td);
- }
- break;
- default:
- internal_error ("Bad token type in expand_argument ()");
- break;
- }
-
- t = next_token (&td);
- }
- }
-
- /*
- * Collect all the arguments to a call of the macro SYM. The arguments
- * are stored on the obstack ARGUMENTS and a table of pointers to the
- * arguments on the obstack ARGPTR.
- */
- static void
- collect_arguments (symbol *sym, struct obstack *argptr,
- struct obstack *arguments)
- {
- int ch; /* lookahead for ( */
- token_data td;
- token_data *tdp;
- boolean more_args;
- boolean groks_macro_args = SYMBOL_MACRO_ARGS (sym);
-
- TOKEN_DATA_TYPE (&td) = TOKEN_TEXT;
- TOKEN_DATA_TEXT (&td) = SYMBOL_NAME (sym);
- tdp = (token_data *) obstack_copy (arguments, &td, sizeof (td));
- obstack_grow (argptr, &tdp, sizeof (tdp));
-
- ch = peek_input ();
- if (ch == '(')
- {
- next_token (&td); /* gobble parenthesis */
- do
- {
- more_args = expand_argument (arguments, &td);
-
- if (!groks_macro_args && TOKEN_DATA_TYPE (&td) == TOKEN_FUNC)
- {
- TOKEN_DATA_TYPE (&td) = TOKEN_TEXT;
- TOKEN_DATA_TEXT (&td) = "";
- }
- tdp = (token_data *) obstack_copy (arguments, &td, sizeof (td));
- obstack_grow (argptr, &tdp, sizeof (tdp));
- }
- while (more_args);
- }
- }
-
-
-
- /*
- * The actual call of a is handled by call_macro (). call_macro () is
- * passed a symbol SYM, whose type are used to call either a builtin
- * function, or the user macro expansion function expand_user_macro ()
- * (lives in builtin.c). There are ARGC arguments to the call, stored
- * in the ARGV table. The expansion is left on the obstack EXPANSION.
- * Macro tracing are also handled here.
- */
- void
- call_macro (symbol *sym, int argc, token_data **argv,
- struct obstack *expansion)
- {
- switch (SYMBOL_TYPE (sym))
- {
- case TOKEN_FUNC:
- (SYMBOL_FUNC (sym)) (expansion, argc, argv);
- break;
- case TOKEN_TEXT:
- expand_user_macro (expansion, sym, argc, argv);
- break;
- default:
- internal_error ("Bad symbol type in call_macro ()");
- break;
- }
- }
-
- /*
- * 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 (symbol *sym)
- {
- struct obstack arguments;
- struct obstack argptr;
- token_data **argv;
- int argc;
- struct obstack *expansion;
- char *expanded;
- boolean traced;
- int my_call_id;
-
- expansion_level++;
- macro_call_id++;
-
- my_call_id = macro_call_id;
-
- traced = (debug_level & DEBUG_TRACE_ALL) || SYMBOL_TRACED (sym);
-
- obstack_init (&argptr);
- obstack_init (&arguments);
-
- if (traced && (debug_level & DEBUG_TRACE_CALL))
- trace_prepre (SYMBOL_NAME (sym), my_call_id);
-
- collect_arguments (sym, &argptr, &arguments);
-
- argc = obstack_object_size (&argptr) / sizeof (token_data *);
- argv = (token_data **) obstack_finish (&argptr);
-
- if (traced)
- trace_pre (SYMBOL_NAME (sym), my_call_id, argc, argv);
-
- expansion = push_string_init ();
- call_macro (sym, argc, argv, expansion);
- expanded = push_string_finish ();
-
- if (traced)
- trace_post (SYMBOL_NAME (sym), my_call_id, argc, argv, expanded);
-
- --expansion_level;
-
- obstack_free (&arguments, NULL);
- obstack_free (&argptr, NULL);
- }
-