added a proper expression parser
authorkramm <kramm>
Fri, 26 Sep 2008 11:51:34 +0000 (11:51 +0000)
committerkramm <kramm>
Fri, 26 Sep 2008 11:51:34 +0000 (11:51 +0000)
src/swfc.c

index fafa388..a8cbdfc 100644 (file)
@@ -2360,7 +2360,7 @@ int parseInt(char*str)
            syntaxerror("Not an Integer: \"%s\"", str);
     return atoi(str);
 }
-int parseRawTwip(char*str)
+static double parseRawTwip(char*str)
 {
     char*dot;
     int sign=1;
@@ -2373,23 +2373,25 @@ int parseRawTwip(char*str)
     if(!dot) {
        int l=strlen(str);
        int t;
-       return sign*parseInt(str)*20;
+       return sign*parseInt(str);
     } else {
        char* old = strdup(str);
        int l=strlen(dot+1);
        char*s;
        *dot++ = 0;
-       for(s=str;s<dot-1;s++)
-        if(*s<'0' || *s>'9')
-        {
-            free(old);
-            syntaxerror("Not a coordinate: \"%s\"", str);
+       for(s=str;s<dot-1;s++) {
+            if(*s<'0' || *s>'9')
+            {
+                free(old);
+                syntaxerror("Not a coordinate: \"%s\"", str);
+            }
         }
-    for(s=dot;*s;s++)
-        if(*s<'0' || *s>'9')
-        {
-            free(old);
-            syntaxerror("Not a coordinate: \"%s\"", str);
+        for(s=dot;*s;s++) {
+            if(*s<'0' || *s>'9')
+            {
+                free(old);
+                syntaxerror("Not a coordinate: \"%s\"", str);
+            }
         }
        if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) {
            dot[1] = ((dot[1]-0x30)/5)*5 + 0x30;
@@ -2399,11 +2401,11 @@ int parseRawTwip(char*str)
        }
        free(old);
        if(l==0)
-           return sign*(atoi(str)*20);
+           return sign*(atoi(str));
        if(l==1)
-           return sign*(atoi(str)*20+atoi(dot)*2);
+           return sign*(atoi(str)+0.1*atoi(dot));
        if(l==2)
-           return sign*(atoi(str)*20+atoi(dot)/5);
+           return sign*(atoi(str)+0.01*atoi(dot));
     }
     return 0;
 }
@@ -2412,49 +2414,131 @@ static dictionary_t defines;
 static int defines_initialized = 0;
 static mem_t define_values;
 
-int parseTwip(char*str)
+static double parseNameOrTwip(char*s)
 {
-    /* TODO: make this a proper expression parser */
-    char*p = str;
-    int val = 0;
-    char ex = 0;
-    char*lastpos = 0;
-    while(*p) {
-       if(*p == '+' || *p == '-' || *p == '/' || *p == '*')
-           ex = *p;
-       else if(!lastpos)
-           lastpos = p;
-       p++;
-       if((*p == '+' || *p == '-' || *p == '/' || *p == '*' || *p == 0) && lastpos) {
-           char save = *p;
-           *p = 0;
-
-           int l = 0;
-           int v = 0;
-           if(defines_initialized) {
-               l = (int)dictionary_lookup(&defines, lastpos);
-           }
-           if(l) {
-               v = *(int*)&define_values.buffer[l-1];
-           } else {
-               v = parseRawTwip(lastpos);
-           }
-           *p = save;
-           if(ex == '+') 
-               val += v;
-           else if(ex == '-')
-               val -= v;
-           else if(ex == '/')
-               val = (val*20) / v;
-           else if(ex == '*')
-               val = (val*v) / 20;
-           else
-               val += v;
-           ex = 0;
-           lastpos = 0;
-       }
+    int l = 0;
+    double v;
+    if(defines_initialized) {
+        l = (int)dictionary_lookup(&defines, s);
     }
-    return val;
+    if(l) {
+        return *(int*)&define_values.buffer[l-1];
+    } else {
+        return parseRawTwip(s);
+    }
+}
+
+/* automatically generated by yiyiyacc, http://www.quiss.org/yiyiyacc/ */
+static double parseExpression(char*s)
+{
+    int chr2index[256];
+    memset(chr2index, -1, sizeof(chr2index));
+    chr2index['+'] = 0;
+    chr2index['-'] = 1;
+    chr2index['*'] = 2;
+    chr2index['/'] = 3;
+    chr2index['('] = 5;
+    chr2index[')'] = 6;
+    chr2index['\0'] = 7;
+
+    int stackpos = 1;
+    int stack[256];
+    double values[256];
+    stack[0]=0;
+    values[0]=0;
+    int accept = 18;
+    int left[10]={11,8,8,8,8,9,9,9,10,10}; //production left side
+    int plen[10]={1,3,2,3,1,3,3,1,1,3}; //production size
+    int table[18][12] = {
+        {0, 4, 0, 0, 5, 6, 0, 0, 1, 2, 3, 0},
+        {7, 8, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0},
+        {-4, -4, 9, 10, 0, 0, -4, -4, 0, 0, 0, 0},
+        {-7, -7, -7, -7, 0, 0, -7, -7, 0, 0, 0, 0},
+        {0, 0, 0, 0, 5, 6, 0, 0, 0, 11, 3, 0},
+        {-8, -8, -8, -8, 0, 0, -8, -8, 0, 0, 0, 0},
+        {0, 4, 0, 0, 5, 6, 0, 0, 12, 2, 3, 0},
+        {0, 0, 0, 0, 5, 6, 0, 0, 0, 13, 3, 0},
+        {0, 0, 0, 0, 5, 6, 0, 0, 0, 14, 3, 0},
+        {0, 0, 0, 0, 5, 6, 0, 0, 0, 0, 15, 0},
+        {0, 0, 0, 0, 5, 6, 0, 0, 0, 0, 16, 0},
+        {-2, -2, 9, 10, 0, 0, -2, -2, 0, 0, 0, 0},
+        {7, 8, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0},
+        {-1, -1, 9, 10, 0, 0, -1, -1, 0, 0, 0, 0},
+        {-3, -3, 9, 10, 0, 0, -3, -3, 0, 0, 0, 0},
+        {-5, -5, -5, -5, 0, 0, -5, -5, 0, 0, 0, 0},
+        {-6, -6, -6, -6, 0, 0, -6, -6, 0, 0, 0, 0},
+        {-9, -9, -9, -9, 0, 0, -9, -9, 0, 0, 0, 0}};
+
+    char*p = s;
+    while(1) {
+        char*pnext = p+1;
+        int action;
+        double value = 0;
+        if(!stackpos) {
+            fprintf(stderr, "Error in expression\n");
+            return 0.0;
+        }
+
+        if(chr2index[*p]<0) {
+            action = table[stack[stackpos-1]][4];
+            if(action>0) {
+                while(chr2index[*pnext]<0) 
+                    pnext++;
+                char save = *pnext;
+                *pnext = 0;
+                value = parseNameOrTwip(p);
+                *pnext = save;
+            }
+        } else {
+            action = table[stack[stackpos-1]][chr2index[*p]];
+        }
+
+        if(action == accept) {
+            return values[stack[stackpos-1]];
+        } else if(action>0) { // shift
+            if(stackpos>254) {
+                fprintf(stderr, "Stack overflow while parsing expression\n");
+                return 0.0;
+            }
+            values[stackpos]=value;
+            stack[stackpos++]=action;
+            p=pnext;
+        } else if(action<0) { // reduce
+            stackpos-=plen[-action];
+            stack[stackpos] = table[stack[stackpos-1]][left[-action]];
+            switch(-action) {
+              case 1:
+                values[stackpos] = values[stackpos+0] + values[stackpos+2];
+              break;
+              case 2:
+                values[stackpos] = 0 - values[stackpos+1];
+              break;
+              case 3:
+                values[stackpos] = values[stackpos+0] - values[stackpos+2];
+              break;
+              case 5:
+                values[stackpos] = values[stackpos+0] * values[stackpos+2];
+              break;
+              case 6:
+                values[stackpos] = values[stackpos+0] / values[stackpos+2];
+              break;
+              case 9:
+                values[stackpos] = values[stackpos+1];
+              break;
+            }
+            stackpos++;
+        } else {
+            fprintf(stderr, "Syntax error in expression\n");
+            return 0.0;
+        }
+    }
+}
+
+int parseTwip(char*str)
+{
+    int v = (int)(parseExpression(str)*20);
+    printf("%s = %.2f\n", str, v/20.0);
+    return v;
 }
 
 int parseArc(char* str)