home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / m / m4v05as.zip / MACRO.C < prev    next >
C/C++ Source or Header  |  1992-02-22  |  8KB  |  290 lines

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