Added support for strings in parser
authorLynus Vaz <lynus@Arch.localdomain>
Mon, 8 Jun 2009 18:29:27 +0000 (23:59 +0530)
committerLynus Vaz <lynus@Arch.localdomain>
Mon, 8 Jun 2009 18:29:27 +0000 (23:59 +0530)
src/hci/arith.c

index 8108b3d..4113c93 100644 (file)
@@ -28,10 +28,11 @@ Ops: !, ~                           (Highest)
 
 #define NUM_OPS                20
 #define MAX_PRIO               11
-#define MIN_TOK                257
+#define MIN_TOK                258
 #define TOK_PLUS               (MIN_TOK + 5)
 #define TOK_MINUS      (MIN_TOK + 6)
 #define TOK_NUMBER     256
+#define TOK_STRING     257
 
 char *inp, *prev;
 int tok;
@@ -39,6 +40,7 @@ int err_val;          //skip, parse_num, eval
 long tok_value;
 
 char *op_table = "!@@" "~@@" "*@@" "/@@" "%@@" "+@@" "-@@" "<@@" "<=@" "<<@" ">@@" ">=@" ">>@" "!=@" "==@" "&@@" "|@@" "^@@" "&&@" "||@";
+char *keyword_table = " \t()";
 signed char op_prio[NUM_OPS]   = { 10, 10, 9, 9, 9, 8, 8, 6, 6, 7, 6, 6, 7, 5, 5, 4, 3, 2, 1, 0 };
 signed char op_assoc[NUM_OPS] = { -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 char op_arity[NUM_OPS] = { 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 };
@@ -54,18 +56,10 @@ char op_arity[NUM_OPS] = { 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
 */     
        
 static void ignore_whitespace(void);
-//static long get_value(char *var, int size);
-
-#if 0
-struct variable
-{
-       char *name;
-       long value;
-       struct variable *next;
-};
-
-struct variable *sym_table;
+#ifndef __ARITH_TEST__
+static long strtol(char *string, char **eptr, int base);
 #endif
+//static long get_value(char *var, int size);
 
 static void input()
 {
@@ -86,19 +80,35 @@ static void input()
                        tok = TOK_NUMBER;
                        while(isdigit(*inp))
                        {
-                               tok_value = tok_value*10 + *inp++ - '0';
+                               tok_value = strtol(inp, &inp, 0);
                        }
                        return;
                }
-               
-               
+                               
                t_op[0] = *inp++;
                                
                p1 = strstr(op_table, t_op);
-               if(!p1 || !*inp)
+               if(!p1)                                 //Ok: so this is not a number, and not an operator
                {
-                       tok = *t_op;
-                       return;
+                       char *start = inp - 1;
+                       if(strchr(keyword_table, *t_op) || (*t_op == '$' && *inp == '(') )
+                       {
+                               tok = *t_op;
+                               return;
+                       }
+                       
+                       while(*inp && !strchr(keyword_table, *inp) && !strchr(op_table, *inp))
+                               inp++;
+                       {
+                               char str_val[inp - start + 1];
+                               char *s;
+                               strncpy(str_val, start, inp - start);
+                               str_val[inp - start] = 0;
+                               tok = TOK_STRING;
+                               asprintf(&s, "%s", str_val);
+                               tok_value = (long)s;
+                               return;
+                       }
                }
                t_op[1] = *inp;
                p2 = strstr(op_table, t_op);
@@ -114,7 +124,7 @@ static void input()
                tok = -1;       
 }
 
-static long parse_expr(void);
+static int parse_expr(char **buffer);
 
 static void ignore_whitespace(void)
 {
@@ -140,30 +150,7 @@ static void skip(char ch)
        }
 }
 
