home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / m / m4v05as.zip / INPUT.C < prev    next >
C/C++ Source or Header  |  1992-02-22  |  16KB  |  622 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/input.c 0.5.1.0 90/09/28 18:35:00 tho Exp $
  31.  */
  32.  
  33. /* 
  34.  * Handling of different input sources, and lexical analysis.
  35.  */
  36.  
  37. #include "m4.h"
  38. /* 
  39.  * Unread input can be either files, that should be read (eg. included
  40.  * files), strings, which should be rescanned (eg. macro expansion
  41.  * text), or quoted macro definitions (as returned by the builtin
  42.  * "defn").  Unread input are organised in a stack, implemented with an
  43.  * obstack.  Each input source is described by a "struct input_block".
  44.  * The obstack is "input_stack".  The top of the input stack is "isp".
  45.  *
  46.  * The macro "m4wrap" places the text to be saved on another input
  47.  * stack, on the obstack "wrapup_stack", whose top is "wsp".  When EOF
  48.  * is seen on normal input (eg, when "input_stack" is empty), input is
  49.  * switched over to "wrapup_stack".  To make this easier, all references
  50.  * to the current input stack, whether it be "input_stack" or
  51.  * "wrapup_stack", are done through a pointer "current_input", which
  52.  * points to either "input_stack" or "wrapup_stack".
  53.  *
  54.  * Pushing new input on the input stack is done by push_file(),
  55.  * push_string(), push_wrapup() (for wrapup text), and push_macro() (for
  56.  * macro definitions).  Because macro expansion needs direct access to
  57.  * the current input obstack (for optimisation), push_string() are split
  58.  * in two functions, push_string_init(), which returns a pointer to the
  59.  * current input stack, and push_string_finish(), which return a pointer
  60.  * to the final text.  The input_block *next is used to manage the
  61.  * coordination between the different push routines.
  62.  *
  63.  * The current file and line number are stored in two global variables,
  64.  * for use by the error handling functions in m4.c.  Whenever a file
  65.  * input_block is pushed, the current file name and line number is saved
  66.  * in the input_block, and the two variables are reset to match the new
  67.  * input file.
  68.  */
  69.  
  70. enum input_type {
  71.     INPUT_FILE,
  72.     INPUT_STRING,
  73.     INPUT_MACRO,
  74. };
  75.  
  76. typedef enum input_type input_type;
  77.  
  78. struct input_block {
  79.     struct input_block *prev;        /* previous input_block on the input stack */
  80.     input_type type;            /* INPUT_FILE, INPUT_STRING or INPUT_MACRO */
  81.     union {
  82.     struct {
  83.         char *string;        /* string value */
  84.     } u_s;
  85.     struct {
  86.         FILE *file;            /* input file handle */
  87.         char *name;            /* name of PREVIOUS input file */
  88.         int lineno;            /* current line number for do. */
  89.         /* yet another attack of "The curse of global variables" (sic). */
  90.         int out_lineno;        /* current output line number do.*/
  91.         boolean advance_line;    /* must_advance_line from advance_input */
  92.     } u_f;
  93.     struct {
  94.         builtin_func *func;        /* pointer to macros function */
  95.     } u_m;
  96.     } u;
  97. };
  98.  
  99. typedef struct input_block input_block;
  100.  
  101.  
  102. /* current input file name */
  103. char *current_file;
  104.  
  105. /* current input line number */
  106. int current_line;
  107.  
  108.  
  109. /* obstack for storing individual tokens */
  110. static struct obstack token_stack;
  111.  
  112. /* normal input stack */
  113. static struct obstack input_stack;
  114.  
  115. /* wrapup input stack */
  116. static struct obstack wrapup_stack;
  117.  
  118. /* input or wrapup */
  119. static struct obstack *current_input;
  120.  
  121. /* buttom of token_stack, for obstack_free */
  122. static char *token_buttom;
  123.  
  124. /* pointer to top of current_input */
  125. static input_block *isp;
  126.  
  127. /* pointer to top of wrapup_stack */
  128. static input_block *wsp;
  129.  
  130. /* aux. for handling split push_string() */
  131. static input_block *next;
  132.  
  133. /* flag for advance_input to increment current_line */
  134. static boolean must_advance_line;
  135.  
  136. #define CHAR_EOF    256        /* character return on EOF */
  137. #define CHAR_MACRO    257        /* character return for MACRO token */
  138.  
  139. /* quote chars */
  140. char rquote; 
  141. char lquote;
  142. /* and comment chars*/
  143. char bcomm;
  144. char ecomm;
  145.  
  146.  
  147. #ifdef MSDOS
  148. static int next_char (void);
  149. static void (*get_macro_func (void)) ();
  150. static void advance_input (void);
  151. static void pop_input (void);
  152. #endif /* MSDOS */
  153.  
  154.  
  155. /* 
  156.  * push_file() pushes an input file on the input stack, saving the
  157.  * current file name and line number.  If next is non-nil, this push
  158.  * invalidates a call to push_string_init(), whose storage are
  159.  * consequentely released.
  160.  */
  161. void 
  162. push_file(fp, title)
  163.     FILE *fp;
  164.     char *title;
  165. {
  166.     input_block *i;
  167.  
  168.     if (next != nil) {
  169.     obstack_free(current_input, next);
  170.     next = nil;
  171.     }
  172.  
  173.     i = (input_block *)obstack_alloc(current_input, sizeof(struct input_block));
  174.     i->type = INPUT_FILE;
  175.  
  176.     i->u.u_f.name = current_file;
  177.     i->u.u_f.lineno = current_line;
  178.     i->u.u_f.out_lineno = output_current_line;
  179.     i->u.u_f.advance_line = must_advance_line;
  180.     current_file = obstack_copy0(current_input, title, strlen(title));
  181.     current_line = 1;
  182.  
  183.     if (sync_output) {
  184.     output_lines = 0;
  185.     sync_line(1, current_file);
  186.     }
  187.  
  188.     i->u.u_f.file = fp;
  189.     i->prev = isp;
  190.     isp = i;
  191. }
  192.  
  193. /* 
  194.  * push_macro() pushes a builtin macros definition on the input stack If
  195.  * next is non-nil, this push invalidates a call to push_string_init(),
  196.  * whose storage are consequentely released.
  197.  */
  198. void 
  199. push_macro(func)
  200.     builtin_func *func;
  201. {
  202.     input_block *i;
  203.  
  204.     if (next != nil) {
  205.     obstack_free(current_input, next);
  206.     next = nil;
  207.     }
  208.  
  209.     i = (input_block *)obstack_alloc(current_input, sizeof(struct input_block));
  210.     i->type = INPUT_MACRO;
  211.  
  212.     i->u.u_m.func = func;
  213.     i->prev = isp;
  214.     isp = i;
  215. }
  216.  
  217. /* 
  218.  * First half of push_string().  The pointer next points to the new
  219.  * input_block. 
  220.  */
  221. struct obstack *
  222. push_string_init()
  223. {
  224.     if (next != nil)
  225.     internal_error("recursive push_string!");
  226.  
  227.     next = (input_block *)obstack_alloc(current_input, sizeof(struct input_block));
  228.     next->type = INPUT_STRING;
  229.     return current_input;
  230. }
  231.  
  232. /* 
  233.  * Last half of push_string().  If next is now nil, a call to
  234.  * push_file() has invalidated the previous call to push_string_init(),
  235.  * so we just give up.  If the new object is void, we do not push it.
  236.  * The function push_string_finish() returns a pointer to the finished
  237.  * object.  This pointer is only for temporary use, since reading the
  238.  * next token might release the memory used for the object.
  239.  */
  240. char *
  241. push_string_finish()
  242. {
  243.     char *ret = nil;
  244.  
  245.     if (next == nil)
  246.     return nil;
  247.  
  248.     if (obstack_object_size(current_input) > 0) {
  249.     obstack_1grow(current_input, '\0');
  250.     next->u.u_s.string = obstack_finish(current_input);
  251.     next->prev = isp;
  252.     isp = next;
  253.     ret = isp->u.u_s.string;    /* for immediate use only */
  254.     } else
  255.     obstack_free(current_input, next); /* people might leave garbage on it. */
  256.     next = nil;
  257.     return ret;
  258. }    
  259.  
  260. #if 0
  261. /* 
  262.  * Simple push_string().
  263.  */
  264. void 
  265. push_string(s)
  266.     char *s;
  267. {
  268.     (void)push_string_init();
  269.     obstack_grow(current_input, s, strlen(s));
  270.     (void)push_string_finish();
  271. }
  272. #endif
  273.  
  274. /* 
  275.  * The function push_wrapup() pushes a string on the wrapup stack.  When
  276.  * he normal input stack gets empty, the wrapup stack will become the
  277.  * input stack, and push_string() and push_file() will operate on
  278.  * wrapup_stack.  Push_wrapup should be done as push_string(), but this
  279.  * will suffice, as long as arguments to m4_m4wrap() are moderate in
  280.  * size.
  281.  */
  282. void 
  283. push_wrapup(s)
  284.     char *s;
  285. {
  286.     input_block *i = (input_block *)obstack_alloc(&wrapup_stack, sizeof(struct input_block));
  287.     i->prev = wsp;
  288.     i->type = INPUT_STRING;
  289.     i->u.u_s.string = obstack_copy0(&wrapup_stack, s, strlen(s));
  290.     wsp = i;
  291. }
  292.  
  293. /* 
  294.  * The function pop_input() pops one level of input sources.  If the
  295.  * popped input_block is a file, current_file and current_line are reset
  296.  * to the saved values before the memory for the input_block are
  297.  * released.
  298.  */
  299. static void 
  300. pop_input()
  301. {
  302.     input_block *tmp = isp->prev;
  303.  
  304.     switch (isp->type) {
  305.     case INPUT_STRING:
  306.     case INPUT_MACRO:
  307.     break;
  308.     case INPUT_FILE:
  309.     fclose(isp->u.u_f.file);
  310.     current_file = isp->u.u_f.name;
  311.     current_line = isp->u.u_f.lineno;
  312.     output_current_line = isp->u.u_f.out_lineno;
  313.     must_advance_line = isp->u.u_f.advance_line;
  314.     if (sync_output && tmp != nil)
  315.         sync_line(current_line, current_file);
  316.     break;
  317.     default:
  318.     internal_error("Input stack botch in pop_input()");
  319.     break;
  320.     }
  321.     obstack_free(current_input, isp);
  322.  
  323.     isp = tmp;
  324. }
  325.  
  326. /* 
  327.  * To switch input over to the wrapup stack, main() calls pop_wrapup().
  328.  * Since wrapup text can install new wrapup text, pop_wrapup() returns
  329.  * false when there is no wrapup text on the stack, and true otherwise.
  330.  */
  331. boolean 
  332. pop_wrapup()
  333. {
  334.     if (wsp == nil)
  335.     return false;
  336.  
  337.     current_input = &wrapup_stack;
  338.     isp = wsp;
  339.     wsp = nil;
  340.  
  341.     return true;
  342. }
  343.  
  344. /* 
  345.  * When a MACRO token is seen, next_token() uses get_macro_func() to
  346.  * retrieve the value of the function pointer. 
  347.  */
  348. static builtin_func *
  349. get_macro_func()
  350. {
  351.     if (isp->type != INPUT_MACRO)
  352.     internal_error("Bad call to get_macro_func()");
  353.  
  354.     return isp->u.u_m.func;
  355. }
  356.  
  357.  
  358. /* 
  359.  * Low level input is done a character at a time.  The function
  360.  * peek_input() is used to look at the next character in the input
  361.  * stream.  At any given time, it reads from the input_block on the top
  362.  * of the current input stack.
  363.  */
  364. int 
  365. peek_input()
  366. {
  367.     register int ch;
  368.  
  369.     while (1) {
  370.     if (isp == nil)
  371.         return CHAR_EOF;
  372.  
  373.     switch (isp->type) {
  374.     case INPUT_STRING:
  375.         ch = isp->u.u_s.string[0];
  376.         if (ch)
  377.         return ch;
  378.         break;
  379.     case INPUT_FILE:
  380.         ch = getc(isp->u.u_f.file);
  381.         if (ch != EOF) {
  382.         ungetc(ch, isp->u.u_f.file);
  383.         return ch;
  384.         }
  385.         break;
  386.     case INPUT_MACRO:
  387.         return CHAR_MACRO;
  388.     default:
  389.         internal_error("Input stack botch in peek_input()");
  390.         break;
  391.     }
  392.     /* end of input --- pop one level */
  393.     pop_input();
  394.     }
  395. }
  396.  
  397. /* 
  398.  * The function advance_input() is used to advance the input to the next
  399.  * character.  It also manages line numbers for error messages, so they
  400.  * do not get wrong, due to lookahead.  The token consisting of a
  401.  * newline alone is taken as belonging to the line it ends, and the
  402.  * current line number is not incremented until the next character is
  403.  * read.
  404.  */
  405. static void 
  406. advance_input()
  407. {
  408.     register int ch;
  409.  
  410.     if (must_advance_line) {
  411.     must_advance_line = false;
  412.     current_line++;
  413.     }
  414.  
  415.     switch (isp->type) {
  416.     case INPUT_STRING:
  417.     isp->u.u_s.string++;
  418.     break;
  419.     case INPUT_FILE:
  420.     ch = getc(isp->u.u_f.file);
  421.     if (ch != EOF) {
  422.         if (ch == '\n') {
  423.         output_lines = 0;
  424.         must_advance_line = true;
  425.         }
  426.     }
  427.     break;
  428.     case INPUT_MACRO:
  429.     pop_input();
  430.     break;
  431.     default:
  432.     internal_error("Input stack botch in advance_input()");
  433.     break;
  434.     }
  435. }
  436.  
  437. /* 
  438.  * A simple function to read the next character from the input stream.
  439.  */
  440. static int 
  441. next_char()
  442. {
  443.     register int ch = peek_input();
  444.     if (ch != CHAR_EOF)
  445.     advance_input();
  446.     return ch;
  447. }
  448.  
  449. /* 
  450.  * Skip_line() simply discards all immediately following characters,
  451.  * upto the first newline.  It is only used from m4_dnl().
  452.  */
  453. void 
  454. skip_line()
  455. {
  456.     int ch;
  457.     
  458.     while ((ch = next_char()) != EOF && ch != '\n')
  459.     ;
  460. }
  461.  
  462.  
  463. /* 
  464.  * Inititialise input stacks, and quote/comment characters.
  465.  */
  466. void 
  467. input_init()
  468. {
  469.     current_file = "End of input";
  470.     current_line = 0;
  471.  
  472.     obstack_init(&token_stack);
  473.     obstack_init(&input_stack);
  474.     obstack_init(&wrapup_stack);
  475.  
  476.     current_input = &input_stack;
  477.  
  478.     obstack_1grow(&token_stack, '\0');
  479.     token_buttom = obstack_finish(&token_stack);
  480.  
  481.     isp = nil;
  482.     wsp = nil;
  483.     next = nil;
  484.  
  485.     must_advance_line = false;
  486.  
  487.     lquote = DEF_LQUOTE;
  488.     rquote = DEF_RQUOTE;
  489.  
  490.     bcomm = DEF_BCOMM;
  491.     ecomm = DEF_ECOMM;
  492. }
  493.  
  494. /* 
  495.  * Parse and return a single token, from the input stream.  A token can
  496.  * either be TOKEN_EOF, if both the input_stack is empty; it can be
  497.  * TOKEN_STRING for a quoted string; TOKEN_WORD for something that is a
  498.  * potential macro name; and TOKEN_SIMPLE for any single character, that
  499.  * is not a part of any of the previous types.
  500.  *
  501.  * Next_token() return the token type, and passes back a pointer to the
  502.  * token data through TD.  The token text is collected on the obstack
  503.  * token_stack, which never contains more than one tokens text at a
  504.  * time.  The storage pointed to by the fields in TD is therefore
  505.  * subject to change the next time next_token() is called.
  506.  */
  507. token_type 
  508. next_token(td)
  509.     token_data *td;
  510. {
  511.     int ch;
  512.     int quote_level;
  513.     token_type type;
  514.  
  515.     obstack_free(&token_stack, token_buttom);
  516.  
  517.     ch = peek_input();
  518.     if (ch == CHAR_EOF) {
  519.     return TOKEN_EOF;
  520. #ifdef DEBUG_INPUT
  521.     fprintf(stderr, "next_token -> EOF\n");
  522. #endif
  523.     }
  524.     if (ch == CHAR_MACRO) {
  525.     TOKEN_DATA_TYPE(td) = TOKEN_FUNC;
  526.     TOKEN_DATA_FUNC(td) = get_macro_func();
  527.     advance_input();
  528.     return TOKEN_MACDEF;
  529.     }
  530.  
  531.     advance_input();
  532.     if (ch == bcomm) {
  533.  
  534.     obstack_1grow(&token_stack, ch);
  535.     while ((ch = next_char()) != CHAR_EOF && ch != ecomm)
  536.         obstack_1grow(&token_stack, ch);
  537.     if (ch != CHAR_EOF)
  538.         obstack_1grow(&token_stack, ch);
  539.     type = TOKEN_STRING;
  540.  
  541.     } else if (isalpha(ch) || ch == '_') {
  542.  
  543.     obstack_1grow(&token_stack, ch);
  544.     while ((ch = peek_input()) != CHAR_EOF && (isalnum(ch) || ch == '_')) {
  545.         obstack_1grow(&token_stack, ch);
  546.         advance_input();
  547.     }
  548.     type = TOKEN_WORD;
  549.  
  550.     } else if (ch != lquote) {
  551.  
  552.     type = TOKEN_SIMPLE;
  553.     obstack_1grow(&token_stack, ch);
  554.  
  555.     } else {
  556.  
  557.     quote_level = 1;
  558.     while (1) {
  559.         ch = next_char();
  560.         if (ch == CHAR_EOF)
  561.         fatal("EOF in string");
  562.  
  563.         if (ch == rquote) {
  564.         if (--quote_level == 0)
  565.             break;
  566.         } else if (ch == lquote)
  567.         quote_level++;
  568.         obstack_1grow(&token_stack, ch);
  569.     }
  570.     type = TOKEN_STRING;
  571.     }
  572.  
  573.     obstack_1grow(&token_stack, '\0');
  574.  
  575.     TOKEN_DATA_TYPE(td) = TOKEN_TEXT;
  576.     TOKEN_DATA_TEXT(td) = obstack_finish(&token_stack);
  577. #ifdef DEBUG_INPUT
  578.     fprintf(stderr, "next_token -> %d (%s)\n", type, TOKEN_DATA_TEXT(td));
  579. #endif
  580.     return type;
  581. }
  582.  
  583.  
  584. #ifdef DEBUG_INPUT
  585.  
  586. print_token(s, t, td)
  587.     char *s;
  588.     token_type t;
  589.     token_data *td;
  590. {
  591.     fprintf(stderr, "%s: ", s);
  592.     switch (t) {            /* TOKSW */
  593.     case TOKEN_SIMPLE:
  594.     fprintf(stderr, "char:");
  595.     break;
  596.     case TOKEN_WORD:
  597.     fprintf(stderr, "word:");
  598.     break;
  599.     case TOKEN_STRING:
  600.     fprintf(stderr, "string:");
  601.     break;
  602.     case TOKEN_MACDEF:
  603.     fprintf(stderr, "macro: 0x%x\n", TOKEN_DATA_FUNC(td));
  604.     break;
  605.     case TOKEN_EOF:
  606.     fprintf(stderr, "eof\n");
  607.     break;
  608.     }
  609.     fprintf(stderr, "\t\"%s\"\n", TOKEN_DATA_TEXT(td));
  610. }
  611.  
  612.  
  613. lex_debug()
  614. {
  615.     token_type t;
  616.     token_data td;
  617.  
  618.     while ((t = next_token(&td)) != nil)
  619.     print_token("lex", t, &td);
  620. }
  621. #endif
  622.