1 /* Recursive descent arithmetic calculator:
22 #ifndef __ARITH_TEST__
29 #define TOK_PLUS (MIN_TOK + 5)
30 #define TOK_MINUS (MIN_TOK + 6)
31 #define TOK_NUMBER 256
32 #define TOK_STRING 257
38 char *inp, *prev, *orig;
46 /* Here is a table of the operators */
47 const char op_table[NUM_OPS * 3 + 1] = { '!', SEP2 , '~', SEP2, '*', SEP2, '/', SEP2, '%', SEP2, '+', SEP2, '-', SEP2,
48 '<', SEP2, '<', '=', SEP1, '<', '<', SEP1, '>', SEP2, '>', '=', SEP1, '>', '>', SEP1, '&', SEP2,
49 '|', SEP2, '^', SEP2, '&', '&', SEP1, '|', '|', SEP1, '!', '=', SEP1, '=', '=', SEP1, '\0'
52 const char *keyword_table = " \t\v()!~*/%+-<=>&|^"; /* Characters that cannot appear in a string */
53 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 };
55 static void ignore_whitespace ( void );
56 static int parse_expr ( char **buffer );
58 static void input ( void ) {
59 char t_op[3] = { '\0', '\0', '\0'};
74 /* Check for a number */
75 if ( isdigit ( *inp ) ) {
77 tok_value.num_value = strtoul ( inp, &inp, 0 );
81 /* Check for a string */
82 len = strcspn ( inp, keyword_table );
88 if ( ( tok_value.str_value = malloc ( len + 1 ) ) == NULL ) {
92 strncpy ( tok_value.str_value, inp - len, len );
93 tok_value.str_value[len] = 0;
97 /* Check for an operator */
99 p1 = strstr ( op_table, t_op );
100 if ( !p1 ) { /* The character is not present in the list of operators */
106 p2 = strstr ( op_table, t_op );
107 if ( !p2 || p1 == p2 ) {
108 if ( ( p1 - op_table ) % 3 ) { /* Without this, it would take '=' as '<=' */
113 tok = MIN_TOK + ( p1 - op_table ) / 3;
117 tok = MIN_TOK + ( p2 - op_table ) / 3;
120 /* 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 */
121 static int isnum ( char *string, long *num ) {
125 if ( *string == '+' ) {
127 } else if ( *string == '-' ) {
131 *num = strtoul ( string, &string, 0 );
132 if ( *string != 0 ) {
141 static void ignore_whitespace ( void ) {
142 while ( isspace ( *inp ) ) {
147 static int accept ( int ch ) {
155 static void skip ( int ch ) {
156 if ( !accept ( ch ) ) {
161 static int parse_num ( char **buffer ) {
165 if ( tok == TOK_MINUS || tok == TOK_PLUS || tok == '(' || tok == TOK_NUMBER ) {
167 if ( accept ( TOK_MINUS ) ) //Handle -NUM and +NUM
169 else if ( accept ( TOK_PLUS ) ) {
172 if ( accept ( '(' ) ) {
173 parse_expr ( buffer );
184 t = isnum ( *buffer, &num );
186 if ( t == 0 ) { /* Trying to do a -string, which should not be permitted */
187 return ( err_val = -4 );
189 return ( ( asprintf ( buffer, "%ld", -num ) < 0 ) ? (err_val = -ENOMEM ) : 0 );
194 if ( tok == TOK_NUMBER ) {
196 num = -tok_value.num_value;
198 num = tok_value.num_value;
200 return ( ( asprintf ( buffer, "%ld", num ) < 0) ? (err_val = -ENOMEM ) : 0 );
202 return ( err_val = -1 );
204 if ( tok == TOK_STRING ) {
205 *buffer = tok_value.str_value;
209 return ( err_val = -1 );
212 static int eval(int op, char *op1, char *op2, char **buffer) {
218 if ( ! isnum ( op1, &lhs ) )
222 if ( ! isnum (op2, &rhs ) )
225 if ( op <= 17 && ! bothints ) {
226 return ( err_val = -4 );
244 return ( err_val = -2 );
290 value = strcmp ( op1, op2 ) != 0;
293 value = strcmp ( op1, op2 ) == 0;
295 default: /* This means the operator is in the op_table, but not defined in this switch statement */
296 return ( err_val = -3 );
298 return ( ( asprintf(buffer, "%ld", value) < 0) ? ( err_val = -ENOMEM ) : 0 );
301 static int parse_prio(int prio, char **buffer) {
305 if ( tok < MIN_TOK || tok == TOK_MINUS || tok == TOK_PLUS ) {
308 if ( tok < MIN_TOK + 2 ) {
311 return ( err_val = -1 );
318 while( tok != -1 && tok != ')' ) {
320 if ( tok < MIN_TOK ) {
323 return ( err_val = -1 );
325 if ( op_prio[tok - MIN_TOK] <= prio - ( tok - MIN_TOK <= 1 ) ? 1 : 0 ) {
331 parse_prio ( op_prio[op - MIN_TOK], &rc );
339 lhs = eval ( op - MIN_TOK, lc, rc, buffer );
352 static int parse_expr ( char **buffer ) {
353 return parse_prio ( -1, buffer );
356 int parse_arith ( char *inp_string, char **end, char **buffer ) {
358 orig = inp = inp_string;
363 parse_expr ( buffer );
373 if ( err_val ) { //Read till we get a ')'
375 if ( tok == TOK_STRING )
376 free ( tok_value.str_value );
379 printf ( "parse error:\n%s\n", orig );
382 printf ( "division by 0\n" );
385 printf ( "operator undefined\n" );
388 printf ( "wrong type of operand\n" );
391 printf("out of memory\n");
400 #ifdef __ARITH_TEST__
401 int main ( int argc, char *argv[] ) {
404 char *head, *tail, *string, *t;
407 while ( !feof ( stdin ) ) {
408 fgets ( line, 100, stdin );
409 if ( line[strlen ( line ) - 1] == '\n' )
410 line[strlen ( line ) - 1] = 0;
411 asprintf ( &string, "%s", line );
412 while ( ( head = strstr ( string, "$(" ) ) != NULL ) {
414 r = parse_arith ( head, &tail, &ret_val );
417 asprintf ( &string, "%s%s%s", string, ret_val, tail );
424 printf ( "Line: %s\n", string );