m4-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Changes to m4/src/macro.c [branch-1_4]


From: Gary V . Vaughan
Subject: Changes to m4/src/macro.c [branch-1_4]
Date: Sun, 01 May 2005 07:54:18 -0400

Index: m4/src/macro.c
diff -u /dev/null m4/src/macro.c:1.1.1.1.2.1
--- /dev/null   Sun May  1 11:54:18 2005
+++ m4/src/macro.c      Sun May  1 11:54:12 2005
@@ -0,0 +1,318 @@
+/* GNU m4 -- A simple macro processor
+
+   Copyright (C) 1989, 90, 91, 92, 93, 94 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 of the License, 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., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301  USA
+*/
+
+/* This file contains the functions, that performs the basic argument
+   parsing and macro expansion.  */
+
+#include "m4.h"
+
+static void expand_macro _((symbol *));
+static void expand_token _((struct obstack *, token_type, token_data *));
+
+/* 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 macros, 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), strlen (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 () != '('))
+       {
+#ifdef ENABLE_CHANGEWORD
+         shipout_text (obs, TOKEN_DATA_ORIG_TEXT (td),
+                       strlen (TOKEN_DATA_ORIG_TEXT (td)));
+#else
+         shipout_text (obs, TOKEN_DATA_TEXT (td),
+                       strlen (TOKEN_DATA_TEXT (td)));
+#endif
+       }
+      else
+       expand_macro (sym);
+      break;
+
+    default:
+      M4ERROR ((warning_status, 0,
+               "INTERNAL ERROR: Bad token type in expand_token ()"));
+      abort ();
+    }
+}
+
+
+/*-------------------------------------------------------------------------.
+| 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:
+         M4ERROR ((EXIT_FAILURE, 0,
+                   "ERROR: 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:
+         M4ERROR ((warning_status, 0,
+                   "INTERNAL ERROR: Bad token type in expand_argument ()"));
+         abort ();
+       }
+
+      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, (voidstar) &td, sizeof (td));
+  obstack_grow (argptr, (voidstar) &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, (voidstar) &td, sizeof (td));
+         obstack_grow (argptr, (voidstar) &tdp, sizeof (tdp));
+       }
+      while (more_args);
+    }
+}
+
+
+/*------------------------------------------------------------------------.
+| The actual call of a macro is handled by call_macro ().  call_macro ()  |
+| is passed a symbol SYM, whose type is 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 is 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:
+      M4ERROR ((warning_status, 0,
+               "INTERNAL ERROR: Bad symbol type in call_macro ()"));
+      abort ();
+    }
+}
+
+/*-------------------------------------------------------------------------.
+| 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;
+  const char *expanded;
+  boolean traced;
+  int my_call_id;
+
+  expansion_level++;
+  if (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 & 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);
+}




reply via email to

[Prev in Thread] Current Thread [Next in Thread]