Smaller parser with strings
authorLynus Vaz <lynus@Arch.localdomain>
Wed, 10 Jun 2009 15:03:20 +0000 (20:33 +0530)
committerLynus Vaz <lynus@Arch.localdomain>
Wed, 10 Jun 2009 15:03:20 +0000 (20:33 +0530)
src/hci/arith.c

index 4113c93..fc37899 100644 (file)
@@ -33,6 +33,7 @@ Ops: !, ~                             (Highest)
 #define TOK_MINUS      (MIN_TOK + 6)
 #define TOK_NUMBER     256
 #define TOK_STRING     257
+#define TOK_TOTAL              20
 
 char *inp, *prev;
 int tok;
@@ -40,11 +41,9 @@ int err_val;         //skip, parse_num, eval
 long tok_value;
 
 char *op_table = "!@@" "~@@" "*@@" "/@@" "%@@" "+@@" "-@@" "<@@" "<=@" "<<@" ">@@" ">=@" ">>@" "!=@" "==@" "&@@" "|@@" "^@@" "&&@" "||@";
-char *keyword_table = " \t()";
+char *keyword_table = " \t\v()!~*/%+-<=>&|^";                  //Characters that cannot appear in a string
 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 };
-       
+
 /*
        Changes:
        1. Common function for all operators.
@@ -52,19 +51,16 @@ char op_arity[NUM_OPS] = { 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
        
        Notes:
        1. Better way to store operators of > 1 characters? I have tried to keep handling operators consistent.
-       2. Currently, only ! and ~ are unary and right-associative. They are also the highest precedence. If they remain so, we can get rid of op_assoc and op_arity.
 */     
        
 static void ignore_whitespace(void);
