1 /* Recursive descent arithmetic calculator:
22 #include <gpxe/parse.h>
27 #define TOK_PLUS (MIN_TOK + 5)
28 #define TOK_MINUS (MIN_TOK + 6)
29 #define TOK_NUMBER 256
30 #define TOK_STRING 257
36 #define EPARSE (EINVAL | EUNIQ_01)
37 #define EDIV0 (EINVAL | EUNIQ_02)
38 #define ENOOP (EINVAL | EUNIQ_03)
39 #define EWRONGOP (EINVAL | EUNIQ_04)
41 static struct string *input_str;
42 static char *inp_ptr = NULL;
50 /* Here is a table of the operators */
51 static const char op_table[NUM_OPS * 3 + 1] = { '!', SEP2 , '~', SEP2, '*', SEP2, '/', SEP2, '%', SEP2, '+', SEP2, '-', SEP2,
52 '<', SEP2, '<', '=', SEP1, '<', '<', SEP1, '>', SEP2, '>', '=', SEP1, '>', '>', SEP1, '&', SEP2,
53 '|', SEP2, '^', SEP2, '&', '&', SEP1, '|', '|', SEP1, '!', '=', SEP1, '=', '=', SEP1, '\0'
56 static signed const char op_prio[NUM_OPS] = { 10, 10, 9, 9, 9, 8, 8, 6, 6, 7, 6, 6, 7, 4, 3, 2, 1, 0, 5, 5 };
58 static void ignore_whitespace ( void );
59 static int parse_expr ( char **buffer );
61 struct char_table table[21] = {
62 { .token = '\\', .type = FUNC, .next.parse_func = parse_escape },
63 { .token = '"', .type = TABLE, .next = { .next_table = { .ntable = dquote_table, .len = 3 } } },
64 { .token = '$', .type = FUNC, .next.parse_func = dollar_expand },
65 { .token = '\'', .type = TABLE, .next = { .next_table = { .ntable = squote_table, .len = 1 } } },
66 { .token = ' ', .type = ENDQUOTES },
67 { .token = '\t', .type = ENDQUOTES },
68 { .token = '~', .type = ENDTOK },
69 { .token = '!', .type = ENDTOK },
70 { .token = '*', .type = ENDTOK },
71 { .token = '/', .type = ENDTOK },
72 { .token = '%', .type = ENDTOK },
73 { .token = '+', .type = ENDTOK },
74 { .token = '-', .type = ENDTOK },
75 { .token = '<', .type = ENDTOK },
76 { .token = '=', .type = ENDTOK },
77 { .token = '>', .type = ENDTOK },
78 { .token = '&', .type = ENDTOK },
79 { .token = '|', .type = ENDTOK },
80 { .token = '^', .type = ENDTOK },
81 { .token = '(', .type = ENDTOK },
82 { .token = ')', .type = ENDTOK }
85 static void input ( void ) {
86 char t_op[3] = { '\0', '\0', '\0'};
88 char *tmp, *strtmp = NULL;
97 if ( *inp_ptr == '\0' ) {
103 tmp = expand_string ( input_str, &inp_ptr, &end, table, 21, 0, &success );
111 strtmp = strndup ( inp_ptr, end - inp_ptr );
112 if ( isnum ( strtmp, &tok_value.num_value ) ) {
116 tok_value.str_value = strtmp;
123 /* Check for an operator */
124 t_op[0] = *inp_ptr++;
125 p1 = strstr ( op_table, t_op );
126 if ( !p1 ) { /* The character is not present in the list of operators */
132 p2 = strstr ( op_table, t_op );
133 if ( !p2 || p1 == p2 ) {
134 if ( ( p1 - op_table ) % 3 ) { /* Without this, it would take '=' as '<=' */
139 tok = MIN_TOK + ( p1 - op_table ) / 3;
143 tok = MIN_TOK + ( p2 - op_table ) / 3;
147 /* Check if a string is a number: "-1" and "+42" is accepted, but not "-1a". If so, place it in num and return 1 else num = 0 and return 0 */
148 int isnum ( char *string, long *num ) {
152 if ( *string == '+' ) {
154 } else if ( *string == '-' ) {
158 *num = strtoul ( string, &string, 0 );
159 if ( *string != 0 ) {
168 static void ignore_whitespace ( void ) {
169 while ( isspace ( *inp_ptr ) ) {
174 static int accept ( int ch ) {
182 static void skip ( int ch ) {
183 if ( !accept ( ch ) ) {
188 static int parse_num ( char **buffer ) {
192 if ( tok == TOK_MINUS || tok == TOK_PLUS || tok == '(' || tok == TOK_NUMBER ) {
194 if ( accept ( TOK_MINUS ) ) //Handle -NUM and +NUM
196 else if ( accept ( TOK_PLUS ) ) {
199 if ( accept ( '(' ) ) {
200 parse_expr ( buffer );
211 t = isnum ( *buffer, &num );
213 if ( t == 0 ) { /* Trying to do a -string, which should not be permitted */
214 return ( err_val = -EWRONGOP );
216 return ( ( asprintf ( buffer, "%ld", -num ) < 0 ) ? (err_val = -ENOMEM ) : 0 );
221 if ( tok == TOK_NUMBER ) {
223 num = -tok_value.num_value;
225 num = tok_value.num_value;
227 return ( ( asprintf ( buffer, "%ld", num ) < 0) ? (err_val = -ENOMEM ) : 0 );
229 return ( err_val = -EPARSE );
231 if ( tok == TOK_STRING ) {
232 *buffer = tok_value.str_value;
236 return ( err_val = -EPARSE );
239 static int eval(int op, char *op1, char *op2, char **buffer) {
245 if ( ! isnum ( op1, &lhs ) )
249 if ( ! isnum (op2, &rhs ) )
252 if ( op <= 17 && ! bothints ) {
253 return ( err_val = -EWRONGOP );
271 return ( err_val = -EDIV0 );
317 value = strcmp ( op1, op2 ) != 0;
320 value = strcmp ( op1, op2 ) == 0;
322 default: /* This means the operator is in the op_table, but not defined in this switch statement */
323 return ( err_val = -ENOOP );
325 return ( ( asprintf(buffer, "%ld", value) < 0) ? ( err_val = -ENOMEM ) : 0 );
328 static int parse_prio(int prio, char **buffer) {
332 if ( tok < MIN_TOK || tok == TOK_MINUS || tok == TOK_PLUS ) {
335 if ( tok < MIN_TOK + 2 ) {
338 return ( err_val = -EPARSE );
345 while( tok != -1 && tok != ')' ) {
347 if ( tok < MIN_TOK ) {
350 return ( err_val = -EPARSE );
352 if ( op_prio[tok - MIN_TOK] <= prio - ( tok - MIN_TOK <= 1 ) ? 1 : 0 ) {
358 parse_prio ( op_prio[op - MIN_TOK], &rc );
366 lhs = eval ( op - MIN_TOK, lc, rc, buffer );
379 static int parse_expr ( char **buffer ) {
380 return parse_prio ( -1, buffer );
383 int parse_arith ( struct string *inp, char *orig, char **end ) {
387 start = orig - inp->value;
396 parse_expr ( &buffer );
403 orig = inp->value + start;
406 orig = string3cat ( inp, buffer, *end );
407 *end = orig + start + strlen ( buffer );
412 if ( tok == TOK_STRING )
413 free ( tok_value.str_value );
416 printf ( "parse error\n" );
419 printf ( "division by 0\n" );
422 printf ( "operator undefined\n" );
425 printf ( "wrong type of operand\n" );
428 printf("out of memory\n");