-#if 0
-static long parse_var(void)
-{
-       int len = 0;
-       char *ptr;
-       struct variable *cur = sym_table;
-       ptr = inp;
-       while(isalphanum(tok) || tok == '_')
-       {
-               input();
-               len++;
-       }
-       while(cur)
-       {
-               if(!strncmp(cur -> name, ptr, len) && cur -> name[len+1] == 0)
-                       return cur -> value;
-               cur = cur -> next;
-       }
-       printf("Variable not found\n");
-       return 0;
-}
-#endif
-
-static long parse_num(void)
+static int parse_num(char **buffer)
 {
        long num = 0;
        int flag = 1;
@@ -173,137 +160,180 @@ static long parse_num(void)
        else if(accept(TOK_PLUS)) {}
        
        if (accept('(')) {
-               num = parse_expr();
+               parse_expr(buffer);
                skip(')');
-               return flag * num;
+               if(flag < 0)
+               {
+                       if(**buffer == '-')
+                               **buffer = '+';
+                       else
+                       {
+                               char t[strlen(*buffer) + 2];
+                               t[0] = '-';
+                               strcpy(t + 1, *buffer);
+                               free(*buffer);
+                               return asprintf(buffer, "%s", t);
+                       }                               
+               }
+               return strlen(*buffer);
        }
        
        if(tok == TOK_NUMBER)
        {
                num = flag * tok_value;
                input();
-               return num;
+               return asprintf(buffer, "%ld", num);
+       } else if (tok == TOK_STRING)
+       {
+               *buffer = (char *)tok_value;
+               input();
+               return strlen(*buffer);
        }
-       else
                err_val = -1;
        return 0;
 }
 
-#if 0
-static long mul_op(void)
-{
-       long a = parse_num();
-       /* This is left-associative */
-       for (;;) {
-               if (accept('*')) {
-                       a *= parse_num();
-               } else if (accept('/')) {
-                       a /= parse_num();
-               } else {
-                       return a;
-               }
-       }
-}
-
-static long add_op(void)
-{
-       long a = mul_op();
-       /* Right-associative is easy */
-       if (accept('+')) {
-               return a + parse_expr();
-       } else if (accept('-')) {
-               return a - parse_expr();
-       } else {
-               return a;
-       }
-}
-
-static long cmp_op(void)
+#ifndef __ARITH_TEST__
+static long strtol(char *string, char **eptr, int base)                //Just a temporary measure. It seems strtol is not defined
 {
-       long a = add_op();
+       int flag = 1;
+       long value = 0;
+       
+       if(base != 0 && base != 10) return 0;
        
-       if(accept(133)) {
-               return a >= parse_expr();
+       while(isspace(*string)) string++;
+       if(*string == '-') flag = -1;
+       else if(*string == '+') flag = 1;
+       while(*string && isdigit(*string))
+       {
+               value = value * 10 + (*string++ - '0');
        }
-       else return a;
-} 
+       if(eptr)
+               *eptr = string;
+       return value;
+}
 #endif
 
 //"!" "~" "*" "/" "%" "+" "-" "<" "<=" "<<" ">" ">=" ">>" "!=" "==" "&" "|" "^" "&&" "||";
