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       while (*p && xisdigit(*p))
00265         *t++ = *p++;
00266       *t++ = '\0';
00267       p--;
00268 
00269       token = TOK_INTEGER;
00270       v = valueMakeInteger(atoi(temp));
00271 
00272     } else if (xisalpha(*p)) {
00273       char temp[EXPRBUFSIZ], *t = temp;
00274 
00275       while (*p && (xisalnum(*p) || *p == '_'))
00276         *t++ = *p++;
00277       *t++ = '\0';
00278       p--;
00279 
00280       token = TOK_IDENTIFIER;
00281       v = valueMakeString( xstrdup(temp) );
00282 
00283     } else if (*p == '\"') {
00284       char temp[EXPRBUFSIZ], *t = temp;
00285 
00286       p++;
00287       while (*p && *p != '\"')
00288         *t++ = *p++;
00289       *t++ = '\0';
00290 
00291       token = TOK_STRING;
00292       v = valueMakeString( rpmExpand(temp, NULL) );
00293 
00294     } else {
00295       rpmError(RPMERR_BADSPEC, _("parse error in expression\n"));
00296       return -1;
00297     }
00298   }
00299 
00300   state->p = p + 1;
00301   state->nextToken = token;
00302   state->tokenValue = v;
00303 
00304   DEBUG(printf("rdToken: \"%s\" (%d)\n", prToken(token), token));
00305   DEBUG(valueDump("rdToken:", state->tokenValue, stdout));
00306 
00307   return 0;
00308 }
00309 
00310 static Value doLogical(ParseState state);
00311 
00315 static Value doPrimary(ParseState state)
00316 {
00317   Value v;
00318 
00319   DEBUG(printf("doPrimary()\n"));
00320 
00321   switch (state->nextToken) {
00322   case TOK_OPEN_P:
00323     if (rdToken(state))
00324       return NULL;
00325     v = doLogical(state);
00326     if (state->nextToken != TOK_CLOSE_P) {
00327       rpmError(RPMERR_BADSPEC, _("unmatched (\n"));
00328       return NULL;
00329     }
00330     break;
00331 
00332   case TOK_INTEGER:
00333   case TOK_STRING:
00334     v = state->tokenValue;
00335     if (rdToken(state))
00336       return NULL;
00337     break;
00338 
00339   case TOK_IDENTIFIER: {
00340     const char *name = state->tokenValue->data.s;
00341 
00342     v = valueMakeString( rpmExpand(name, NULL) );
00343     if (rdToken(state))
00344       return NULL;
00345     break;
00346   }
00347 
00348   case TOK_MINUS:
00349     if (rdToken(state))
00350       return NULL;
00351 
00352     v = doPrimary(state);
00353     if (v == NULL)
00354       return NULL;
00355 
00356     if (! valueIsInteger(v)) {
00357       rpmError(RPMERR_BADSPEC, _("- only on numbers\n"));
00358       return NULL;
00359     }
00360 
00361     v = valueMakeInteger(- v->data.i);
00362     break;
00363 
00364   case TOK_NOT:
00365     if (rdToken(state))
00366       return NULL;
00367 
00368     v = doPrimary(state);
00369     if (v == NULL)
00370       return NULL;
00371 
00372     if (! valueIsInteger(v)) {
00373       rpmError(RPMERR_BADSPEC, _("! only on numbers\n"));
00374       return NULL;
00375     }
00376 
00377     v = valueMakeInteger(! v->data.i);
00378     break;
00379   default:
00380     return NULL;
00381     /*@notreached@*/ break;
00382   }
00383 
00384   DEBUG(valueDump("doPrimary:", v, stdout));
00385   return v;
00386 }
00387 
00391 static Value doMultiplyDivide(ParseState state)
00392 {
00393   Value v1, v2 = NULL;
00394 
00395   DEBUG(printf("doMultiplyDivide()\n"));
00396 
00397   v1 = doPrimary(state);
00398   if (v1 == NULL)
00399     return NULL;
00400 
00401   while (state->nextToken == TOK_MULTIPLY
00402          || state->nextToken == TOK_DIVIDE) {
00403     int op = state->nextToken;
00404 
00405     if (rdToken(state))
00406       return NULL;
00407 
00408     if (v2) valueFree(v2);
00409 
00410     v2 = doPrimary(state);
00411     if (v2 == NULL)
00412       return NULL;
00413 
00414     if (! valueSameType(v1, v2)) {
00415       rpmError(RPMERR_BADSPEC, _("types must match\n"));
00416       return NULL;
00417     }
00418 
00419     if (valueIsInteger(v1)) {
00420       int i1 = v1->data.i, i2 = v2->data.i;
00421 
00422       valueFree(v1);
00423       if (op == TOK_MULTIPLY)
00424         v1 = valueMakeInteger(i1 * i2);
00425       else
00426         v1 = valueMakeInteger(i1 / i2);
00427     } else {
00428       rpmError(RPMERR_BADSPEC, _("* / not suported for strings\n"));
00429       return NULL;
00430     }
00431   }
00432 
00433   if (v2) valueFree(v2);
00434   return v1;
00435 }
00436 
00440 static Value doAddSubtract(ParseState state)
00441 {
00442   Value v1, v2 = NULL;
00443 
00444   DEBUG(printf("doAddSubtract()\n"));
00445 
00446   v1 = doMultiplyDivide(state);
00447   if (v1 == NULL)
00448     return NULL;
00449 
00450   while (state->nextToken == TOK_ADD || state->nextToken == TOK_MINUS) {
00451     int op = state->nextToken;
00452 
00453     if (rdToken(state))
00454       return NULL;
00455 
00456     if (v2) valueFree(v2);
00457 
00458     v2 = doMultiplyDivide(state);
00459     if (v2 == NULL)
00460       return NULL;
00461 
00462     if (! valueSameType(v1, v2)) {
00463       rpmError(RPMERR_BADSPEC, _("types must match\n"));
00464       return NULL;
00465     }
00466 
00467     if (valueIsInteger(v1)) {
00468       int i1 = v1->data.i, i2 = v2->data.i;
00469 
00470       valueFree(v1);
00471       if (op == TOK_ADD)
00472         v1 = valueMakeInteger(i1 + i2);
00473       else
00474         v1 = valueMakeInteger(i1 - i2);
00475     } else {
00476       char *copy;
00477 
00478       if (op == TOK_MINUS) {
00479         rpmError(RPMERR_BADSPEC, _("- not suported for strings\n"));
00480         return NULL;
00481       }
00482 
00483       copy = xmalloc(strlen(v1->data.s) + strlen(v2->data.s) + 1);
00484       (void) stpcpy( stpcpy(copy, v1->data.s), v2->data.s);
00485 
00486       valueFree(v1);
00487       v1 = valueMakeString(copy);
00488     }
00489   }
00490 
00491   if (v2) valueFree(v2);
00492   return v1;
00493 }
00494 
00498 static Value doRelational(ParseState state)
00499 {
00500   Value v1, v2 = NULL;
00501 
00502   DEBUG(printf("doRelational()\n"));
00503 
00504   v1 = doAddSubtract(state);
00505   if (v1 == NULL)
00506     return NULL;
00507 
00508   while (state->nextToken >= TOK_EQ && state->nextToken <= TOK_GE) {
00509     int op = state->nextToken;
00510 
00511     if (rdToken(state))
00512       return NULL;
00513 
00514     if (v2) valueFree(v2);
00515 
00516     v2 = doAddSubtract(state);
00517     if (v2 == NULL)
00518       return NULL;
00519 
00520     if (! valueSameType(v1, v2)) {
00521       rpmError(RPMERR_BADSPEC, _("types must match\n"));
00522       return NULL;
00523     }
00524 
00525     if (valueIsInteger(v1)) {
00526       int i1 = v1->data.i, i2 = v2->data.i, r = 0;
00527       switch (op) {
00528       case TOK_EQ:
00529         r = (i1 == i2);
00530         break;
00531       case TOK_NEQ:
00532         r = (i1 != i2);
00533         break;
00534       case TOK_LT:
00535         r = (i1 < i2);
00536         break;
00537       case TOK_LE:
00538         r = (i1 <= i2);
00539         break;
00540       case TOK_GT:
00541         r = (i1 > i2);
00542         break;
00543       case TOK_GE:
00544         r = (i1 >= i2);
00545         break;
00546       default:
00547         break;
00548       }
00549       valueFree(v1);
00550       v1 = valueMakeInteger(r);
00551     } else {
00552       const char * s1 = v1->data.s;
00553       const char * s2 = v2->data.s;
00554       int r = 0;
00555       switch (op) {
00556       case TOK_EQ:
00557         r = (strcmp(s1,s2) == 0);
00558         break;
00559       case TOK_NEQ:
00560         r = (strcmp(s1,s2) != 0);
00561         break;
00562       case TOK_LT:
00563         r = (strcmp(s1,s2) < 0);
00564         break;
00565       case TOK_LE:
00566         r = (strcmp(s1,s2) <= 0);
00567         break;
00568       case TOK_GT:
00569         r = (strcmp(s1,s2) > 0);
00570         break;
00571       case TOK_GE:
00572         r = (strcmp(s1,s2) >= 0);
00573         break;
00574       default:
00575         break;
00576       }
00577       valueFree(v1);
00578       v1 = valueMakeInteger(r);
00579     }
00580   }
00581 
00582   if (v2) valueFree(v2);
00583   return v1;
00584 }
00585 
00589 static Value doLogical(ParseState state)
00590 {
00591   Value v1, v2 = NULL;
00592 
00593   DEBUG(printf("doLogical()\n"));
00594 
00595   v1 = doRelational(state);
00596   if (v1 == NULL)
00597     return NULL;
00598 
00599   while (state->nextToken == TOK_LOGICAL_AND
00600          || state->nextToken == TOK_LOGICAL_OR) {
00601     int op = state->nextToken;
00602 
00603     if (rdToken(state))
00604       return NULL;
00605 
00606     if (v2) valueFree(v2);
00607 
00608     v2 = doRelational(state);
00609     if (v2 == NULL)
00610       return NULL;
00611 
00612     if (! valueSameType(v1, v2)) {
00613       rpmError(RPMERR_BADSPEC, _("types must match\n"));
00614       return NULL;
00615     }
00616 
00617     if (valueIsInteger(v1)) {
00618       int i1 = v1->data.i, i2 = v2->data.i;
00619 
00620       valueFree(v1);
00621       if (op == TOK_LOGICAL_AND)
00622         v1 = valueMakeInteger(i1 && i2);
00623       else
00624         v1 = valueMakeInteger(i1 || i2);
00625     } else {
00626       rpmError(RPMERR_BADSPEC, _("&& and || not suported for strings\n"));
00627       return NULL;
00628     }
00629   }
00630 
00631   if (v2) valueFree(v2);
00632   return v1;
00633 }
00634 
00635 int parseExpressionBoolean(Spec spec, const char *expr)
00636 {
00637   struct _parseState state;
00638   int result = -1;
00639   Value v;
00640 
00641   DEBUG(printf("parseExprBoolean(?, '%s')\n", expr));
00642 
00643   /* Initialize the expression parser state. */
00644   state.p = state.str = xstrdup(expr);
00645   state.spec = spec;
00646   state.nextToken = 0;
00647   state.tokenValue = NULL;
00648   (void) rdToken(&state);
00649 
00650   /* Parse the expression. */
00651   v = doLogical(&state);
00652   if (!v) {
00653     state.str = _free(state.str);
00654     return -1;
00655   }
00656 
00657   /* If the next token is not TOK_EOF, we have a syntax error. */
00658   if (state.nextToken != TOK_EOF) {
00659     rpmError(RPMERR_BADSPEC, _("syntax error in expression\n"));
00660     state.str = _free(state.str);
00661     return -1;
00662   }
00663 
00664   DEBUG(valueDump("parseExprBoolean:", v, stdout));
00665 
00666   switch (v->type) {
00667   case VALUE_TYPE_INTEGER:
00668     result = v->data.i != 0;
00669     break;
00670   case VALUE_TYPE_STRING:
00671     result = v->data.s[0] != '\0';
00672     break;
00673   default:
00674     break;
00675   }
00676 
00677   state.str = _free(state.str);
00678   valueFree(v);
00679   return result;
00680 }
00681 
00682 char * parseExpressionString(Spec spec, const char *expr)
00683 {
00684   struct _parseState state;
00685   char *result = NULL;
00686   Value v;
00687 
00688   DEBUG(printf("parseExprString(?, '%s')\n", expr));
00689 
00690   /* Initialize the expression parser state. */
00691   state.p = state.str = xstrdup(expr);
00692   state.spec = spec;
00693   state.nextToken = 0;
00694   state.tokenValue = NULL;
00695   (void) rdToken(&state);
00696 
00697   /* Parse the expression. */
00698   v = doLogical(&state);
00699   if (!v) {
00700     state.str = _free(state.str);
00701     return NULL;
00702   }
00703 
00704   /* If the next token is not TOK_EOF, we have a syntax error. */
00705   if (state.nextToken != TOK_EOF) {
00706     rpmError(RPMERR_BADSPEC, _("syntax error in expression\n"));
00707     state.str = _free(state.str);
00708     return NULL;
00709   }
00710 
00711   DEBUG(valueDump("parseExprString:", v, stdout));
00712 
00713   switch (v->type) {
00714   case VALUE_TYPE_INTEGER: {
00715     char buf[128];
00716     sprintf(buf, "%d", v->data.i);
00717     result = xstrdup(buf);
00718   } break;
00719   case VALUE_TYPE_STRING:
00720     result = xstrdup(v->data.s);
00721     break;
00722   default:
00723     break;
00724   }
00725 
00726   state.str = _free(state.str);
00727   valueFree(v);
00728   return result;
00729 }

Generated at Mon Sep 24 10:37:08 2001 for rpm by doxygen1.2.8.1 written by Dimitri van Heesch, © 1997-2001