From 7d07ff825dc7cff7ee80b04346e0d2c49a91e190 Mon Sep 17 00:00:00 2001 From: scratko Date: Sun, 31 Mar 2024 21:05:36 +0300 Subject: Initial commit --- arith_exp.c | 239 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 239 insertions(+) create mode 100644 arith_exp.c (limited to 'arith_exp.c') diff --git a/arith_exp.c b/arith_exp.c new file mode 100644 index 0000000..8a4c002 --- /dev/null +++ b/arith_exp.c @@ -0,0 +1,239 @@ +#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; +} -- cgit v1.2.3