home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume18 / rh / rhparse.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-03-23  |  10.0 KB  |  551 lines

  1.  
  2. /* ----------------------------------------------------------------------
  3.  * FILE: rhparse.c
  4.  * (c) 1989 Ken Stauffer
  5.  * This contains the parser for the C expressions,
  6.  * gettoken(), getit() and ungetit() routines.
  7.  * sectime(), datespec(), expression(), expr(), exp0(), ... , factor()
  8.  * locatename(), push(), find_macro()
  9.  *
  10.  *
  11.  * ---------------------------------------------------------------------- */
  12.  
  13. #include "rh.h"
  14. #include <ctype.h>
  15. #include <pwd.h>
  16.  
  17. static int cpos;        /* current character position */
  18.  
  19. /* ----------------------------------------------------------------------
  20.  * getit:
  21.  *    Return the next character, input of from a file or
  22.  *    a string.
  23.  */
  24.  
  25. getit()
  26. {
  27.     cpos++;
  28.     if( dashe ) return( (*expstr) ? *expstr++ : EOF );
  29.     else return( getc(expfile) );
  30. }
  31.  
  32. /* ----------------------------------------------------------------------
  33.  * ungetit:
  34.  *    Unget a char.
  35.  *
  36.  */
  37.  
  38. ungetit(c)
  39. int c;
  40. {
  41.     cpos--;
  42.     if( dashe ) expstr = (*expstr) ? expstr-1 : expstr;
  43.     else ungetc(c,expfile);
  44. }
  45.  
  46. /* ----------------------------------------------------------------------
  47.  * error:
  48.  *    Print an error message an quit.
  49.  */
  50.  
  51. error(s)
  52. char *s;
  53. {
  54.     if( dashf )
  55.         fprintf(stderr,"File: %s, ",expstr);
  56.     else if( dashe )
  57.         fprintf(stderr,"argv[%d], ",dashe);
  58.     else
  59.         fprintf(stderr,"File: stdin, ");
  60.  
  61.     fprintf(stderr,"char: %d, %s\n",cpos,s);
  62.     exit(-1);
  63. }
  64.  
  65. /* ----------------------------------------------------------------------
  66.  * push:
  67.  *    "assemble" the instruction into the StackProgram[] array.
  68.  *
  69.  */
  70.  
  71. push(t,val)
  72. long t,val;
  73. {
  74.     if( PC >= LENGTH ) error("no more space for expression!"); 
  75.     StackProgram[PC].i_type=t;
  76.     StackProgram[PC++].i_value=val;
  77.     return(PC-1);
  78. }
  79.  
  80. /* ----------------------------------------------------------------------
  81.  * find_macro:
  82.  *    Routine consumes the input file until it reaches the
  83.  *    macro name followed by a colon. If EOF
  84.  *    is encountered first then the program quits.
  85.  *
  86.  */
  87.  
  88. find_macro()
  89. {
  90.     while( token != MACRONAME && token != EOF ) token = gettoken();
  91.     if( token == EOF ) error("macro name not found");
  92.     token = gettoken();
  93.     if( token != COLON ) error("missing ':' after macro name");
  94.     token = gettoken();
  95. }
  96.  
  97. /* ----------------------------------------------------------------------
  98.  * expression()
  99.  *    Parse an expression.
  100.  *    This routine calls exp() and exp() calls exp0() and so on...
  101.  *    If the -m option was specified then the routine find_macro()
  102.  *    is called.
  103.  *    The NOW constant is initialized here.
  104.  *
  105.  */
  106.     
  107. expression()
  108. {
  109.     PC = 0; cpos = 0;
  110.     constants[ NOW_INDEX ] = time(0);
  111.     token = gettoken();
  112.     if( dashm ) find_macro();
  113.     expr();
  114.     if( token!= ';' && token!= EOF ) error("missing ';' or EOF");
  115.     push(0,0);            /* NULL terminated the program */
  116. }
  117.  
  118. /* OPERATOR ?: */
  119. expr()
  120. {
  121.     int qm,colon,nop;
  122.  
  123.     expr0();
  124.     if( token == QM ) {
  125.         token = gettoken();
  126.         qm = push(QM,0);
  127.         expr();
  128.         if( token != COLON ) error("missing ':'");
  129.         token = gettoken();
  130.         colon = push(COLON,0);
  131.         expr();
  132.         nop = push(NOP,0);        /* nop */
  133.  
  134.         StackProgram[qm].i_value = colon;
  135.         StackProgram[colon].i_value = nop;
  136.     }
  137. }        
  138.  
  139. /* OPERATOR || */ 
  140. expr0()
  141. {
  142.     expr1();
  143.     for(;;)
  144.         if( token == OR ) {
  145.             token = gettoken();
  146.             expr1();
  147.             push(OR,0);
  148.            } else break;
  149. }
  150.  
  151. /* OPERATOR && */ 
  152. expr1()
  153. {
  154.     expr2();
  155.     for(;;)
  156.         if( token == AND ) {
  157.             token = gettoken();
  158.             expr2();
  159.             push(AND,0);
  160.         } else break;
  161. }
  162.  
  163. /* OPERATOR | */
  164. expr2()
  165. {
  166.     expr3();
  167.     for(;;)
  168.         if( token == BOR ) {
  169.             token = gettoken();
  170.             expr3();
  171.             push(BOR,0);
  172.         } else break;
  173. }
  174.  
  175. /* OPERATOR ^ */
  176. expr3()
  177. {
  178.     expr4();
  179.     for(;;)
  180.         if( token == BXOR ) {
  181.             token = gettoken();
  182.             expr4();
  183.             push(BXOR,0);
  184.         } else break;
  185. }
  186.  
  187. /* OPERATOR & */
  188. expr4()
  189. {
  190.     expr5();
  191.     for(;;)
  192.         if( token == BAND ) {
  193.             token = gettoken();
  194.             expr5();
  195.             push(BAND,0);
  196.         } else break;
  197. }
  198.  
  199. /* OPERATOR == != */
  200. expr5()
  201. {
  202.     int t;
  203.     expr6();
  204.     for(;t=token;)
  205.         if( t==EQ || t==NE ) {
  206.             token = gettoken();
  207.             expr6();
  208.             push(t,0);
  209.         } else break;
  210. }
  211.  
  212. /* OPERATOR < <= > >= */
  213. expr6()
  214. {
  215.     int t;
  216.     expr7();
  217.     for(;t=token;)
  218.         if( t==LE || t==GE || t==GT || t==LT ) {
  219.             token = gettoken();
  220.             expr7();
  221.             push(t,0);
  222.         } else break;
  223. }
  224.  
  225. /* OPERATOR << >> */
  226. expr7()
  227. {
  228.     int t;
  229.     expr8();
  230.     for(;t=token;)
  231.         if( t==SHIFTL || t==SHIFTR ) {
  232.             token = gettoken();
  233.             expr8();
  234.             push(t,0);
  235.         } else break;
  236. }
  237.  
  238. /* OPERATOR + - */
  239. expr8()
  240. {
  241.     int t;
  242.     expr9();
  243.     for(;t=token;)
  244.         if( t==PLUS || t==MINUS ) {
  245.             token = gettoken();
  246.             expr9();
  247.             push(t,0);
  248.         } else break;
  249. }
  250.  
  251. /* OPERATOR * / % */
  252. expr9()
  253. {
  254.     int t;
  255.     expr10();
  256.     for(;t=token;)
  257.         if( t==MUL || t==DIV || t==MOD ) {
  258.             token = gettoken();
  259.             expr10();
  260.             push(t,0);
  261.         } else break;
  262. }
  263.  
  264. /* OPERATOR ~ ! - */ 
  265. expr10()
  266. {
  267.     int t;
  268.     t = token;    
  269.     if( t==NOT || t==BNOT || t==MINUS ){
  270.         token = gettoken();
  271.         expr10();
  272.         push((t==MINUS)? UNIMINUS : t ,0);
  273.     } else factor();
  274. }
  275.  
  276. /* ----------------------------------------------------------------------
  277.  * factor:
  278.  *    Parse a factor. Could be a number, variable or
  279.  *    string.
  280.  */
  281.  
  282. factor()
  283. {
  284.     long l,datespec();
  285.  
  286.     switch(token) {
  287.         case '(':
  288.             token = gettoken();
  289.             expr();
  290.             if( token != ')' )
  291.                 error("missing ')'");
  292.             token = gettoken();
  293.             break;
  294.         case NUMBER:
  295.             push(NUMBER,tokenval);
  296.             token = gettoken();
  297.             break;
  298.         case FIELD:
  299.             push(FIELD,tokenval);
  300.             token = gettoken();
  301.             break;
  302.         case '[':
  303.             token = gettoken();
  304.             l=datespec();
  305.             if( token != ']' )
  306.                 error("missing ']'");
  307.             token = gettoken();
  308.             push(NUMBER,l);
  309.             break;
  310.         case STAR:
  311.             push(STAR,tokenval);
  312.             token = gettoken();
  313.             break;
  314.         default:
  315.             error("syntax error");
  316.     }
  317. }
  318.  
  319. /* ----------------------------------------------------------------------
  320.  * sectime:
  321.  *    calculate the number of seconds between January 1, 1970
  322.  *    and year/month/day. Return that value.
  323.  *
  324.  */
  325.  
  326. #define leap(d)    (((d % 4 == 0) && (d % 100 != 0)) || (d % 400 == 0))
  327. #define DAYSEC    (3600*24)
  328. #define YERSEC    (3600*24*365)
  329. #define TIME0    1970
  330.  
  331. long sectime(year,month,day)
  332. int year,month,day;
  333. {
  334.  
  335.         static int months[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
  336.     int yeardays,leapers,x;
  337.     long seconds;
  338.  
  339.     if(month>12 || month<1 || year<TIME0 || day<1 || day>months[month]+
  340.         (month==2 && leap(year)) )
  341.             return(-1);
  342.  
  343.     yeardays = leapers = 0;
  344.  
  345.     for(x=1;x<month;x++)
  346.         yeardays += months[x];
  347.     if ((month > 2) && leap(year)) yeardays++;
  348.  
  349.     for(x=TIME0; x<year; x++)
  350.         if(leap(x)) leapers++;
  351.     
  352.     seconds = yeardays*DAYSEC+(year-TIME0)*YERSEC+7*3600+
  353.             leapers*DAYSEC + day*DAYSEC;
  354.  
  355.     return(seconds);
  356.  
  357. }
  358.  
  359. /* ----------------------------------------------------------------------
  360.  * datespec:
  361.  *    parse a date. Return the number of seconds from
  362.  *    some date in 1970, until the specified date.
  363.  */
  364.  
  365. long datespec()
  366. {
  367.     int year,month,day,seconds;
  368.  
  369.     if( token != NUMBER ) error("number expected");
  370.     year = tokenval;
  371.     token = gettoken();
  372.     if( token != DIV ) error("missing '/'");
  373.     token = gettoken();
  374.     if( token != NUMBER ) error("number expected");
  375.     month = tokenval;
  376.     token = gettoken();
  377.     if( token != DIV ) error("missing '/'");
  378.     token = gettoken();
  379.     if( token != NUMBER ) error("number expected");
  380.     day = tokenval;
  381.     token = gettoken();
  382.  
  383.     if( (seconds = sectime(year,month,day)) < 0 ) 
  384.         error("invalid date");
  385.  
  386.     return(seconds);
  387. }
  388.  
  389.  
  390. /* ----------------------------------------------------------------------
  391.  * locatename:
  392.  *    Does a linear seach for 's' in the array 'identifiers[]'.
  393.  *
  394.  */
  395.  
  396. locatename(s)
  397. char *s;
  398. {
  399.     register int i;
  400.  
  401.     for(i=0; identifiers[i]; i++ )
  402.         if( !strcmp(s,identifiers[i]) ) return(i);
  403.     return(-1);
  404. }
  405.  
  406. /* ----------------------------------------------------------------------
  407.  * gettoken:
  408.  *    Return the next token.
  409.  *    global variable: tokenval will contain any extra
  410.  *    attribute associated with the returned token, ie
  411.  *    the VALUE of a number, the index of the string etc...
  412.  *
  413.  */
  414.  
  415. gettoken()
  416. {
  417.     char buf[IDLENGTH+1],*bufp=buf;
  418.     int c;
  419.  
  420.     for(;;) { 
  421.         while( (c=getit()) == ' ' || c=='\n' || c=='\t' );
  422.         if( c == '#' ) while( (c=getit())!= '\n' && c!= EOF );
  423.         else break;
  424.     }
  425.  
  426.     if(c=='0') {
  427.         tokenval=0;
  428.         while( ( c=getit() ) >= '0' && c <= '7' ) {
  429.             tokenval <<= 3;
  430.             tokenval += c-'0';
  431.         }
  432.         if( isdigit(c) ) error("bad octal constant");
  433.         ungetit(c);
  434.         return(NUMBER);
  435.     }
  436.  
  437.     if(isdigit(c)) {
  438.         tokenval=c-'0';
  439.         while(isdigit( (c=getit()) )) {
  440.             tokenval *=10;
  441.             tokenval += c-'0';
  442.         }
  443.         ungetit(c);
  444.         return(NUMBER);
  445.     }
  446.     
  447.     if(isalpha(c)) {
  448.        int count=0,index;
  449.        do {
  450.         if(count++ < IDLENGTH) *bufp++ = c;
  451.         c=getit();
  452.        } while( isalnum(c) );
  453.        ungetit(c);
  454.        *bufp='\0';
  455.        if( (index=locatename(buf)) < 0 ) return(UNKNOWN);
  456.        tokenval = constants[index];
  457.        if( index==MACRO_INDEX ) return(MACRONAME);
  458.        return( ( isupper( *(identifiers[index]) ) ? NUMBER : FIELD ) );
  459.     }
  460.  
  461.     if( c == '"' ) {
  462.         int index,st=0;
  463.         index=starfree;
  464.         while( (c=getit())!= '"' ) {
  465.             if( starfree > STARLEN )
  466.                 error("no more string space");
  467.             if(c=='*') st++;
  468.             if(st>1) error("too many *'s present");
  469.             Starbuf[starfree++]=c;
  470.         }
  471.         Starbuf[starfree++]='\0';
  472.         tokenval=index;
  473.         return(STAR);
  474.     }
  475.  
  476.     if( c == '=' ) {
  477.         c=getit();
  478.         if(c== '=') return(EQ);
  479.         else {
  480.             ungetit(c);
  481.             return('=');
  482.         }
  483.     }
  484.  
  485.     if( c== '$' ) {
  486.        int count=0;
  487.        struct passwd *info,*getpwnam();
  488.        c=getit();
  489.        do {
  490.         if (count++ < IDLENGTH) *bufp++ = c;
  491.         c=getit();
  492.        } while( isalnum(c) );
  493.        ungetit(c);
  494.        *bufp='\0';
  495.        info=getpwnam(buf);
  496.        if(info == NULL)
  497.         error("unknown user name after $");
  498.        tokenval = info->pw_uid;
  499.        return( NUMBER );
  500.     }
  501.     
  502.     if( c == '!' ) {
  503.         c=getit();
  504.         if( c == '=' ) return(NE);
  505.         ungetit(c);
  506.         return(NOT);
  507.     }
  508.  
  509.     if( c == '>' ) {
  510.         c=getit();
  511.         if( c == '=' ) return(GE);
  512.         if( c == '>' ) return(SHIFTR);
  513.         ungetit(c);
  514.         return(GT);
  515.     }
  516.  
  517.     if( c == '<' ) {
  518.         c=getit();
  519.         if( c == '=' ) return(LE);
  520.         if( c == '<' ) return(SHIFTL);
  521.         ungetit(c);
  522.         return(LT);
  523.     }
  524.  
  525.     if( c == '&' ) {
  526.         c=getit();
  527.         if( c == '&' ) return(AND);
  528.         ungetit(c);
  529.         return(BAND);
  530.     }
  531.  
  532.     if( c == '|' ) {
  533.         c=getit();
  534.         if( c == '|' ) return(OR);
  535.         ungetit(c);
  536.         return(BOR);
  537.     }
  538.     if( c == '^' ) return(BXOR);
  539.     if( c == '+' ) return(PLUS);
  540.     if( c == '-' ) return(MINUS);
  541.     if( c == '*' ) return(MUL);
  542.     if( c == '/' ) return(DIV);
  543.     if( c == '%' ) return(MOD);
  544.     if( c == '~' ) return(BNOT);
  545.     if( c == '?' ) return(QM);
  546.     if( c == ':' ) return(COLON);
  547.     
  548.     return(c);
  549. }
  550.  
  551.