home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_100 / 195_01 / macro.c < prev    next >
Text File  |  1987-10-05  |  10KB  |  555 lines

  1. /* [MACRO.C of JUGPDS Vol.18]
  2. *****************************************************************
  3. *                                *
  4. *    Written by  Hakuo Katayose (JUG-CP/M No.179)        *
  5. *            49-114 Kawauchi-Sanjuunin-machi        *
  6. *            Sendai, Miyagi 980                          *
  7. *            Phone: 0222-61-3219                *
  8. *                                *
  9. *    Edited & tested by Y. Monma (JUG-C/M Disk Editor)       *
  10. *                                *
  11. *****************************************************************
  12. */
  13.  
  14. /* macro (m4) - expand macros with arguments */
  15.  
  16. #include "stdio.h"
  17. #include "def.h"
  18.  
  19. #define ARGFLAG     '$'
  20.  
  21. #define    IFTYPE        3
  22. #define    INCTYPE        4
  23. #define    ARTTYPE        5
  24. #define SUBTYPE        7
  25. #define DEFTYPE        8
  26. #define LENTYPE     9
  27.  
  28. #define    UBUFSIZE  256
  29. #define ARGSIZE      128
  30. #define CALLSIZE  128
  31. #define EVALSIZE 1024
  32.  
  33. char    ubuf[UBUFSIZE];
  34. int    ubufp;
  35.  
  36. struct    mac {
  37.     char    *name;
  38.     char    *repn;
  39. } deftbl[1000];
  40.  
  41. int    tcnt;
  42.  
  43. char    ctype[256];
  44. char    inbuf[BUFSIZ];
  45.  
  46. char    evalst[EVALSIZE];
  47. int    ep, cp;
  48.  
  49. main(argc, argv)
  50. int    argc;
  51. char    *argv[];
  52.  
  53. {
  54.     int    ap, i, t, nbl, plev[CALLSIZE];
  55.     char    token[(MAXTOK-1)], defn[MAXDEF], *balp, s[2];
  56.     int    callst[CALLSIZE];
  57.     int    argstk[ARGSIZE];
  58.  
  59.     balp = "()";
  60.     if (argc < 2) {
  61.         fprintf(STDERR, "Usage: m4 filename");
  62.         exit();
  63.     }
  64.     if (fopen(argv[1], inbuf) == ERROR) {
  65.         fprintf(STDERR, "Can't open file:%s", argv[1]);
  66.         exit();
  67.     }
  68.     initialize();
  69.     s[0] = DEFTYPE;
  70.     s[1] = EOS;
  71.     install("define", s);
  72.     s[0] = IFTYPE;
  73.     s[1] = EOS;
  74.      install("ifelse", s);
  75.     s[0] = INCTYPE;
  76.     s[1] = EOS;
  77.     install("incr", s);
  78.     s[0] = ARTTYPE;
  79.     s[1] = EOS;
  80.     install("arith", s);
  81.     s[0] = SUBTYPE;
  82.     s[1] = EOS;
  83.     install("substr", s);
  84.     s[0] = LENTYPE;
  85.     s[1] = EOS;
  86.     install("len", s);
  87.  
  88.     cp = 0;
  89.     ap = 1;
  90.     ep = 1;
  91.     while ((t = gettok(token, MAXTOK)) != EOF) {
  92.         if (t == ALPHA) {
  93.         if (lookup(token, defn) == NO)
  94.             puttok(token);
  95.         else { /* defined, put it in eval stack */
  96.             if (++cp > CALLSIZE) {
  97.                 fprintf(STDERR, "Call stack overflow.\n");
  98.             }
  99.                 callst[cp] = ap;
  100.                 ap = push(ep, argstk, ap);
  101.                 puttok(defn); /* stack definition */
  102.                 putchr(EOS);
  103.                 ap = push(ep, argstk, ap);
  104.                 puttok(token); /* stack name */
  105.                 putchar(EOS);
  106.                 ap = push(ep, argstk, ap);
  107.                 t = gettok(token, MAXTOK); /* peek a next */
  108.                 ungets(token);
  109.                 if (t != LPAREN) /* add () if not present */
  110.                     ungets(balp);
  111.                 plev[cp] = 0;
  112.         }
  113.     }
  114.     else if (t == LBRACKET) { /* strip one level of [] */
  115.         nbl = 1;
  116.         while (1) {
  117.             if ((t = gettok(token, MAXTOK)) == LBRACKET)
  118.                 nbl++;
  119.             else if (t == RBRACKET) {
  120.                 if (--nbl == 0)
  121.                     break;
  122.             }
  123.             else if (t == EOF) {
  124.                 fprintf(STDERR, "EOF inserting.\n");
  125.                 exit();
  126.             }
  127.             puttok(token);
  128.         }
  129.     }
  130.     else if (cp == 0)    /* not in a macro at all */
  131.         puttok(token);
  132.     else if (t == LPAREN) {
  133.         if (plev[cp] > 0)
  134.             puttok(token);
  135.         plev[cp]++;
  136.     }
  137.     else if (t == RPAREN) {
  138.         if (--plev[cp] > 0)
  139.             puttok(token);
  140.         else { /* end of argument list */
  141.             putchr(EOS);
  142.             eval(argstk, callst[cp], ap-1);
  143.             ap = callst[cp]; /* pop eval stack */
  144.             ep = argstk[ap];
  145.             cp--;
  146.             }
  147.         }
  148.         else if (t == ',' && plev[cp] == 1) { /* new arg */
  149.             putchr(EOS);
  150.         ap = push(ep, argstk, ap);
  151.         }
  152.     else
  153.         puttok(token); /* just stack it */
  154.     }
  155.     if (cp != 0)
  156.     fprintf(STDERR, "Unexpeced EOF.");
  157. }
  158.  
  159. /* eval - expand arg i through j: evaluate builtin or push back defn */
  160. eval(argstk, i, j)
  161. int    argstk[];
  162.  
  163. {
  164.     int    t, argno, k, td;
  165.  
  166.     t = argstk[i];
  167.     if ((td = evalst[t]) == DEFTYPE)
  168.         dodef(argstk, i , j);
  169.     else if (evalst[t] == INCTYPE)
  170.         doincr(argstk, i, j);
  171.     else if (evalst[t] == ARTTYPE)
  172.         doarith(argstk, i, j);
  173.     else if (evalst[t] == SUBTYPE)
  174.         dosub(argstk, i, j);
  175.     else if (evalst[t] == IFTYPE)
  176.         doif(argstk, i, j);
  177.     else if (evalst[t] == LENTYPE)
  178.         dolen(argstk, i, j);
  179.     else {
  180.         for (k = t + strlen(&evalst[t]) - 1; k > t; k--)
  181.             if (evalst[k-1] != ARGFLAG)
  182.                 ungetch(evalst[k]);
  183.             else {
  184.                 argno = evalst[k--]-'0';
  185.                 if (argno >= 0 && argno < j-i)
  186.                     ungets(&evalst[argstk[i+argno+1]]);
  187.             }
  188.         if (k == t) /* do last character */
  189.             ungetch(evalst[k]);
  190.     }
  191. }
  192.  
  193.  
  194. /* dodef - install definition in table */
  195. dodef(argstk, i, j)
  196. int    argstk[];
  197.  
  198. {
  199.     if (j-i >2)
  200.         install(&evalst[argstk[i+2]], &evalst[argstk[i+3]]);
  201. }
  202.  
  203.  
  204. /* delen - compute length of string */
  205. dolen(argstk, i, j)
  206. int    argstk[];
  207.  
  208. {
  209.     int    num;
  210.  
  211.     num = strlen(&evalst[argstk[i+2]]);
  212.     pbnum(num);
  213. }
  214.  
  215.  
  216. /* pbnum - convert number to string, push back on input */
  217. pbnum(num)
  218. int    num;
  219.  
  220. {
  221.     do {
  222.         ungetch(num%10+'0');
  223.         num /= 10;
  224.     } while (num != 0);
  225. }
  226.  
  227.  
  228. /* doif - select one of two arguents */
  229. doif(argstk, i, j)
  230. int    argstk[];
  231.  
  232.  {
  233.     if (j-i < 5)
  234.         return;
  235.     if (!strcmp(&evalst[argstk[i+2]], &evalst[argstk[i+3]]))
  236.         ungets(&evalst[argstk[i+4]]);
  237.     else
  238.         ungets(&evalst[argstk[i+5]]);
  239. }
  240.  
  241.  
  242. /* dosub - select substring */
  243. dosub(argstk, i, j)
  244. int    argstk[];
  245.  
  246. {
  247.     int    fc, nc, app, k;
  248.  
  249.     if (j-i < 3)
  250.         return;
  251.     nc = (j-i < 4) ? MAXTOK : ctoi(&evalst[argstk[i+4]]);
  252.     app = argstk[i+2];
  253.     fc = app + ctoi(&evalst[argstk[i+3]]) - 1;
  254.     if (fc >= app && fc < app + strlen(&evalst[app])) {
  255.         k = fc + min(nc, strlen(&evalst[fc])) - 1;
  256.         while (k >= fc)
  257.             ungetch(evalst[k--]);
  258.     }
  259. }
  260.  
  261.  
  262. /* doincr - increment argument by 1 */
  263. doincr(argstk, i, j)
  264. int    argstk[];
  265.  
  266. {
  267.     int    k, num;
  268.  
  269.     k = (j-i < 3) ? 1 : ctoi(&evalst[argstk[i+3]]);
  270.     num = ctoi(&evalst[argstk[i+2]])+k;
  271.     pbnum(num);
  272. }
  273.  
  274.  
  275. /* doarith - arithmetic computation */
  276. doarith(argstk, i, j)
  277. int    argstk[];
  278.  
  279. {
  280.     int    k, num, l;
  281.  
  282.     if (j-i < 3)
  283.         return;
  284.     num = ctoi(&evalst[argstk[i+2]]);
  285.     k = (j-i < 4) ? num : ctoi(&evalst[argstk[i+4]]);
  286.     switch (evalst[(l = argstk[i+3])]) {
  287.         case     '+' :
  288.             num += k;
  289.             break;
  290.         case    '-' :
  291.             num -= k;
  292.             break;
  293.         case    '*' :
  294.             num *= k;
  295.             break;
  296.         case    '/' :
  297.             num /= k;
  298.             break;
  299.         case    '%' :
  300.             num %= k;
  301.             break;
  302.         case    '=' :
  303.             switch (evalst[l+1]) {
  304.                 case '<' :
  305.                     num = (num <= k);
  306.                     break;
  307.                 case '>' :
  308.                     num = (num >= k);
  309.                     break;
  310.                   case '=' :
  311.                     num = (num ==k);
  312.                     break;
  313.                 case EOS :
  314.                     num = (num < k);
  315.                     break;
  316.                 default :
  317.                     return;
  318.             }
  319.             break;
  320.         case '<':
  321.             switch (evalst[l+1]) {
  322.                 case '<' :
  323.                     num = (num <<= k);
  324.                     break;
  325.                 case '>' :
  326.                     num = (num != k);
  327.                     break;
  328.                 case '=' :
  329.                     num = (num <= k);
  330.                     break;
  331.                 case EOS :
  332.                     num = (num < k);
  333.                     break;
  334.                 default :
  335.                 return;
  336.             }
  337.             break;
  338.         case '>' :
  339.             switch (evalst[l+1]) {
  340.                 case '<' :
  341.                     num = (num != k);
  342.                     break;
  343.                 case '>' :
  344.                     num = (num >>= k);
  345.                     break;
  346.                 case '=' :
  347.                     num = (num >= k);
  348.                     break;
  349.                 case EOS :
  350.                     num = (num > k);
  351.                     break;
  352.                 default :
  353.                     return;
  354.             }
  355.             break;
  356.         default :
  357.             return;
  358.             break;
  359.     }
  360.     pbnum(num);
  361. }
  362.  
  363.  
  364. /* ctoi - convert string to integer */
  365. ctoi(s)
  366. char    *s;
  367.  
  368. {
  369.     int    c, sign;
  370.  
  371.     sign = 1;
  372.     while (*s == ' ' || *s == '\t')
  373.         s++;
  374.     c = 0;
  375.     if (*s == '+' || *s == '-')
  376.         sign = (*s++ == '-') ? -1 : 1;
  377.     while (*s != EOS && ctype[*s] == DIGIT)
  378.         c = c*10 + *s++ - '0';
  379.     return(sign * c);
  380. }
  381.  
  382.  
  383. /* lookup - locate name, extract definition from table */
  384. lookup(s, defn)
  385. char    *s, *defn;
  386.  
  387. {
  388.     int    i;
  389.  
  390.     i = tcnt;
  391.     while (--i >= 0)
  392.         if (!strcmp(deftbl[i].name, s))
  393.             break;
  394.     if (i < 0)
  395.         return(NO);
  396.     strcpy(defn, deftbl[i].repn);
  397.     return(YES);
  398. }
  399.  
  400.  
  401. /* install - add name and definition to table */
  402. install(s, defn)
  403. char    *s, *defn;
  404.  
  405. {
  406.     char    *alloc();
  407.     struct mac *p;
  408.  
  409.     p = &deftbl[tcnt];
  410.     if ((p->name = alloc(strlen(s)+1)) == NULL) {
  411.         fprintf(STDERR, "Variable table overflow!\n");
  412.         exit();
  413.     }
  414.     strcpy(p->name, s);
  415.     if ((p->repn = alloc(strlen(defn)+1)) == NULL) {
  416.         fprintf(STDERR, "Variable table overflow!\n");
  417.         exit();
  418.     }
  419.     strcpy(p->repn, defn);
  420.     tcnt++;
  421. }
  422.  
  423.  
  424. /* gettok - get alphanumeric string or single non-alpha */
  425. gettok(w, lim)
  426. char    *w;
  427. int    lim;
  428.  
  429. {
  430.     int    c;
  431.  
  432.     if ((c = getchr()) == EOF)
  433.         return(c);
  434.     else {
  435.         *w++ = c;
  436.         if (ctype[c] != LETTER && ctype[c] != DIGIT) {
  437.             *w = '\0';
  438.             return(c);
  439.         }
  440.         else
  441.             lim--;
  442.     }
  443.     while (lim-- > 0 && (c= getchr()) != EOF) {
  444.         *w++ = c;
  445.         if (ctype[c] != LETTER && ctype[c] != DIGIT) {
  446.             *--w = '\0';
  447.             ungetch(c);
  448.             return(ALPHA);
  449.         }
  450.     }
  451.     *w = '\0';
  452.     ungetch(c);
  453.     fprintf(STDERR," Token too long.\n");
  454.     return(ALPHA);
  455. }
  456.  
  457.  
  458. /* initialize - initializ arrays and others */
  459. initialize()
  460.  
  461. {
  462.     int i;
  463.  
  464.     for (i = 0; i < 26; i++)
  465.         ctype[i] = i;
  466.     for (i = 'a'; i <= 'z'; i++)
  467.         ctype[i] = LETTER;
  468.     for (i = 'A'; i <= 'Z'; i++)
  469.         ctype[i] = LETTER;
  470.     for (i = '0'; i <= '9'; i++)
  471.         ctype[i] = DIGIT;
  472.     ubufp =0;
  473.     tcnt =0;
  474. }
  475.  
  476.  
  477. /* push -push ep onto argstk, return new pointer ap */
  478. push(evlp, argstk, argp)
  479. int    argstk[];
  480.  
  481. {
  482.     if (argp > ARGSIZE) {
  483.         printf(STDERR, " Arg stack overflow!\n");
  484.         exit();
  485.     }
  486.     argstk[argp] = evlp;
  487.     return(argp+1);
  488. }
  489.  
  490.  
  491. /* puttok - put a token either on output or into evaluatin stack */
  492. puttok(s)
  493. char    *s;
  494.  
  495. {
  496.     while (*s) putchr(*s++);
  497. }
  498.  
  499.  
  500. /* putchr - put single char on output or into evaluation stack */
  501. putchr(c)
  502.  
  503. {
  504.     if (!cp)
  505.         putchar(c);
  506.     else {
  507.         if (ep > EVALSIZE) {
  508.             fprintf(STDERR, "Evalation stack overflow!\n");
  509.             exit();
  510.         }
  511.         evalst[ep++] = c;
  512.     }
  513. }
  514.  
  515.  
  516. /* ungets - push string backonto input */
  517. ungets(s)
  518. char    *s;
  519.  
  520. {
  521.     char    *p;
  522.  
  523.     p = s;
  524.     while (*s)
  525.         s++;
  526.     while (p != s)
  527.         ungetch(*--s);
  528. }
  529.  
  530.  
  531. /* getchr - get single character */
  532. getchr()
  533.  
  534. {
  535.     if (ubufp)
  536.         return(ubuf[--ubufp]);
  537.     else
  538.         return(getc(inbuf));
  539. }
  540.  
  541.  
  542. /* ungetch - push string back onto input */
  543. ungetch(c)
  544. int    c;
  545.  
  546. {
  547.     if (ubufp > UBUFSIZE)
  548.         fprintf(STDERR,"ungetch: too many characters\n");
  549.     else
  550.         ubuf[ubufp++] = c;
  551. }
  552.  
  553. /* Enf of MACRO.C */
  554.  
  555. STD