expr.c (5514B)
1 /* See LICENSE file for copyright and license details. */ 2 #include <limits.h> 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <string.h> 6 7 #include "utf.h" 8 #include "util.h" 9 10 /* tokens, one-character operators represent themselves */ 11 enum { 12 VAL = CHAR_MAX + 1, GE, LE, NE 13 }; 14 15 struct val { 16 char *str; 17 long long num; 18 }; 19 20 static void 21 tonum(struct val *v) 22 { 23 const char *errstr; 24 long long d; 25 26 /* check if val is the result of an earlier calculation */ 27 if (!v->str) 28 return; 29 30 d = strtonum(v->str, LLONG_MIN, LLONG_MAX, &errstr); 31 if (errstr) 32 enprintf(2, "error: expected integer, got %s\n", v->str); 33 v->num = d; 34 } 35 36 static void 37 ezero(struct val *v) 38 { 39 if (v->num != 0) 40 return; 41 enprintf(2, "division by zero\n"); 42 } 43 44 static int 45 valcmp(struct val *a, struct val *b) 46 { 47 int ret; 48 const char *err1, *err2; 49 long long d1, d2; 50 51 d1 = strtonum(a->str, LLONG_MIN, LLONG_MAX, &err1); 52 d2 = strtonum(b->str, LLONG_MIN, LLONG_MAX, &err2); 53 54 if (!err1 && !err2) { 55 ret = (d1 > d2) - (d1 < d2); 56 } else { 57 ret = strcmp(a->str, b->str); 58 } 59 60 return ret; 61 } 62 63 static void 64 match(struct val *vstr, struct val *vregx, struct val *ret) 65 { 66 regex_t re; 67 regmatch_t matches[2]; 68 size_t anchlen; 69 char *s, *p, *anchreg; 70 char *str = vstr->str, *regx = vregx->str; 71 72 /* anchored regex */ 73 anchlen = strlen(regx) + 1 + 1; 74 anchreg = emalloc(anchlen); 75 estrlcpy(anchreg, "^", anchlen); 76 estrlcat(anchreg, regx, anchlen); 77 enregcomp(3, &re, anchreg, 0); 78 free(anchreg); 79 80 if (regexec(&re, str, 2, matches, 0)) { 81 regfree(&re); 82 ret->str = re.re_nsub ? "" : NULL; 83 return; 84 } else if (re.re_nsub) { 85 regfree(&re); 86 87 s = str + matches[1].rm_so; 88 p = str + matches[1].rm_eo; 89 *p = '\0'; 90 ret->str = enstrdup(3, s); 91 return; 92 } else { 93 regfree(&re); 94 str += matches[0].rm_so; 95 ret->num = utfnlen(str, matches[0].rm_eo - matches[0].rm_so); 96 return; 97 } 98 } 99 100 static void 101 doop(int *ophead, int *opp, struct val *valhead, struct val *valp) 102 { 103 struct val ret = { .str = NULL, .num = 0 }, *a, *b; 104 int op; 105 106 /* an operation "a op b" needs an operator and two values */ 107 if (opp[-1] == '(') 108 enprintf(2, "syntax error: extra (\n"); 109 if (valp - valhead < 2) 110 enprintf(2, "syntax error: missing expression or extra operator\n"); 111 112 a = valp - 2; 113 b = valp - 1; 114 op = opp[-1]; 115 116 switch (op) { 117 case '|': 118 if ( a->str && *a->str) ret.str = a->str; 119 else if (!a->str && a->num) ret.num = a->num; 120 else if ( b->str && *b->str) ret.str = b->str; 121 else ret.num = b->num; 122 break; 123 case '&': 124 if (((a->str && *a->str) || a->num) && 125 ((b->str && *b->str) || b->num)) { 126 ret.str = a->str; 127 ret.num = a->num; 128 } 129 break; 130 131 case '=': ret.num = (valcmp(a, b) == 0); break; 132 case '>': ret.num = (valcmp(a, b) > 0); break; 133 case GE : ret.num = (valcmp(a, b) >= 0); break; 134 case '<': ret.num = (valcmp(a, b) < 0); break; 135 case LE : ret.num = (valcmp(a, b) <= 0); break; 136 case NE : ret.num = (valcmp(a, b) != 0); break; 137 138 case '+': tonum(a); tonum(b); ret.num = a->num + b->num; break; 139 case '-': tonum(a); tonum(b); ret.num = a->num - b->num; break; 140 case '*': tonum(a); tonum(b); ret.num = a->num * b->num; break; 141 case '/': tonum(a); tonum(b); ezero(b); ret.num = a->num / b->num; break; 142 case '%': tonum(a); tonum(b); ezero(b); ret.num = a->num % b->num; break; 143 144 case ':': match(a, b, &ret); break; 145 } 146 147 valp[-2] = ret; 148 } 149 150 static int 151 lex(char *s, struct val *v) 152 { 153 int type = VAL; 154 char *ops = "|&=><+-*/%():"; 155 156 if (s[0] && strchr(ops, s[0]) && !s[1]) { 157 /* one-char operand */ 158 type = s[0]; 159 } else if (s[0] && strchr("><!", s[0]) && s[1] == '=' && !s[2]) { 160 /* two-char operand */ 161 type = (s[0] == '>') ? GE : (s[0] == '<') ? LE : NE; 162 } 163 164 return type; 165 } 166 167 static int 168 parse(char *expr[], int numexpr) 169 { 170 struct val *valhead, *valp, v = { .str = NULL, .num = 0 }; 171 int *ophead, *opp, type, lasttype = 0; 172 char prec[] = { 173 [ 0 ] = 0, [VAL] = 0, ['('] = 0, [')'] = 0, 174 ['|'] = 1, 175 ['&'] = 2, 176 ['='] = 3, ['>'] = 3, [GE] = 3, ['<'] = 3, [LE] = 3, [NE] = 3, 177 ['+'] = 4, ['-'] = 4, 178 ['*'] = 5, ['/'] = 5, ['%'] = 5, 179 [':'] = 6, 180 }; 181 182 valp = valhead = enreallocarray(3, NULL, numexpr, sizeof(*valp)); 183 opp = ophead = enreallocarray(3, NULL, numexpr, sizeof(*opp)); 184 for (; *expr; expr++) { 185 switch ((type = lex(*expr, &v))) { 186 case VAL: 187 /* treatment of *expr is not known until 188 * doop(); treat as a string for now */ 189 valp->str = *expr; 190 valp++; 191 break; 192 case '(': 193 *opp++ = type; 194 break; 195 case ')': 196 if (lasttype == '(') 197 enprintf(2, "syntax error: empty ( )\n"); 198 while (opp > ophead && opp[-1] != '(') 199 doop(ophead, opp--, valhead, valp--); 200 if (opp == ophead) 201 enprintf(2, "syntax error: extra )\n"); 202 opp--; 203 break; 204 default: /* operator */ 205 if (prec[lasttype]) 206 enprintf(2, "syntax error: extra operator\n"); 207 while (opp > ophead && prec[opp[-1]] >= prec[type]) 208 doop(ophead, opp--, valhead, valp--); 209 *opp++ = type; 210 break; 211 } 212 lasttype = type; 213 v.str = NULL; 214 v.num = 0; 215 } 216 while (opp > ophead) 217 doop(ophead, opp--, valhead, valp--); 218 if (valp == valhead) 219 enprintf(2, "syntax error: missing expression\n"); 220 if (--valp > valhead) 221 enprintf(2, "syntax error: extra expression\n"); 222 223 if (valp->str) 224 puts(valp->str); 225 else 226 printf("%lld\n", valp->num); 227 228 return (valp->str && *valp->str) || valp->num; 229 } 230 231 int 232 main(int argc, char *argv[]) 233 { 234 int ret; 235 236 argv0 = *argv, argv0 ? (argc--, argv++) : (void *)0; 237 238 ret = !parse(argv, argc); 239 240 if (fshut(stdout, "<stdout>")) 241 ret = 3; 242 243 return ret; 244 }