Main Page   Modules   Compound List   File List   Compound Members   File Members   Related Pages  

build/expression.c

Go to the documentation of this file.
00001 
00014 #include "system.h"
00015 
00016 #include <rpmbuild.h>
00017 #include <rpmlib.h>
00018 
00019 #include "debug.h"
00020 
00021 /* #define DEBUG_PARSER 1 */
00022 
00023 #ifdef DEBUG_PARSER
00024 #include <stdio.h>
00025 #define DEBUG(x) do { x ; } while (0)
00026 #else
00027 #define DEBUG(x)
00028 #endif
00029 
00033 typedef struct _value {
00034   enum { VALUE_TYPE_INTEGER, VALUE_TYPE_STRING } type;
00035   union {
00036     const char *s;
00037     int i;
00038   } data;
00039 } *Value;
00040 
00043 static Value valueMakeInteger(int i)
00044 {
00045   Value v;
00046 
00047   v = (Value) xmalloc(sizeof(struct _value));
00048   v->type = VALUE_TYPE_INTEGER;
00049   v->data.i = i;
00050   return v;
00051 }
00052 
00055 static Value valueMakeString(/*@only@*/ const char *s)
00056 {
00057   Value v;
00058 
00059   v = (Value) xmalloc(sizeof(struct _value));
00060   v->type = VALUE_TYPE_STRING;
00061   v->data.s = s;
00062   return v;
00063 }
00064 
00067 static void valueFree( /*@only@*/ Value v)
00068 {
00069   if (v) {
00070     if (v->type == VALUE_TYPE_STRING) free((void *)v->data.s);
00071     free(v);
00072   }
00073 }
00074 
00075 #ifdef DEBUG_PARSER
00076 static void valueDump(const char *msg, Value v, FILE *fp)
00077 {
00078   if (msg)
00079     fprintf(fp, "%s ", msg);
00080   if (v) {
00081     if (v->type == VALUE_TYPE_INTEGER)
00082       fprintf(fp, "INTEGER %d\n", v->data.i);
00083     else
00084       fprintf(fp, "STRING '%s'\n", v->data.s);
00085   } else
00086     fprintf(fp, "NULL\n");
00087 }
00088 #endif
00089 
00090 #define valueIsInteger(v) ((v)->type == VALUE_TYPE_INTEGER)
00091 #define valueIsString(v) ((v)->type == VALUE_TYPE_STRING)
00092 #define valueSameType(v1,v2) ((v1)->type == (v2)->type)
00093 
00094 
00098 typedef struct _parseState {
00099   /*@owned@*/ char *str;        
00100   /*@dependent@*/ char *p;      
00101   int nextToken;                
00102   Value tokenValue;             
00103   Spec spec;                    
00104 } *ParseState;
00105 
00106 
00111 #define TOK_EOF          1
00112 #define TOK_INTEGER      2
00113 #define TOK_STRING       3
00114 #define TOK_IDENTIFIER   4
00115 #define TOK_ADD          5
00116 #define TOK_MINUS        6
00117 #define TOK_MULTIPLY     7
00118 #define TOK_DIVIDE       8
00119 #define TOK_OPEN_P       9
00120 #define TOK_CLOSE_P     10
00121 #define TOK_EQ          11
00122 #define TOK_NEQ         12
00123 #define TOK_LT          13
00124 #define TOK_LE          14
00125 #define TOK_GT          15
00126 #define TOK_GE          16
00127 #define TOK_NOT         17
00128 #define TOK_LOGICAL_AND 18
00129 #define TOK_LOGICAL_OR  19
00130 
00132 #define EXPRBUFSIZ      BUFSIZ
00133 
00134 #if defined(DEBUG_PARSER)
00135 typedef struct exprTokTableEntry {
00136     const char *name;
00137     int val;
00138 } ETTE_t;
00139 
00140 ETTE_t exprTokTable[] = {
00141     { "EOF",    TOK_EOF },
00142     { "I",      TOK_INTEGER },
00143     { "S",      TOK_STRING },
00144     { "ID",     TOK_IDENTIFIER },
00145     { "+",      TOK_ADD },
00146     { "-",      TOK_MINUS },
00147     { "*",      TOK_MULTIPLY },
00148     { "/",      TOK_DIVIDE },
00149     { "( ",     TOK_OPEN_P },
00150     { " )",     TOK_CLOSE_P },
00151     { "==",     TOK_EQ },
00152     { "!=",     TOK_NEQ },
00153     { "<",      TOK_LT },
00154     { "<=",     TOK_LE },
00155     { ">",      TOK_GT },
00156     { ">=",     TOK_GE },
00157     { "!",      TOK_NOT },
00158     { "&&",     TOK_LOGICAL_AND },
00159     { "||",     TOK_LOGICAL_OR },
00160     { NULL, 0 }
00161 };
00162 
00163 static const char *prToken(int val)
00164 {
00165     ETTE_t *et;
00166     
00167     for (et = exprTokTable; et->name != NULL; et++) {
00168         if (val == et->val)
00169             return et->name;
00170     }
00171     return "???";
00172 }
00173 #endif  /* DEBUG_PARSER */
00174 
00178 static int rdToken(ParseState state)
00179 {
00180   int token;
00181   Value v = NULL;
00182   char *p = state->p;
00183 
00184   /* Skip whitespace before the next token. */
00185   while (*p && isspace(*p)) p++;
00186 
00187   switch (*p) {
00188   case '\0':
00189     token = TOK_EOF;
00190     p--;
00191     break;
00192   case '+':
00193     token = TOK_ADD;
00194     break;
00195   case '-':
00196     token = TOK_MINUS;
00197     break;
00198   case '*':
00199     token = TOK_MULTIPLY;
00200     break;
00201   case '/':
00202     token = TOK_DIVIDE;
00203     break;
00204   case '(':
00205     token = TOK_OPEN_P;
00206     break;
00207   case ')':
00208     token = TOK_CLOSE_P;
00209     break;
00210   case '=':
00211     if (p[1] == '=') {
00212       token = TOK_EQ;
00213       p++;
00214     } else {
00215       rpmError(RPMERR_BADSPEC, _("syntax error while parsing ==\n"));
00216       return -1;
00217     }
00218     break;
00219   case '!':
00220     if (p[1] == '=') {
00221       token = TOK_NEQ;
00222       p++;
00223     } else
00224       token = TOK_NOT;
00225     break;
00226   case '<':
00227     if (p[1] == '=') {
00228       token = TOK_LE;
00229       p++;
00230     } else
00231       token = TOK_LT;
00232     break;
00233   case '>':
00234     if (p[1] == '=') {
00235       token = TOK_GE;
00236       p++;
00237     } else
00238       token = TOK_GT;
00239     break;
00240   case '&':
00241     if (p[1] == '&') {
00242       token = TOK_LOGICAL_AND;
00243       p++;
00244     } else {
00245       rpmError(RPMERR_BADSPEC, _("syntax error while parsing &&\n"));
00246       return -1;
00247     }
00248     break;
00249   case '|':
00250     if (p[1] == '|') {
00251       token = TOK_LOGICAL_OR;
00252       p++;
00253     } else {
00254       rpmError(RPMERR_BADSPEC, _("syntax error while parsing ||\n"));
00255       return -1;
00256     }
00257     break;
00258 
00259   default:
00260     if (isdigit(*p)) {
00261       char temp[EXPRBUFSIZ], *t = temp;
00262 
00263       while (*p && isdigit(*p))
00264         *t++ = *p++;
00265       *t++ = '\0';
00266       p--;
00267 
00268       token = TOK_INTEGER;
00269       v = valueMakeInteger(atoi(temp));
00270 
00271     } else if (isalpha(*p)) {
00272       char temp[EXPRBUFSIZ], *t = temp;
00273 
00274       while (*p && (isalnum(*p) || *p == '_'))
00275         *t++ = *p++;
00276       *t++ = '\0';
00277       p--;
00278 
00279       token = TOK_IDENTIFIER;
00280       v = valueMakeString( xstrdup(temp) );
00281 
00282     } else if (*p == '\"') {
00283       char temp[EXPRBUFSIZ], *t = temp;
00284 
00285       p++;
00286       while (*p && *p != '\"')
00287         *t++ = *p++;
00288       *t++ = '\0';
00289 
00290       token = TOK_STRING;
00291       v = valueMakeString( rpmExpand(temp, NULL) );
00292 
00293     } else {
00294       rpmError(RPMERR_BADSPEC, _("parse error in expression\n"));
00295       return -1;
00296     }
00297   }
00298 
00299   state->p = p + 1;
00300   state->nextToken = token;
00301   state->tokenValue = v;
00302 
00303   DEBUG(printf("rdToken: \"%s\" (%d)\n", prToken(token), token));
00304   DEBUG(valueDump("rdToken:", state->tokenValue, stdout));
00305 
00306   return 0;
00307 }
00308 
00309 static Value doLogical(ParseState state);
00310 
00314 static Value doPrimary(ParseState state)
00315 {
00316   Value v;
00317 
00318   DEBUG(printf("doPrimary()\n"));
00319 
00320   switch (state->nextToken) {
00321   case TOK_OPEN_P:
00322     if (rdToken(state))
00323       return NULL;
00324     v = doLogical(state);
00325     if (state->nextToken != TOK_CLOSE_P) {
00326       rpmError(RPMERR_BADSPEC, _("unmatched (\n"));
00327       return NULL;
00328     }
00329     break;
00330 
00331   case TOK_INTEGER:
00332   case TOK_STRING:
00333     v = state->tokenValue;
00334     if (rdToken(state))
00335       return NULL;
00336     break;
00337 
00338   case TOK_IDENTIFIER: {
00339     const char *name = state->tokenValue->data.s;
00340 
00341     v = valueMakeString( rpmExpand(name, NULL) );
00342     if (rdToken(state))
00343       return NULL;
00344     break;
00345   }
00346 
00347   case TOK_MINUS:
00348     if (rdToken(state))
00349       return NULL;
00350 
00351     v = doPrimary(state);
00352     if (v == NULL)
00353       return NULL;
00354 
00355     if (! valueIsInteger(v)) {
00356       rpmError(RPMERR_BADSPEC, _("- only on numbers\n"));
00357       return NULL;
00358     }
00359 
00360     v = valueMakeInteger(- v->data.i);
00361     break;
00362 
00363   case TOK_NOT:
00364     if (rdToken(state))
00365       return NULL;
00366 
00367     v = doPrimary(state);
00368     if (v == NULL)
00369       return NULL;
00370 
00371     if (! valueIsInteger(v)) {
00372       rpmError(RPMERR_BADSPEC, _("! only on numbers\n"));
00373       return NULL;
00374     }
00375 
00376     v = valueMakeInteger(! v->data.i);
00377     break;
00378   default:
00379     return NULL;
00380     /*@notreached@*/ break;
00381   }
00382 
00383   DEBUG(valueDump("doPrimary:", v, stdout));
00384   return v;
00385 }
00386 
00390 static Value doMultiplyDivide(ParseState state)
00391 {
00392   Value v1, v2 = NULL;
00393 
00394   DEBUG(printf("doMultiplyDivide()\n"));
00395 
00396   v1 = doPrimary(state);
00397   if (v1 == NULL)
00398     return NULL;
00399 
00400   while (state->nextToken == TOK_MULTIPLY
00401          || state->nextToken == TOK_DIVIDE) {
00402     int op = state->nextToken;
00403 
00404     if (rdToken(state))
00405       return NULL;
00406 
00407     if (v2) valueFree(v2);
00408 
00409     v2 = doPrimary(state);
00410     if (v2 == NULL)
00411       return NULL;
00412 
00413     if (! valueSameType(v1, v2)) {
00414       rpmError(RPMERR_BADSPEC, _("types must match\n"));
00415       return NULL;
00416     }
00417 
00418     if (valueIsInteger(v1)) {
00419       int i1 = v1->data.i, i2 = v2->data.i;
00420 
00421       valueFree(v1);
00422       if (op == TOK_MULTIPLY)
00423         v1 = valueMakeInteger(i1 * i2);
00424       else
00425         v1 = valueMakeInteger(i1 / i2);
00426     } else {
00427       rpmError(RPMERR_BADSPEC, _("* / not suported for strings\n"));
00428       return NULL;
00429     }
00430   }
00431 
00432   if (v2) valueFree(v2);
00433   return v1;
00434 }
00435 
00439 static Value doAddSubtract(ParseState state)
00440 {
00441   Value v1, v2 = NULL;
00442 
00443   DEBUG(printf("doAddSubtract()\n"));
00444 
00445   v1 = doMultiplyDivide(state);
00446   if (v1 == NULL)
00447     return NULL;
00448 
00449   while (state->nextToken == TOK_ADD || state->nextToken == TOK_MINUS) {
00450     int op = state->nextToken;
00451 
00452     if (rdToken(state))
00453       return NULL;
00454 
00455     if (v2) valueFree(v2);
00456 
00457     v2 = doMultiplyDivide(state);
00458     if (v2 == NULL)
00459       return NULL;
00460 
00461     if (! valueSameType(v1, v2)) {
00462       rpmError(RPMERR_BADSPEC, _("types must match\n"));
00463       return NULL;
00464     }
00465 
00466     if (valueIsInteger(v1)) {
00467       int i1 = v1->data.i, i2 = v2->data.i;
00468 
00469       valueFree(v1);
00470       if (op == TOK_ADD)
00471         v1 = valueMakeInteger(i1 + i2);
00472       else
00473         v1 = valueMakeInteger(i1 - i2);
00474     } else {
00475       char *copy;
00476 
00477       if (op == TOK_MINUS) {
00478         rpmError(RPMERR_BADSPEC, _("- not suported for strings\n"));
00479         return NULL;
00480       }
00481 
00482       copy = xmalloc(strlen(v1->data.s) + strlen(v2->data.s) + 1);
00483       (void) stpcpy( stpcpy(copy, v1->data.s), v2->data.s);
00484 
00485       valueFree(v1);
00486       v1 = valueMakeString(copy);
00487     }
00488   }
00489 
00490   if (v2) valueFree(v2);
00491   return v1;
00492 }
00493 
00497 static Value doRelational(ParseState state)
00498 {
00499   Value v1, v2 = NULL;
00500 
00501   DEBUG(printf("doRelational()\n"));
00502 
00503   v1 = doAddSubtract(state);
00504   if (v1 == NULL)
00505     return NULL;
00506 
00507   while (state->nextToken >= TOK_EQ && state->nextToken <= TOK_GE) {
00508     int op = state->nextToken;
00509 
00510     if (rdToken(state))
00511       return NULL;
00512 
00513     if (v2) valueFree(v2);
00514 
00515     v2 = doAddSubtract(state);
00516     if (v2 == NULL)
00517       return NULL;
00518 
00519     if (! valueSameType(v1, v2)) {
00520       rpmError(RPMERR_BADSPEC, _("types must match\n"));
00521       return NULL;
00522     }
00523 
00524     if (valueIsInteger(v1)) {
00525       int i1 = v1->data.i, i2 = v2->data.i, r = 0;
00526       switch (op) {
00527       case TOK_EQ:
00528         r = (i1 == i2);
00529         break;
00530       case TOK_NEQ:
00531         r = (i1 != i2);
00532         break;
00533       case TOK_LT:
00534         r = (i1 < i2);
00535         break;
00536       case TOK_LE:
00537         r = (i1 <= i2);
00538         break;
00539       case TOK_GT:
00540         r = (i1 > i2);
00541         break;
00542       case TOK_GE:
00543         r = (i1 >= i2);
00544         break;
00545       default:
00546         break;
00547       }
00548       valueFree(v1);
00549       v1 = valueMakeInteger(r);
00550     } else {
00551       const char * s1 = v1->data.s;
00552       const char * s2 = v2->data.s;
00553       int r = 0;
00554       switch (op) {
00555       case TOK_EQ:
00556         r = (strcmp(s1,s2) == 0);
00557         break;
00558       case TOK_NEQ:
00559         r = (strcmp(s1,s2) != 0);
00560         break;
00561       case TOK_LT:
00562         r = (strcmp(s1,s2) < 0);
00563         break;
00564       case TOK_LE:
00565         r = (strcmp(s1,s2) <= 0);
00566         break;
00567       case TOK_GT:
00568         r = (strcmp(s1,s2) > 0);
00569         break;
00570       case TOK_GE:
00571         r = (strcmp(s1,s2) >= 0);
00572         break;
00573       default:
00574         break;
00575       }
00576       valueFree(v1);
00577       v1 = valueMakeInteger(r);
00578     }
00579   }
00580 
00581   if (v2) valueFree(v2);
00582   return v1;
00583 }
00584 
00588 static Value doLogical(ParseState state)
00589 {
00590   Value v1, v2 = NULL;
00591 
00592   DEBUG(printf("doLogical()\n"));
00593 
00594   v1 = doRelational(state);
00595   if (v1 == NULL)
00596     return NULL;
00597 
00598   while (state->nextToken == TOK_LOGICAL_AND
00599          || state->nextToken == TOK_LOGICAL_OR) {
00600     int op = state->nextToken;
00601 
00602     if (rdToken(state))
00603       return NULL;
00604 
00605     if (v2) valueFree(v2);
00606 
00607     v2 = doRelational(state);
00608     if (v2 == NULL)
00609       return NULL;
00610 
00611     if (! valueSameType(v1, v2)) {
00612       rpmError(RPMERR_BADSPEC, _("types must match\n"));
00613       return NULL;
00614     }
00615 
00616     if (valueIsInteger(v1)) {
00617       int i1 = v1->data.i, i2 = v2->data.i;
00618 
00619       valueFree(v1);
00620       if (op == TOK_LOGICAL_AND)
00621         v1 = valueMakeInteger(i1 && i2);
00622       else
00623         v1 = valueMakeInteger(i1 || i2);
00624     } else {
00625       rpmError(RPMERR_BADSPEC, _("&& and || not suported for strings\n"));
00626       return NULL;
00627     }
00628   }
00629 
00630   if (v2) valueFree(v2);
00631   return v1;
00632 }
00633 
00634 int parseExpressionBoolean(Spec spec, const char *expr)
00635 {
00636   struct _parseState state;
00637   int result = -1;
00638   Value v;
00639 
00640   DEBUG(printf("parseExprBoolean(?, '%s')\n", expr));
00641 
00642   /* Initialize the expression parser state. */
00643   state.p = state.str = xstrdup(expr);
00644   state.spec = spec;
00645   state.nextToken = 0;
00646   state.tokenValue = NULL;
00647   rdToken(&state);
00648 
00649   /* Parse the expression. */
00650   v = doLogical(&state);
00651   if (!v) {
00652     free(state.str);
00653     return -1;
00654   }
00655 
00656   /* If the next token is not TOK_EOF, we have a syntax error. */
00657   if (state.nextToken != TOK_EOF) {
00658     rpmError(RPMERR_BADSPEC, _("syntax error in expression\n"));
00659     free(state.str);
00660     return -1;
00661   }
00662 
00663   DEBUG(valueDump("parseExprBoolean:", v, stdout));
00664 
00665   switch (v->type) {
00666   case VALUE_TYPE_INTEGER:
00667     result = v->data.i != 0;
00668     break;
00669   case VALUE_TYPE_STRING:
00670     result = v->data.s[0] != '\0';
00671     break;
00672   default:
00673     break;
00674   }
00675 
00676   free(state.str);
00677   valueFree(v);
00678   return result;
00679 }
00680 
00681 char * parseExpressionString(Spec spec, const char *expr)
00682 {
00683   struct _parseState state;
00684   char *result = NULL;
00685   Value v;
00686 
00687   DEBUG(printf("parseExprString(?, '%s')\n", expr));
00688 
00689   /* Initialize the expression parser state. */
00690   state.p = state.str = xstrdup(expr);
00691   state.spec = spec;
00692   state.nextToken = 0;
00693   state.tokenValue = NULL;
00694   rdToken(&state);
00695 
00696   /* Parse the expression. */
00697   v = doLogical(&state);
00698   if (!v) {
00699     free(state.str);
00700     return NULL;
00701   }
00702 
00703   /* If the next token is not TOK_EOF, we have a syntax error. */
00704   if (state.nextToken != TOK_EOF) {
00705     rpmError(RPMERR_BADSPEC, _("syntax error in expression\n"));
00706     free(state.str);
00707     return NULL;
00708   }
00709 
00710   DEBUG(valueDump("parseExprString:", v, stdout));
00711 
00712   switch (v->type) {
00713   case VALUE_TYPE_INTEGER: {
00714     char buf[128];
00715     sprintf(buf, "%d", v->data.i);
00716     result = xstrdup(buf);
00717   } break;
00718   case VALUE_TYPE_STRING:
00719     result = xstrdup(v->data.s);
00720     break;
00721   default:
00722     break;
00723   }
00724 
00725   free(state.str);
00726   valueFree(v);
00727   return result;
00728 }

Generated at Mon May 21 08:53:38 2001 for rpm by doxygen1.2.6 written by Dimitri van Heesch, © 1997-2001