home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / TOP / USR / SRC / scpp.t.Z / scpp.t / parse.y < prev    next >
Text File  |  2009-11-06  |  10KB  |  466 lines

  1. /*
  2.  * parse.y - #if parser for the selective C preprocessor, scpp.
  3.  *
  4.  * Copyright (c) 1985 by
  5.  * Tektronix, Incorporated Beaverton, Oregon 97077
  6.  * All rights reserved.
  7.  *
  8.  * Permission is hereby granted for personal, non-commercial
  9.  * reproduction and use of this program, provided that this
  10.  * notice and all copyright notices are included in any copy.
  11.  */
  12.  
  13. %term    MUL        /* *        */
  14. %term    DIV        /* /        */
  15. %term    MOD        /* %        */
  16. %term    PLUS        /* +        */
  17. %term    MINUS        /* -        */
  18. %term    LS        /* <<        */
  19. %term    RS        /* >>        */
  20. %term    AND        /* &        */
  21. %term    OR        /* |        */
  22. %term    ER        /* ^        */
  23. %term    LT        /* <        */
  24. %term    LE        /* <=        */
  25. %term    GT        /* >        */
  26. %term    GE        /* >=        */
  27. %term    EQ        /* ==        */
  28. %term    NE        /* !=        */
  29. %term    ANDAND        /* &&        */
  30. %term    OROR        /* ||        */
  31. %term    CM        /* , (comma)    */
  32. %term    QUEST        /* ?        */
  33. %term    COLON        /* :        */
  34. %term    NOT        /* !        */
  35. %term    COMPL        /* ~        */
  36. %term    LP        /* (        */
  37. %term    RP        /* )        */
  38. %term    INT        /* an integer    */
  39. %term    FLOAT        /* a float    */
  40. %term    IDENT        /* a identifier    */
  41. %term    QUOTE        /* ' (apostrophe) */
  42. %term    DQUOTE        /* "        */
  43. %term    BACKS        /* \ (backslash) */
  44. %term    OPENC        /* open comment sequence */
  45. %term    CLOSEC        /* close comment sequence */
  46. %term    WHITE        /* whitespace    */
  47. %term    NL        /* newline    */
  48. %term    QNL        /* escaped (quoted) newline    */
  49. %term    COMMENT        /* a comment    */
  50. %term    OTHER        /* anything else */
  51. %term    STRING        /* a double-quote enclosed string constant    */
  52. %term    CHARS        /* a single-quote enclosed char constant    */
  53. %term    POUNDLINE    /*
  54.              * The initial '#' of a preprocessor directive
  55.              * (as opposed to a normal '#', which is of type OTHER).
  56.              */
  57. %term    DEFMAC        /* an uninterpreted 'defined(x)' invocation    */
  58.  
  59. %left    CM
  60. %right    QUEST COLON
  61. %left    OROR
  62. %left    ANDAND
  63. %left    OR
  64. %left    ER
  65. %left    AND
  66. %left    EQ NE
  67. %left    LT LE GE GT
  68. %left    LS RS
  69. %left    PLUS MINUS
  70. %left    MUL DIV MOD
  71. %right    NOT COMPL
  72. %left    LP
  73.  
  74. %union {
  75.     int intval;        /* yacc stack entries    */
  76.     struct anode *lexval;    /* everything in this file    */
  77. }
  78.  
  79. %type <lexval>    exp e term
  80. %type <lexval> MUL DIV MOD PLUS MINUS LS RS AND OR ER LT LE GT GE EQ NE
  81.         ANDAND OROR CM QUEST COLON NOT COMPL LP RP INT FLOAT IDENT
  82.         QUOTE DQUOTE BACKS OPENC CLOSEC WHITE NL QNL COMMENT OTHER
  83.         STRING CHARS POUNDLINE DEFMAC
  84.  
  85. %{
  86. # include "scpp.h"
  87.  
  88. /*
  89.  * struct anode - the structure used to pass strings.
  90.  *  Allocated by mknode();
  91.  *  Deallocated by freenode().
  92.  * The string described will be in pend[] and is NOT NULL-TERMINATED.
  93.  */
  94.  
  95. struct anode {
  96.     int an_val;    /*
  97.              * lexical (token) value of this string.
  98.              * A value of 0 == this node is free.
  99.              */
  100.     int an_ifval;    /* integer result of this expression */
  101. };
  102.  
  103. # define NODESIZ 100    /* max number of nodes in a #if expresssion    */
  104. struct anode nodepool[NODESIZ];
  105.  
  106. struct anode *mknode();
  107.  
  108. # define NIL ((struct anode *) 0)
  109. %}
  110.  
  111. %start exp
  112. %%
  113. exp:    e
  114.         {
  115.             /*
  116.              * If the expression can be evaluated, set the result
  117.              */
  118.  
  119.             if ($1->an_val == INT) {
  120.                 *curif |= $1->an_ifval != 0 ?
  121.                   IF_TRUE : IF_FALSE;
  122.             }
  123.             freenode($1);
  124.         }
  125.     ;
  126. e:      e MUL e
  127.         {
  128.             $1->an_ifval = $1->an_ifval * $3->an_ifval;
  129.         binop:
  130.             $$ = $1;
  131.             if ($1->an_val == INT && $3->an_val == INT) {
  132.                 $$->an_val == INT;
  133.             } else {
  134.                 $$->an_val = OTHER;
  135.             }
  136.             freenode($2);
  137.             freenode($3);
  138.         }
  139.     | e DIV e
  140.         {
  141.           if ($3->an_ifval == 0 && $3->an_val == INT) {
  142.             $3->an_val = OTHER;
  143.             warnf("division by zero in #if");
  144.           } else {
  145.             $1->an_ifval = $1->an_ifval / $3->an_ifval;
  146.           }
  147.           goto binop;
  148.         }
  149.     | e MOD e
  150.         {
  151.           if ($3->an_ifval == 0 && $3->an_val == INT) {
  152.             $3->an_val = OTHER;
  153.             warnf("mod by zero in #if");
  154.           } else {
  155.             $1->an_ifval = $1->an_ifval % $3->an_ifval;
  156.           }
  157.           goto binop;
  158.         }
  159.     | e PLUS e
  160.         {$1->an_ifval = $1->an_ifval + $3->an_ifval; goto binop;}
  161.     | e MINUS e
  162.         {$1->an_ifval = $1->an_ifval - $3->an_ifval; goto binop;}
  163.     | e LS e
  164.         {$1->an_ifval = $1->an_ifval << $3->an_ifval; goto binop;}
  165.     | e RS e
  166.         {$1->an_ifval = $1->an_ifval >> $3->an_ifval; goto binop;}
  167.     | e LT e
  168.         {$1->an_ifval = $1->an_ifval < $3->an_ifval; goto binop;}
  169.     | e GT e
  170.         {$1->an_ifval = $1->an_ifval > $3->an_ifval; goto binop;}
  171.     | e LE e
  172.         {$1->an_ifval = $1->an_ifval <= $3->an_ifval; goto binop;}
  173.     | e GE e
  174.         {$1->an_ifval = $1->an_ifval >= $3->an_ifval; goto binop;}
  175.     | e EQ e
  176.         {$1->an_ifval = $1->an_ifval == $3->an_ifval; goto binop;}
  177.     | e NE e
  178.         {$1->an_ifval = $1->an_ifval != $3->an_ifval; goto binop;}
  179.     | e AND e
  180.         {$1->an_ifval = $1->an_ifval & $3->an_ifval; goto binop;}
  181.     | e ER e
  182.         {$1->an_ifval = $1->an_ifval ^ $3->an_ifval; goto binop;}
  183.     | e OR e
  184.         {$1->an_ifval = $1->an_ifval | $3->an_ifval; goto binop;}
  185.     | e ANDAND e
  186.         {
  187.             /*
  188.              * since this is a logical AND, its value
  189.              *  is known if either subexpression is false.
  190.              */
  191.  
  192.             $$ = $1;
  193.             if ($1->an_val == INT && $3->an_val == INT) {
  194.                 /* both subexpressions are known */
  195.                 $$->an_ifval = $1->an_ifval && $3->an_ifval;
  196.             } else {
  197.                 if (($1->an_val == INT && !$1->an_ifval) ||
  198.                     ($3->an_val == INT && !$3->an_ifval)) {
  199.                     $$->an_val = INT;
  200.                     $$->an_ifval = FALSE;
  201.                 } else {
  202.                     $$->an_val = OTHER;
  203.                 }
  204.             }
  205.             freenode($2); freenode($3);
  206.         }
  207.     | e OROR e
  208.         {
  209.             /*
  210.              * since this is a logical OR, its value
  211.              *  is known if either subexpression is true.
  212.              */
  213.  
  214.             $$ = $1;
  215.             if ($1->an_val == INT && $3->an_val == INT) {
  216.                 /* both subexpressions are known */
  217.                 $$->an_ifval = $1->an_ifval || $3->an_ifval;
  218.             } else {
  219.                 if (($1->an_val == INT && $1->an_ifval) ||
  220.                     ($3->an_val == INT && $3->an_ifval)) {
  221.                     $$->an_val = INT;
  222.                     $$->an_ifval = TRUE;
  223.                 } else {
  224.                     $$->an_val = OTHER;
  225.                 }
  226.             }
  227.             freenode($2); freenode($3);
  228.         }
  229.     | e QUEST e COLON e
  230.         {
  231.             /*
  232.              * since this is an IF-ELSE, its value is known
  233.              * in some cases even if one subexpression is unknown.
  234.              */
  235.  
  236.             $$ = $1;
  237.             if ($1->an_val == INT) {
  238.                 if ($1->an_ifval) {
  239.                     $$->an_val = $3->an_val;
  240.                     $$->an_ifval = $3->an_ifval;
  241.                 } else {
  242.                     $$->an_val = $5->an_val;
  243.                     $$->an_ifval = $5->an_ifval;
  244.                 }
  245.             } else {
  246.                 $$->an_val = OTHER;
  247.             }
  248.             freenode($2); freenode($3); freenode($4);
  249.             freenode($5);
  250.         }
  251.     | e CM e
  252.         {
  253.             /*
  254.              * since this is a comma operator, the value of
  255.              * the first expression is irrelevant.
  256.              */
  257.  
  258.             $$ = $3;
  259.             freenode($1);
  260.             freenode($2);
  261.         }
  262.     | term
  263.         {$$ = $1;}
  264.     ;
  265. term:
  266.       MINUS term
  267.         {
  268.             $2->an_ifval = -($2->an_ifval);
  269.         unop:
  270.             $$ = $2;
  271.             freenode($1);
  272.         }
  273.     | NOT term
  274.         {$2->an_ifval = !($2->an_ifval); goto unop;}
  275.     | COMPL term
  276.         {$2->an_ifval = ~($2->an_ifval); goto unop;}
  277.     | LP e RP
  278.         {
  279.             $$ = $2;
  280.             freenode($1); freenode($3);
  281.         }
  282.     | INT
  283.         {$$= $1;}
  284.     | IDENT
  285.         {/* an uninterpreted macro */ $$ = $1;}
  286.     | DEFMAC
  287.         {/* an uninterpreted 'defined(x)' invocation */ $$ = $1;}
  288.     ;
  289. %%
  290.  
  291. yyerror(s)
  292. char *s;
  293. {
  294.     struct anode *anp;
  295.  
  296.     /* free all nodes */
  297.  
  298.     for (anp = &nodepool[0]; anp < &nodepool[NODESIZ]; anp++) {
  299.         anp->an_val = 0;
  300.     }
  301.     warnf("syntax error in #if");
  302. }
  303.  
  304. /*
  305.  * yylex() - the lexical analyzer for #if statements.
  306.  *  yylex() reads from the stream of interpreted macros, skipping
  307.  *  insignificant tokens, then sets yylval appropriately and returns
  308.  *  the token number of the token.
  309.  */
  310.  
  311. int
  312. yylex()
  313. {
  314.     int tok;
  315.  
  316.  
  317.     /*
  318.      * Skip whitespace, quoted newlines, and interpreted preprocessor
  319.      * directives;
  320.      * End-of-file or an unquoted newline marks the end of the parse;
  321.      * calculate the value of integers and character constants.
  322.      */
  323.  
  324.     if (!(yylval.lexval = mknode())) {
  325.         return(0);
  326.     }
  327.  
  328.     while ((tok = gintok()) == WHITE || tok == COMMENT || tok == QNL)
  329.         ;
  330.  
  331.     if (tok == 0 || tok == NL) {
  332.         freenode(yylval.lexval);
  333.         yylval.lexval = NIL;
  334.         return(0);
  335.     }
  336.  
  337.     yylval.lexval->an_val = tok;
  338.     if (tok == INT) {
  339.         yylval.lexval->an_ifval = inttok(curtext, nxtout);
  340.     } else if (tok == CHARS) {
  341.         yylval.lexval->an_val = INT;
  342.         yylval.lexval->an_ifval = chartok(curtext, nxtout);
  343.     }
  344.     return(yylval.lexval->an_val);
  345. }
  346.  
  347. /*
  348.  * inttok - convert integer token.
  349.  *  Given the bounds of a token of type INT, return the value of that integer.
  350.  */
  351.  
  352. int
  353. inttok(s, e)
  354. char *s, *e;
  355. {
  356.     char *str;    /* points to a (dynamically alloc'ed) copy of the tok */
  357.     char *cp;
  358.     int base;    /* the radix of this integer            */
  359.     int value;    /* the value to return                */
  360.     int digit;    /* the value of the current digit        */
  361.  
  362.     /*
  363.      * get a copy of the token (to remove ATTN bytes and null-terminate
  364.      *  the string), and find out what the number base is.
  365.      */
  366.  
  367.     str = savtok(s, e);
  368.     cp = str;
  369.     if (*cp != '0') {
  370.         base = 10;
  371.     } else {
  372.         if (*cp && (*++cp == 'x' || *cp == 'X')) {
  373.             ++cp;
  374.             base = 16;
  375.         } else {
  376.             base = 8;
  377.         }
  378.     }
  379.  
  380.     /*
  381.      * convert the string
  382.      */
  383.  
  384.     value = 0;
  385.     for (;*cp; ++cp) {
  386.         if (*cp >= '0' && *cp <= '7') {
  387.             digit = (int)(*cp - '0');
  388.         } else if (*cp >= '8' && *cp <= '9' && base >= 10) {
  389.             digit = (int)(*cp - '0');
  390.         } else if (*cp >= 'a' && *cp <= 'f' && base == 16) {
  391.             digit = (int)(*cp - 'a') + 10;
  392.         } else if (*cp >= 'A' && *cp <= 'F' && base == 16) {
  393.             digit = (int)(*cp - 'A') + 10;
  394.         } else {
  395.             break;
  396.         }
  397.         value = value * base + digit;
  398.     }
  399.  
  400.     free(str);
  401.     return(value);
  402. }
  403.  
  404. /*
  405.  * chartok() - convert a character constant token.
  406.  *  given the bounds of a character constant, return the integer value
  407.  *   of that character constant.
  408.  */
  409.  
  410. int
  411. chartok(s, e)
  412. char *s, *e;
  413. {
  414.     char *str;    /* (dynamically alloc'ed) copy of the token    */
  415.     char *cp;
  416.     int value;    /* value to return                */
  417.     int cnt;
  418.  
  419.  
  420.     str = savtok(s, e);
  421.  
  422.     cp = str + 1;
  423.     if (*cp != '\\') {
  424.         value = (int) *cp;
  425.     } else if (*++cp == 'n') {
  426.         value = (int) '\n';
  427.     } else if (*cp == 't') {
  428.         value = (int) '\t';
  429.     } else if (*cp == 'b') {
  430.         value = (int) '\b';
  431. /*--read the book to find out the other chars supported--*/
  432.     } else if (*cp >= '0' && *cp <= '7') {
  433.         for (value = 0, cnt = 3; cnt >= 1 && *cp >= '0' && *cp <= '7';
  434.           --cnt, ++cp) {
  435.             value = value * 8 + (int)(*cp - '0');
  436.         }
  437.     } else {
  438.         value = (int) *cp;
  439.     }
  440.  
  441.     free(str);
  442.     return(value);
  443. }
  444.  
  445. struct anode *
  446. mknode()
  447. {
  448.     struct anode *anp;
  449.  
  450.     for (anp = &nodepool[0];
  451.       anp < &nodepool[NODESIZ] && anp->an_val != 0; anp++)
  452.         ;
  453.     if (anp >= &nodepool[NODESIZ]) {
  454.         warnf("#if expression too complex");
  455.         return(NIL);
  456.     }
  457.     anp->an_val = OTHER;
  458.     return(anp);
  459. }
  460.  
  461. freenode(n)
  462. struct anode *n;
  463. {
  464.     n->an_val = 0;
  465. }
  466.