#include "calls.h" #include "stack.h" #define BUF_SIZE 80 char buffer[BUF_SIZE]; enum { success = 1, error = -1, base = 10 }; enum state { yes, no }; static int is_higher_priority(const stack *operation_stack, int current_operation) { int prev_operation = top_stack(operation_stack); return (prev_operation == '+' || prev_operation == '-') && (current_operation == '*' || current_operation == '/'); } static void make_operation(stack *rpn_stack, int operation) { long first_operand, second_operand, result; second_operand = pop_stack(rpn_stack); first_operand = pop_stack(rpn_stack); switch(operation) { case '+': result = first_operand + second_operand; break; case '-': result = first_operand - second_operand; break; case '*': result = first_operand * second_operand; break; case '/': result = first_operand / second_operand; break; } push_stack(rpn_stack, result); } static long translate_to_number(const char *begin_address, int size, enum state is_negative_number) { long number = 0; int i; if(is_negative_number == yes) ++begin_address; for(i = 0; i < size; ++i) number = number * base + (begin_address[i] - '0'); if(is_negative_number == yes) { number = ~number; ++number; } return number; } static int extract_digit(const char *buf, long *number, int buf_length, int *pos) { enum state is_negative_number = no; enum state is_positive_number = no; enum state is_end_negative_expression = no; const char *begin_address; int number_length = 0; for( ; *pos < buf_length; ++*pos) { if(buf[*pos] == '(' && *pos+1 < buf_length && buf[*pos+1] == '-') { is_negative_number = yes; begin_address = &buf[*pos+1]; ++*pos; continue; } switch(buf[*pos]) { case '(': if(is_negative_number == no && is_positive_number == no) return '('; else return error; case ')': if(is_negative_number == yes && is_end_negative_expression == no) { is_end_negative_expression = yes; continue; } *number = translate_to_number(begin_address, number_length, is_negative_number == yes ? yes : no); return ')'; case '+': case '-': case '*': case '/': case '\n': if(is_negative_number == yes || is_positive_number == yes) { *number = translate_to_number(begin_address, number_length, is_negative_number == yes ? yes : no); return success; } else return error; } if(buf[*pos] >= '0' && buf[*pos] <= '9') { if(is_negative_number == no && is_positive_number == no) { begin_address = &buf[*pos]; is_positive_number = yes; } ++number_length; continue; } return error; } return error; } static void clean_operation_stack(stack *operation_stack, stack *rpn_stack) { int operation; while(!is_empty_stack(operation_stack) && top_stack(operation_stack) != '(') { operation = pop_stack(operation_stack); make_operation(rpn_stack, operation); } if(is_empty_stack(operation_stack)) sys_exit(2); pop_stack(operation_stack); } static void print_number(stack *rpn_stack) { enum { string_buffer_size = 20 }; long symbol; char string[string_buffer_size]; int i = 0; long number = pop_stack(rpn_stack); if(number < 0) { number = ~number; ++number; string[i] = '-'; ++i; } stack reverse_number; init_stack(&reverse_number); while(number) { symbol = number % base; symbol += '0'; push_stack(&reverse_number, symbol); number /= base; } for( ; !is_empty_stack(&reverse_number) && i < string_buffer_size; ++i) string[i] = pop_stack(&reverse_number); if(i < string_buffer_size) { /* new line */ string[i] = '\n'; ++i; } sys_write(1, string, i); } static void buffer_process(const char *buffer, int length, stack *rpn_stack, stack *operation_stack) { int top, pos, result; char symbol; long operand; pos = 0; while(pos < length) { result = extract_digit(buffer, &operand, length, &pos); if(result == error) sys_exit(1); symbol = buffer[pos]; if(symbol == '(') { push_stack(operation_stack, symbol); ++pos; continue; } if(symbol == '\n' || symbol == ')' || symbol == '+' || symbol == '-' || symbol == '*' || symbol == '/') { push_stack(rpn_stack, operand); } if(symbol == ')') { clean_operation_stack(operation_stack, rpn_stack); ++pos; while(pos < length && buffer[pos] == ')') { clean_operation_stack(operation_stack, rpn_stack); ++pos; } if(pos >= length) sys_exit(1); } switch(buffer[pos]) { case '\n': clean_operation_stack(operation_stack, rpn_stack); if(is_empty_stack(operation_stack)) print_number(rpn_stack); else sys_exit(1); return; case '+': case '-': case '*': case '/': top = top_stack(operation_stack); if(top == '(' || is_higher_priority(operation_stack, buffer[pos])) { push_stack(operation_stack, buffer[pos]); ++pos; continue; } else { while(top_stack(operation_stack) != '(' && !is_higher_priority(operation_stack, buffer[pos])) { make_operation(rpn_stack, pop_stack(operation_stack)); } push_stack(operation_stack, buffer[pos]); ++pos; } } } } int main() { int length; stack rpn_stack, operation_stack; init_stack(&rpn_stack); init_stack(&operation_stack); push_stack(&operation_stack, '('); length = sys_read(0, buffer, BUF_SIZE); if(!length) /* EOF */ return 0; if(length == -1) /* error */ return 3; buffer_process(buffer, length, &rpn_stack, &operation_stack); sys_free(heap_base); return 0; }