home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume44 / a32src / part02 / cppsubs.c < prev   
Encoding:
C/C++ Source or Header  |  1994-09-23  |  18.9 KB  |  770 lines

  1. /*    CPPSUBS.C - "C" preprocessor     */
  2. /*
  3.     cppsubs - subroutines for the C pre-processor.
  4.  
  5.     Copyright 3/19/84 by Tom Roberts. All rights reserved.
  6.  
  7.  
  8.     The C pre-processor implemented here has a few changes from the
  9.     standard UNIX(TM) pre-processor:
  10.  
  11.     1) #line is not recognized.
  12.     2) defined(symbol) is not recognized
  13.     3) __FILE__ and __LINE__ are not recognized.
  14.     4) #if/#else/#endif (all flavors) MAY be used inside a #define:
  15.         #define m(a)    \
  16.         #ifdef a    \
  17.             a is defined\
  18.         #else        \
  19.             a is not defined\
  20.         #endif
  21.        all of the #'s MUST follow an escaped newline.
  22.     5) there is a new statement:
  23.         #set name expression
  24.        the expression is expanded (for #define-d symbols),
  25.        name is #undef-ed, and the expression
  26.        is evaluated (must contain only operators and constants);
  27.        name is then #define-d to be the result (in ASCII, decimal radix).
  28.        All C operators are permitted.
  29.     6) newlines in the input are not rigorously preserved (e.g. within
  30.        comments).
  31.     7) comments are normally crunched out of #define macro-bodies; an
  32.        exception is made for the null comment (slash-star-slash -
  33.        indicated by <sss> below).
  34.        This permits generating unique labels inside #define-s:
  35.         #define l 0
  36.         #define m    \
  37.             x<sss>l:    operation();\
  38.         #set l l+1
  39.        The null comment can be used for any concatenation desired.
  40.        (I cannot use <sss> here, because it would end this comment!)
  41.     8) In expressions, the conditional operator (a ? b : c) MUST
  42.        be surrounded by parentheses when nested within another
  43.        conditional operator.
  44.        In expressions, brackets ([]) are equivalent to parentheses (()).
  45.        Comma (,) and semicolon (;) will terminate the expression.
  46.        (#if and #set are the only places expressions are interpreted).
  47.  
  48.  
  49.     Calling sequences:
  50.  
  51.     ppinit(filename) MUST be the first routine called.
  52.     use filename="-" for stdin.
  53.  
  54.     ppgetline(line,MX_LINE) implements a line-oriented version of "cpp";
  55.     line-orientation mainly refers to the ability to list
  56.     the raw input-lines (via listit()).
  57.  
  58.     ppclose() will close the input-file, and free all space used by
  59.     #defines. need not be called.
  60.  
  61.  
  62.     externs required:
  63.  
  64.         char line[MX_LINE];    expanded line put here  (argument)
  65.         char rawline[MX_LINE];    raw line read here
  66.         char errbuf[];        space to form error-message
  67.                       (at least 50 chars long)
  68.         char *filename;        pointer for current file-name
  69.                       (is set for each #include-file)
  70.         int lineno;        int for current line-number
  71.                       (of current file)
  72.         error(string,code);    error-message print - should
  73.                       prepend prog-name, filename, and
  74.                       lineno to string, and add '\n'.
  75.                       should call listit() internally.
  76.                       code > 0 means fatal error (error
  77.                       will call exit(code)).
  78.         void listit(level,skip);routine to list rawline[], level =
  79.                        nesting-level of #include files.
  80.                        skip = 1 if text is skipped.
  81.                        it should guarantee not to list the
  82.                        same line twice. rawline[] may
  83.                        be clobbered by listit().
  84.                        (called just before a line is read)
  85.  
  86.     These will be given suitable defaults, if not #defined:
  87.  
  88.         #define PP_AUXNL ';'    to translate ';' to '\n' (leave
  89.                        undefined, if no such char)
  90.         #define N_HASH 32    number of hash-table entries - MUST
  91.                       be a power of 2. defaults to 32.
  92.  
  93.  
  94.     externs supplied to control the pre-processor:
  95.  
  96.         int pp_symb        symbol-argument to cexpr(); set
  97.                     non-zero to allow all symbols known
  98.                     to cexpr in #if and #set. zero
  99.                     (default) means only constants (and
  100.                     names #define-d to constants) can
  101.                     be used.
  102.  
  103.         int Keep_comments    set non-zero to preserve comments.
  104. */
  105. /**************
  106.  
  107. THIS SOFTWARE IS RELEASED "AS IS", WITH NO WARRANTY EXPRESSED OR IMPLIED.
  108. This software is copyright 1984, 1991, 1992, 1993, 1994 by Tom Roberts.
  109. License is granted for unlimited distribution, as long as the following
  110. conditions are met:
  111.   A. This notice is preserved intact.
  112.   B. No charge is made for the software (other than a reasonable
  113.      distribution/duplication fee).
  114.  
  115. ***************/
  116.  
  117. #include "port.h"
  118.  
  119.  
  120. extern char line[];
  121. extern char rawline[];
  122. extern char errbuf[];
  123. extern char *filename;
  124. extern int lineno;
  125. extern long value;
  126.  
  127.  
  128. #define MX_INCLUDE    4    /* max nesting of #include files */
  129. #define MX_TOKEN        128      /* max identifier, string, etc. */
  130. #define MX_ARG          10      /* max # args to macro */
  131. #ifndef MX_PPBUF
  132. #define MX_PPBUF         2000    /* size of expand-buffer */
  133. #endif
  134.  
  135. #ifndef N_HASH        /* size of hash-table */
  136. #define N_HASH 32    /* MUST be a power of 2! */
  137. #endif
  138.  
  139. #ifndef PP_AUXNL        /* char to be converted to '\n' */
  140. #define PP_AUXNL 0
  141. #endif
  142.  
  143. int pp_symb = 0;        /* set non-zero to enable symbols in pp */
  144. int Keep_comments = 0;        /* set non-zero to preserve comments */
  145.  
  146. static char ppbuf[MX_PPBUF+2];  /* expand buffer */
  147. static char *pparg[MX_ARG];     /* pointers to argument-values (last char) */
  148. static char *pp_ptr;            /* current pointer into ppbuf[] */
  149. static char *ppmacro;           /* pointer to macro-body (last char) */
  150. static char *pptemp;        /* temporary pointer */
  151. static char ppname[MX_TOKEN];   /* current token */
  152. static FILE * infile[MX_INCLUDE];    /* #include file-pointers */
  153. static int inlevel = 0;        /* current #include-file level */
  154. static int inskip = 0;        /* 1 = skipping text, 0 = not skipping */
  155. static int incomment = 0;    /* 1 = within comment (Keep_comments!=0) */
  156. static int no_list = 0;        /* 1 = no list on next raw read */
  157. static char inname[MX_INCLUDE][MX_FNAME]; /* file-names */
  158. static int inline[MX_INCLUDE];    /* line numbers */
  159. static int mx_line;        /* max size of line[] */
  160. static int def_level = 0;    /* level of #define-s */
  161.  
  162.  
  163. static struct PP_SYMBOL {
  164.         struct PP_SYMBOL *ppnext;
  165.         char ppname[MX_IDENT];
  166.         char *ppstart;
  167.         char *ppmacro;
  168. } *pptable[N_HASH], *ppentry;
  169.  
  170.  
  171. ppinit(name)                /* initialize ppgetline() */
  172. char *name;
  173. {
  174.     extern char *strncpy();
  175.  
  176.     inlevel = 0;
  177.     inskip = 0;
  178.     if(strcmp(name,"-") == 0) {
  179.         infile[0] = stdin;
  180.     } else {
  181.         infile[0] = fopen(name,"r");
  182.         if(infile[0] == 0) {
  183.             sprintf(errbuf,"cannot open file '%.16s'",name);
  184.             error(errbuf,1);
  185.         }
  186.     }
  187.     strncpy(inname[0],name,16);
  188.     filename = inname[0];
  189.     inline[0] = 0;
  190.     lineno = 0;
  191.     line[0] = '\0';
  192.     rawline[0] = '\0';
  193.  
  194.     pp_ptr = &ppbuf[MX_PPBUF];
  195. }
  196.  
  197. ppclose()
  198. {
  199.     register struct PP_SYMBOL *ptr, *ptr1;
  200.     register int i;
  201.  
  202.     fclose(infile[0]);
  203.  
  204.     for(i=0; i<N_HASH; ++i) {
  205.         for(ptr=pptable[i]; ptr; ptr=ptr1) {
  206.             ptr1 = ptr->ppnext;
  207.             if(ptr->ppstart)
  208.                 free(ptr->ppstart);
  209.             free(ptr);
  210.         }
  211.         pptable[i] = (char *) 0;
  212.     }
  213. }
  214.  
  215.  
  216. ppgetline(line,nline)        /* get expanded line into line[] */
  217. char *line;            /* (recursive, through ppexpr()) */
  218. int nline;
  219. {
  220.         register char *pp_put, *ptr, ch;
  221.         register int i;
  222.  
  223.         pp_put = line;
  224.     mx_line = nline - 2;    /* space for '\n' '\0' */
  225.  
  226.         for(;;) {
  227.                 if(pp_ptr >= &ppbuf[MX_PPBUF])
  228.                         if(fillppbuf())
  229.                                 return(EOF);
  230.                 if(*pp_ptr == '#') {
  231.                         if(pp_stmt())
  232.                 return(EOF);
  233.                         continue;
  234.                 }
  235.  
  236.                 while(pp_ptr < &ppbuf[MX_PPBUF]) {
  237.                         if( (pp_put-line) >= mx_line) {
  238.                                 *pp_put++ = '\n';
  239.                 *pp_put = '\0';
  240.                                 return(0);
  241.                         }
  242.                         i = pptoken();
  243.                         switch(i) {
  244. #if PP_AUXNL
  245.                         case PP_AUXNL:
  246. #endif
  247.                         case '\n':
  248.                                 *pp_put++ = '\n';
  249.                 *pp_put-- = '\0';
  250.                                 return(0);
  251.             case 'c':    /* comment */
  252.                                 for(ptr=ppname; *ptr; ++ptr) {
  253.                     if( (pp_put-line) >= mx_line) {
  254.                         *pp_put++ = '\n';
  255.                         *pp_put = '\0';
  256.                         return(0);
  257.                     }   
  258.                     *pp_put++ = *ptr;
  259.                     if(*ptr == '\n') {
  260.                         *pp_put++ = '\0';
  261.                         return(0);
  262.                     }
  263.                 }
  264.                 break;
  265.                         case 'a':       /* name */
  266.                                 if(ppsymb() && !incomment) {
  267.                                         pparglist(1);
  268.                                         while (ch = *ppmacro--) {
  269.                         if(pp_ptr < ppbuf)
  270.                             ppbufovfl();
  271.                         if(ISARG(ch)) {
  272.                                                         ptr = pparg[ARGNO(ch)];
  273.                                                         while(*ptr) {
  274.                                 if(pp_ptr < ppbuf)
  275.                                 ppbufovfl();
  276.                                                             *--pp_ptr = *ptr--;
  277.                             }
  278.                                                 } else {
  279.                                                         *--pp_ptr = ch;
  280.                                                 }
  281.                                         }
  282.                                         break;
  283.                                 }
  284.                                 /* flow through */
  285.                         default:
  286.                                 for(ptr=ppname; *ptr; ++ptr)
  287.                                         *pp_put++ = *ptr;
  288.                                 break;
  289.                         }
  290.                 }
  291.         }
  292. }
  293.  
  294. fillppbuf()     /* read into rawline[], copy to end of ppbuf[] */
  295. {
  296.         register  int n;
  297.         register  char *ptr;
  298.         extern char *fgets();
  299.  
  300.         for(;;) {
  301.         if(!no_list)
  302.                     listit(inlevel,inskip);
  303.         else
  304.             no_list = 0;
  305.  
  306.                 while(!fgets(rawline,mx_line,infile[inlevel])) {
  307.             fclose(infile[inlevel]);
  308.             if(--inlevel < 0)
  309.                 return(EOF);
  310.             filename = inname[inlevel];
  311.             lineno = inline[inlevel];
  312.         }
  313.         /* increment abs(lineno) */
  314.         lineno = ((lineno<0) ? -lineno : lineno) + 1;
  315.         
  316.                 n = strlen(rawline);
  317.                 if(n) {
  318.                         ptr = rawline + n;      /* this is the '\0' */
  319.             if(*(ptr-2) == '\r' && *(ptr-1) == '\n') {
  320.                 *--ptr = '\0';
  321.                 *(ptr-1) = '\n';
  322.                 --n;
  323.             }
  324.                         pp_ptr = &ppbuf[MX_PPBUF];
  325.             ++n;
  326.                         while(n--)
  327.                 *pp_ptr-- = *ptr--;
  328.             ++pp_ptr;
  329.                         break;
  330.                 }
  331.         }
  332.         return(0);
  333. }
  334.  
  335. int
  336. pp_stmt()
  337. {
  338.     extern char *strncpy();
  339.         register int i, level;
  340.         register struct PP_SYMBOL *sym, **psym;
  341.         register char *ptr, *ptr1;
  342.     register int j, state;
  343.     auto char t_name[MX_IDENT+1], t_line[80];
  344.         static char *keyword[] = {"include","define","undef",
  345.                                    "ifdef","ifndef","if","else","endif",
  346.                                    "set","pushdef","pushset","popdef",NULL};
  347.     FILE *f;
  348.  
  349.         ++pp_ptr;        /* (eat the '#') */
  350.  
  351.         while(isspace(*pp_ptr) && *pp_ptr != '\n')
  352.                 ++pp_ptr;
  353.         if(pptoken() != 'a')
  354.                 goto err;
  355.         while(isspace(*pp_ptr) && *pp_ptr != '\n')
  356.                 ++pp_ptr;
  357.  
  358.         for(i=0; keyword[i]; ++i) {
  359.                 if(strcmp(ppname,keyword[i]) == 0)
  360.                         break;
  361.         }
  362.         switch(i) {
  363.  
  364.         case 0: /* include */
  365.         if(inlevel >= MX_INCLUDE) {
  366.             error("#include-files nested too deeply - ignored",0);
  367.             break;
  368.         }
  369.         if(*pp_ptr == '"')
  370.             i = '"';
  371.         else if(*pp_ptr == '<')
  372.             i = '>';
  373.         else
  374.             goto err;
  375.         ptr = ++pp_ptr;
  376.         while(*pp_ptr) {
  377.             if(*pp_ptr++ == i)
  378.                 break;
  379.         }
  380.         *(pp_ptr-1) = '\0';
  381.         f = fopen(ptr,"r");
  382.         if(!f) {
  383.             sprintf(errbuf,"cannot open #include-file '%.16s'",ptr);
  384.             error(errbuf,0);
  385.             break;
  386.         }
  387.         listit(inlevel,inskip);
  388.         no_list = 1;
  389.         inline[inlevel] = lineno;
  390.         infile[++inlevel] = f;
  391.         strncpy(inname[inlevel],ptr,16);
  392.         filename = inname[inlevel];
  393.         lineno = 0;
  394.         break;
  395.  
  396.     case 9:    /* pushdef */
  397.         case 1: /* define */
  398.                 if(pptoken() != 'a')
  399.                         goto err;
  400.                 if(i == 1 && ppsymb()) {
  401.                     sym = ppentry;
  402.                     free(sym->ppstart);
  403.             sprintf(errbuf,"WARNING: re-definition of macro '%.8s'",
  404.             ppname);
  405.             error(errbuf,0);
  406.                 } else {
  407.                         sym =(struct PP_SYMBOL *)malloc(sizeof(struct PP_SYMBOL));
  408.                         if(sym == 0)
  409.                 ppmemovfl();
  410.                         strncpy(sym->ppname,ppname,MX_IDENT);
  411.                         i = hash(ppname);
  412.                         sym->ppnext = pptable[i];
  413.                         pptable[i] = sym;
  414.                 }
  415.         ++def_level;
  416.         pparglist(0);
  417.         *pptemp++ = '\0';    /* initialized in pparglist() */
  418.         while(isspace(*pp_ptr) && *pp_ptr != '\n')
  419.             ++pp_ptr;
  420.         ptr = pptemp;
  421.         for(;;) {
  422. next:            if(ptr >= pp_ptr)
  423.                 ppbufovfl();
  424.             switch(pptoken()) {
  425.             case 'a':
  426.                 for(i=0; i<MX_ARG; ++i) {
  427.                     if(strncmp(ppname,pparg[i],MX_IDENT)
  428.                              == 0) {
  429.                         *ptr++ = (ARGFLAG(i));
  430.                         goto next;
  431.                     }
  432.                 }
  433.                 goto copy;
  434.             case '\n':
  435. #if PP_AUXNL
  436.                 if(*(pp_ptr-1) == PP_AUXNL)
  437.                     ppname[0] = PP_AUXNL;
  438.                 else
  439. #endif
  440.                      if(*(ptr-1) == '\\')
  441.                     --ptr;
  442.                 else
  443.                     goto done;
  444.                 /* flow through */
  445.             default:
  446. copy:                for(ptr1=ppname; *ptr1;)
  447.                     *ptr++ = *ptr1++;
  448.             }
  449.         }
  450. done:        --def_level;
  451.         *ptr++ = '\0';
  452.                 ptr = malloc(ptr - pptemp + 1);
  453.                 sym->ppstart = ptr;
  454.                 if(!ptr)
  455.             ppmemovfl();
  456.         *ptr++ = '\0';    /* (end string when scanned backwards) */
  457.                 for(ptr1=pptemp; *ptr++ = *ptr1++;)
  458.                         ;
  459.                 sym->ppmacro = ptr - 2;
  460.                 return(0);
  461.  
  462.     case 11:/* popdef */
  463.         case 2: /* undef */
  464.                 if(pptoken() != 'a')
  465.                         goto err;
  466.                 psym = &pptable[hash(ppname)];
  467.         while(*psym) {
  468.                         if(strncmp((*psym)->ppname,ppname,MX_IDENT) == 0) {
  469.                                 free((*psym)->ppstart);
  470.                                 ptr = (char *)*psym;
  471.                                 *psym = (*psym)->ppnext;
  472.                 free(ptr);
  473.                 if(i == 11)
  474.                                     break;
  475.                 else
  476.                     continue;
  477.                         }
  478.             psym = &((*psym)->ppnext);
  479.                 }
  480.                 break;
  481.  
  482.         case 3: /* ifdef */
  483.         if(pptoken() != 'a')
  484.             goto err;
  485.         if(!ppsymb())
  486.             goto skip;
  487.         break;
  488.  
  489.         case 4: /* ifndef */
  490.         if(pptoken() != 'a')
  491.             goto err;
  492.         if(ppsymb())
  493.             goto skip;
  494.         break;
  495.  
  496.         case 5: /* if */
  497.         i = ppexpr();
  498.         if(i == EOF)
  499.             return(EOF);
  500.         if(i != 0)
  501.             goto err;
  502.         if(value == 0l)
  503.             goto skip;
  504.         break;
  505.  
  506.         case 6: /* else */
  507. skip:        listit(inlevel,inskip);
  508.         no_list = 1;
  509.         level = 1;
  510.         inskip = 1;
  511.         state = 0;
  512.         /* state=0: looking for '\n'; state=1: found '\n';
  513.            state=2: found '\n#' or '\n# \t', looking for name */
  514.         while(level > 0) {
  515.             i = pptoken();
  516.             if(i == EOF)
  517.                 return(EOF);
  518.             if(state == 1 && i == '#') {
  519.                 state = 2;
  520.                 continue;
  521.             } else if(state == 2 && (i == ' ' || i == '\t')) {
  522.                 continue;
  523.             } else if(state == 2 && i == 'a') {
  524.                 if(strcmp(ppname,"endif") == 0)
  525.                     --level;
  526.                 else if(level == 1 && strcmp(ppname,"else")==0)
  527.                     --level;
  528.                 else if(ppname[0] == 'i' && ppname[1] == 'f')
  529.                     ++level;
  530.             }
  531.             if(i == '\n')
  532.                 state = 1;
  533.             else
  534.                 state = 0;
  535.         }
  536.         inskip = 0;
  537.         break;
  538.  
  539.         case 7: /* endif */
  540.         break;
  541.  
  542.     case 10:/* pushset */
  543.     case 8:    /* set */
  544.         if(pptoken() != 'a')
  545.             goto err;
  546.         strncpy(t_name,ppname,MX_IDENT);
  547.         t_name[MX_IDENT] = '\0';
  548.         j = ppexpr();
  549.         if(j == EOF)
  550.             return(EOF);
  551.         if(j != 0)
  552.             goto err;
  553.         if(i == 8)
  554.             sprintf(t_line,"#undef %s\n#define %s 0%lo",
  555.                 t_name,t_name,value);
  556.         else
  557.             sprintf(t_line,"#pushdef %s 0%lo",
  558.                 t_name,value);
  559.         i = strlen(t_line);
  560.         while(i--)
  561.             *--pp_ptr = t_line[i];
  562.         return(0);
  563.  
  564.         default:
  565.                 goto err;
  566.         }
  567.  
  568.     goto ret;
  569.  
  570. err:    sprintf(errbuf,"illegal cpp-statement  token='%.16s'",ppname);
  571.     error(errbuf,0);
  572.  
  573. ret:    while(pptoken() != '\n')
  574.                 ;
  575.         return(0);
  576. }
  577.  
  578. int
  579. ppexpr()    /* expand rest of line, and evaluate expression */
  580. {
  581.     register int t_mxline, i;
  582.     auto char t_line[MX_TOKEN+MX_TOKEN];
  583.  
  584.     t_mxline = mx_line;
  585.     t_line[0] = '\0';
  586.     ++def_level;
  587.     i = ppgetline(t_line,MX_TOKEN+MX_TOKEN);
  588.     if(i == EOF)
  589.         return(EOF);
  590.     --pp_ptr;    /* put back '\n' */
  591.     --def_level;
  592.     mx_line = t_mxline;
  593.     if(i || cexpr(t_line,pp_symb))
  594.         return(1);
  595.     return(0);
  596. }
  597.  
  598. ppsymb()        /* check if ppname[] is a cpp-known symbol */
  599. {
  600.         register struct PP_SYMBOL *sym;
  601.  
  602.         for(sym=pptable[hash(ppname)]; sym!=0; sym=sym->ppnext) {
  603.                 if(strncmp(ppname,sym->ppname,MX_IDENT) == 0) {
  604.                         ppmacro = sym->ppmacro;
  605.                         ppentry = sym;
  606.                         return(1);
  607.                 }
  608.         }
  609.         return(0);
  610. }
  611.  
  612.  
  613. hash(name)              /* simple hash (N_HASH is a power of 2) */
  614. register char *name;
  615. {
  616.         BEST int h, n;
  617.  
  618.     n = MX_IDENT;
  619.         h = 0;
  620.         while(*name && n--)
  621.                 h += *name++;
  622.         
  623.         return(h & (N_HASH-1));
  624. }
  625.  
  626. pptoken()       /* return the next token from *pp_ptr */
  627. {
  628.     BEST int ch;
  629.     BEST char *ptr;
  630.  
  631. loop:    while(pp_ptr >= &ppbuf[MX_PPBUF])
  632.         if(fillppbuf())
  633.             return(EOF);
  634.  
  635.     ch = *pp_ptr++;
  636.     ppname[0] = ch;
  637.     ptr = &ppname[1];
  638.     if(ch == '/' && (*pp_ptr == '*' || *pp_ptr == '/') && !incomment) {
  639.         if(*pp_ptr == '*') {
  640.             if(Keep_comments) {
  641.                 incomment = 1;
  642.             } else if(*(pp_ptr+1)!='/' || def_level==0) {
  643.                 while( !(*pp_ptr++ == '*' && *pp_ptr == '/') ){
  644.                 if(pp_ptr >= &ppbuf[MX_PPBUF])
  645.                     if(fillppbuf())
  646.                         return(EOF);
  647.                 }
  648.                 ++pp_ptr;
  649.                 goto loop;
  650.             }
  651.         } else {
  652.             if(Keep_comments) {
  653.                 incomment = -1;
  654.             } else {
  655.                 while(*pp_ptr++ != '\n') {
  656.                 if(pp_ptr >= &ppbuf[MX_PPBUF])
  657.                     if(fillppbuf())
  658.                         return EOF;
  659.                 }
  660.                 --pp_ptr;
  661.                 goto loop;
  662.             }
  663.         }
  664.     }
  665.     if((incomment == 1 && ch == '*' && *pp_ptr == '/') ||
  666.        (incomment == -1 && ch == '\n'))
  667.         incomment = 0;
  668.         
  669.     if(ch == '"') {
  670.         while(ch = *pp_ptr++) {
  671.             *ptr++ = ch;
  672.             if(ch == '\\')
  673.                 *ptr++ = *pp_ptr++;
  674.             else if(ch == '"')
  675.                 break;
  676.             if(ptr >= &ppname[MX_TOKEN]) {
  677.                 error("string too long",0);
  678.                 break;
  679.             }
  680.             if(pp_ptr >= &ppbuf[MX_PPBUF])
  681.                 if(fillppbuf())
  682.                     return(EOF);
  683.         }
  684.     } else if(ch == '\'') {
  685.         while(ch = *pp_ptr++) {
  686.             *ptr++ = ch;
  687.             if(ch == '\\')
  688.                 *ptr++ = *pp_ptr++;
  689.             else if(ch == '\'')
  690.                 break;
  691.             if(ptr >= &ppname[MX_TOKEN]) {
  692.                 error("string too long",0);
  693.                 break;
  694.             }
  695.             if(pp_ptr >= &ppbuf[MX_PPBUF])
  696.                 if(fillppbuf())
  697.                     return(EOF);
  698.         }
  699.     } else if(isident(ch)) {
  700.         while(isident(*pp_ptr))
  701.             *ptr++ = *pp_ptr++;
  702.         ch = 'a';
  703.     }
  704.  
  705.     *ptr = '\0';
  706.     return(ch);
  707. }
  708.  
  709. pparglist(type)     /* collect macro arg-list */
  710. int type;        /* 0=point to start, 1=point to end of arg */
  711. {
  712.     register char *ptr, *ptr1, *begin;
  713.     register int level, i;
  714.  
  715.     for(i=0; i<MX_ARG; ++i)
  716.         pparg[i] = "";
  717.     pptemp = ppbuf;
  718.  
  719.     if(*pp_ptr != '(')
  720.         return(0);
  721.  
  722.     level = 1;
  723.     ++pp_ptr;
  724.     ptr = ppbuf;
  725.     *ptr++ = '\0';    /* end string when scanned backwards */
  726.  
  727.     for(i=0; i<MX_ARG; ++i) {
  728.         begin = ptr;
  729.         while (level > 0) {
  730.         switch(pptoken()) {
  731.         case '\n':
  732. #if PP_AUXNL
  733.             ppname[0] = PP_AUXNL;
  734. #else
  735.             ppname[0] = ' ';
  736. #endif
  737.             break;
  738.         case '(': case '[': case '{':
  739.             ++level;
  740.             break;
  741.         case ')': case ']': case '}':
  742.             if(--level <= 0)
  743.                 goto end_arg;
  744.             break;
  745.         case ',':
  746.             if(level == 1)
  747.                 goto end_arg;
  748.         }
  749.         for(ptr1=ppname; *ptr1;)
  750.             *ptr++ = *ptr1++ & 0177;
  751.         }
  752. end_arg:    *ptr++ = '\0';
  753.         if(type)
  754.         pparg[i] = ptr-2;
  755.         else
  756.         pparg[i] = begin;
  757.     }
  758.     pptemp = ptr;
  759. }
  760.  
  761. ppbufovfl()
  762. {
  763.     error("macro expand-buffer overflow",1);
  764. }
  765.  
  766. ppmemovfl()
  767. {
  768.     error("MEMORY OVERFLOW in cpp",1);
  769. }
  770.