tweaks to plural rules evaluator
authorSzabolcs Nagy <nsz@port70.net>
Tue, 29 Jul 2014 17:39:19 +0000 (19:39 +0200)
committerSzabolcs Nagy <nsz@port70.net>
Tue, 29 Jul 2014 17:39:19 +0000 (19:39 +0200)
const parsing, depth accounting and failure handling was changed
a bit so the generated code is slightly smaller.

src/locale/pleval.c

index 47aefc340ec7689d0c9d362ff16749fcd5f4643b..03370bcfc3b6116b56ea58b8e1e571e7374ea892 100644 (file)
@@ -33,15 +33,10 @@ static const char *skipspace(const char *s)
        return s;
 }
 
-static unsigned long evalconst(struct st *st)
+static unsigned long fail(struct st *st)
 {
-       char *e;
-       unsigned long n;
-       n = strtoul(st->s, &e, 10);
-       if (!isdigit(*st->s) || e == st->s || n == -1)
-               st->err = 1;
-       st->s = skipspace(e);
-       return n;
+       st->err = 1;
+       return 0;
 }
 
 static unsigned long evalexpr(struct st *st, int d);
@@ -49,47 +44,47 @@ static unsigned long evalexpr(struct st *st, int d);
 static unsigned long evalterm(struct st *st, int d)
 {
        unsigned long a;
-       if (d <= 0) {
-               st->err = 1;
-               return 0;
-       }
+       char *e;
+       if (--d < 0) return fail(st);
        st->s = skipspace(st->s);
-       if (*st->s == '!') {
-               st->s++;
-               return !evalterm(st, d-1);
+       if (isdigit(*st->s)) {
+               a = strtoul(st->s, &e, 10);
+               if (e == st->s || a == -1) return fail(st);
+               st->s = skipspace(e);
+               return a;
+       }
+       if (*st->s == 'n') {
+               st->s = skipspace(st->s + 1);
+               return st->n;
        }
        if (*st->s == '(') {
                st->s++;
-               a = evalexpr(st, d-1);
-               if (*st->s != ')') {
-                       st->err = 1;
-                       return 0;
-               }
+               a = evalexpr(st, d);
+               if (*st->s != ')') return fail(st);
                st->s = skipspace(st->s + 1);
                return a;
        }
-       if (*st->s == 'n') {
-               st->s = skipspace(st->s + 1);
-               return st->n;
+       if (*st->s == '!') {
+               st->s++;
+               return !evalterm(st, d);
        }
-       return evalconst(st);
+       return fail(st);
 }
 
 static unsigned long evalmul(struct st *st, int d)
 {
-       unsigned long b, a = evalterm(st, d-1);
+       unsigned long b, a = evalterm(st, d);
        int op;
        for (;;) {
                op = *st->s;
                if (op != '*' && op != '/' && op != '%')
                        return a;
                st->s++;
-               b = evalterm(st, d-1);
+               b = evalterm(st, d);
                if (op == '*') {
                        a *= b;
                } else if (!b) {
-                       st->err = 1;
-                       return 0;
+                       return fail(st);
                } else if (op == '%') {
                        a %= b;
                } else {
@@ -101,19 +96,19 @@ static unsigned long evalmul(struct st *st, int d)
 static unsigned long evaladd(struct st *st, int d)
 {
        unsigned long a = 0;
-       int add = 1;
+       int sub = 0;
        for (;;) {
-               a += (add?1:-1) * evalmul(st, d-1);
+               a += (sub ? -1 : 1) * evalmul(st, d);
                if (*st->s != '+' && *st->s != '-')
                        return a;
-               add = *st->s == '+';
+               sub = *st->s == '-';
                st->s++;
        }
 }
 
 static unsigned long evalrel(struct st *st, int d)
 {
-       unsigned long b, a = evaladd(st, d-1);
+       unsigned long b, a = evaladd(st, d);
        int less, eq;
        for (;;) {
                if (*st->s != '<' && *st->s != '>')
@@ -121,65 +116,60 @@ static unsigned long evalrel(struct st *st, int d)
                less = st->s[0] == '<';
                eq = st->s[1] == '=';
                st->s += 1 + eq;
-               b = evaladd(st, d-1);
+               b = evaladd(st, d);
                a = (less ? a < b : a > b) || (eq && a == b);
        }
 }
 
 static unsigned long evaleq(struct st *st, int d)
 {
-       unsigned long a = evalrel(st, d-1);
-       int neg;
+       unsigned long a = evalrel(st, d);
+       int c;
        for (;;) {
-               if ((st->s[0] != '=' && st->s[0] != '!') || st->s[1] != '=')
+               c = st->s[0];
+               if ((c != '=' && c != '!') || st->s[1] != '=')
                        return a;
-               neg = st->s[0] == '!';
                st->s += 2;
-               a = evalrel(st, d-1) == a;
-               a ^= neg;
+               a = (evalrel(st, d) == a) ^ (c == '!');
        }
 }
 
 static unsigned long evaland(struct st *st, int d)
 {
-       unsigned long a = evaleq(st, d-1);
+       unsigned long a = evaleq(st, d);
        for (;;) {
                if (st->s[0] != '&' || st->s[1] != '&')
                        return a;
                st->s += 2;
-               a = evaleq(st, d-1) && a;
+               a = evaleq(st, d) && a;
        }
 }
 
 static unsigned long evalor(struct st *st, int d)
 {
-       unsigned long a = evaland(st, d-1);
+       unsigned long a = evaland(st, d);
        for (;;) {
                if (st->s[0] != '|' || st->s[1] != '|')
                        return a;
                st->s += 2;
-               a = evaland(st, d-1) || a;
+               a = evaland(st, d) || a;
        }
 }
 
 static unsigned long evalexpr(struct st *st, int d)
 {
        unsigned long a1, a2, a3;
-       if (d <= 0) {
-               st->err = 1;
-               return 0;
-       }
-       a1 = evalor(st, d-1);
+       if (--d < 0)
+               return fail(st);
+       a1 = evalor(st, d-6);
        if (*st->s != '?')
                return a1;
        st->s++;
-       a2 = evalexpr(st, d-1);
-       if (*st->s != ':') {
-               st->err = 1;
-               return 0;
-       }
+       a2 = evalexpr(st, d);
+       if (*st->s != ':')
+               return fail(st);
        st->s++;
-       a3 = evalexpr(st, d-1);
+       a3 = evalexpr(st, d);
        return a1 ? a2 : a3;
 }