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 >
Wrap
Text File
|
2009-11-06
|
10KB
|
466 lines
/*
* 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;
}