home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 4 / FreshFish_May-June1994.bin / bbs / gnu / m4-1.1-src.lha / src / amiga / m4-1.1 / macro.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-11-02  |  8.5 KB  |  291 lines

  1. /* GNU m4 -- A simple macro processor
  2.    Copyright (C) 1989, 90, 91, 92, 93 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_token ();
  25. static void expand_macro ();
  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 macroes, 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.     case TOKEN_SIMPLE:
  66.     case TOKEN_STRING:
  67.       shipout_text (obs, TOKEN_DATA_TEXT (td));
  68.       break;
  69.     case TOKEN_WORD:
  70.       sym = lookup_symbol (TOKEN_DATA_TEXT (td), SYMBOL_LOOKUP);
  71.       if (sym == NULL || SYMBOL_TYPE (sym) == TOKEN_VOID
  72.       || (SYMBOL_TYPE (sym) == TOKEN_FUNC
  73.           && SYMBOL_BLIND_NO_ARGS (sym)
  74.           && peek_input () != '('))
  75.     shipout_text (obs, TOKEN_DATA_TEXT (td));
  76.       else
  77.     expand_macro (sym);
  78.       break;
  79.     default:
  80.       internal_error ("Bad token type in expand_token ()");
  81.       break;
  82.     }
  83. }
  84.  
  85.  
  86. /*-------------------------------------------------------------------------.
  87. | This function parses one argument to a macro call.  It expects the first |
  88. | left parenthesis, or the separating comma to have been read by the       |
  89. | caller.  It skips leading whitespace, and reads and expands tokens,       |
  90. | until it finds a comma or an right parenthesis at the same level of       |
  91. | parentheses.  It returns a flag indicating whether the argument read are |
  92. | the last for the active macro call.  The argument are build on the       |
  93. | obstack OBS, indirectly through expand_token ().               |
  94. `-------------------------------------------------------------------------*/
  95.  
  96. static boolean
  97. expand_argument (struct obstack *obs, token_data *argp)
  98. {
  99.   token_type t;
  100.   token_data td;
  101.   char *text;
  102.   int paren_level;
  103.  
  104.   TOKEN_DATA_TYPE (argp) = TOKEN_VOID;
  105.  
  106.   /* Skip leading white space.  */
  107.   do
  108.     {
  109.       t = next_token (&td);
  110.     }
  111.   while (t == TOKEN_SIMPLE && isspace (*TOKEN_DATA_TEXT (&td)));
  112.  
  113.   paren_level = 0;
  114.  
  115.   while (1)
  116.     {
  117.  
  118.       switch (t)
  119.     {            /* TOKSW */
  120.     case TOKEN_SIMPLE:
  121.       text = TOKEN_DATA_TEXT (&td);
  122.       if ((*text == ',' || *text == ')') && paren_level == 0)
  123.         {
  124.  
  125.           /* The argument MUST be finished, whether we want it or not.  */
  126.           obstack_1grow (obs, '\0');
  127.           text = obstack_finish (obs);
  128.  
  129.           if (TOKEN_DATA_TYPE (argp) == TOKEN_VOID)
  130.         {
  131.           TOKEN_DATA_TYPE (argp) = TOKEN_TEXT;
  132.           TOKEN_DATA_TEXT (argp) = text;
  133.         }
  134.           return (boolean) (*TOKEN_DATA_TEXT (&td) == ',');
  135.         }
  136.  
  137.       if (*text == '(')
  138.         paren_level++;
  139.       else if (*text == ')')
  140.         paren_level--;
  141.       expand_token (obs, t, &td);
  142.       break;
  143.     case TOKEN_EOF:
  144.       fatal ("EOF in argument list");
  145.       break;
  146.     case TOKEN_WORD:
  147.     case TOKEN_STRING:
  148.       expand_token (obs, t, &td);
  149.       break;
  150.     case TOKEN_MACDEF:
  151.       if (obstack_object_size (obs) == 0)
  152.         {
  153.           TOKEN_DATA_TYPE (argp) = TOKEN_FUNC;
  154.           TOKEN_DATA_FUNC (argp) = TOKEN_DATA_FUNC (&td);
  155.           TOKEN_DATA_FUNC_TRACED (argp) = TOKEN_DATA_FUNC_TRACED (&td);
  156.         }
  157.       break;
  158.     default:
  159.       internal_error ("Bad token type in expand_argument ()");
  160.       break;
  161.     }
  162.  
  163.       t = next_token (&td);
  164.     }
  165. }
  166.  
  167. /*-------------------------------------------------------------------------.
  168. | Collect all the arguments to a call of the macro SYM.  The arguments are |
  169. | stored on the obstack ARGUMENTS and a table of pointers to the arguments |
  170. | on the obstack ARGPTR.                           |
  171. `-------------------------------------------------------------------------*/
  172.  
  173. static void
  174. collect_arguments (symbol *sym, struct obstack *argptr,
  175.            struct obstack *arguments)
  176. {
  177.   int ch;            /* lookahead for ( */
  178.   token_data td;
  179.   token_data *tdp;
  180.   boolean more_args;
  181.   boolean groks_macro_args = SYMBOL_MACRO_ARGS (sym);
  182.  
  183.   TOKEN_DATA_TYPE (&td) = TOKEN_TEXT;
  184.   TOKEN_DATA_TEXT (&td) = SYMBOL_NAME (sym);
  185.   tdp = (token_data *) obstack_copy (arguments, &td, sizeof (td));
  186.   obstack_grow (argptr, &tdp, sizeof (tdp));
  187.  
  188.   ch = peek_input ();
  189.   if (ch == '(')
  190.     {
  191.       next_token (&td);        /* gobble parenthesis */
  192.       do
  193.     {
  194.       more_args = expand_argument (arguments, &td);
  195.  
  196.       if (!groks_macro_args && TOKEN_DATA_TYPE (&td) == TOKEN_FUNC)
  197.         {
  198.           TOKEN_DATA_TYPE (&td) = TOKEN_TEXT;
  199.           TOKEN_DATA_TEXT (&td) = "";
  200.         }
  201.       tdp = (token_data *) obstack_copy (arguments, &td, sizeof (td));
  202.       obstack_grow (argptr, &tdp, sizeof (tdp));
  203.     }
  204.       while (more_args);
  205.     }
  206. }
  207.  
  208.  
  209. /*------------------------------------------------------------------------.
  210. | The actual call of a is handled by call_macro ().  call_macro () is      |
  211. | passed a symbol SYM, whose type are used to call either a builtin      |
  212. | function, or the user macro expansion function expand_user_macro ()      |
  213. | (lives in builtin.c).  There are ARGC arguments to the call, stored in  |
  214. | the ARGV table.  The expansion is left on the obstack EXPANSION.  Macro |
  215. | tracing are also handled here.                      |
  216. `------------------------------------------------------------------------*/
  217.  
  218. void
  219. call_macro (symbol *sym, int argc, token_data **argv,
  220.          struct obstack *expansion)
  221. {
  222.   switch (SYMBOL_TYPE (sym))
  223.     {
  224.     case TOKEN_FUNC:
  225.       (SYMBOL_FUNC (sym)) (expansion, argc, argv);
  226.       break;
  227.     case TOKEN_TEXT:
  228.       expand_user_macro (expansion, sym, argc, argv);
  229.       break;
  230.     default:
  231.       internal_error ("Bad symbol type in call_macro ()");
  232.       break;
  233.     }
  234. }
  235.  
  236. /*-------------------------------------------------------------------------.
  237. | The macro expansion is handled by expand_macro ().  It parses the       |
  238. | arguments, using collect_arguments (), and builds a table of pointers to |
  239. | the arguments.  The arguments themselves are stored on a local obstack.  |
  240. | Expand_macro () uses call_macro () to do the call of the macro.       |
  241. |                                        |
  242. | Expand_macro () is potentially recursive, since it calls expand_argument |
  243. | (), which might call expand_token (), which might call expand_macro ().  |
  244. `-------------------------------------------------------------------------*/
  245.  
  246. static void
  247. expand_macro (symbol *sym)
  248. {
  249.   struct obstack arguments;
  250.   struct obstack argptr;
  251.   token_data **argv;
  252.   int argc;
  253.   struct obstack *expansion;
  254.   char *expanded;
  255.   boolean traced;
  256.   int my_call_id;
  257.  
  258.   expansion_level++;
  259.   macro_call_id++;
  260.  
  261.   my_call_id = macro_call_id;
  262.  
  263.   traced = (debug_level & DEBUG_TRACE_ALL) || SYMBOL_TRACED (sym);
  264.  
  265.   obstack_init (&argptr);
  266.   obstack_init (&arguments);
  267.  
  268.   if (traced && (debug_level & DEBUG_TRACE_CALL))
  269.     trace_prepre (SYMBOL_NAME (sym), my_call_id);
  270.  
  271.   collect_arguments (sym, &argptr, &arguments);
  272.  
  273.   argc = obstack_object_size (&argptr) / sizeof (token_data *);
  274.   argv = (token_data **) obstack_finish (&argptr);
  275.  
  276.   if (traced)
  277.     trace_pre (SYMBOL_NAME (sym), my_call_id, argc, argv);
  278.  
  279.   expansion = push_string_init ();
  280.   call_macro (sym, argc, argv, expansion);
  281.   expanded = push_string_finish ();
  282.  
  283.   if (traced)
  284.     trace_post (SYMBOL_NAME (sym), my_call_id, argc, argv, expanded);
  285.  
  286.   --expansion_level;
  287.  
  288.   obstack_free (&arguments, NULL);
  289.   obstack_free (&argptr, NULL);
  290. }
  291.