home *** CD-ROM | disk | FTP | other *** search
-
- /* ----------------------------------------------------------------------
- * FILE: rhparse.c
- * (c) 1989 Ken Stauffer
- * This contains the parser for the C expressions,
- * gettoken(), getit() and ungetit() routines.
- * sectime(), datespec(), expression(), expr(), exp0(), ... , factor()
- * locatename(), push(), find_macro()
- *
- *
- * ---------------------------------------------------------------------- */
-
- #include "rh.h"
- #include <ctype.h>
- #include <pwd.h>
-
- static int cpos; /* current character position */
-
- /* ----------------------------------------------------------------------
- * getit:
- * Return the next character, input of from a file or
- * a string.
- */
-
- getit()
- {
- cpos++;
- if( dashe ) return( (*expstr) ? *expstr++ : EOF );
- else return( getc(expfile) );
- }
-
- /* ----------------------------------------------------------------------
- * ungetit:
- * Unget a char.
- *
- */
-
- ungetit(c)
- int c;
- {
- cpos--;
- if( dashe ) expstr = (*expstr) ? expstr-1 : expstr;
- else ungetc(c,expfile);
- }
-
- /* ----------------------------------------------------------------------
- * error:
- * Print an error message an quit.
- */
-
- error(s)
- char *s;
- {
- if( dashf )
- fprintf(stderr,"File: %s, ",expstr);
- else if( dashe )
- fprintf(stderr,"argv[%d], ",dashe);
- else
- fprintf(stderr,"File: stdin, ");
-
- fprintf(stderr,"char: %d, %s\n",cpos,s);
- exit(-1);
- }
-
- /* ----------------------------------------------------------------------
- * push:
- * "assemble" the instruction into the StackProgram[] array.
- *
- */
-
- push(t,val)
- long t,val;
- {
- if( PC >= LENGTH ) error("no more space for expression!");
- StackProgram[PC].i_type=t;
- StackProgram[PC++].i_value=val;
- return(PC-1);
- }
-
- /* ----------------------------------------------------------------------
- * find_macro:
- * Routine consumes the input file until it reaches the
- * macro name followed by a colon. If EOF
- * is encountered first then the program quits.
- *
- */
-
- find_macro()
- {
- while( token != MACRONAME && token != EOF ) token = gettoken();
- if( token == EOF ) error("macro name not found");
- token = gettoken();
- if( token != COLON ) error("missing ':' after macro name");
- token = gettoken();
- }
-
- /* ----------------------------------------------------------------------
- * expression()
- * Parse an expression.
- * This routine calls exp() and exp() calls exp0() and so on...
- * If the -m option was specified then the routine find_macro()
- * is called.
- * The NOW constant is initialized here.
- *
- */
-
- expression()
- {
- PC = 0; cpos = 0;
- constants[ NOW_INDEX ] = time(0);
- token = gettoken();
- if( dashm ) find_macro();
- expr();
- if( token!= ';' && token!= EOF ) error("missing ';' or EOF");
- push(0,0); /* NULL terminated the program */
- }
-
- /* OPERATOR ?: */
- expr()
- {
- int qm,colon,nop;
-
- expr0();
- if( token == QM ) {
- token = gettoken();
- qm = push(QM,0);
- expr();
- if( token != COLON ) error("missing ':'");
- token = gettoken();
- colon = push(COLON,0);
- expr();
- nop = push(NOP,0); /* nop */
-
- StackProgram[qm].i_value = colon;
- StackProgram[colon].i_value = nop;
- }
- }
-
- /* OPERATOR || */
- expr0()
- {
- expr1();
- for(;;)
- if( token == OR ) {
- token = gettoken();
- expr1();
- push(OR,0);
- } else break;
- }
-
- /* OPERATOR && */
- expr1()
- {
- expr2();
- for(;;)
- if( token == AND ) {
- token = gettoken();
- expr2();
- push(AND,0);
- } else break;
- }
-
- /* OPERATOR | */
- expr2()
- {
- expr3();
- for(;;)
- if( token == BOR ) {
- token = gettoken();
- expr3();
- push(BOR,0);
- } else break;
- }
-
- /* OPERATOR ^ */
- expr3()
- {
- expr4();
- for(;;)
- if( token == BXOR ) {
- token = gettoken();
- expr4();
- push(BXOR,0);
- } else break;
- }
-
- /* OPERATOR & */
- expr4()
- {
- expr5();
- for(;;)
- if( token == BAND ) {
- token = gettoken();
- expr5();
- push(BAND,0);
- } else break;
- }
-
- /* OPERATOR == != */
- expr5()
- {
- int t;
- expr6();
- for(;t=token;)
- if( t==EQ || t==NE ) {
- token = gettoken();
- expr6();
- push(t,0);
- } else break;
- }
-
- /* OPERATOR < <= > >= */
- expr6()
- {
- int t;
- expr7();
- for(;t=token;)
- if( t==LE || t==GE || t==GT || t==LT ) {
- token = gettoken();
- expr7();
- push(t,0);
- } else break;
- }
-
- /* OPERATOR << >> */
- expr7()
- {
- int t;
- expr8();
- for(;t=token;)
- if( t==SHIFTL || t==SHIFTR ) {
- token = gettoken();
- expr8();
- push(t,0);
- } else break;
- }
-
- /* OPERATOR + - */
- expr8()
- {
- int t;
- expr9();
- for(;t=token;)
- if( t==PLUS || t==MINUS ) {
- token = gettoken();
- expr9();
- push(t,0);
- } else break;
- }
-
- /* OPERATOR * / % */
- expr9()
- {
- int t;
- expr10();
- for(;t=token;)
- if( t==MUL || t==DIV || t==MOD ) {
- token = gettoken();
- expr10();
- push(t,0);
- } else break;
- }
-
- /* OPERATOR ~ ! - */
- expr10()
- {
- int t;
- t = token;
- if( t==NOT || t==BNOT || t==MINUS ){
- token = gettoken();
- expr10();
- push((t==MINUS)? UNIMINUS : t ,0);
- } else factor();
- }
-
- /* ----------------------------------------------------------------------
- * factor:
- * Parse a factor. Could be a number, variable or
- * string.
- */
-
- factor()
- {
- long l,datespec();
-
- switch(token) {
- case '(':
- token = gettoken();
- expr();
- if( token != ')' )
- error("missing ')'");
- token = gettoken();
- break;
- case NUMBER:
- push(NUMBER,tokenval);
- token = gettoken();
- break;
- case FIELD:
- push(FIELD,tokenval);
- token = gettoken();
- break;
- case '[':
- token = gettoken();
- l=datespec();
- if( token != ']' )
- error("missing ']'");
- token = gettoken();
- push(NUMBER,l);
- break;
- case STAR:
- push(STAR,tokenval);
- token = gettoken();
- break;
- default:
- error("syntax error");
- }
- }
-
- /* ----------------------------------------------------------------------
- * sectime:
- * calculate the number of seconds between January 1, 1970
- * and year/month/day. Return that value.
- *
- */
-
- #define leap(d) (((d % 4 == 0) && (d % 100 != 0)) || (d % 400 == 0))
- #define DAYSEC (3600*24)
- #define YERSEC (3600*24*365)
- #define TIME0 1970
-
- long sectime(year,month,day)
- int year,month,day;
- {
-
- static int months[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
- int yeardays,leapers,x;
- long seconds;
-
- if(month>12 || month<1 || year<TIME0 || day<1 || day>months[month]+
- (month==2 && leap(year)) )
- return(-1);
-
- yeardays = leapers = 0;
-
- for(x=1;x<month;x++)
- yeardays += months[x];
- if ((month > 2) && leap(year)) yeardays++;
-
- for(x=TIME0; x<year; x++)
- if(leap(x)) leapers++;
-
- seconds = yeardays*DAYSEC+(year-TIME0)*YERSEC+7*3600+
- leapers*DAYSEC + day*DAYSEC;
-
- return(seconds);
-
- }
-
- /* ----------------------------------------------------------------------
- * datespec:
- * parse a date. Return the number of seconds from
- * some date in 1970, until the specified date.
- */
-
- long datespec()
- {
- int year,month,day,seconds;
-
- if( token != NUMBER ) error("number expected");
- year = tokenval;
- token = gettoken();
- if( token != DIV ) error("missing '/'");
- token = gettoken();
- if( token != NUMBER ) error("number expected");
- month = tokenval;
- token = gettoken();
- if( token != DIV ) error("missing '/'");
- token = gettoken();
- if( token != NUMBER ) error("number expected");
- day = tokenval;
- token = gettoken();
-
- if( (seconds = sectime(year,month,day)) < 0 )
- error("invalid date");
-
- return(seconds);
- }
-
-
- /* ----------------------------------------------------------------------
- * locatename:
- * Does a linear seach for 's' in the array 'identifiers[]'.
- *
- */
-
- locatename(s)
- char *s;
- {
- register int i;
-
- for(i=0; identifiers[i]; i++ )
- if( !strcmp(s,identifiers[i]) ) return(i);
- return(-1);
- }
-
- /* ----------------------------------------------------------------------
- * gettoken:
- * Return the next token.
- * global variable: tokenval will contain any extra
- * attribute associated with the returned token, ie
- * the VALUE of a number, the index of the string etc...
- *
- */
-
- gettoken()
- {
- char buf[IDLENGTH+1],*bufp=buf;
- int c;
-
- for(;;) {
- while( (c=getit()) == ' ' || c=='\n' || c=='\t' );
- if( c == '#' ) while( (c=getit())!= '\n' && c!= EOF );
- else break;
- }
-
- if(c=='0') {
- tokenval=0;
- while( ( c=getit() ) >= '0' && c <= '7' ) {
- tokenval <<= 3;
- tokenval += c-'0';
- }
- if( isdigit(c) ) error("bad octal constant");
- ungetit(c);
- return(NUMBER);
- }
-
- if(isdigit(c)) {
- tokenval=c-'0';
- while(isdigit( (c=getit()) )) {
- tokenval *=10;
- tokenval += c-'0';
- }
- ungetit(c);
- return(NUMBER);
- }
-
- if(isalpha(c)) {
- int count=0,index;
- do {
- if(count++ < IDLENGTH) *bufp++ = c;
- c=getit();
- } while( isalnum(c) );
- ungetit(c);
- *bufp='\0';
- if( (index=locatename(buf)) < 0 ) return(UNKNOWN);
- tokenval = constants[index];
- if( index==MACRO_INDEX ) return(MACRONAME);
- return( ( isupper( *(identifiers[index]) ) ? NUMBER : FIELD ) );
- }
-
- if( c == '"' ) {
- int index,st=0;
- index=starfree;
- while( (c=getit())!= '"' ) {
- if( starfree > STARLEN )
- error("no more string space");
- if(c=='*') st++;
- if(st>1) error("too many *'s present");
- Starbuf[starfree++]=c;
- }
- Starbuf[starfree++]='\0';
- tokenval=index;
- return(STAR);
- }
-
- if( c == '=' ) {
- c=getit();
- if(c== '=') return(EQ);
- else {
- ungetit(c);
- return('=');
- }
- }
-
- if( c== '$' ) {
- int count=0;
- struct passwd *info,*getpwnam();
- c=getit();
- do {
- if (count++ < IDLENGTH) *bufp++ = c;
- c=getit();
- } while( isalnum(c) );
- ungetit(c);
- *bufp='\0';
- info=getpwnam(buf);
- if(info == NULL)
- error("unknown user name after $");
- tokenval = info->pw_uid;
- return( NUMBER );
- }
-
- if( c == '!' ) {
- c=getit();
- if( c == '=' ) return(NE);
- ungetit(c);
- return(NOT);
- }
-
- if( c == '>' ) {
- c=getit();
- if( c == '=' ) return(GE);
- if( c == '>' ) return(SHIFTR);
- ungetit(c);
- return(GT);
- }
-
- if( c == '<' ) {
- c=getit();
- if( c == '=' ) return(LE);
- if( c == '<' ) return(SHIFTL);
- ungetit(c);
- return(LT);
- }
-
- if( c == '&' ) {
- c=getit();
- if( c == '&' ) return(AND);
- ungetit(c);
- return(BAND);
- }
-
- if( c == '|' ) {
- c=getit();
- if( c == '|' ) return(OR);
- ungetit(c);
- return(BOR);
- }
- if( c == '^' ) return(BXOR);
- if( c == '+' ) return(PLUS);
- if( c == '-' ) return(MINUS);
- if( c == '*' ) return(MUL);
- if( c == '/' ) return(DIV);
- if( c == '%' ) return(MOD);
- if( c == '~' ) return(BNOT);
- if( c == '?' ) return(QM);
- if( c == ':' ) return(COLON);
-
- return(c);
- }
-
-