home *** CD-ROM | disk | FTP | other *** search
- /*
- * parse.y - #if parser for the selective C preprocessor, scpp.
- *
- * Copyright (c) 1985 by
- * Tektronix, Incorporated Beaverton, Oregon 97077
- * All rights reserved.
- *
- * Permission is hereby granted for personal, non-commercial
- * reproduction and use of this program, provided that this
- * notice and all copyright notices are included in any copy.
- */
-
- %term MUL /* * */
- %term DIV /* / */
- %term MOD /* % */
- %term PLUS /* + */
- %term MINUS /* - */
- %term LS /* << */
- %term RS /* >> */
- %term AND /* & */
- %term OR /* | */
- %term ER /* ^ */
- %term LT /* < */
- %term LE /* <= */
- %term GT /* > */
- %term GE /* >= */
- %term EQ /* == */
- %term NE /* != */
- %term ANDAND /* && */
- %term OROR /* || */
- %term CM /* , (comma) */
- %term QUEST /* ? */
- %term COLON /* : */
- %term NOT /* ! */
- %term COMPL /* ~ */
- %term LP /* ( */
- %term RP /* ) */
- %term INT /* an integer */
- %term FLOAT /* a float */
- %term IDENT /* a identifier */
- %term QUOTE /* ' (apostrophe) */
- %term DQUOTE /* " */
- %term BACKS /* \ (backslash) */
- %term OPENC /* open comment sequence */
- %term CLOSEC /* close comment sequence */
- %term WHITE /* whitespace */
- %term NL /* newline */
- %term QNL /* escaped (quoted) newline */
- %term COMMENT /* a comment */
- %term OTHER /* anything else */
- %term STRING /* a double-quote enclosed string constant */
- %term CHARS /* a single-quote enclosed char constant */
- %term POUNDLINE /*
- * The initial '#' of a preprocessor directive
- * (as opposed to a normal '#', which is of type OTHER).
- */
- %term DEFMAC /* an uninterpreted 'defined(x)' invocation */
-
- %left CM
- %right QUEST COLON
- %left OROR
- %left ANDAND
- %left OR
- %left ER
- %left AND
- %left EQ NE
- %left LT LE GE GT
- %left LS RS
- %left PLUS MINUS
- %left MUL DIV MOD
- %right NOT COMPL
- %left LP
-
- %union {
- int intval; /* yacc stack entries */
- struct anode *lexval; /* everything in this file */
- }
-
- %type <lexval> exp e term
- %type <lexval> MUL DIV MOD PLUS MINUS LS RS AND OR ER LT LE GT GE EQ NE
- ANDAND OROR CM QUEST COLON NOT COMPL LP RP INT FLOAT IDENT
- QUOTE DQUOTE BACKS OPENC CLOSEC WHITE NL QNL COMMENT OTHER
- STRING CHARS POUNDLINE DEFMAC
-
- %{
- # include "scpp.h"
-
- /*
- * struct anode - the structure used to pass strings.
- * Allocated by mknode();
- * Deallocated by freenode().
- * The string described will be in pend[] and is NOT NULL-TERMINATED.
- */
-
- struct anode {
- int an_val; /*
- * lexical (token) value of this string.
- * A value of 0 == this node is free.
- */
- int an_ifval; /* integer result of this expression */
- };
-
- # define NODESIZ 100 /* max number of nodes in a #if expresssion */
- struct anode nodepool[NODESIZ];
-
- struct anode *mknode();
-
- # define NIL ((struct anode *) 0)
- %}
-
- %start exp
- %%
- exp: e
- {
- /*
- * If the expression can be evaluated, set the result
- */
-
- if ($1->an_val == INT) {
- *curif |= $1->an_ifval != 0 ?
- IF_TRUE : IF_FALSE;
- }
- freenode($1);
- }
- ;
- e: e MUL e
- {
- $1->an_ifval = $1->an_ifval * $3->an_ifval;
- binop:
- $$ = $1;
- if ($1->an_val == INT && $3->an_val == INT) {
- $$->an_val == INT;
- } else {
- $$->an_val = OTHER;
- }
- freenode($2);
- freenode($3);
- }
- | e DIV e
- {
- if ($3->an_ifval == 0 && $3->an_val == INT) {
- $3->an_val = OTHER;
- warnf("division by zero in #if");
- } else {
- $1->an_ifval = $1->an_ifval / $3->an_ifval;
- }
- goto binop;
- }
- | e MOD e
- {
- if ($3->an_ifval == 0 && $3->an_val == INT) {
- $3->an_val = OTHER;
- warnf("mod by zero in #if");
- } else {
- $1->an_ifval = $1->an_ifval % $3->an_ifval;
- }
- goto binop;
- }
- | e PLUS e
- {$1->an_ifval = $1->an_ifval + $3->an_ifval; goto binop;}
- | e MINUS e
- {$1->an_ifval = $1->an_ifval - $3->an_ifval; goto binop;}
- | e LS e
- {$1->an_ifval = $1->an_ifval << $3->an_ifval; goto binop;}
- | e RS e
- {$1->an_ifval = $1->an_ifval >> $3->an_ifval; goto binop;}
- | e LT e
- {$1->an_ifval = $1->an_ifval < $3->an_ifval; goto binop;}
- | e GT e
- {$1->an_ifval = $1->an_ifval > $3->an_ifval; goto binop;}
- | e LE e
- {$1->an_ifval = $1->an_ifval <= $3->an_ifval; goto binop;}
- | e GE e
- {$1->an_ifval = $1->an_ifval >= $3->an_ifval; goto binop;}
- | e EQ e
- {$1->an_ifval = $1->an_ifval == $3->an_ifval; goto binop;}
- | e NE e
- {$1->an_ifval = $1->an_ifval != $3->an_ifval; goto binop;}
- | e AND e
- {$1->an_ifval = $1->an_ifval & $3->an_ifval; goto binop;}
- | e ER e
- {$1->an_ifval = $1->an_ifval ^ $3->an_ifval; goto binop;}
- | e OR e
- {$1->an_ifval = $1->an_ifval | $3->an_ifval; goto binop;}
- | e ANDAND e
- {
- /*
- * since this is a logical AND, its value
- * is known if either subexpression is false.
- */
-
- $$ = $1;
- if ($1->an_val == INT && $3->an_val == INT) {
- /* both subexpressions are known */
- $$->an_ifval = $1->an_ifval && $3->an_ifval;
- } else {
- if (($1->an_val == INT && !$1->an_ifval) ||
- ($3->an_val == INT && !$3->an_ifval)) {
- $$->an_val = INT;
- $$->an_ifval = FALSE;
- } else {
- $$->an_val = OTHER;
- }
- }
- freenode($2); freenode($3);
- }
- | e OROR e
- {
- /*
- * since this is a logical OR, its value
- * is known if either subexpression is true.
- */
-
- $$ = $1;
- if ($1->an_val == INT && $3->an_val == INT) {
- /* both subexpressions are known */
- $$->an_ifval = $1->an_ifval || $3->an_ifval;
- } else {
- if (($1->an_val == INT && $1->an_ifval) ||
- ($3->an_val == INT && $3->an_ifval)) {
- $$->an_val = INT;
- $$->an_ifval = TRUE;
- } else {
- $$->an_val = OTHER;
- }
- }
- freenode($2); freenode($3);
- }
- | e QUEST e COLON e
- {
- /*
- * since this is an IF-ELSE, its value is known
- * in some cases even if one subexpression is unknown.
- */
-
- $$ = $1;
- if ($1->an_val == INT) {
- if ($1->an_ifval) {
- $$->an_val = $3->an_val;
- $$->an_ifval = $3->an_ifval;
- } else {
- $$->an_val = $5->an_val;
- $$->an_ifval = $5->an_ifval;
- }
- } else {
- $$->an_val = OTHER;
- }
- freenode($2); freenode($3); freenode($4);
- freenode($5);
- }
- | e CM e
- {
- /*
- * since this is a comma operator, the value of
- * the first expression is irrelevant.
- */
-
- $$ = $3;
- freenode($1);
- freenode($2);
- }
- | term
- {$$ = $1;}
- ;
- term:
- MINUS term
- {
- $2->an_ifval = -($2->an_ifval);
- unop:
- $$ = $2;
- freenode($1);
- }
- | NOT term
- {$2->an_ifval = !($2->an_ifval); goto unop;}
- | COMPL term
- {$2->an_ifval = ~($2->an_ifval); goto unop;}
- | LP e RP
- {
- $$ = $2;
- freenode($1); freenode($3);
- }
- | INT
- {$$= $1;}
- | IDENT
- {/* an uninterpreted macro */ $$ = $1;}
- | DEFMAC
- {/* an uninterpreted 'defined(x)' invocation */ $$ = $1;}
- ;
- %%
-
- yyerror(s)
- char *s;
- {
- struct anode *anp;
-
- /* free all nodes */
-
- for (anp = &nodepool[0]; anp < &nodepool[NODESIZ]; anp++) {
- anp->an_val = 0;
- }
- warnf("syntax error in #if");
- }
-
- /*
- * yylex() - the lexical analyzer for #if statements.
- * yylex() reads from the stream of interpreted macros, skipping
- * insignificant tokens, then sets yylval appropriately and returns
- * the token number of the token.
- */
-
- int
- yylex()
- {
- int tok;
-
-
- /*
- * Skip whitespace, quoted newlines, and interpreted preprocessor
- * directives;
- * End-of-file or an unquoted newline marks the end of the parse;
- * calculate the value of integers and character constants.
- */
-
- if (!(yylval.lexval = mknode())) {
- return(0);
- }
-
- while ((tok = gintok()) == WHITE || tok == COMMENT || tok == QNL)
- ;
-
- if (tok == 0 || tok == NL) {
- freenode(yylval.lexval);
- yylval.lexval = NIL;
- return(0);
- }
-
- yylval.lexval->an_val = tok;
- if (tok == INT) {
- yylval.lexval->an_ifval = inttok(curtext, nxtout);
- } else if (tok == CHARS) {
- yylval.lexval->an_val = INT;
- yylval.lexval->an_ifval = chartok(curtext, nxtout);
- }
- return(yylval.lexval->an_val);
- }
-
- /*
- * inttok - convert integer token.
- * Given the bounds of a token of type INT, return the value of that integer.
- */
-
- int
- inttok(s, e)
- char *s, *e;
- {
- char *str; /* points to a (dynamically alloc'ed) copy of the tok */
- char *cp;
- int base; /* the radix of this integer */
- int value; /* the value to return */
- int digit; /* the value of the current digit */
-
- /*
- * get a copy of the token (to remove ATTN bytes and null-terminate
- * the string), and find out what the number base is.
- */
-
- str = savtok(s, e);
- cp = str;
- if (*cp != '0') {
- base = 10;
- } else {
- if (*cp && (*++cp == 'x' || *cp == 'X')) {
- ++cp;
- base = 16;
- } else {
- base = 8;
- }
- }
-
- /*
- * convert the string
- */
-
- value = 0;
- for (;*cp; ++cp) {
- if (*cp >= '0' && *cp <= '7') {
- digit = (int)(*cp - '0');
- } else if (*cp >= '8' && *cp <= '9' && base >= 10) {
- digit = (int)(*cp - '0');
- } else if (*cp >= 'a' && *cp <= 'f' && base == 16) {
- digit = (int)(*cp - 'a') + 10;
- } else if (*cp >= 'A' && *cp <= 'F' && base == 16) {
- digit = (int)(*cp - 'A') + 10;
- } else {
- break;
- }
- value = value * base + digit;
- }
-
- free(str);
- return(value);
- }
-
- /*
- * chartok() - convert a character constant token.
- * given the bounds of a character constant, return the integer value
- * of that character constant.
- */
-
- int
- chartok(s, e)
- char *s, *e;
- {
- char *str; /* (dynamically alloc'ed) copy of the token */
- char *cp;
- int value; /* value to return */
- int cnt;
-
-
- str = savtok(s, e);
-
- cp = str + 1;
- if (*cp != '\\') {
- value = (int) *cp;
- } else if (*++cp == 'n') {
- value = (int) '\n';
- } else if (*cp == 't') {
- value = (int) '\t';
- } else if (*cp == 'b') {
- value = (int) '\b';
- /*--read the book to find out the other chars supported--*/
- } else if (*cp >= '0' && *cp <= '7') {
- for (value = 0, cnt = 3; cnt >= 1 && *cp >= '0' && *cp <= '7';
- --cnt, ++cp) {
- value = value * 8 + (int)(*cp - '0');
- }
- } else {
- value = (int) *cp;
- }
-
- free(str);
- return(value);
- }
-
- struct anode *
- mknode()
- {
- struct anode *anp;
-
- for (anp = &nodepool[0];
- anp < &nodepool[NODESIZ] && anp->an_val != 0; anp++)
- ;
- if (anp >= &nodepool[NODESIZ]) {
- warnf("#if expression too complex");
- return(NIL);
- }
- anp->an_val = OTHER;
- return(anp);
- }
-
- freenode(n)
- struct anode *n;
- {
- n->an_val = 0;
- }
-