home *** CD-ROM | disk | FTP | other *** search
- /* GNU m4 -- A simple macro processor
- Copyright (C) 1989, 90, 91, 92, 93 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
- || (SYMBOL_TYPE (sym) == TOKEN_FUNC
- && SYMBOL_BLIND_NO_ARGS (sym)
- && peek_input () != '('))
- 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);
- }
-