home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Professional / OS2PRO194.ISO / os2 / fileutil / rh / rhparse.c < prev    next >
C/C++ Source or Header  |  1990-02-13  |  15KB  |  789 lines

  1.  
  2. /* ----------------------------------------------------------------------
  3.  * FILE: rhparse.c
  4.  * VERSION: 2
  5.  * Written by: Ken Stauffer
  6.  * This contains the parser for the C expressions,
  7.  * gettoken(), getit() and ungetit() routines.
  8.  * sectime(), datespec(), expression(), expr(), exp0(), ... , factor()
  9.  * locatename(), push(), find_macro()
  10.  *
  11.  *
  12.  * ---------------------------------------------------------------------- */
  13.  
  14. #include "rh.h"
  15. #include <ctype.h>
  16.  
  17. #ifndef MSDOS
  18. #include <pwd.h>
  19. #endif
  20.  
  21. static int cpos;        /* current character position */
  22. static int lineno;        /* current line number */
  23.  
  24. /* ----------------------------------------------------------------------
  25.  * getit:
  26.  *    Return the next character, input is obtained from a file or
  27.  *    a string.
  28.  *    If expstr == NULL then input is from the file called 'expfname'
  29.  *    with file pointer 'expfile'.
  30.  *
  31.  *    If expstr != NULL then input is from the string 'expstr'
  32.  *
  33.  */
  34.  
  35. getit()
  36. {
  37.     int c;
  38.  
  39.     if( expstr ) c = (*expstr) ? *expstr++ : EOF;
  40.     else c = getc(expfile);
  41.  
  42.     if( c == '\n' ) { lineno++; cpos = 0; }
  43.     cpos++;
  44.  
  45.     return(c);
  46. }
  47.  
  48. /* ----------------------------------------------------------------------
  49.  * ungetit:
  50.  *    Unget a char.
  51.  *    A character is ungotten using the same scheme as stated for
  52.  *    getit() for determining where input is comming from.
  53.  *
  54.  */
  55.  
  56. ungetit(c)
  57. int c;
  58. {
  59.     if( c == '\n' ) { lineno--; cpos = 1; }
  60.     else cpos--;
  61.     if( expstr ) expstr = (c > 0) ? expstr-1 : expstr;
  62.     else ungetc(c,expfile);
  63. }
  64.  
  65. /* ----------------------------------------------------------------------
  66.  * error:
  67.  *    Print an error message and quit.
  68.  */
  69.  
  70. error(s)
  71. char *s;
  72. {
  73.     if( expstr )
  74.         fprintf(stderr,"Command line: ");
  75.     else
  76.         fprintf(stderr,"%s: ",expfname);
  77.  
  78.     fprintf(stderr,"line: %d, char: %d, %s.\n",lineno,cpos,s);
  79.     exit(1);
  80. }
  81.  
  82. /* ----------------------------------------------------------------------
  83.  * insertname:
  84.  *    Inserts the symbol named 's' with type 't' and value 'val'
  85.  *    into the symbol table. Return the a pointer to the symbol
  86.  *    table entry. The symbol is inserted into the head of the
  87.  *    linked list. This behavior is relied upon elswhere.
  88.  *
  89.  */
  90.  
  91. struct symbol *insertname(s,t,val)
  92. char *s;
  93. int t;
  94. long val;
  95. {
  96.     char *p,*malloc();
  97.     struct symbol *sym;
  98.  
  99.     sym = (struct symbol *) malloc( sizeof(struct symbol) );
  100.     if( sym == NULL ) error("no more memory");
  101.  
  102.     p = sym->name = malloc( strlen(s)+1 );
  103.     if( sym->name == NULL ) error("no more memory");
  104.     while( *p++ = *s++ );
  105.     sym->type = t;
  106.     sym->value = val;
  107.  
  108.     sym->next = symbols;
  109.     symbols = sym;
  110.  
  111.     return( sym );
  112. }
  113.  
  114. /* ----------------------------------------------------------------------
  115.  * locatename:
  116.  *    Do a linear search for 's' in the linked list symbols.
  117.  *
  118.  */
  119.  
  120. struct symbol *locatename(s)
  121. char *s;
  122. {
  123.     struct symbol *p;
  124.  
  125.     for(p=symbols; p; p = p->next )
  126.         if( !strcmp(s,p->name) ) return(p);
  127.  
  128.     return(NULL);
  129. }
  130.  
  131. /* ----------------------------------------------------------------------
  132.  * push:
  133.  *    "assemble" the instruction into the StackProgram[] array.
  134.  *
  135.  */
  136.  
  137. push(func,val)
  138. int (*func)();
  139. long val;
  140. {
  141.     if( PC >= LENGTH ) error("program to big");
  142.     StackProgram[PC].func=func;
  143.     StackProgram[PC++].value=val;
  144. }
  145.  
  146. /* ----------------------------------------------------------------------
  147.  * program:
  148.  *    Parse a program of the form:
  149.  *        <program> ==> <function-list> <expression> EOF
  150.  *            | <function-list> EOF
  151.  *            | <function-list> <expression> ;
  152.  *
  153.  *        <function-list> ==> <function> <function-list>
  154.  *                | empty
  155.  */
  156.  
  157. program()
  158. {
  159.     cpos = 0; lineno = 1;
  160.  
  161.     token = gettoken();
  162.     for(;;) {
  163.         if( token != IDENTIFIER ) break;
  164.         function();
  165.     }
  166.  
  167.     if( token != EOF ) {
  168.         startPC = PC;
  169.         expression();
  170.         push(NULL,0);
  171.     }
  172.     if( token != EOF && token != ';') error("EOF expected");
  173. }
  174.  
  175. /* ----------------------------------------------------------------------
  176.  * function:
  177.  *    parse a function definition. Grammer for a function is:
  178.  *    <function> ==> IDENTIFIER <id-list> { RETURN <expression> ; }
  179.  *
  180.  *    <id-list> ==> ( <ids> )
  181.  *            | ( )
  182.  *            | empty
  183.  *
  184.  *    <ids> ==> IDENTIFIER <idtail>
  185.  *
  186.  *    <idtail> ==> , <ids>
  187.  *        | empty
  188.  *
  189.  */
  190.  
  191. function()
  192. {
  193.     struct symbol *s;
  194.  
  195.     s = tokensym;
  196.     tokensym->value = PC;
  197.     tokensym->type = FUNCTION;
  198.     tokensym->func = c_func;
  199.  
  200.     token = gettoken();
  201.  
  202.     push(NULL, idlist() );        /* save number of args for function */
  203.  
  204.     if( token != '{' ) error("expected '{'");
  205.     token = gettoken();
  206.  
  207.     if( token != RETURN ) error("expected keyword: return");
  208.     token = gettoken();
  209.  
  210.     expression();
  211.  
  212.     if( token != ';' ) error("expected ';'");
  213.     token = gettoken();
  214.  
  215.     push(c_return,StackProgram[s->value].value);
  216.  
  217.     /* free up the parameter symbols */
  218.     while( symbols->type == PARAM ) {
  219.         s = symbols;
  220.         symbols = symbols->next;
  221.         free(s->name);
  222.         free(s);
  223.     }
  224.  
  225.     if( token != '}' ) error("expected '}'");
  226.     token = gettoken();
  227. }
  228.  
  229. /* ----------------------------------------------------------------------
  230.  * idlist:
  231.  *    Return the maximum offset obtained in parsing the parameter list.
  232.  *    <id-list> ==> ( <ids> )
  233.  *        | ()
  234.  *        | empty
  235.  *
  236.  *    <ids> ==> IDENTIFIER <idtail>
  237.  *    <idtail> ==> <ids> , <idtail>
  238.  *        | empty
  239.  */
  240.  
  241. idlist()
  242. {
  243.     int offset = 0;
  244.  
  245.     if( token == '(' ) token = gettoken();
  246.     else if( token == '{' ) return(0);
  247.     else error("expected '(' or '{'");
  248.  
  249.     if( token == ')' ) {
  250.         token = gettoken();
  251.         return(0);
  252.     }
  253.  
  254.     for(;;) {
  255.         if( token != IDENTIFIER ) error("identifier expected");
  256.         tokensym->type = PARAM;
  257.         tokensym->func = c_param;
  258.         tokensym->value = offset++;
  259.         token = gettoken();
  260.         if( token == ')' ) break;
  261.         if( token != ',' ) error("expected ')'");
  262.         token = gettoken();
  263.     }
  264.  
  265.     token = gettoken();
  266.     return(offset);
  267. }
  268.  
  269. /* ----------------------------------------------------------------------
  270.  * expression:
  271.  *    Parse an expression. (top-level routine)
  272.  *    OPERATOR ?:
  273.  *
  274.  */
  275.  
  276. expression()
  277. {
  278.     int qm,colon,nop;
  279.  
  280.     expr0();
  281.     if( token == '?' ) {
  282.         token = gettoken();
  283.         qm = PC;
  284.         push(c_qm,0);
  285.         expression();
  286.         if( token != ':' ) error("missing ':'");
  287.         token = gettoken();
  288.         colon = PC;
  289.         push(c_colon,0);
  290.         expression();
  291.  
  292.         StackProgram[qm].value = colon;
  293.         StackProgram[colon].value = PC-1;
  294.     }
  295. }
  296.  
  297. /* OPERATOR || */
  298. expr0()
  299. {
  300.     expr1();
  301.     for(;;)
  302.         if( token == OR ) {
  303.             token = gettoken();
  304.             expr1();
  305.             push(c_or,0);
  306.            } else break;
  307. }
  308.  
  309. /* OPERATOR && */
  310. expr1()
  311. {
  312.     expr2();
  313.     for(;;)
  314.         if( token == AND ) {
  315.             token = gettoken();
  316.             expr2();
  317.             push(c_and,0);
  318.         } else break;
  319. }
  320.  
  321. /* OPERATOR | */
  322. expr2()
  323. {
  324.     expr3();
  325.     for(;;)
  326.         if( token == '|' ) {
  327.             token = gettoken();
  328.             expr3();
  329.             push(c_bor,0);
  330.         } else break;
  331. }
  332.  
  333. /* OPERATOR ^ */
  334. expr3()
  335. {
  336.     expr4();
  337.     for(;;)
  338.         if( token == '^' ) {
  339.             token = gettoken();
  340.             expr4();
  341.             push(c_bxor,0);
  342.         } else break;
  343. }
  344.  
  345. /* OPERATOR & */
  346. expr4()
  347. {
  348.     expr5();
  349.     for(;;)
  350.         if( token == '&' ) {
  351.             token = gettoken();
  352.             expr5();
  353.             push(c_band,0);
  354.         } else break;
  355. }
  356.  
  357. /* OPERATOR == != */
  358. expr5()
  359. {
  360.     int t;
  361.     expr6();
  362.     for(;t=token;)
  363.         if( t==EQ ) {
  364.             token = gettoken();
  365.             expr6();
  366.             push(c_eq,0);
  367.         } else if( t==NE ) {
  368.             token = gettoken();
  369.             expr6();
  370.             push(c_ne,0);
  371.         } else break;
  372. }
  373.  
  374. /* OPERATOR < <= > >= */
  375. expr6()
  376. {
  377.     int t;
  378.     expr7();
  379.     for(;t=token;)
  380.         if( t==LE ) {
  381.             token = gettoken();
  382.             expr7();
  383.             push(c_le,0);
  384.         } else if( t==GE ) {
  385.             token = gettoken();
  386.             expr7();
  387.             push(c_ge,0);
  388.         } else if( t=='>' ) {
  389.             token = gettoken();
  390.             expr7();
  391.             push(c_gt,0);
  392.         } else if( t=='<' ) {
  393.             token = gettoken();
  394.             expr7();
  395.             push(c_lt,0);
  396.         } else break;
  397. }
  398.  
  399. /* OPERATOR << >> */
  400. expr7()
  401. {
  402.     int t;
  403.     expr8();
  404.     for(;t=token;)
  405.         if( t==SHIFTL ) {
  406.             token = gettoken();
  407.             expr8();
  408.             push(c_lshift,0);
  409.         } else if( t==SHIFTR ) {
  410.             token = gettoken();
  411.             expr8();
  412.             push(c_rshift,0);
  413.         } else break;
  414. }
  415.  
  416. /* OPERATOR + - */
  417. expr8()
  418. {
  419.     int t;
  420.     expr9();
  421.     for(;t=token;)
  422.         if( t=='+' ) {
  423.             token = gettoken();
  424.             expr9();
  425.             push(c_plus,0);
  426.         } else if( t=='-' ) {
  427.             token = gettoken();
  428.             expr9();
  429.             push(c_minus,0);
  430.         } else break;
  431. }
  432.  
  433. /* OPERATOR * / % */
  434. expr9()
  435. {
  436.     int t;
  437.     expr10();
  438.     for(;t=token;)
  439.         if( t== '*' ) {
  440.             token = gettoken();
  441.             expr10();
  442.             push(c_mul,0);
  443.         } else if( t== '/' ) {
  444.             token = gettoken();
  445.             expr10();
  446.             push(c_div,0);
  447.         } else if( t== '%' ) {
  448.             token = gettoken();
  449.             expr10();
  450.             push(c_mod,0);
  451.         } else break;
  452. }
  453.  
  454. /* OPERATOR ~ ! - */
  455. expr10()
  456. {
  457.     int t;
  458.     t = token;
  459.     if( t=='!' ){
  460.         token = gettoken();
  461.         expr10();
  462.         push(c_not,0);
  463.     } else if( t== '~' ) {
  464.         token = gettoken();
  465.         expr10();
  466.         push(c_bnot,0);
  467.     } else if( t== '-' ) {
  468.         token = gettoken();
  469.         expr10();
  470.         push(c_uniminus,0);
  471.     } else factor();
  472. }
  473.  
  474. /* ----------------------------------------------------------------------
  475.  * explist:
  476.  *    argc is the number of arguments expected.
  477.  *    Parse an expression list of the form:
  478.  *        <explist> ==> ( <exps> )
  479.  *            | ( )
  480.  *            | empty
  481.  *
  482.  *        <exps> ==> <exps> , <expression>
  483.  *            | <expression>
  484.  *
  485.  */
  486.  
  487. explist( argc )
  488. {
  489.     if( token != '(' && !argc ) return;
  490.  
  491.     if( token != '(' ) error("missing '('");
  492.     token = gettoken();
  493.  
  494.     if( !argc && token == ')' ) {
  495.         token = gettoken();
  496.         return;
  497.     }
  498.  
  499.     for(;;) {
  500.         expression();
  501.         argc--;
  502.         if( token == ')' ) break;
  503.         if( token != ',' ) error("missing ','");
  504.         token = gettoken();
  505.     }
  506.  
  507.     token = gettoken();
  508.     if( argc ) error("wrong number of arguments");
  509. }
  510.  
  511. /* ----------------------------------------------------------------------
  512.  * factor:
  513.  *    Parse a factor. Could be a number, variable, date, function call or
  514.  *    regular expression string.
  515.  */
  516.  
  517. factor()
  518. {
  519.     long l,datespec();
  520.     int pc;
  521.  
  522.         switch((int)token) {
  523.         case '(':
  524.             token = gettoken();
  525.             expression();
  526.             if( token != ')' )
  527.                 error("missing ')'");
  528.             token = gettoken();
  529.             break;
  530.         case NUMBER:
  531.             push(c_number,tokenval);
  532.             token = gettoken();
  533.             break;
  534.         case FUNCTION:
  535.             pc = tokensym->value;
  536.             token = gettoken();
  537.             explist( StackProgram[ pc ].value );
  538.             push(c_func,pc);
  539.             break;
  540.         case PARAM:
  541.             push(c_param,tokensym->value);
  542.             token = gettoken();
  543.             break;
  544.         case FIELD:
  545.             push(tokensym->func,tokenval);
  546.             token = gettoken();
  547.             break;
  548.         case '[':
  549.             token = gettoken();
  550.             l=datespec();
  551.             if( token != ']' )
  552.                 error("missing ']'");
  553.             token = gettoken();
  554.             push(c_number,l);
  555.             break;
  556.         case STR:
  557.             push(c_str,tokenval);
  558.             token = gettoken();
  559.             break;
  560.         case IDENTIFIER:
  561.             error("undefined identifier");
  562.         default:
  563.             error("syntax error");
  564.     }
  565. }
  566.  
  567. /* ----------------------------------------------------------------------
  568.  * sectime:
  569.  *    calculate the number of seconds between January 1, 1970
  570.  *    and year/month/day. Return that value.
  571.  *
  572.  */
  573.  
  574. #define leap(d)    (((d % 4 == 0) && (d % 100 != 0)) || (d % 400 == 0))
  575. #define DAYSEC    (3600*24)
  576. #define YERSEC    (3600*24*365)
  577. #define TIME0    1970
  578.  
  579. long sectime(year,month,day)
  580. int year,month,day;
  581. {
  582.  
  583.         static int months[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
  584.     int yeardays,leapers,x;
  585.     long seconds;
  586.  
  587.     if(month>12 || month<1 || year<TIME0 || day<1 || day>months[month]+
  588.         (month==2 && leap(year)) )
  589.             return(-1);
  590.  
  591.     yeardays = leapers = 0;
  592.  
  593.     for(x=1;x<month;x++)
  594.         yeardays += months[x];
  595.     if ((month > 2) && leap(year)) yeardays++;
  596.  
  597.     for(x=TIME0; x<year; x++)
  598.         if(leap(x)) leapers++;
  599.  
  600.     seconds = yeardays*DAYSEC+(year-TIME0)*YERSEC+7*3600+
  601.             leapers*DAYSEC + day*DAYSEC;
  602.  
  603.     return(seconds);
  604.  
  605. }
  606.  
  607. /* ----------------------------------------------------------------------
  608.  * datespec:
  609.  *    parse a date. Return the number of seconds from
  610.  *    some date in 1970, until the specified date.
  611.  */
  612.  
  613. long datespec()
  614. {
  615.     int year,month,day,seconds;
  616.  
  617.     if( token != NUMBER ) error("number expected");
  618.     year = tokenval;
  619.     token = gettoken();
  620.     if( token != '/' ) error("missing '/'");
  621.     token = gettoken();
  622.     if( token != NUMBER ) error("number expected");
  623.     month = tokenval;
  624.     token = gettoken();
  625.     if( token != '/' ) error("missing '/'");
  626.     token = gettoken();
  627.     if( token != NUMBER ) error("number expected");
  628.     day = tokenval;
  629.     token = gettoken();
  630.  
  631.     if( (seconds = sectime(year,month,day)) < 0 )
  632.         error("invalid date");
  633.  
  634.     return(seconds);
  635. }
  636.  
  637.  
  638. /* ----------------------------------------------------------------------
  639.  * gettoken:
  640.  *    Return the next token.
  641.  *    global variable: tokenval will contain any extra
  642.  *    attribute associated with the returned token, ie
  643.  *    the VALUE of a number, the index of the string etc...
  644.  *    tokensym will be a pointer to the symbol table entry for
  645.  *    any symbol encountered.
  646.  *
  647.  */
  648.  
  649. gettoken()
  650. {
  651.     char buf[IDLENGTH+1],*bufp=buf;
  652.     int c,incomment;
  653.  
  654.     incomment = 0;
  655.     c = getit();
  656.     while( c == ' ' || c == '\t' || c == '\n' || c == '/' || incomment) {
  657.        if( c == '/' && !incomment) {
  658.         c = getit();
  659.         if( c != '*' ) {
  660.             ungetit(c);
  661.             c = '/';
  662.             break;
  663.         }
  664.         incomment = 1;
  665.        } else if( c == '*' ) {
  666.         c = getit();
  667.         if( c == '/' ) incomment = 0;
  668.        }
  669.        c = getit();
  670.     }
  671.  
  672.     if(c=='0') {
  673.         tokenval=0;
  674.         while( ( c=getit() ) >= '0' && c <= '7' ) {
  675.             tokenval <<= 3;
  676.             tokenval += c-'0';
  677.         }
  678.         if( isdigit(c) ) error("bad octal constant");
  679.         ungetit(c);
  680.         return(NUMBER);
  681.     }
  682.  
  683.     if(isdigit(c)) {
  684.         tokenval=c-'0';
  685.         while(isdigit( (c=getit()) )) {
  686.             tokenval *=10;
  687.             tokenval += c-'0';
  688.         }
  689.         ungetit(c);
  690.         return(NUMBER);
  691.     }
  692.  
  693.     if(isalpha(c)) {
  694.        int count=0;
  695.        do {
  696.         if(count++ < IDLENGTH) *bufp++ = c;
  697.         c=getit();
  698.        } while( isalnum(c) );
  699.        ungetit(c);
  700.        *bufp='\0';
  701.        if( (tokensym=locatename(buf)) == NULL ) {
  702.             tokensym = insertname(buf,IDENTIFIER,0);
  703.        }
  704.        tokenval = tokensym->value;
  705.        return( tokensym->type );
  706.     }
  707.  
  708.     if( c == '"' ) {
  709.         tokenval=strfree;
  710.         while( (c=getit()) != '"' ) {
  711.             if( strfree > STRLEN )
  712.                 error("no more string space");
  713.             Strbuf[strfree++]= c;
  714.         }
  715.         Strbuf[strfree++]='\0';
  716.         return(STR);
  717.     }
  718.  
  719.     if( c == '=' ) {
  720.         c=getit();
  721.         if(c== '=') return(EQ);
  722.         else {
  723.             ungetit(c);
  724.             return('=');
  725.         }
  726.     }
  727.  
  728. #ifndef MSDOS
  729.     if( c== '$' ) {
  730.        int count=0;
  731.        struct passwd *info,*getpwnam();
  732.        c=getit();
  733.        if( c=='$' ) {
  734.         tokenval = getuid();
  735.         return( NUMBER );
  736.        }
  737.        do {
  738.         if (count++ < IDLENGTH) *bufp++ = c;
  739.         c=getit();
  740.        } while( isalnum(c) );
  741.        ungetit(c);
  742.        *bufp='\0';
  743.        if( (info=getpwnam(buf)) == NULL )
  744.         error("no such user");
  745.        tokenval = info->pw_uid;
  746.        return( NUMBER );
  747.         }
  748. #endif
  749.  
  750.     if( c == '!' ) {
  751.         c=getit();
  752.         if( c == '=' ) return(NE);
  753.         ungetit(c);
  754.         return('!');
  755.     }
  756.  
  757.     if( c == '>' ) {
  758.         c=getit();
  759.         if( c == '=' ) return(GE);
  760.         if( c == '>' ) return(SHIFTR);
  761.         ungetit(c);
  762.         return('>');
  763.     }
  764.  
  765.     if( c == '<' ) {
  766.         c=getit();
  767.         if( c == '=' ) return(LE);
  768.         if( c == '<' ) return(SHIFTL);
  769.         ungetit(c);
  770.         return('<');
  771.     }
  772.  
  773.     if( c == '&' ) {
  774.         c=getit();
  775.         if( c == '&' ) return(AND);
  776.         ungetit(c);
  777.         return('&');
  778.     }
  779.  
  780.     if( c == '|' ) {
  781.         c=getit();
  782.         if( c == '|' ) return(OR);
  783.         ungetit(c);
  784.         return('|');
  785.     }
  786.  
  787.     return(c);
  788. }
  789.