infix.c (6427B)
1 /* 2 * 3 * 4 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 5 * 6 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 7 */ 8 9 /* 10 * 11 * $Copyright: $ 12 */ 13 #include <appl/diag/infix.h> 14 15 #include <assert.h> 16 #include <sal/core/libc.h> 17 #include <appl/diag/system.h> 18 19 typedef struct infix_data_s { 20 INFIX_TYPE astk[INFIX_ASTK_SIZE], *asp; 21 int ostk[INFIX_OSTK_SIZE], *osp; 22 int err; 23 } infix_data_t; 24 25 typedef struct infix_op_s { 26 char *str; 27 int op; 28 } infix_op_t; 29 30 #define OP_LPAR '(' 31 #define OP_RPAR ')' 32 #define OP_BNOT '~' 33 #define OP_CNOT 'N' 34 #define OP_UNEG 'U' 35 #define OP_UPLUS 'P' 36 #define OP_MUL '*' 37 #define OP_DIV '/' 38 #define OP_MOD '%' 39 #define OP_ADD '+' 40 #define OP_SUB '-' 41 #define OP_LSH 'l' /* << */ 42 #define OP_RSH 'r' /* >> */ 43 #define OP_LT '<' /* < */ 44 #define OP_LE '[' /* <= */ 45 #define OP_GT '>' /* > */ 46 #define OP_GE ']' /* >= */ 47 #define OP_EQ '=' /* == */ 48 #define OP_NE '!' /* != */ 49 #define OP_BAND '&' 50 #define OP_BOR '|' 51 #define OP_BXOR '^' 52 #define OP_CAND 'A' /* && */ 53 #define OP_COR 'O' /* || */ 54 #define OP_ERR 'x' 55 56 static infix_op_t infix_ops[] = { 57 /* Two-char operators first */ 58 { "<<", OP_LSH }, 59 { ">>", OP_RSH }, 60 { "<=", OP_LE }, 61 { ">=", OP_GE }, 62 { "!=", OP_NE }, 63 { "==", OP_EQ }, 64 { "&&", OP_CAND }, 65 { "||", OP_COR }, 66 { "(", OP_LPAR }, 67 { ")", OP_RPAR }, 68 { "~", OP_BNOT }, 69 { "!", OP_CNOT }, 70 { "*", OP_MUL }, 71 { "/", OP_DIV }, 72 { "%", OP_MOD }, 73 { "+", OP_ADD }, 74 { "-", OP_SUB }, 75 { "&", OP_BAND }, 76 { "|", OP_BOR }, 77 { "^", OP_BXOR }, 78 { "<", OP_LT }, 79 { ">", OP_GT }, 80 { NULL, 0 }, 81 }; 82 83 static int infix_pri(infix_data_t *id, int op) 84 { 85 switch (op) { 86 case OP_LPAR: return 0; 87 case OP_BNOT: case OP_CNOT: 88 case OP_UNEG: case OP_UPLUS: return 1; 89 case OP_MUL: case OP_DIV: 90 case OP_MOD: return 2; 91 case OP_ADD: case OP_SUB: return 3; 92 case OP_LSH: case OP_RSH: return 4; 93 case OP_LT: case OP_LE: 94 case OP_GT: case OP_GE: return 5; 95 case OP_EQ: case OP_NE: return 6; 96 case OP_BAND: return 7; 97 case OP_BXOR: return 8; 98 case OP_BOR: return 9; 99 case OP_CAND: return 10; 100 case OP_COR: return 11; 101 case OP_RPAR: return 12; 102 } 103 104 id->err = 1; 105 106 return 0; 107 } 108 109 static void infix_push(infix_data_t *id, INFIX_TYPE v) 110 { 111 if (id->asp == &id->astk[INFIX_ASTK_SIZE]) 112 { id->err = -1; } 113 else 114 { *id->asp++ = v; } 115 } 116 117 static INFIX_TYPE infix_pop(infix_data_t *id) 118 { 119 if (id->asp == &id->astk[0]) { 120 id->err = -1; 121 return 0; 122 } else { 123 --id->asp; 124 return *id->asp; 125 } 126 } 127 128 static void infix_doop(infix_data_t *id, int op) 129 { 130 INFIX_TYPE v; 131 132 if (op == OP_LPAR || op == OP_RPAR) 133 { return; } 134 135 v = infix_pop(id); 136 137 switch (op) { 138 case OP_BNOT: v = ~v; break; 139 case OP_UNEG: v = 0 - v; break; 140 case OP_CNOT: v = ! v; break; 141 case OP_MUL: v = infix_pop(id) * v; break; 142 case OP_DIV: if (v == 0) { id->err = 1; } 143 else { v = infix_pop(id) / v; } break; 144 case OP_MOD: if (v == 0) { id->err = 1; } 145 else { v = infix_pop(id) % v; } break; 146 case OP_ADD: v = infix_pop(id) + v; break; 147 case OP_SUB: v = infix_pop(id) - v; break; 148 case OP_LSH: v = infix_pop(id) << v; break; 149 case OP_RSH: v = infix_pop(id) >> v; break; 150 case OP_BAND: v = infix_pop(id) & v; break; 151 case OP_BXOR: v = infix_pop(id) ^ v; break; 152 case OP_BOR: v = infix_pop(id) | v; break; 153 case OP_LT: v = infix_pop(id) < v; break; 154 case OP_GT: v = infix_pop(id) > v; break; 155 case OP_LE: v = infix_pop(id) <= v; break; 156 case OP_GE: v = infix_pop(id) >= v; break; 157 case OP_NE: v = infix_pop(id) != v; break; 158 case OP_EQ: v = infix_pop(id) == v; break; 159 case OP_CAND: v = infix_pop(id) && v; break; 160 case OP_COR: v = infix_pop(id) || v; break; 161 } 162 163 infix_push(id, v); 164 } 165 166 int infix_getop(char **s) 167 { 168 int i; 169 170 for (i = 0; infix_ops[i].str != NULL; i++) { 171 if (infix_ops[i].str[1] == 0) { 172 if (infix_ops[i].str[0] == (*s)[0]) { 173 (*s)++; 174 return infix_ops[i].op; 175 } 176 } else if (infix_ops[i].str[0] == (*s)[0] && 177 infix_ops[i].str[1] == (*s)[1]) { 178 (*s) += 2; 179 return infix_ops[i].op; 180 } 181 } 182 183 return OP_ERR; 184 } 185 186 int infix_eval(char *s, INFIX_TYPE *v) 187 { 188 int i, p, prev_was_op = 1; 189 infix_data_t id; 190 191 id.asp = &id.astk[0]; 192 id.osp = &id.ostk[0]; 193 id.err = 0; 194 195 while ((i = *s) != 0) { 196 if (isspace(i)) 197 { s++; } 198 else if (isdigit(i)) { 199 infix_push(&id, sal_ctoi(s, &s)); 200 prev_was_op = 0; 201 } else { 202 i = infix_getop(&s); 203 if (i == OP_ERR) { 204 id.err = 1; 205 break; 206 } 207 if (i == OP_SUB && prev_was_op) 208 { i = OP_UNEG; } 209 else if (i == OP_ADD && prev_was_op) 210 i = OP_UPLUS; 211 else if ((i == OP_CNOT || i == OP_BNOT) && prev_was_op) { 212 /* skip */ 213 } else { 214 p = infix_pri(&id, i); 215 while (id.osp > id.ostk && infix_pri(&id, id.osp[-1]) <= p) 216 infix_doop(&id, *--id.osp); 217 } 218 *id.osp++ = i; 219 prev_was_op = (i != OP_RPAR); 220 } 221 } 222 223 while (id.osp > id.ostk) 224 infix_doop(&id, *--id.osp); 225 226 *v = infix_pop(&id); 227 228 if (id.asp != id.astk) 229 { id.err = -1; } 230 231 return id.err; 232 }