-#ifndef __ARITH_TEST__
-static long strtol(char *string, char **eptr, int base);
-#endif
 //static long get_value(char *var, int size);
 
 static void input()
 {
-       char t_op[3] = { 0, 0, 0};
+       char t_op[3] = { '\0', '\0', '\0'};
        char *p1, *p2;
+       size_t len;
        
        if(tok == -1)
                return;
@@ -72,47 +68,39 @@ static void input()
        prev = inp;
        ignore_whitespace();
        
-       if(*inp)
+       if(*inp != '\0')
        {
                if(isdigit(*inp))
                {
                        tok_value = 0;
                        tok = TOK_NUMBER;
-                       while(isdigit(*inp))
-                       {
-                               tok_value = strtol(inp, &inp, 0);
-                       }
+                       tok_value = strtoul(inp, &inp, 0);
+                       return;
+               }
+               
+               len = strcspn(inp, keyword_table);
+               
+               if(len > 0)
+               {
+                       char str_val[len + 1];
+                       strncpy(str_val, inp, len);
+                       str_val[len] = '\0';
+                       asprintf((char **)&tok_value, "%s", str_val);
+                       inp += len;
+                       tok = TOK_STRING;
                        return;
                }
-                               
+               
                t_op[0] = *inp++;
-                               
                p1 = strstr(op_table, t_op);
-               if(!p1)                                 //Ok: so this is not a number, and not an operator
+               if(!p1)
                {
-                       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;
-                       }
+                       tok = *t_op;
+                       return;
                }
                t_op[1] = *inp;
                p2 = strstr(op_table, t_op);
-               if(!p2)
+               if(!p2 || p1 == p2)
                {
                        tok = MIN_TOK + (p1 - op_table)/3;
                        return;
@@ -142,7 +130,7 @@ static int accept(int ch)
        return 0;
 }
 
-static void skip(char ch)
+static void skip(int ch)
 {
        if (!accept(ch)) {
                err_val = -1;
@@ -193,92 +181,90 @@ static int parse_num(char **buffer)
        return 0;
 }
 
-#ifndef __ARITH_TEST__
-static long strtol(char *string, char **eptr, int base)                //Just a temporary measure. It seems strtol is not defined
+//"!" "~" "*" "/" "%" "+" "-" "<" "<=" "<<" ">" ">=" ">>" "!=" "==" "&" "|" "^" "&&" "||";
+static int eval(int op, char *op1, char *op2, char **buffer)
 {
-       int flag = 1;
-       long value = 0;
+       long value;
        
-       if(base != 0 && base != 10) return 0;
+       long lhs, rhs;
+       int flag1 = 0, flag2 = 0;
        
-       while(isspace(*string)) string++;
-       if(*string == '-') flag = -1;
-       else if(*string == '+') flag = 1;
-       while(*string && isdigit(*string))
+       if(*op1 == '-')
        {
-               value = value * 10 + (*string++ - '0');
+               flag1 = 1;
+               op1++;
        }
-       if(eptr)
-               *eptr = string;
-       return value;
-}
-#endif
-
-//"!" "~" "*" "/" "%" "+" "-" "<" "<=" "<<" ">" ">=" ">>" "!=" "==" "&" "|" "^" "&&" "||";
-static int eval(int op, char *op1, char *op2, char **buffer)
-{
-       long value;
+       if(*op2 == '-')
+       {
+               flag2 = 1;
+               op2++;
+       }
+       lhs = strtoul(op1, NULL, 0);
+       if(flag1) lhs = -lhs;
+       rhs = strtoul(op2, NULL, 0);
+       if(flag2) rhs = -rhs;
+       
        switch(op)
        {
                case 0:
-                       value = !strtol(op2, NULL, 0);
+                       value = !rhs;
                        break;
                case 1: 
-                       value = ~strtol(op2, NULL, 0);
+                       value = ~rhs;
                        break;
                case 2: 
-                       value = strtol(op1, NULL, 0) * strtol(op2, NULL, 0);
+                       value = lhs * rhs;
                        break;
                case 3: 
-                       value = strtol(op1, NULL, 0) / strtol(op2, NULL, 0);
+                       value = lhs / rhs;
                        break;
                case 4: 
-                       value = strtol(op1, NULL, 0) % strtol(op2, NULL, 0);
+                       value = lhs % rhs;
                        break;
                case 5:
-                       value = strtol(op1, NULL, 0) + strtol(op2, NULL, 0);
+                       value = lhs + rhs;
                        break;
                case 6: 
-                       value = strtol(op1, NULL, 0) - strtol(op2, NULL, 0);
+                       value = lhs - rhs;
                        break;
                case 7: 
-                       value = strtol(op1, NULL, 0) < strtol(op2, NULL, 0);
+                       value = lhs < rhs;
                        break;
                case 8: 
-                       value = strtol(op1, NULL, 0) <= strtol(op2, NULL, 0);
+                       value = lhs <= rhs;
                        break;
                case 9: 
-                       value = strtol(op1, NULL, 0) << strtol(op2, NULL, 0);
+                       value = lhs << rhs;
                        break;
                case 10: 
-                       value = strtol(op1, NULL, 0) > strtol(op2, NULL, 0);
+                       value = lhs > rhs;
                        break;
                case 11: 
-                       value = strtol(op1, NULL, 0) >= strtol(op2, NULL, 0);
+                       value = lhs >= rhs;
                        break;
                case 12: 
-                       value = strtol(op1, NULL, 0) >> strtol(op2, NULL, 0);
+                       value = lhs >> rhs;
                        break;
                case 13:
-                       value = strtol(op1, NULL, 0) != strtol(op2, NULL, 0);
+                       value = strcmp(op1, op2) ? 1 : 0;
                        break;
                case 14:
                        value = !strcmp(op1, op2);
                        break;
                case 15:
-                       value = strcmp(op1, op2) ? 1 : 0;
+                       value = lhs & rhs;
                        break;
                case 16: 
-                       value = strtol(op1, NULL, 0) | strtol(op2, NULL, 0);
+                       value = lhs | rhs;
                        break;
                case 17:
-                       value = strtol(op1, NULL, 0) ^ strtol(op2, NULL, 0);
+                       value = lhs ^ rhs;
                        break;
                case 18: 
-                       value = strtol(op1, NULL, 0) && strtol(op2, NULL, 0);
+                       value = lhs && rhs;
                        break;
                case 19: 
-                       value = strtol(op1, NULL, 0) || strtol(op2, NULL, 0);
+                       value = lhs || rhs;
                        break;
                
                default: 
@@ -298,9 +284,10 @@ static int parse_prio(int prio, char **buffer)
        {
                parse_num(&lc);
        }
+       else asprintf(&lc, " ");
        if(err_val)
                return 0;
-       while(tok != -1 && tok >= MIN_TOK && (op_prio[tok - MIN_TOK] > prio + op_assoc[tok - MIN_TOK]))
+       while(tok != -1 && tok >= MIN_TOK && (op_prio[tok - MIN_TOK] > prio - (tok - MIN_TOK <= 1) ? 1 : 0) ) 
        {
                long lhs;
                op  = tok;
@@ -361,7 +348,6 @@ int main(int argc, char *argv[])
 {
        char *ret_val;
        int r;
-       int brackets = 0;
        char *tail;
        r = parse_arith(argv[1], &tail, &ret_val);
        if(r < 0)