home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 25 / nopv25.iso / 040A / CCDL151S.ZIP / SOURCE / PREPROC.C < prev    next >
Encoding:
C/C++ Source or Header  |  1997-06-26  |  19.1 KB  |  878 lines

  1. /*                               `
  2.  * 68K/386 32-bit C compiler.
  3.  *
  4.  * copyright (c) 1997, David Lindauer
  5.  * 
  6.  * This compiler is intended for educational use.  It may not be used
  7.  * for profit without the express written consent of the author.
  8.  *
  9.  * It may be freely redistributed, as long as this notice remains intact
  10.  * and either the original sources or derived sources 
  11.  * are distributed along with any executables derived from the originals.
  12.  *
  13.  * The author is not responsible for any damages that may arise from use
  14.  * of this software, either idirect or consequential.
  15.  *
  16.  * v1.35 March 1997
  17.  * David Lindauer, gclind01@starbase.spd.louisville.edu
  18.  *
  19.  * Credits to Mathew Brandt for original K&R C compiler
  20.  *
  21.  */
  22. #include        <stdio.h>
  23. #include                 <ctype.h>
  24. #include                "utype.h"
  25. #include                "cmdline.h"
  26. #include        "expr.h"
  27. #include        "c.h"
  28. #include        "errors.h"
  29. #include                "time.h"
  30.  
  31. extern short inputline[];
  32. extern FILE *inputFile;
  33. extern TABLE gsyms,defsyms;
  34. extern long ival;
  35. extern char laststr[];
  36. extern HASHREC **defhash;
  37. extern char *infile;
  38. extern int incconst;
  39. extern char *prm_searchpath;
  40. extern int prm_cplusplus, prm_ansi;
  41. extern short *lptr;
  42. extern int cantnewline;
  43. extern char *infile;
  44. extern int backupchar;
  45. extern int floatregs,dataregs,addrregs,basefr,basedr,basear;
  46. extern int prm_cmangle;
  47. extern enum e_sym lastst;
  48. extern char lastid[];
  49. extern int lastch;
  50. extern int lineno;
  51. extern int global_flag;
  52. typedef struct _list {
  53.         struct _list *link;
  54.         char *data;
  55. } LIST;
  56. typedef struct _startups_ {
  57.         struct _startups_ *link;
  58.         char *name;
  59.         int prio;
  60. } STARTUPS;
  61. char *errfile;
  62. int errlineno = 0;
  63. IFSTRUCT              *ifshold[10];
  64. char                         *inclfname[10];
  65. FILE            *inclfile[10];
  66. int             incldepth = 0;
  67. int             inclline[10];
  68. short            *lptr;
  69. LIST *incfiles = 0,*lastinc;
  70.  
  71. IFSTRUCT *ifs = 0;
  72. int ifskip = 0;
  73. int elsetaken = 0;
  74.  
  75. void filemac(short *string);
  76. void datemac(short *string);
  77. void timemac(short *string);
  78. void linemac(short *string);
  79.  
  80. static char *unmangid;        /* In this module we have to ignore leading underscores */
  81. static STARTUPS *startuplist, *rundownlist;
  82. static short defkw[] = { 'd','e','f','i','n','e','d', 0 };
  83.  
  84. /* List of standard macros */
  85. #define INGROWNMACROS 4
  86.  
  87. struct inmac {
  88.         char *s;
  89.         void (*func)();
  90. } ingrownmacros[INGROWNMACROS] = { 
  91.             { "__FILE__",filemac }, { "__DATE__",datemac, },
  92.             { "__TIME__", timemac }, { "__LINE__",linemac } };
  93.  
  94. void pushif(void);
  95.  
  96. /* Moudle init */
  97. void preprocini()
  98. {
  99.     floatregs = basefr;
  100.     dataregs = basedr;
  101.     addrregs = basear;
  102.     incldepth = 0;
  103.     incfiles = 0;
  104.     ifs = 0;
  105.     ifskip = elsetaken = 0;
  106.     unmangid = lastid;
  107.     if (prm_cmangle)
  108.         unmangid++;
  109.     startuplist = rundownlist = 0;
  110. }
  111. /* Preprocessor dispatch */
  112. int preprocess(void)
  113. {
  114.         ++lptr;
  115.         lastch = ' ';
  116.         getsym();               /* get first word on line */
  117.  
  118.         if( lastst != id  && lastst != kw_else && lastst!= kw_if) {
  119.                 generror(ERR_IDEXPECT,0,0);
  120.                 return incldepth == 0;
  121.                 }
  122.         if( strcmp(unmangid,"include") == 0 )
  123.                 return doinclude();
  124.         else if( strcmp(unmangid,"define") == 0 )
  125.                 return dodefine();
  126.                 else if (strcmp(unmangid,"endif") == 0)
  127.                                 return doendif();
  128.                 else if (lastst == kw_else)
  129.                                 return doelse();
  130.                 else if (strcmp(unmangid,"ifdef") == 0)
  131.                                 return doifdef(TRUE);
  132.                 else if (strcmp(unmangid,"ifndef") == 0)
  133.                                 return doifdef(FALSE);
  134.                 else if (lastst == kw_if) {
  135.                                 repdefines(lptr);
  136.                                 defcheck(lptr);
  137.                                 return doif(0);
  138.                 }
  139.         else if( strcmp(unmangid,"elif") == 0 ) {
  140.                                 repdefines(lptr);
  141.                                 defcheck(lptr);
  142.                 return doelif();
  143.                 }
  144.                 else if (strcmp(unmangid,"undef") == 0)
  145.                                 return(doundef());
  146.                 else if (strcmp(unmangid,"error") == 0)
  147.                                 return(doerror());
  148.                 else if (strcmp(unmangid,"pragma") == 0)
  149.                                 return(dopragma());
  150.                 else if (strcmp(unmangid,"line") == 0)
  151.                                 return(doline());
  152.         else    {
  153.                 gensymerror(ERR_PREPROCID,unmangid);
  154.                 return incldepth == 0;
  155.                 }
  156. }
  157.  
  158. int doerror(void)
  159. {
  160.     char *temp;
  161.     int i=0;
  162.     if (ifskip)
  163.         return incldepth == 0;
  164.     global_flag++;
  165.     temp = xalloc(pstrlen(lptr)*3+2);
  166.     pstrcpy(temp,lptr);
  167.     while (*lptr)
  168.         i+=installphichar(*lptr++,temp,i);
  169.     temp[i-1] = 0;
  170.     global_flag--;
  171.     basicerror(ERR_ERROR,temp);
  172.     return incldepth == 0;
  173. }
  174. int dopragma(void)
  175. {
  176.     char buf[40],*p=buf;
  177.   STARTUPS *a;
  178.     int val = 0,sflag;
  179.     if (ifskip)
  180.         return incldepth == 0;
  181.     lineToCpp();
  182.     getsym();
  183.     if (lastst != id)
  184.         return incldepth == 0;
  185.     if (!strcmp(unmangid,"startup"))
  186.         sflag = 1;
  187.     else if (!strcmp(unmangid,"rundown"))
  188.         sflag = 0;
  189.     else if (!strncmp(unmangid,"regopt",6)) {
  190.         short *s = lptr;
  191.         dataregs = floatregs = addrregs = 0;
  192.         while (*s != '\n') {
  193.             switch (*s) {
  194.                 case 'a':
  195.                 case 'A':
  196.                     addrregs = 1;
  197.                     break;
  198.                 case 'f':
  199.                 case 'F':
  200.                     floatregs = 1;
  201.                     break;
  202.                 case 'd':
  203.                 case 'D':
  204.                     dataregs = 1;
  205.                     break;
  206.             }
  207.             s++;
  208.         }
  209.         return incldepth == 0;
  210.     }
  211.     else return incldepth == 0;
  212.  
  213.     if (prm_cmangle)    
  214.         *p++ = '_';
  215.     while (isalnum(*lptr) || *lptr == '_')
  216.         *p++=*lptr++;
  217.     *p=0;
  218.     while (*lptr && (*lptr == ' ' || *lptr == '\t' || *lptr == ','))
  219.         lptr++;
  220.     if (*lptr  && *lptr != '\n' && !isdigit(*lptr)) {
  221.         generror(ERR_ILLCHAR,*lptr,0);
  222.         while (*lptr)
  223.             lptr++;
  224.     }
  225.  
  226.     if (isdigit(*lptr))
  227.         while (isdigit(*lptr)) {
  228.             val *= 10;
  229.             val += (*lptr++)-'0';
  230.         }
  231.     else
  232.         val = 64;
  233.     ++global_flag;
  234.     a = xalloc(sizeof(STARTUPS));
  235.     a->name = litlate(buf);
  236.     a->prio = val;
  237.   if (sflag) {
  238.         a->link = startuplist;
  239.         startuplist = a;
  240.     }
  241.     else {
  242.         a->link = rundownlist;
  243.         rundownlist = a;
  244.     }
  245.     --global_flag;
  246.     while (*lptr && (*lptr == ' ' || *lptr == '\t'))
  247.         lptr++;
  248.     if (*lptr  && *lptr != '\n')
  249.         generror(ERR_ILLCHAR,*lptr,0);
  250.     return incldepth == 0;
  251. }
  252. void dumpstartups(void)
  253. /*
  254.  * Dump references to startup/rundown code
  255.  */
  256. {
  257.     SYM *s;
  258.     if (startuplist) {
  259.         startupseg();
  260.         while (startuplist) {
  261.             s = search(startuplist->name,&gsyms);
  262.             if (!s || s->tp->type != bt_ifunc)
  263.                 gensymerror(ERR_UPDOWN,startuplist->name);
  264.             else  {
  265.                 gensrref(s,startuplist->prio);
  266.                 s->tp->uflags |= UF_USED;
  267.             }
  268.             startuplist = startuplist->link;
  269.         }
  270.     }
  271.     if (rundownlist) {
  272.         rundownseg();
  273.         while (rundownlist) {
  274.             s = search(rundownlist->name,&gsyms);
  275.             if (!s || s->tp->type != bt_ifunc)
  276.                 gensymerror(ERR_UPDOWN,rundownlist->name);
  277.             else {
  278.                 gensrref(s,rundownlist->prio);
  279.                 s->tp->uflags |= UF_USED;
  280.             }
  281.             rundownlist = rundownlist->link;
  282.         }
  283.     }
  284. }
  285. int doline(void)
  286. /*
  287.  * Handle #line directive
  288.  */
  289. {
  290.     int n;
  291.     getsym();
  292.     if (lastst != iconst) 
  293.         gensymerror(ERR_PREPROCID,"#line");
  294.     else {
  295.         n = ival;
  296.         getsym();
  297.         if (lastst != sconst) 
  298.             gensymerror(ERR_PREPROCID,"#line");
  299.         else 
  300.             if (!ifskip) {
  301.                 errfile = litlate(laststr);
  302.                 errlineno = n-1;
  303.             }
  304.     }
  305.     return incldepth == 0;
  306. }
  307. int doinclude(void)
  308. /*
  309.  * HAndle include files
  310.  */
  311. {       int     rv;
  312.                 FILE *oldfile = inputFile;
  313.                 incconst = TRUE;
  314.         getsym();               /* get file to include */
  315.                 incconst = FALSE;
  316.                 if (ifskip)
  317.                     return incldepth == 0;
  318.         if( lastst != sconst ) {
  319.                 gensymerror(ERR_INCLFILE,"include");
  320.                 return incldepth == 0;
  321.                 }
  322.                 if (incldepth > 9) {
  323.                     generror(ERR_PREPROCID, 0,0);
  324.                     return incldepth == 0;
  325.                 }
  326.         inputFile = SearchPath(laststr,prm_searchpath,"r");
  327.         if( inputFile == 0 ) {
  328.                 gensymerror(ERR_CANTOPEN,laststr);
  329.                 inputFile = oldfile;
  330.                 rv = incldepth == 0;
  331.                 }
  332.         else    {
  333.                                 LIST *list;
  334.                                 pushif();
  335.                                 ifshold[incldepth] = ifs;
  336.                                 elsetaken = 0;
  337.                                 ifskip = 0;
  338.                                 ifs = 0;
  339.                         inclline[incldepth] = lineno;
  340.                         inclfile[incldepth] = oldfile;  /* push current input file */
  341.                                 inclfname[incldepth++] = infile;
  342.                                 global_flag++;
  343.                                 infile = litlate(laststr);
  344.                                 list = xalloc(sizeof(LIST));
  345.                                 list->data = infile;
  346.                                 list->link = 0;
  347.                                 if (incfiles)
  348.                                     lastinc = lastinc->link = list;
  349.                                 else
  350.                                     incfiles = lastinc = list;
  351.                                 errfile = infile;
  352.                                 errlineno = 0;
  353.                                 global_flag--;
  354.                 rv = incldepth == 1;
  355.                 lineno = 0;
  356.                 }
  357.         return rv;
  358. }
  359.  
  360. short *plitlate(short *string)
  361. {
  362.     short *temp = xalloc(pstrlen(string)*sizeof(short)+sizeof(short));
  363.     pstrcpy(temp,string);
  364.     return temp;
  365. }
  366. void glbdefine(char *name, char*value)
  367. {
  368. {       SYM     *sp;
  369.                 short *p;
  370.                 DEFSTRUCT *def;
  371.                 if (( sp = search(name,&defsyms) )!= 0)
  372.                     return;
  373.         ++global_flag;          /* always do #define as globals */
  374.         sp = xalloc(sizeof(SYM));
  375.         sp->name = litlate(name);
  376.                 def = xalloc(sizeof(DEFSTRUCT));
  377.                 def->args = 0;
  378.                 def->argcount = 0;
  379.                 def->string = p = xalloc(strlen(value)*sizeof(short));
  380.                 while (*value)
  381.                     *p++=*value++;
  382.                 *p++=0;
  383.         sp->value.s = (char *) def;
  384.         insert(sp,&defsyms);
  385.         --global_flag;
  386.         return;
  387. }
  388. }
  389. /* Handle #defines
  390.  * Doesn't check for redefine with different value
  391.  * Does handle ANSI macros
  392.  */
  393. int dodefine(void)
  394. {       SYM     *sp;
  395.                 DEFSTRUCT *def;
  396.                 short *args[40],count=0;
  397.                 short *olptr;
  398.                 int p;
  399.         getsym();               /* get past #define */
  400.                 if (ifskip)
  401.                     return incldepth == 0;
  402.                 olptr = lptr;
  403.         if( lastst != id ) {
  404.                 generror(ERR_IDEXPECT,0,0);
  405.                 return incldepth == 0;
  406.                 }
  407.                 if (( sp = search(unmangid,&defsyms) )!= 0)
  408.                     undef2();
  409.         ++global_flag;          /* always do #define as globals */
  410.         sp = xalloc(sizeof(SYM));
  411.         sp->name = litlate(unmangid);
  412.                 def = xalloc(sizeof(DEFSTRUCT));
  413.                 def->args = 0;
  414.                 def->argcount = 0;
  415.                 if (lastch == '(') {
  416.                     getdefsym();
  417.                     getdefsym();
  418.                     while (lastst == id) {
  419.                         args[count++] = plitlate(unmangid);
  420.                         getdefsym();
  421.                         if (lastst != comma)
  422.                             break;
  423.                         getdefsym();
  424.                     }
  425.                     if (lastst != closepa)
  426.                       generror(ERR_PUNCT,closepa,0);
  427.                     olptr = lptr;
  428.                     def->args = xalloc(count*sizeof(short *));
  429.                     memcpy(def->args,args,count*sizeof(short *));
  430.                     def->argcount = count+1;
  431.                 }
  432.                 while (iswhitespacechar(*olptr))
  433.                     olptr++;
  434.                 p = pstrlen(olptr);
  435.                 if (olptr[p-1] == 0x0a)
  436.                     olptr[p-1] = 0;
  437.                 def->string = plitlate(olptr);
  438.         sp->value.s = (char *) def;
  439.         insert(sp,&defsyms);
  440.         --global_flag;
  441.         return incldepth == 0;
  442. }
  443. /*
  444.  * Undefine
  445.  */
  446. int doundef(void)
  447. {
  448.     getsym();
  449.     if (!ifskip)
  450.         undef2();
  451.     return(incldepth == 0);
  452. }
  453. int undef2(void)
  454. {
  455.     if (lastst != id) 
  456.     generror(ERR_IDEXPECT,0,0);
  457.     else {
  458.         SYM **p = (SYM **)LookupHash(unmangid,defhash,HASHTABLESIZE);
  459.         if (p) {
  460.             *p = (*p)->next;
  461.         }
  462.     }
  463. }
  464. void getdefsym(void)
  465. {
  466.                 if (backupchar != -1) {
  467.                     lastst = backupchar;
  468.                     backupchar = -1;
  469.                     return;
  470.                 }
  471. restart:        /* we come back here after comments */
  472.         while(iswhitespacechar(lastch))
  473.                 getch();
  474.         if( lastch == -1)
  475.                 lastst = eof;
  476.         else if(isdigit(lastch))
  477.                 getnum();
  478.         else if(isstartchar(lastch)) {
  479.                                 lptr--;
  480.                 defid(unmangid,&lptr,0);    
  481.                                 lastch = *lptr++;
  482.                                 lastst = id;
  483.                 }
  484.         else if (getsym2())
  485.                     goto restart;
  486. }
  487. int defid(short *name, short **p, char *q)
  488. /*
  489.  * Get an identifier during macro replacement
  490.  */
  491. {
  492.     int count = 0,i=0;
  493.             while (issymchar(**p)) {
  494.                 if (count < 100) {
  495.                     name[count++] = *(*p);
  496.                     if (q)
  497.                         i+=installphichar(*(*p),q,i);
  498.                 }
  499.                 (*p)++;
  500.             }
  501.             if (q) {
  502.                 if ((q[i-1] & 0xf0) == 0x90)
  503.                     q[i-1] = 0x90;
  504.           q[i] = '\0';
  505.             }
  506.     name[count] = 0;
  507.     return(count);
  508. }
  509. /* 
  510.  * Insert a replacement string
  511.  */
  512. int definsert(short *end, short *begin, short * text, int len, int replen)
  513. {
  514.     short *q;
  515.     int i,p, r;
  516.     int val;
  517.     if (begin != inputline) 
  518.         if (*(begin-1) == '#') {
  519.             if (*(begin-2) != '#') {
  520.                 begin--;
  521.                 replen++;
  522.                 r = pstrlen(text);
  523.             
  524.                 text[r++] = '\"';
  525.                 text[r] = 0;
  526.                 for (i=r; i >= 0; i--)
  527.                     text[i+1] = text[i];
  528.                 *text = '\"';
  529.             }
  530.         }
  531.     p = pstrlen(text);
  532.     val = p - replen;
  533.     r = pstrlen(begin);
  534.     if (val + strlen(begin) >= len-1) {
  535.         generror(ERR_MACROSUBS,0,0);
  536.         return(-8000);
  537.     }
  538.     if (val > 0)
  539.         for (q = begin + r+1; q >= end; q--)
  540.             *(q+val) = *q;
  541.     else
  542.         if (val < 0) {
  543.             r = pstrlen(end)+1;
  544.             for (q = end; q < end+r; q++ )
  545.                 *(q+val) = *q;
  546.         }
  547.     for (i=0; i < p; i++)
  548.         begin[i] = text[i]; 
  549.     return(val);
  550. }
  551. /* replace macro args */    
  552. int defreplace(short *macro, int count, short **oldargs, short **newargs)
  553. {
  554.     int i,rv;
  555.     int instring = 0;
  556.     short narg[1024];
  557.     short name[100];
  558.     short *p=macro,*q;
  559.     while (*p) {
  560.         if (*p == instring)
  561.             instring = 0;
  562.         else if (*p == '\'' || *p == '"')
  563.             instring = *p;
  564.         else if (!instring && isstartchar(*p)) {
  565.             q = p;
  566.             defid(name,&p,0);
  567.             for (i=0; i < count; i++)
  568.                 if (!pstrcmp(name,oldargs[i])) {
  569.                     pstrcpy(narg,newargs[i]);
  570.                     if ((rv = definsert(p,q,narg,1024-(q-macro),p-q)) == -8000)
  571.                         return(FALSE);
  572.                     else {
  573.                         p += rv;
  574.                         break;
  575.                     }
  576.                 }
  577.         }
  578.         p++;
  579.     }
  580.     return(TRUE);
  581. }
  582. /* Handlers for default macros */
  583. void cnvt(short *out,char *in)
  584. {
  585.     while (*in) 
  586.         *out++=*in++;
  587.     *out = 0;
  588. }
  589. void filemac(short *string)
  590. {
  591.     char str1[40];
  592.     sprintf(str1,"\"%s\"",infile);
  593.     cnvt(string,str1);
  594. }
  595. void datemac(short *string)
  596. {
  597.     char str1[40];
  598.     struct tm *t1;
  599.     time_t t2;
  600.     time(&t2);
  601.     t1 = localtime(&t2);
  602.      strftime(str1,40,"\"%b %d %Y\"",t1);
  603.     cnvt(string,str1);
  604. }
  605. void timemac(short *string)
  606. {
  607.     char str1[40];
  608.     struct tm *t1;
  609.     time_t t2;
  610.     time(&t2);
  611.     t1 = localtime(&t2);
  612.     str1[0] = '"';
  613.      strftime(str1,40,"\"%X\"",t1);
  614.     cnvt(string,str1);
  615. }
  616. void linemac(short *string)
  617. {
  618.     char str1[40];
  619.     sprintf(str1,"%d",lineno);
  620.     cnvt(string,str1);
  621. }
  622. /* Scan for default macros and replace them */
  623. void defmacroreplace(short *macro, short *name)
  624. {
  625.     int i;
  626.     macro[0] = 0;
  627.     for (i=0; i < INGROWNMACROS; i++)
  628.         if (!strcmp(name,ingrownmacros[i].s)) {
  629.             (ingrownmacros[i].func)(macro);
  630.             break;
  631.         }
  632. }
  633. /* Scan line for macros and do replacements */
  634. void defcheck(short *line)
  635. {
  636.     short macro[1024];
  637.     short name[100];
  638.     short *args[40];
  639.     char ascii[60];
  640.     int tryagain = TRUE, changed = FALSE, waiting = FALSE,rv;
  641.     short *p = line,*q;
  642.     SYM *sp;
  643.     while (tryagain) {
  644.         p = line;
  645.         tryagain = FALSE;
  646.         while(*p) {
  647.             q = p;
  648.             if (*p == '"') {
  649.                 waiting = !waiting;
  650.                 p++;
  651.             }
  652.             else if (waiting)
  653.                 p++;
  654.             else if (isstartchar(*p)) {
  655.                 defid(name,&p,ascii);
  656.                 if ((sp = search(ascii,&defsyms)) != 0) {
  657.                     DEFSTRUCT *def = sp->value.s;
  658.                     pstrcpy(macro,def->string);
  659.                     if (def->argcount) {
  660.                         int count = 0;
  661.                         short *q = p;
  662.                             while (iswhitespacechar(*q))
  663.                                 q++;
  664.                         if (*q++ != '(')
  665.                             goto join;
  666.                         p = q;
  667.                         if (def->argcount > 1) {
  668.                             do {
  669.                                 short *nm = name;
  670.                                 int nestedparen = 0;
  671.                                 while (((*p != ',' && *p != ')') || nestedparen) && *p != '\n') {
  672.                                         if (*p == '(')
  673.                                             nestedparen++;
  674.                                         if (*p == ')' && nestedparen)
  675.                                             nestedparen--;
  676.                                         *nm++ = *p++;
  677.                                 }
  678.                                 while (iswhitespacechar(*(nm-1)))
  679.                                     nm--;
  680.                                 *nm = 0;
  681.                                 nm = name;
  682.                                 while (iswhitespacechar(*nm))
  683.                                     nm++;
  684.                                 args[count++] = plitlate(nm);
  685.                             } while (*p++ == ',');
  686.                         }
  687.                         else while (iswhitespacechar(*p++));
  688.                         if (*(p-1) != ')' || count != def->argcount-1) {
  689.                             generror(ERR_MACROSUBS,0,0);
  690.                             return;
  691.                         }
  692.                         /* Can't replace if tokenizing next */
  693.                         if (*p == '#' && *(p+1) == '#')
  694.                             continue;
  695.                         if (count == 0)
  696.                             goto insert;
  697.                         if (!defreplace(macro,count,def->args,args))
  698.                             return;
  699.                     }
  700. insert:
  701.                     if ((rv=definsert(p,q,macro,4096-(q-line),p-q))==-8000)
  702.                         return;
  703.                     p+=rv;
  704.                     changed = tryagain = TRUE;
  705.                 }
  706.                 else {
  707. join:
  708.                     defmacroreplace(macro,ascii);
  709.                     if (macro[0]) {
  710.                         if ((rv=definsert(p,q,macro,4096-(q-line),p-q))==-8000)
  711.                             return;
  712.                         p += rv;
  713.                         changed = TRUE;
  714.                     }
  715.                 }
  716.             }
  717.             else p++;
  718.         }
  719.     }
  720.     /* Token pasting */
  721.     if (changed) {
  722.         p = q = line;
  723.         while (*p) {
  724.             if (*p == '#' && *(p+1) == '#')
  725.                 p+=2;
  726.             else
  727.                 *q++ = *p++;
  728.         }
  729.         *q = 0;
  730.     }
  731. }
  732. static void repdefines(short *lptr)
  733. /*
  734.  * replace 'defined' keyword in #IF and #ELIF statements
  735.  */
  736. {
  737.     short *q = lptr;
  738.     short name[40];
  739.     char ascii[60];
  740.     while (*lptr) {
  741.         if (!pstrncmp(lptr,defkw,7)) {
  742.             lptr +=7;
  743.             if (*lptr == '(') 
  744.                 lptr++;
  745.             else 
  746.                  expecttoken(openpa,0);
  747.       while(iswhitespacechar(*lptr))
  748.               lptr++;
  749.             defid(name,&lptr,ascii);
  750.       while(iswhitespacechar(*lptr))
  751.               lptr++;
  752.             if (*lptr == ')')
  753.                 lptr++;
  754.             else
  755.                 expecttoken(closepa,0);
  756.             if (search(ascii,&defsyms) != 0)
  757.                 *q++ = '1';
  758.             else
  759.                 *q++ = '0';
  760.             *q++ = ' ';
  761.                 
  762.         }
  763.         else {
  764.             *q++ = *lptr++;
  765.         }
  766.     }
  767.   *q = 0;
  768. }
  769. void pushif(void)
  770. /* Push an if context */
  771. {
  772.     IFSTRUCT *p;
  773.     global_flag++;
  774.     p = xalloc(sizeof(IFSTRUCT));
  775.     global_flag--;
  776.     p->link = ifs;
  777.     p->iflevel = ifskip;
  778.     p->elsetaken = elsetaken;
  779.     elsetaken = FALSE;
  780.     ifs = p;
  781. }
  782. void popif(void)
  783. /* Pop an if context */
  784. {
  785.     if (ifs) {
  786.         ifskip = ifs->iflevel;
  787.         elsetaken = ifs->elsetaken;
  788.         ifs = ifs->link;
  789.     }
  790.     else {
  791.         ifskip = 0;
  792.         elsetaken = 0;
  793.     }
  794. }    
  795. void ansieol(void)
  796. {
  797.     if (prm_ansi) {
  798.         while (iswhitespacechar(*lptr))
  799.             lptr++;
  800.         if (*lptr) {
  801.             lastch = *lptr;
  802.             lastst = kw_if;
  803.             generror(ERR_UNEXPECT,0,0);
  804.         }
  805.     }
  806. }
  807. int doifdef (int flag)
  808. /* Handle IFDEF */
  809. {
  810.     SYM *sp;
  811.     getch();
  812.     while(isspace(lastch))
  813.         getch();
  814.     if (!isstartchar(lastch)) {
  815.     generror(ERR_IDEXPECT,0,0);
  816.     return incldepth == 0;
  817.     }
  818.     else
  819.         getid();
  820.      sp = search(unmangid,&defsyms);
  821.   pushif();
  822.     if (sp && !flag || !sp && flag)
  823.         ifskip = TRUE;
  824.     ansieol();
  825.     return(incldepth == 0);
  826. }
  827. int doif(int flag)
  828. /* Handle #if */
  829. {
  830.     getsym();
  831.   pushif();
  832.     cantnewline = TRUE;
  833.     if (!intexpr(0))
  834.         ifskip = TRUE;
  835.     cantnewline = FALSE;
  836.     ansieol();
  837.     return(incldepth == 0);
  838. }
  839. int doelif(void)
  840. /* Handle #elif */
  841. {
  842.     int is;
  843.     getsym();
  844.     cantnewline = TRUE;
  845.     is = !intexpr(0);
  846.     cantnewline = FALSE;
  847.     if (ifs) {
  848.         if (!ifs->iflevel)
  849.             ifskip = !ifskip || is || elsetaken;
  850.             if (!ifskip)
  851.                 elsetaken = TRUE;
  852.     }
  853.     else
  854.         generror(ERR_PREPROCMATCH,0,0);
  855.     ansieol();
  856.     return(incldepth == 0);
  857. }
  858. /* handle else */
  859. int doelse(void)
  860. {
  861.     if (ifs) {
  862.         if (!ifs->iflevel)
  863.             ifskip = !ifskip || elsetaken;
  864.     }
  865.     else
  866.         generror(ERR_PREPROCMATCH,0,0);
  867.     ansieol();
  868.     return(incldepth == 0);
  869. }
  870. /* HAndle endif */
  871. int doendif(void)
  872. {
  873.     if (!ifs)
  874.         generror(ERR_PREPROCMATCH,0,0);
  875.     popif();
  876.     ansieol();
  877.     return(incldepth == 0);
  878. }