-static long eval(int op, long op1, long op2)
+static int eval(int op, char *op1, char *op2, char **buffer)
 {
+       long value;
        switch(op)
        {
-               case 0: return !op2;
-               case 1: return ~op2;
-               case 2: return op1 * op2;
-               case 3: return op1 / op2;
-               case 4: return op1 % op2;
-               case 5: return op1 + op2;
-               case 6: return op1 - op2;
-               case 7: return op1 < op2;
-               case 8: return op1 <= op2;
-               case 9: return op1 << op2;
-               case 10: return op1 > op2;
-               case 11: return op1 >= op2;
-               case 12: return op1 >> op2;
-               case 13: return op1 != op2;
-               case 14: return op1 == op2;
-               case 15: return op1 & op2;
-               case 16: return op1 | op2;
-               case 17: return op1 ^ op2;
-               case 18: return op1 && op2;
-               case 19: return op1 || op2;
+               case 0:
+                       value = !strtol(op2, NULL, 0);
+                       break;
+               case 1: 
+                       value = ~strtol(op2, NULL, 0);
+                       break;
+               case 2: 
+                       value = strtol(op1, NULL, 0) * strtol(op2, NULL, 0);
+                       break;
+               case 3: 
+                       value = strtol(op1, NULL, 0) / strtol(op2, NULL, 0);
+                       break;
+               case 4: 
+                       value = strtol(op1, NULL, 0) % strtol(op2, NULL, 0);
+                       break;
+               case 5:
+                       value = strtol(op1, NULL, 0) + strtol(op2, NULL, 0);
+                       break;
+               case 6: 
+                       value = strtol(op1, NULL, 0) - strtol(op2, NULL, 0);
+                       break;
+               case 7: 
+                       value = strtol(op1, NULL, 0) < strtol(op2, NULL, 0);
+                       break;
+               case 8: 
+                       value = strtol(op1, NULL, 0) <= strtol(op2, NULL, 0);
+                       break;
+               case 9: 
+                       value = strtol(op1, NULL, 0) << strtol(op2, NULL, 0);
+                       break;
+               case 10: 
+                       value = strtol(op1, NULL, 0) > strtol(op2, NULL, 0);
+                       break;
+               case 11: 
+                       value = strtol(op1, NULL, 0) >= strtol(op2, NULL, 0);
+                       break;
+               case 12: 
+                       value = strtol(op1, NULL, 0) >> strtol(op2, NULL, 0);
+                       break;
+               case 13:
+                       value = strtol(op1, NULL, 0) != strtol(op2, NULL, 0);
+                       break;
+               case 14:
+                       value = !strcmp(op1, op2);
+                       break;
+               case 15:
+                       value = strcmp(op1, op2) ? 1 : 0;
+                       break;
+               case 16: 
+                       value = strtol(op1, NULL, 0) | strtol(op2, NULL, 0);
+                       break;
+               case 17:
+                       value = strtol(op1, NULL, 0) ^ strtol(op2, NULL, 0);
+                       break;
+               case 18: 
+                       value = strtol(op1, NULL, 0) && strtol(op2, NULL, 0);
+                       break;
+               case 19: 
+                       value = strtol(op1, NULL, 0) || strtol(op2, NULL, 0);
+                       break;
                
                default: 
                        err_val = -1;
+                       return 0;
                        //printf("Undefined operator\n");
-               return 0;
        }
+       return asprintf(buffer, "%ld", value);
 }
 
-static long parse_prio(int prio)
+static int parse_prio(int prio, char **buffer)
 {
-       long lhs = 0, rhs;
        int op;
-       
-       //input();
+       char *lc, *rc;
        
        if(tok < MIN_TOK || tok == TOK_MINUS || tok == TOK_PLUS)                //All operators are >= 128. If it is not an operator, look for number
        {
-               lhs = parse_num();
+               parse_num(&lc);
        }
        if(err_val)
                return 0;
        while(tok != -1 && tok >= MIN_TOK && (op_prio[tok - MIN_TOK] > prio + op_assoc[tok - MIN_TOK]))
        {
+               long lhs;
                op  = tok;
                input();
-               rhs = parse_prio(op_prio[op - MIN_TOK]);
+               parse_prio(op_prio[op - MIN_TOK], &rc);
                
                if(err_val)
                        return 0;
                
-               lhs = eval(op - MIN_TOK, lhs, rhs);
+               lhs = eval(op - MIN_TOK, lc, rc, buffer);
+               free(rc);
+               free(lc);
+               lc = *buffer;
                
                if(err_val)
                        return 0;
        }
-       return lhs;
+       *buffer = lc;
+       return strlen(*buffer);
 }
 
-static long parse_expr(void)
+static int parse_expr(char **buffer)
 {
-       return parse_prio(-1);
+       return parse_prio(-1, buffer);
 }
 
 int parse_arith(char *inp_string, char **end, char **buffer)
 {
-       long value;
        err_val = tok = 0;
        inp = inp_string;
        input();
-       value = parse_expr();
+       
+       parse_expr(buffer);
        
        if(err_val)                             //Read till we get a ')'
        {
@@ -314,18 +344,15 @@ int parse_arith(char *inp_string, char **end, char **buffer)
        }
        else
        *end = prev;
-               
-       if(buffer)
+       
+       if(err_val)
        {
-               if(err_val)
-               {
-                       printf("Parse error\n");
-                       *buffer = malloc(1);
-                       **buffer = 0;
-                       return 0;
-               }
-               return asprintf(buffer, "%ld", value);
+               printf("parse error\n");
+               return 0;
        }
+       
+       return strlen(*buffer);
+       
        return -1;
 }