#include #include #include #include #define ROW_SIZE 1024 #define STACK_ROWS 256 #define VIEW_ROWS 10 #define STRLEN 1024 char **stack; char **undo_stack; char **temp_stack; enum { BASE_NONE, BASE_HEX, BASE_BINARY, BASE_TIME, }; enum { ANGLE_RAD, ANGLE_DEG }; int current_base = BASE_HEX; int current_angle = ANGLE_RAD; char hex_table[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; // Units #define UNITS_NONE 0 #define UNITS_LB 1 #define UNITS_OZ 2 #define UNITS_KG 3 #define UNITS_MI 4 #define UNITS_YD 5 #define UNITS_FT 6 #define UNITS_IN 7 #define UNITS_KM 8 #define UNITS_MM 9 #define UNITS_CM 10 #define UNITS_M 11 #define UNITS_C 12 #define UNITS_F 13 #define UNITS_G 14 // 2 letter units must come before 1 letter units because they're longer const char *unit_titles[] = { "", "_lb", "_oz", "_kg", "_mi", "_yd", "_ft", "_in", "_km", "_mm", "_cm", "_m", "_c", "_f", "_g" }; typedef struct { int from_units; int to_units; double factor; double offset; } conversion_t; conversion_t conversions[] = { { UNITS_LB, UNITS_OZ, 16.0, 0.0 }, { UNITS_KG, UNITS_LB, 2.2046, 0.0 }, { UNITS_KG, UNITS_G, 1000.0, 0.0 }, { UNITS_MI, UNITS_YD, 1760, 0.0 }, { UNITS_YD, UNITS_FT, 3, 0.0 }, { UNITS_FT, UNITS_IN, 12, 0.0 }, { UNITS_M, UNITS_FT, 3.2808, 0.0 }, { UNITS_KM, UNITS_M, 1000, 0.0 }, { UNITS_M, UNITS_CM, 100, 0.0 }, { UNITS_CM, UNITS_MM, 10, 0.0 }, { UNITS_C, UNITS_F, 9.0 / 5.0, 32.0 } }; #define TOTAL_CONVERSIONS (sizeof(conversions) / sizeof(conversion_t)) // Replica of conversion table with the current value in // the positions of the different units typedef struct { double from_value; double to_value; int from_valid; int to_valid; } current_conversion_t; current_conversion_t current_conversions[TOTAL_CONVERSIONS]; typedef struct { double value; int units; int base; } number_t; number_t to_number(char *string); void to_string(char *string, number_t number); void copy_stack(char **dst, char **src) { int i; for(i = 0; i < STACK_ROWS; i++) { strcpy(dst[i], src[i]); } } int stack_size() { int total_rows = 0; int i; for(i = 0 ; i < VIEW_ROWS; i++) { if(strlen(stack[i])) total_rows++; else break; } return total_rows; } void dump_usage() { printf( "Operators: + - / * %% & | ^ -= 1/ << >>\n" "Functions: pow sqrt sin cos tan asin acos atan log log10\n" "Constants: pi e\n" "Stack: c - clear stack | d - clear row | s - swap rows | u - undo | Enter - copy\n" "Mode: b - bin | h - hex | : - time | rb - real to base | br - base to real | rad | deg\n" "Units: _c _f | _lb _oz | _kg _g | _mi _yd _ft _in | _km _m _cm _mm\n" ); } void dump_base() { char current_base_string[STRLEN]; char current_angle_string[STRLEN]; switch(current_base) { case BASE_HEX: sprintf(current_base_string, "HEX"); break; case BASE_BINARY: sprintf(current_base_string, "BIN"); break; case BASE_TIME: sprintf(current_base_string, "TIME"); break; } switch(current_angle) { case ANGLE_RAD: sprintf(current_angle_string, "RAD"); break; case ANGLE_DEG: sprintf(current_angle_string, "DEG"); break; } printf( "%s %s -------------------------------------------------------\n", current_base_string, current_angle_string ); } void dump_stack() { int i; int total_rows = stack_size(); dump_base(); // for(i = VIEW_ROWS - 1; i >= 0; i--) for(i = total_rows - 1; i >= 0; i--) { // printf("%d:%s\n", i, stack[i]); printf("%s\n", stack[i]); } } int is_hex(char *ptr) { int got_it = 1; int j; while(*ptr != 0 && got_it) { got_it = 0; for(j = 0; j < sizeof(hex_table) && !got_it; j++) { if(toupper(*ptr) == hex_table[j]) { got_it = 1; } } ptr++; } if(!got_it) { printf("*** Not a hex number\n"); return 0; } return 1; } int is_bin(char *ptr) { while(*ptr != 0) { if(*ptr != '0' && *ptr != '1' && *ptr != ' ') { printf("*** Not a binary number\n"); return 0; } ptr++; } return 1; } void reformat_binary(char *string) { int counter = 0; int i, j; //printf("reformat_binary %d %s\n", __LINE__, string); // remove spaces for(i = 0; i < strlen(string); i++) { if(string[i] == ' ') { for(j = i; j < strlen(string); j++) { string[j] = string[j + 1]; } string[j] = 0; } } // pad to 4 bits int increment = 4; int bits = strlen(string) - 2; int padding = increment - (bits % increment); //printf("reformat_binary %d padding=%d\n", __LINE__, padding); if(padding < increment && padding > 0) { int len = strlen(string); string[len + padding] = 0; for(i = len - 1; i >= 2; i--) { string[i + padding] = string[i]; } for(i = 2; i < 2 + padding; i++) { string[i] = '0'; } } // add spaces for(i = strlen(string) - 1; i >= 2; i--) { if(counter == 4) { // insert a space after 4 digits if(string[i] != ' ') { string[strlen(string) + 1] = 0; for(j = strlen(string) - 1; j > i; j--) { string[j + 1] = string[j]; } string[i + 1] = ' '; } counter = 1; } else { counter++; } } //printf("reformat_binary %d %s\n", __LINE__, string); } void push_stack(char *string) { int i, j; if(string[0]) { // check the base // if(string[0] == '#') // { // if(current_base == BASE_TIME) // { // printf("*** Not a time\n"); // return; // } // else // if(current_base == BASE_BINARY) // { // if(!is_bin(string + 1)) // { // return; // } // } // else // if(current_base == BASE_HEX) // { // if(!is_hex(string + 1)) // { // return; // } // } // } // else if(string[1] && string[0] == '0' && string[1] == 'b') { reformat_binary(string); //printf("push_stack %d %s\n", __LINE__, string); if(!is_bin(string + 2)) return; } else if(string[1] && string[0] == '0' && (string[1] == 'x' || string[1] == 'h')) { if(!is_hex(string + 2)) return; } else // Throw out unknown bases if(string[1] && string[0] == '0' && isalpha(string[1])) { printf("*** Unrecognized format\n"); return; } for(i = STACK_ROWS - 1; i >= 1; i--) { strcpy(stack[i], stack[i - 1]); } strcpy(stack[0], string); } // dump_stack(); } // Remove the lowest item and put it in the string. void pop_stack(char *string) { int i; strcpy(string, stack[0]); for(i = 0; i < STACK_ROWS - 1; i++) { strcpy(stack[i], stack[i + 1]); } stack[STACK_ROWS - 1][0] = 0; } void replicate_row() { int i; for(i = STACK_ROWS - 1; i >= 1; i--) { strcpy(stack[i], stack[i - 1]); } dump_stack(); } void delete_row() { int i; for(i = 0; i < STACK_ROWS - 1; i++) { strcpy(stack[i], stack[i + 1]); } stack[STACK_ROWS - 1][0] = 0; dump_stack(); } void swap_row() { char *temp; temp = stack[0]; stack[0] = stack[1]; stack[1] = temp; dump_stack(); } void clear_stack(char **stack) { int i; for(i = 0; i < STACK_ROWS; i++) stack[i][0] = 0; dump_stack(); } // return the offset if it's a #, 0x, or 0b // return 0 if it's decimal int base_offset(char *string) { int len = strlen(string); // if(len > 0 && string[0] == '#') return 1; if(len > 1 && string[0] == '0' && string[1] == 'x') return 2; if(len > 1 && string[0] == '0' && string[1] == 'h') return 2; if(len > 1 && string[0] == '0' && string[1] == 'b') return 2; return 0; } int64_t read_binary(char *string) { int i; int64_t result = 0; int len = strlen(string); int offset = base_offset(string); for(i = offset; i < len; i++) { if(string[i] != ' ') { result <<= 1; if(string[i] == '1') result |= 1; } } return result; } int64_t read_hex(char *string) { int i, j; int64_t result = 0; int len = strlen(string); int offset = base_offset(string); for(i = offset; i < len; i++) { result <<= 4; for(j = 0; j < 0x10; j++) { if(toupper(string[i]) == hex_table[j]) { result |= j; j = 0x10; } } } return result; } void write_binary(char *string, int64_t number) { int64_t i; int got_it = 0; sprintf(string, "0b"); for(i = 0x4000000000000000LL; i > 0; i >>= 1) { if(number & i) { strcat(string, "1"); got_it = 1; } else if(got_it) strcat(string, "0"); } if(!got_it) strcat(string, "0"); //printf("write_binary %d %s\n", __LINE__, string); // Add formatting spaces reformat_binary(string); //printf("write_binary %d %s\n", __LINE__, string); } void to_hex() { int i; for(i = 0; i < STACK_ROWS; i++) { number_t number = to_number(stack[i]); if(number.base != BASE_NONE && number.base != BASE_HEX) { number.base = BASE_HEX; to_string(stack[i], number); } } current_base = BASE_HEX; dump_stack(); } void to_bin() { int i; for(i = 0; i < STACK_ROWS; i++) { number_t number = to_number(stack[i]); if(number.base != BASE_NONE && number.base != BASE_BINARY) { number.base = BASE_BINARY; to_string(stack[i], number); } } current_base = BASE_BINARY; dump_stack(); } void to_time() { int i; for(i = 0; i < STACK_ROWS; i++) { number_t number = to_number(stack[i]); if(number.base != BASE_NONE && number.base != BASE_TIME) { number.base = BASE_TIME; to_string(stack[i], number); } } current_base = BASE_TIME; dump_stack(); } void to_rad() { current_angle = ANGLE_RAD; dump_stack(); } void to_deg() { current_angle = ANGLE_DEG; dump_stack(); } // Convert stack line into a number with units number_t to_number(char *string) { int len = strlen(string); char string2[ROW_SIZE]; number_t result; result.units = UNITS_NONE; result.base = BASE_NONE; // extract units char *ptr = strrchr(string, '_'); //printf("to_number %d string=%s ptr=%s\n", __LINE__, string, ptr); if(ptr) { int i; for(i = 0; i < sizeof(unit_titles) / sizeof(char*); i++) { if(!strcmp(ptr, unit_titles[i])) { result.units = i; //printf("to_number %d units=%d\n", __LINE__, i); break; } } } // extract time ptr = strrchr(string, ':'); //printf("to_number %d %s\n", __LINE__, ptr); if(ptr) { // Get seconds double seconds = atof(ptr + 1); double minutes = 0; double hours = 0; char *ptr2 = ptr - 1; while(ptr2 >= string) { if(*ptr2 == ':' || ptr2 == string) { char *ptr3 = ptr2; if(*ptr3 == ':') ptr3++; memcpy(string2, ptr3, ptr - ptr3); string2[ptr - ptr3] = 0; // printf("to_number %d %s\n", __LINE__, string2); minutes = atof(string2); break; } ptr2--; } if(ptr2 && ptr2 > string) { memcpy(string2, string, ptr2 - string); string2[ptr2 - string] = 0; // printf("to_number %d %s\n", __LINE__, string2); hours = atof(string2); } // printf("to_number %d hours=%f minutes=%f seconds=%f\n", // __LINE__, // hours, // minutes, // seconds); result.value = hours * 3600 + minutes * 60 + seconds; result.base = BASE_TIME; return result; } // extract base // if(string[0] == '#') // { // switch(current_base) // { // case BASE_HEX: // result.base = BASE_HEX; // result.value = (double)read_hex(string); // break; // // case BASE_BINARY: // result.base = BASE_BINARY; // result.value = (double)read_binary(string + 1); // break; // } // } if(len > 2 && string[0] == '0' && (string[1] == 'x' || string[1] == 'h')) { result.base = BASE_HEX; result.value = (double)read_hex(string); } if(len > 2 && string[0] == '0' && string[1] == 'b') { result.base = BASE_BINARY; result.value = (double)read_binary(string + 2); } // return now if(result.base != BASE_NONE) return result; // Remove commas char *in = string; char *out = string2; while(*in) { if(*in != ',') *out++ = *in; in++; } *out++ = 0; // Convert exponents to scientific notation // atof can't handle large numbers if(labs(atoll(string2)) > 0x7fffffff) { result.value = (double)atoll(string2); } else { result.value = atof(string2); } return result; } number_t pop_number() { char string[ROW_SIZE]; int i, j; pop_stack(string); return to_number(string); } // Convert number to stack line void to_string(char *string, number_t number) { int has_fraction = (floor(number.value) != number.value); switch(number.base) { case BASE_NONE: // Number has no fraction part if(!has_fraction) { sprintf(string, "%ld", (int64_t)number.value); } else { int i; if(fabs(number.value) > 0.00001) sprintf(string, "%f", number.value); else sprintf(string, "%.16e", number.value); // Truncate fraction part for(i = strlen(string) - 1; i > 0; i--) { if(string[i] != '0') { string[i + 1] = 0; break; } } } break; case BASE_HEX: sprintf(string, "0x%lx", (int64_t)number.value); break; case BASE_BINARY: write_binary(string, (int64_t)number.value); break; case BASE_TIME: { char string2[STRLEN]; int force = 0; string[0] = 0; // hours if(number.value > 60 * 60) { sprintf(string, "%d:", (int)number.value / 60 / 60); force = 1; } // minutes if(number.value > 60 || force) { if(force) { sprintf(string2, "%02d:", ((int)number.value / 60) % 60); } else { sprintf(string2, "%d:", (int)number.value / 60); } strcat(string, string2); force = 1; } // seconds if(force) { sprintf(string2, "%02d", (int)number.value % 60); strcat(string, string2); if(has_fraction) { sprintf(string2, "%f", number.value - (int)number.value); strcat(string, string2 + 1); } } else { sprintf(string2, "%f", number.value); strcat(string, string2); } } } strcat(string, unit_titles[number.units]); // printf("to_string %d: string=%s\n", __LINE__, string); } // arg1 is most recent slot void promote_units(number_t *output, number_t arg1, number_t arg2) { if(arg1.units == UNITS_NONE) output->units = arg2.units; else output->units = arg1.units; if(arg1.base == BASE_NONE) output->base = arg2.base; else output->base = arg1.base; } void push_number(number_t number) { char string[ROW_SIZE]; to_string(string, number); push_stack(string); dump_stack(); } void convert_units(int to_units) { // Get units of current item char prev_item[ROW_SIZE]; int i, j; int total_rows = stack_size(); pop_stack(prev_item); // Does previous item have units? char *ptr = strrchr(prev_item, '_'); // Add dimension to item if(!ptr) { strcat(prev_item, unit_titles[to_units]); } else // Convert item's dimension { // Fill in every value in the table until the output units are found bzero(current_conversions, sizeof(current_conversions)); int done = 0; // Get the number number_t from_number; from_number = to_number(prev_item); //printf("convert_units %d %d %d\n", __LINE__, to_units, from_number.units); // First fill in every matching table entry with the number for(i = 0; i < TOTAL_CONVERSIONS; i++) { conversion_t *conversion = &conversions[i]; if(conversion->from_units == from_number.units) { current_conversions[i].from_value = from_number.value; current_conversions[i].from_valid = 1; } if(conversion->to_units == from_number.units) { current_conversions[i].to_value = from_number.value; current_conversions[i].to_valid = 1; } } // Iterate through the table until the output is found while(!done) { int conversion_done = 0; // Propogate incomplete conversions to all slots for(i = 0; i < TOTAL_CONVERSIONS; i++) { // Find an incomplete conversion current_conversion_t *current_conversion = ¤t_conversions[i]; conversion_t *conversion = &conversions[i]; number_t propogate; propogate.value = 0; propogate.units = UNITS_NONE; propogate.base = BASE_NONE; if(current_conversion->from_valid && !current_conversion->to_valid) { current_conversion->to_value = current_conversion->from_value * conversion->factor + conversion->offset; current_conversion->to_valid = 1; propogate.units = conversion->to_units; propogate.value = current_conversion->to_value; } else if(current_conversion->to_valid && !current_conversion->from_valid) { current_conversion->from_value = (current_conversion->to_value - conversion->offset) / conversion->factor; current_conversion->from_valid = 1; propogate.units = conversion->from_units; propogate.value = current_conversion->from_value; } // Propogate the new value to matching slots if(propogate.units != UNITS_NONE) { // If the units match, quit if(propogate.units == to_units) { done = 1; to_string(prev_item, propogate); break; } for(i = 0; i < TOTAL_CONVERSIONS; i++) { conversion_t *conversion = &conversions[i]; if(conversion->from_units == propogate.units) { current_conversions[i].from_value = propogate.value; current_conversions[i].from_valid = 1; conversion_done = 1; } if(conversion->to_units == propogate.units) { current_conversions[i].to_value = propogate.value; current_conversions[i].to_valid = 1; conversion_done = 1; } } } } if(!conversion_done && !done) break; } if(!done) { printf("*** Unsupported unit conversion %s to %s\n", unit_titles[from_number.units], unit_titles[to_units]); } } // Replace item push_stack(prev_item); // Failed to replace item if(total_rows > stack_size()) { copy_stack(stack, undo_stack); } dump_stack(); } int main(int argc, char *argv[]) { int i; stack = calloc(STACK_ROWS, sizeof(char*)); undo_stack = calloc(STACK_ROWS, sizeof(char*)); temp_stack = calloc(STACK_ROWS, sizeof(char*)); for(i = 0; i < STACK_ROWS; i++) { stack[i] = calloc(1, ROW_SIZE); undo_stack[i] = calloc(1, ROW_SIZE); temp_stack[i] = calloc(1, ROW_SIZE); } // printf("Heroine Calculator\n"); dump_stack(); char string[ROW_SIZE]; while(1) { fgets(string, ROW_SIZE, stdin); // remove trailing garbage char *ptr = string + strlen(string) - 1; while(ptr >= string && (*ptr == 0xa || *ptr == ' ')) *ptr-- = 0; // remove leading garbage while(string[0] != 0 && string[0] ==' ') { memcpy(string, string + 1, strlen(string + 1) + 1); } // detect invalid characters if(string[0] == '#') { printf("*** # notation is not supported. Use 0x or 0b instead.\n"); } else { // Detect conversion command int is_units = 0; int to_units = UNITS_NONE; if(string[0] == '_') { for(i = 0; i < TOTAL_CONVERSIONS; i++) { if(!strcmp(string, unit_titles[conversions[i].from_units])) { is_units = 1; to_units = conversions[i].from_units; break; } else if(!strcmp(string, unit_titles[conversions[i].to_units])) { is_units = 1; to_units = conversions[i].to_units; break; } } } // Detect command with trailing arithmetic operator if(strcmp(string, "1/")) { // If a trailing arithmetic operator exists, split the command into 2 lines. for(ptr = string + strlen(string) - 1; ptr >= string; ptr--) { if(*ptr != '+' && *ptr != '-' && *ptr != '/' && *ptr != '*' && *ptr != '%' && *ptr != '&' && *ptr != '|' && *ptr != '^' && *ptr != '<' && *ptr != '>') { ptr++; if(!strcmp(ptr, "+") || !strcmp(ptr, "-") || !strcmp(ptr, "/") || !strcmp(ptr, "*") || !strcmp(ptr, "%") || !strcmp(ptr, "&") || !strcmp(ptr, "|") || !strcmp(ptr, "^") || !strcmp(ptr, "<<") || !strcmp(ptr, ">>")) { char temp[ROW_SIZE]; strcpy(temp, string); temp[ptr - string] = 0; copy_stack(undo_stack, stack); // These are constants which may be followed by an operator // Expand temp if(!strcmp(temp, "pi")) { number_t number; number.units = UNITS_NONE; number.base = BASE_NONE; number.value = M_PI; push_number(number); } else if(!strcmp(temp, "e")) { number_t number; number.units = UNITS_NONE; number.base = BASE_NONE; number.value = exp(1); push_number(number); } else { push_stack(temp); } strcpy(string, ptr); //printf("main %d temp=%s string=%s\n", __LINE__, temp, string); } break; } } } // replicate row if(!string[0]) { copy_stack(undo_stack, stack); replicate_row(); } else if(is_units) { copy_stack(undo_stack, stack); convert_units(to_units); } else if(!strcmp(string, "-=")) { copy_stack(undo_stack, stack); number_t number = pop_number(); number.value = -number.value; push_number(number); } else if(!strcmp(string, "1/")) { copy_stack(undo_stack, stack); number_t number = pop_number(); number.value = 1.0 / number.value; push_number(number); } else if(!strcmp(string, "sqrt")) { copy_stack(undo_stack, stack); number_t number = pop_number(); number.value = sqrt(number.value); push_number(number); } else if(!strcmp(string, "sin")) { copy_stack(undo_stack, stack); number_t number = pop_number(); if(current_angle == ANGLE_DEG) number.value = number.value * 2.0 * M_PI / 360; number.value = sin(number.value); push_number(number); } else if(!strcmp(string, "cos")) { copy_stack(undo_stack, stack); number_t number = pop_number(); if(current_angle == ANGLE_DEG) number.value = number.value * 2.0 * M_PI / 360; number.value = cos(number.value); push_number(number); } else if(!strcmp(string, "tan")) { copy_stack(undo_stack, stack); number_t number = pop_number(); if(current_angle == ANGLE_DEG) number.value = number.value * 2.0 * M_PI / 360; number.value = tan(number.value); push_number(number); } else if(!strcmp(string, "asin")) { copy_stack(undo_stack, stack); number_t number = pop_number(); number.value = asin(number.value); if(current_angle == ANGLE_DEG) number.value = number.value * 360 / 2.0 / M_PI; push_number(number); } else if(!strcmp(string, "acos")) { copy_stack(undo_stack, stack); number_t number = pop_number(); number.value = acos(number.value); if(current_angle == ANGLE_DEG) number.value = number.value * 360 / 2.0 / M_PI; push_number(number); } else if(!strcmp(string, "atan")) { copy_stack(undo_stack, stack); number_t number = pop_number(); number.value = atan(number.value); if(current_angle == ANGLE_DEG) number.value = number.value * 360 / 2.0 / M_PI; push_number(number); } else if(!strcmp(string, "log")) { copy_stack(undo_stack, stack); number_t number = pop_number(); number.value = log(number.value); push_number(number); } else if(!strcmp(string, "log10")) { copy_stack(undo_stack, stack); number_t number = pop_number(); number.value = log10(number.value); push_number(number); } else if(!strcmp(string, "pi")) { copy_stack(undo_stack, stack); number_t number; number.value = M_PI; number.units = UNITS_NONE; number.base = BASE_NONE; push_number(number); } else if(!strcmp(string, "e")) { copy_stack(undo_stack, stack); number_t number; number.value = exp(1); number.units = UNITS_NONE; number.base = BASE_NONE; push_number(number); } else if(!strcmp(string, "br")) { number_t number = pop_number(); // printf("main %d %f %d %d\n", __LINE__, number.value, number.units, number.base); number.base = BASE_NONE; push_number(number); } else if(!strcmp(string, "rb")) { number_t number = pop_number(); number.base = current_base; push_number(number); } else if(!strcmp(string, "rad")) { if(current_angle != ANGLE_RAD) { to_rad(); } else printf("*** Already in radian mode\n"); } else if(!strcmp(string, "deg")) { if(current_angle != ANGLE_DEG) { to_deg(); } else printf("*** Already in degree mode\n"); } else if(!strcmp(string, "h")) { // if(current_base != BASE_HEX) // { to_hex(); // } // else // printf("*** Already in hex mode\n"); } else if(!strcmp(string, "b")) { // if(current_base != BASE_BINARY) // { to_bin(); // } // else // printf("*** Already in binary mode\n"); } else if(!strcmp(string, ":")) { // if(current_base != BASE_TIME) // { to_time(); // } // else // printf("*** Already in time mode\n"); } else if(!strcmp(string, "pow")) { copy_stack(undo_stack, stack); number_t arg1 = pop_number(); number_t arg2 = pop_number(); number_t result; result.value = pow(arg2.value, arg1.value); promote_units(&result, arg1, arg2); push_number(result); } else if(!strcmp(string, "+")) { copy_stack(undo_stack, stack); number_t arg1 = pop_number(); number_t arg2 = pop_number(); number_t result; result.value = arg2.value + arg1.value; promote_units(&result, arg1, arg2); push_number(result); } else if(!strcmp(string, "-")) { copy_stack(undo_stack, stack); number_t arg1 = pop_number(); number_t arg2 = pop_number(); number_t result; result.value = arg2.value - arg1.value; promote_units(&result, arg1, arg2); push_number(result); } else if(!strcmp(string, "/")) { copy_stack(undo_stack, stack); number_t arg1 = pop_number(); number_t arg2 = pop_number(); number_t result; result.value = arg2.value / arg1.value; promote_units(&result, arg1, arg2); push_number(result); } else if(!strcmp(string, "*")) { copy_stack(undo_stack, stack); number_t arg1 = pop_number(); number_t arg2 = pop_number(); number_t result; result.value = arg2.value * arg1.value; promote_units(&result, arg1, arg2); push_number(result); } else if(!strcmp(string, "%")) { copy_stack(undo_stack, stack); number_t arg1 = pop_number(); number_t arg2 = pop_number(); number_t result; result.value = (int64_t)arg2.value % (int64_t)arg1.value; promote_units(&result, arg1, arg2); push_number(result); } else if(!strcmp(string, "&")) { copy_stack(undo_stack, stack); number_t arg1 = pop_number(); number_t arg2 = pop_number(); number_t result; result.value = (double)(((int64_t)arg1.value) & ((int64_t)arg2.value)); promote_units(&result, arg1, arg2); push_number(result); } else if(!strcmp(string, "|")) { copy_stack(undo_stack, stack); number_t arg1 = pop_number(); number_t arg2 = pop_number(); number_t result; result.value = (double)(((int64_t)arg1.value) | ((int64_t)arg2.value)); promote_units(&result, arg1, arg2); push_number(result); } else if(!strcmp(string, "^")) { copy_stack(undo_stack, stack); number_t arg1 = pop_number(); number_t arg2 = pop_number(); number_t result; result.value = (double)(((int64_t)arg1.value) ^ ((int64_t)arg2.value)); promote_units(&result, arg1, arg2); push_number(result); } else if(!strcmp(string, "<<")) { copy_stack(undo_stack, stack); number_t arg1 = pop_number(); number_t arg2 = pop_number(); number_t result; result.value = (double)(((int64_t)arg2.value) << ((int64_t)arg1.value)); promote_units(&result, arg1, arg2); push_number(result); } else if(!strcmp(string, ">>")) { copy_stack(undo_stack, stack); number_t arg1 = pop_number(); number_t arg2 = pop_number(); number_t result; result.value = (double)(((int64_t)arg2.value) >> ((int64_t)arg1.value)); // printf("main %d arg2=%d arg1=%d result=%d\n", // __LINE__, // (int)arg2.value, // (int)arg1.value, // (int)result.value); promote_units(&result, arg1, arg2); push_number(result); } else if(!strcmp(string, "c")) { copy_stack(undo_stack, stack); clear_stack(stack); } else if(!strcmp(string, "d")) { copy_stack(undo_stack, stack); delete_row(stack); } else if(!strcmp(string, "s")) { copy_stack(undo_stack, stack); swap_row(stack); } else if(!strcmp(string, "u")) { copy_stack(temp_stack, stack); copy_stack(stack, undo_stack); copy_stack(undo_stack, temp_stack); dump_stack(); } else if(!strcmp(string, "help") || !strcmp(string, "he") || !strcmp(string, "?")) { dump_usage(); dump_stack(); } else { copy_stack(undo_stack, stack); push_stack(string); dump_stack(); } } } }