home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / m4-1.4-src.tgz / tar.out / fsf / m4 / src / macro.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  9KB  |  317 lines

  1. /* GNU m4 -- A simple macro processor
  2.    Copyright (C) 1989, 90, 91, 92, 93, 94 Free Software Foundation, Inc.
  3.   
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 2, or (at your option)
  7.    any later version.
  8.   
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.   
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. */
  18.  
  19. /* This file contains the functions, that performs the basic argument
  20.    parsing and macro expansion.  */
  21.  
  22. #include "m4.h"
  23.  
  24. static void expand_macro _((symbol *));
  25. static void expand_token _((struct obstack *, token_type, token_data *));
  26.  
  27. /* Current recursion level in expand_macro ().  */
  28. int expansion_level = 0;
  29.  
  30. /* The number of the current call of expand_macro ().  */
  31. static int macro_call_id = 0;
  32.  
  33. /*----------------------------------------------------------------------.
  34. | This function read all input, and expands each token, one at a time.  |
  35. `----------------------------------------------------------------------*/
  36.  
  37. void
  38. expand_input (void)
  39. {
  40.   token_type t;
  41.   token_data td;
  42.  
  43.   while ((t = next_token (&td)) != TOKEN_EOF)
  44.     expand_token ((struct obstack *) NULL, t, &td);
  45. }
  46.  
  47.  
  48. /*------------------------------------------------------------------------.
  49. | Expand one token, according to its type.  Potential macro names      |
  50. | (TOKEN_WORD) are looked up in the symbol table, to see if they have a      |
  51. | macro definition.  If they have, they are expanded as macros, otherwise |
  52. | the text are just copied to the output.                  |
  53. `------------------------------------------------------------------------*/
  54.  
  55. static void
  56. expand_token (struct obstack *obs, token_type t, token_data *td)
  57. {
  58.   symbol *sym;
  59.  
  60.   switch (t)
  61.     {                /* TOKSW */
  62.     case TOKEN_EOF:
  63.     case TOKEN_MACDEF:
  64.       break;
  65.  
  66.     case TOKEN_SIMPLE:
  67.     case TOKEN_STRING:
  68.       shipout_text (obs, TOKEN_DATA_TEXT (td), strlen (TOKEN_DATA_TEXT (td)));
  69.       break;
  70.  
  71.     case TOKEN_WORD:
  72.       sym = lookup_symbol (TOKEN_DATA_TEXT (td), SYMBOL_LOOKUP);
  73.       if (sym == NULL || SYMBOL_TYPE (sym) == TOKEN_VOID
  74.       || (SYMBOL_TYPE (sym) == TOKEN_FUNC
  75.           && SYMBOL_BLIND_NO_ARGS (sym)
  76.           && peek_input () != '('))
  77.     {
  78. #ifdef ENABLE_CHANGEWORD
  79.       shipout_text (obs, TOKEN_DATA_ORIG_TEXT (td),
  80.             strlen (TOKEN_DATA_ORIG_TEXT (td)));
  81. #else
  82.       shipout_text (obs, TOKEN_DATA_TEXT (td),
  83.             strlen (TOKEN_DATA_TEXT (td)));
  84. #endif
  85.     }
  86.       else
  87.     expand_macro (sym);
  88.       break;
  89.  
  90.     default:
  91.       M4ERROR ((warning_status, 0,
  92.         "INTERNAL ERROR: Bad token type in expand_token ()"));
  93.       abort ();
  94.     }
  95. }
  96.  
  97.  
  98. /*-------------------------------------------------------------------------.
  99. | This function parses one argument to a macro call.  It expects the first |
  100. | left parenthesis, or the separating comma to have been read by the       |
  101. | caller.  It skips leading whitespace, and reads and expands tokens,       |
  102. | until it finds a comma or an right parenthesis at the same level of       |
  103. | parentheses.  It returns a flag indicating whether the argument read are |
  104. | the last for the active macro call.  The argument are build on the       |
  105. | obstack OBS, indirectly through expand_token ().               |
  106. `-------------------------------------------------------------------------*/
  107.  
  108. static boolean
  109. expand_argument (struct obstack *obs, token_data *argp)
  110. {
  111.   token_type t;
  112.   token_data td;
  113.   char *text;
  114.   int paren_level;
  115.  
  116.   TOKEN_DATA_TYPE (argp) = TOKEN_VOID;
  117.  
  118.   /* Skip leading white space.  */
  119.   do
  120.     {
  121.       t = next_token (&td);
  122.     }
  123.   while (t == TOKEN_SIMPLE && isspace (*TOKEN_DATA_TEXT (&td)));
  124.  
  125.   paren_level = 0;
  126.  
  127.   while (1)
  128.     {
  129.  
  130.       switch (t)
  131.     {            /* TOKSW */
  132.     case TOKEN_SIMPLE:
  133.       text = TOKEN_DATA_TEXT (&td);
  134.       if ((*text == ',' || *text == ')') && paren_level == 0)
  135.         {
  136.  
  137.           /* The argument MUST be finished, whether we want it or not.  */
  138.           obstack_1grow (obs, '\0');
  139.           text = obstack_finish (obs);
  140.  
  141.           if (TOKEN_DATA_TYPE (argp) == TOKEN_VOID)
  142.         {
  143.           TOKEN_DATA_TYPE (argp) = TOKEN_TEXT;
  144.           TOKEN_DATA_TEXT (argp) = text;
  145.         }
  146.           return (boolean) (*TOKEN_DATA_TEXT (&td) == ',');
  147.         }
  148.  
  149.       if (*text == '(')
  150.         paren_level++;
  151.       else if (*text == ')')
  152.         paren_level--;
  153.       expand_token (obs, t, &td);
  154.       break;
  155.  
  156.     case TOKEN_EOF:
  157.       M4ERROR ((EXIT_FAILURE, 0,
  158.             "ERROR: EOF in argument list"));
  159.       break;
  160.  
  161.     case TOKEN_WORD:
  162.     case TOKEN_STRING:
  163.       expand_token (obs, t, &td);
  164.       break;
  165.  
  166.     case TOKEN_MACDEF:
  167.       if (obstack_object_size (obs) == 0)
  168.         {
  169.           TOKEN_DATA_TYPE (argp) = TOKEN_FUNC;
  170.           TOKEN_DATA_FUNC (argp) = TOKEN_DATA_FUNC (&td);
  171.           TOKEN_DATA_FUNC_TRACED (argp) = TOKEN_DATA_FUNC_TRACED (&td);
  172.         }
  173.       break;
  174.  
  175.     default:
  176.       M4ERROR ((warning_status, 0,
  177.             "INTERNAL ERROR: Bad token type in expand_argument ()"));
  178.       abort ();
  179.     }
  180.  
  181.       t = next_token (&td);
  182.     }
  183. }
  184.  
  185. /*-------------------------------------------------------------------------.
  186. | Collect all the arguments to a call of the macro SYM.  The arguments are |
  187. | stored on the obstack ARGUMENTS and a table of pointers to the arguments |
  188. | on the obstack ARGPTR.                           |
  189. `-------------------------------------------------------------------------*/
  190.  
  191. static void
  192. collect_arguments (symbol *sym, struct obstack *argptr,
  193.            struct obstack *arguments)
  194. {
  195.   int ch;            /* lookahead for ( */
  196.   token_data td;
  197.   token_data *tdp;
  198.   boolean more_args;
  199.   boolean groks_macro_args = SYMBOL_MACRO_ARGS (sym);
  200.  
  201.   TOKEN_DATA_TYPE (&td) = TOKEN_TEXT;
  202.   TOKEN_DATA_TEXT (&td) = SYMBOL_NAME (sym);
  203.   tdp = (token_data *) obstack_copy (arguments, (voidstar) &td, sizeof (td));
  204.   obstack_grow (argptr, (voidstar) &tdp, sizeof (tdp));
  205.  
  206.   ch = peek_input ();
  207.   if (ch == '(')
  208.     {
  209.       next_token (&td);        /* gobble parenthesis */
  210.       do
  211.     {
  212.       more_args = expand_argument (arguments, &td);
  213.  
  214.       if (!groks_macro_args && TOKEN_DATA_TYPE (&td) == TOKEN_FUNC)
  215.         {
  216.           TOKEN_DATA_TYPE (&td) = TOKEN_TEXT;
  217.           TOKEN_DATA_TEXT (&td) = "";
  218.         }
  219.       tdp = (token_data *)
  220.         obstack_copy (arguments, (voidstar) &td, sizeof (td));
  221.       obstack_grow (argptr, (voidstar) &tdp, sizeof (tdp));
  222.     }
  223.       while (more_args);
  224.     }
  225. }
  226.  
  227.  
  228. /*------------------------------------------------------------------------.
  229. | The actual call of a macro is handled by call_macro ().  call_macro ()  |
  230. | is passed a symbol SYM, whose type is used to call either a builtin      |
  231. | function, or the user macro expansion function expand_user_macro ()      |
  232. | (lives in builtin.c).  There are ARGC arguments to the call, stored in  |
  233. | the ARGV table.  The expansion is left on the obstack EXPANSION.  Macro |
  234. | tracing is also handled here.                          |
  235. `------------------------------------------------------------------------*/
  236.  
  237. void
  238. call_macro (symbol *sym, int argc, token_data **argv,
  239.          struct obstack *expansion)
  240. {
  241.   switch (SYMBOL_TYPE (sym))
  242.     {
  243.     case TOKEN_FUNC:
  244.       (*SYMBOL_FUNC (sym)) (expansion, argc, argv);
  245.       break;
  246.  
  247.     case TOKEN_TEXT:
  248.       expand_user_macro (expansion, sym, argc, argv);
  249.       break;
  250.  
  251.     default:
  252.       M4ERROR ((warning_status, 0,
  253.         "INTERNAL ERROR: Bad symbol type in call_macro ()"));
  254.       abort ();
  255.     }
  256. }
  257.  
  258. /*-------------------------------------------------------------------------.
  259. | The macro expansion is handled by expand_macro ().  It parses the       |
  260. | arguments, using collect_arguments (), and builds a table of pointers to |
  261. | the arguments.  The arguments themselves are stored on a local obstack.  |
  262. | Expand_macro () uses call_macro () to do the call of the macro.       |
  263. |                                        |
  264. | Expand_macro () is potentially recursive, since it calls expand_argument |
  265. | (), which might call expand_token (), which might call expand_macro ().  |
  266. `-------------------------------------------------------------------------*/
  267.  
  268. static void
  269. expand_macro (symbol *sym)
  270. {
  271.   struct obstack arguments;
  272.   struct obstack argptr;
  273.   token_data **argv;
  274.   int argc;
  275.   struct obstack *expansion;
  276.   const char *expanded;
  277.   boolean traced;
  278.   int my_call_id;
  279.  
  280.   expansion_level++;
  281.   if (expansion_level > nesting_limit)
  282.     M4ERROR ((EXIT_FAILURE, 0,
  283.           "ERROR: Recursion limit of %d exceeded, use -L<N> to change it",
  284.           nesting_limit));
  285.  
  286.   macro_call_id++;
  287.   my_call_id = macro_call_id;
  288.  
  289.   traced = (boolean) ((debug_level & DEBUG_TRACE_ALL) || SYMBOL_TRACED (sym));
  290.  
  291.   obstack_init (&argptr);
  292.   obstack_init (&arguments);
  293.  
  294.   if (traced && (debug_level & DEBUG_TRACE_CALL))
  295.     trace_prepre (SYMBOL_NAME (sym), my_call_id);
  296.  
  297.   collect_arguments (sym, &argptr, &arguments);
  298.  
  299.   argc = obstack_object_size (&argptr) / sizeof (token_data *);
  300.   argv = (token_data **) obstack_finish (&argptr);
  301.  
  302.   if (traced)
  303.     trace_pre (SYMBOL_NAME (sym), my_call_id, argc, argv);
  304.  
  305.   expansion = push_string_init ();
  306.   call_macro (sym, argc, argv, expansion);
  307.   expanded = push_string_finish ();
  308.  
  309.   if (traced)
  310.     trace_post (SYMBOL_NAME (sym), my_call_id, argc, argv, expanded);
  311.  
  312.   --expansion_level;
  313.  
  314.   obstack_free (&arguments, NULL);
  315.   obstack_free (&argptr, NULL);
  316. }
  317.