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

Generated on Wed Mar 13 15:34:46 2002 for rpm by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002