diff options
Diffstat (limited to 'graphs/piscine/evalexpr')
| -rw-r--r-- | graphs/piscine/evalexpr/Makefile | 23 | ||||
| -rw-r--r-- | graphs/piscine/evalexpr/src/evalexpr.c | 93 | ||||
| -rw-r--r-- | graphs/piscine/evalexpr/src/evalexpr.h | 43 | ||||
| -rw-r--r-- | graphs/piscine/evalexpr/src/evalrpn.c | 145 | ||||
| -rw-r--r-- | graphs/piscine/evalexpr/src/fifo.h | 29 | ||||
| -rw-r--r-- | graphs/piscine/evalexpr/src/fifo_access.c | 61 | ||||
| -rw-r--r-- | graphs/piscine/evalexpr/src/fifo_setup_destroy.c | 44 | ||||
| -rw-r--r-- | graphs/piscine/evalexpr/src/shunting_yard.c | 199 | ||||
| -rw-r--r-- | graphs/piscine/evalexpr/src/stack.c | 57 | ||||
| -rw-r--r-- | graphs/piscine/evalexpr/src/stack.h | 20 | ||||
| -rw-r--r-- | graphs/piscine/evalexpr/src/stack_struct.h | 10 | ||||
| -rwxr-xr-x | graphs/piscine/evalexpr/tests/tests.sh | 82 | ||||
| -rw-r--r-- | graphs/piscine/evalexpr/tests/unit_tests.c | 208 |
13 files changed, 1014 insertions, 0 deletions
diff --git a/graphs/piscine/evalexpr/Makefile b/graphs/piscine/evalexpr/Makefile new file mode 100644 index 0000000..280f19c --- /dev/null +++ b/graphs/piscine/evalexpr/Makefile @@ -0,0 +1,23 @@ +CC = gcc +CFLAGS = -Wall -Werror -Wextra -pedantic -std=c99 -Wvla +AFLAGS = -fsanitize=address + +SRC=src/stack.c src/evalrpn.c src/shunting_yard.c src/fifo_access.c src/fifo_setup_destroy.c src/evalexpr.c +SRC_TEST=tests/unit_tests.c +#OBJ=src/stack.o src/evalrpn.o +OBJ=$(SRC:.c=.o) +#OBJ_TEST=$(SRC_TEST:.c=.o) + +all: $(OBJ) + $(CC) -o evalexpr $(OBJ) + +$(OBJ): $(SRC) + +check: #$(OBJ) $(OBJ_TEST) +# $(CC) $(CFLAGS) -o evaltest $(OBJ) $(OBJ_TEST) -lcriterion + tests/tests.sh + +.PHONY: clean + +clean: + rm $(OBJ) evalexpr diff --git a/graphs/piscine/evalexpr/src/evalexpr.c b/graphs/piscine/evalexpr/src/evalexpr.c new file mode 100644 index 0000000..5012355 --- /dev/null +++ b/graphs/piscine/evalexpr/src/evalexpr.c @@ -0,0 +1,93 @@ +#include "evalexpr.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define BUFFER_SIZE 10 + +char *get_input(void) +{ + size_t r; + char buf[BUFFER_SIZE]; + size_t size = 0; + char *expr = malloc(size * sizeof(char) + 1); + if (expr == NULL) + return NULL; + expr[0] = '\0'; + do + { + r = fread(buf, sizeof(char), BUFFER_SIZE - 1, stdin); + if (r != 0) + { + buf[r] = '\0'; + size += r; + char *tmp = realloc(expr, size * sizeof(char) + 1); + if (tmp == NULL) + { + free(expr); + return NULL; + } + expr = tmp; + strcat(expr, buf); + } + } while (r != 0); + if (size == 0) + { + free(expr); + return NULL; + } + if (expr[size - 1] == '\n') + expr[size - 1] = '\0'; + return expr; +} + +void cleanup(char *expr, char *rpn) +{ + free(expr); + free(rpn); +} + +int main(int argc, char **argv) +{ + if ((argc == 2 && strcmp(argv[1], "-rpn") != 0) || (argc > 2)) + return 4; + char *expr = get_input(); + if (expr == NULL) + return 4; + if (argc == 1) + { + char *rpn; + int e = shunting_yard(expr, &rpn); + if (e != 0) + return e; + // call shunting yard + int retval; + e = evalrpn(rpn, &retval); + if (e != 0) + { + cleanup(expr, rpn); + return e; + } + // FREE RPN + printf("%d\n", retval); + cleanup(expr, rpn); + // return + return 0; + } + + if (argc == 2 && strcmp(argv[1], "-rpn") == 0) + { + // call rpn eval + int retval; + int e = evalrpn(expr, &retval); + printf("%d\n", retval); + // return + free(expr); + if (e != 0) + return e; + return 0; + } + + return 4; +} diff --git a/graphs/piscine/evalexpr/src/evalexpr.h b/graphs/piscine/evalexpr/src/evalexpr.h new file mode 100644 index 0000000..d440ae1 --- /dev/null +++ b/graphs/piscine/evalexpr/src/evalexpr.h @@ -0,0 +1,43 @@ +#ifndef EVALEXPR_H +#define EVALEXPR_H + +#include <stddef.h> + +#include "fifo.h" +#include "stack.h" +#include "stack_struct.h" + +enum token_type +{ + NUMBER = 0, + SUB = 1, + ADD = 1, + MOD = 2, + DIV = 2, + MUL = 2, + EXP = 3, + UN_PLUS = 4, + UN_MINUS = 4, + PAR_LEFT = 5, + PAR_RIGHT = 5, + WRONG_TOKEN = -1, +}; + +struct token +{ + enum token_type type; + int value; +}; + +// evalrpn +int parse_number(const char *expr, size_t *offset); +int get_operands(struct stack **s, int *op1, int *op2); +int my_pow(int a, int b); +int evalrpn(const char *expr, int *retval); + +// shunting yard +int opcmp(struct token *op1, struct token *op2); +enum token_type get_type(char op); +int shunting_yard(const char *expr, char **rpn); + +#endif /* ! EVALEXPR_H */ diff --git a/graphs/piscine/evalexpr/src/evalrpn.c b/graphs/piscine/evalexpr/src/evalrpn.c new file mode 100644 index 0000000..db493eb --- /dev/null +++ b/graphs/piscine/evalexpr/src/evalrpn.c @@ -0,0 +1,145 @@ +#include <ctype.h> + +#include "evalexpr.h" + +int parse_number(const char *expr, size_t *offset) +{ + for (*offset = 0; + expr[*offset] && expr[*offset] >= '0' && expr[*offset] <= '9'; + (*offset)++) + { + continue; + } + (*offset)--; + + int res = 0; + int pow = 1; + for (size_t n = 0; n <= *offset; n++, pow *= 10) + { + res += (expr[*offset - n] - '0') * pow; + } + + return res; +} + +int get_operands(struct stack **s, int *op1, int *op2) +{ + if (*s == NULL) + { + return 2; + } + *op1 = stack_peek(*s); + *s = stack_pop(*s); + if (*s == NULL) + { + return 2; + } + *op2 = stack_peek(*s); + *s = stack_pop(*s); + return 0; +} + +// Computes a to the bth +int my_pow(int a, int b) +{ + if (b == 0) + { + return 1; + } + if (a == 0) + { + return 0; + } + + int res = 1; + int c = b / 2; + while (c != 0) + { + res *= a * a; + c /= 2; + } + if (b % 2 != 0) + res *= a; + return res; +} + +int dispatch(const char c, struct stack **s, int op1, int op2) +{ + switch (c) + { + case '*': + *s = stack_push(*s, op1 * op2); + break; + case '+': + *s = stack_push(*s, op1 + op2); + break; + case '-': + *s = stack_push(*s, op2 - op1); + break; + case '/': + if (op1 == 0) + { + return 3; + } + *s = stack_push(*s, op2 / op1); + break; + case '%': + if (op1 == 0) + { + return 3; + } + *s = stack_push(*s, op2 % op1); + break; + case '^': + if (op1 < 0) + { + return 3; + } + *s = stack_push(*s, my_pow(op2, op1)); + break; + default: + return 1; + } + return 0; +} + +int evalrpn(const char *expr, int *retval) +{ + struct stack *s = NULL; + + for (size_t i = 0; expr[i]; i++) + { + if (expr[i] >= '0' && expr[i] <= '9') + { + size_t offset; + int val = parse_number(expr + i, &offset); + s = stack_push(s, val); + i += offset; + } + else if (isspace(expr[i])) + continue; + else + { + int op1; + int op2; + if (get_operands(&s, &op1, &op2) == 2) + { + return 2; + } + + int d = dispatch(expr[i], &s, op1, op2); + if (d != 0) + { + return d; + } + } + } + + if (s == NULL) + { + return 0; + } + *retval = stack_peek(s); + s = stack_pop(s); + return (!s) ? 0 : 2; +} diff --git a/graphs/piscine/evalexpr/src/fifo.h b/graphs/piscine/evalexpr/src/fifo.h new file mode 100644 index 0000000..b330eac --- /dev/null +++ b/graphs/piscine/evalexpr/src/fifo.h @@ -0,0 +1,29 @@ +#ifndef FIFO_H +#define FIFO_H + +#include <stddef.h> + +#include "evalexpr.h" + +struct list +{ + struct token *data; + struct list *next; +}; + +struct fifo +{ + struct list *head; + struct list *tail; + size_t size; +}; + +struct fifo *fifo_init(void); +size_t fifo_size(struct fifo *fifo); +void fifo_push(struct fifo *fifo, struct token *elt); +struct token *fifo_head(struct fifo *fifo); +void fifo_pop(struct fifo *fifo); +void fifo_clear(struct fifo *fifo); +void fifo_destroy(struct fifo *fifo); + +#endif /* !FIFO_H */ diff --git a/graphs/piscine/evalexpr/src/fifo_access.c b/graphs/piscine/evalexpr/src/fifo_access.c new file mode 100644 index 0000000..1986a09 --- /dev/null +++ b/graphs/piscine/evalexpr/src/fifo_access.c @@ -0,0 +1,61 @@ +#include <stdio.h> +#include <stdlib.h> + +#include "fifo.h" + +size_t fifo_size(struct fifo *fifo) +{ + return fifo->size; +} + +void fifo_push(struct fifo *fifo, struct token *elt) +{ + struct list *new = malloc(sizeof(struct list)); + if (new == NULL) + { + return; + } + new->data = elt; + + if (fifo_size(fifo) == 0) + { + fifo->head = new; + } + new->next = NULL; + if (fifo_size(fifo) != 0) + { + fifo->tail->next = new; + } + fifo->tail = new; + + fifo->size++; +} + +struct token *fifo_head(struct fifo *fifo) +{ + return fifo->head->data; +} + +void fifo_pop(struct fifo *fifo) +{ + if (fifo_size(fifo) == 0) + { + return; + } + if (fifo_size(fifo) == 1) + { + free(fifo->head->data); + free(fifo->head); + fifo->head = NULL; + fifo->tail = NULL; + fifo->size = 0; + return; + } + + struct list *tmp = fifo->head->next; + free(fifo->head->data); + free(fifo->head); + fifo->head = tmp; + + fifo->size--; +} diff --git a/graphs/piscine/evalexpr/src/fifo_setup_destroy.c b/graphs/piscine/evalexpr/src/fifo_setup_destroy.c new file mode 100644 index 0000000..0f99ad0 --- /dev/null +++ b/graphs/piscine/evalexpr/src/fifo_setup_destroy.c @@ -0,0 +1,44 @@ +#include <stdlib.h> + +#include "fifo.h" + +struct fifo *fifo_init(void) +{ + struct fifo *f = malloc(sizeof(struct fifo)); + if (f == NULL) + { + return NULL; + } + + f->size = 0; + f->head = NULL; + f->tail = NULL; + + return f; +} + +void fifo_clear(struct fifo *fifo) +{ + for (struct list *l = fifo->head; l != fifo->tail;) + { + struct list *tmp = l->next; + free(l->data); + free(l); + l = tmp; + } + if (fifo->tail) + { + free(fifo->tail->data); + free(fifo->tail); + } + + fifo->head = NULL; + fifo->tail = NULL; + fifo->size = 0; +} + +void fifo_destroy(struct fifo *fifo) +{ + fifo_clear(fifo); + free(fifo); +} diff --git a/graphs/piscine/evalexpr/src/shunting_yard.c b/graphs/piscine/evalexpr/src/shunting_yard.c new file mode 100644 index 0000000..2db5fc8 --- /dev/null +++ b/graphs/piscine/evalexpr/src/shunting_yard.c @@ -0,0 +1,199 @@ +#include <stdio.h> +#include <stdlib.h> + +#include "evalexpr.h" + +enum assoc +{ + NONE, + RIGHT, + LEFT, +}; + +int opcmp(struct token *op1, struct token *op2) +{ + return op1->type - op2->type; +} + +enum assoc get_assoc(struct token *op) +{ + if (op->type == EXP) + { + return RIGHT; + } + return LEFT; +} + +enum token_type get_type(char op) +{ + switch (op) + { + case '*': + return MUL; + case '/': + return DIV; + case '-': + return SUB; + case '+': + return ADD; + case '%': + return MOD; + case '^': + return EXP; + case '(': + return PAR_LEFT; + case ')': + return PAR_RIGHT; + default: + return WRONG_TOKEN; + } +} + +char *fifo_to_expr(struct fifo *output, size_t size_offset) +{ + char *res = malloc((2 * fifo_size(output) + size_offset) * sizeof(char)); + if (!res) + { + fifo_destroy(output); + return NULL; + } + res[2 * fifo_size(output) + size_offset - 1] = '\0'; + size_t i = 0; + while (fifo_size(output) > 0) + { + if (fifo_head(output)->type == NUMBER) + { + i += sprintf(res + i, "%d", fifo_head(output)->value) - 1; + } + else + { + res[i] = fifo_head(output)->value; + } + fifo_pop(output); + i++; + if (fifo_size(output) != 0) + { + res[i] = ' '; + i++; + } + } + fifo_destroy(output); + return res; +} + +int handle_rpar(struct tstack **opstack, struct fifo *output, struct token **t) +{ + while (*opstack) + { + struct token *o2 = tstack_peek(*opstack); + if (o2->value == '(') + { + free(o2); + break; + } + *opstack = tstack_pop(*opstack); + fifo_push(output, o2); + } + if (*opstack == NULL) + { + free(*t); + fifo_destroy(output); + return 2; + } + free(*t); + *opstack = tstack_pop(*opstack); + return 0; +} + +int empty_opstack(struct tstack **opstack, struct fifo *output) +{ + while (*opstack) + { + struct token *t = tstack_peek(*opstack); + if (t->value == '(' || t->value == ')') + { + fifo_destroy(output); + return 1; + } + *opstack = tstack_pop(*opstack); + fifo_push(output, t); + } + return 0; +} + +void pop_ops(struct tstack **opstack, struct fifo *output, struct token *t) +{ + while (*opstack) + { + struct token *o2 = tstack_peek(*opstack); + if (!(o2->value != '(' + && (opcmp(t, o2) < 0 + || (opcmp(t, o2) == 0 && get_assoc(t) == LEFT)))) + { + break; + } + + *opstack = tstack_pop(*opstack); + fifo_push(output, o2); + } +} + +void handle_numbers(struct fifo *output, size_t *i, int *size_offset, + const char *expr) +{ + size_t offset; + int val = parse_number(expr + *i, &offset); + struct token *t = malloc(sizeof(struct token)); + t->type = NUMBER; + t->value = val; + fifo_push(output, t); + *i += offset; + *size_offset += offset; +} + +int shunting_yard(const char *expr, char **rpn) +{ + struct fifo *output = fifo_init(); + struct tstack *opstack = NULL; + int size_offset = 0; + for (size_t i = 0; expr[i]; i++) + { + if (expr[i] >= '0' && expr[i] <= '9') + { + handle_numbers(output, &i, &size_offset, expr); + } + else if (expr[i] != ' ') + { + struct token *t = malloc(sizeof(struct token)); + t->value = expr[i]; + if ((t->type = get_type(expr[i])) == WRONG_TOKEN) + { + free(t); + return 1; + } + if (t->value == '(') + { + opstack = tstack_push(opstack, t); + continue; + } + else if (t->value == ')') + { + if (handle_rpar(&opstack, output, &t) != 0) + return 2; + continue; + } + pop_ops(&opstack, output, t); + opstack = tstack_push(opstack, t); + } + } + + if (empty_opstack(&opstack, output) != 0) + { + return 1; + } + *rpn = fifo_to_expr(output, size_offset); + if (!*rpn) + return 4; + + return 0; +} diff --git a/graphs/piscine/evalexpr/src/stack.c b/graphs/piscine/evalexpr/src/stack.c new file mode 100644 index 0000000..14f659e --- /dev/null +++ b/graphs/piscine/evalexpr/src/stack.c @@ -0,0 +1,57 @@ +#include "stack.h" + +#include <stdlib.h> + +struct stack *stack_push(struct stack *s, int e) +{ + struct stack *new = malloc(sizeof(struct stack)); + new->data = e; + new->next = NULL; + + new->next = s; + return new; +} + +struct stack *stack_pop(struct stack *s) +{ + if (s == NULL) + { + return NULL; + } + + struct stack *res = s->next; + free(s); + return res; +} + +int stack_peek(struct stack *s) +{ + return s->data; +} + +struct tstack *tstack_push(struct tstack *s, struct token *e) +{ + struct tstack *new = malloc(sizeof(struct tstack)); + new->token = e; + new->next = NULL; + + new->next = s; + return new; +} + +struct tstack *tstack_pop(struct tstack *s) +{ + if (s == NULL) + { + return NULL; + } + + struct tstack *res = s->next; + free(s); + return res; +} + +struct token *tstack_peek(struct tstack *s) +{ + return s->token; +} diff --git a/graphs/piscine/evalexpr/src/stack.h b/graphs/piscine/evalexpr/src/stack.h new file mode 100644 index 0000000..d08e465 --- /dev/null +++ b/graphs/piscine/evalexpr/src/stack.h @@ -0,0 +1,20 @@ +#ifndef STACK_H +#define STACK_H + +#include "evalexpr.h" +#include "stack_struct.h" + +struct tstack +{ + struct token *token; + struct tstack *next; +}; + +struct stack *stack_push(struct stack *s, int e); +struct stack *stack_pop(struct stack *s); +int stack_peek(struct stack *s); + +struct tstack *tstack_push(struct tstack *s, struct token *e); +struct tstack *tstack_pop(struct tstack *s); +struct token *tstack_peek(struct tstack *s); +#endif /* !STACK_H */ diff --git a/graphs/piscine/evalexpr/src/stack_struct.h b/graphs/piscine/evalexpr/src/stack_struct.h new file mode 100644 index 0000000..105cd5d --- /dev/null +++ b/graphs/piscine/evalexpr/src/stack_struct.h @@ -0,0 +1,10 @@ +#ifndef STACK_STRUCT_H +#define STACK_STRUCT_H + +struct stack +{ + int data; + struct stack *next; +}; + +#endif /* ! STACK_STRUCT_H */ diff --git a/graphs/piscine/evalexpr/tests/tests.sh b/graphs/piscine/evalexpr/tests/tests.sh new file mode 100755 index 0000000..920f09b --- /dev/null +++ b/graphs/piscine/evalexpr/tests/tests.sh @@ -0,0 +1,82 @@ +#!/bin/sh + +REF_OUT="ref.out" +TEST_OUT="test.out" + +testrpn() +{ + echo "$2" > "$REF_OUT" + echo "Evaluating '$1' in RPN notation..." + echo "$1" | ./evalexpr -rpn > "$TEST_OUT" + diff "$REF_OUT" "$TEST_OUT" && echo "Success" +} + +testeval() +{ + echo "$1" | bc 2> /dev/null > "$REF_OUT" + echo "Evaluating '$1' in standard notation..." + echo "$1" | ./evalexpr > "$TEST_OUT" + diff "$REF_OUT" "$TEST_OUT" && echo "Success" +} + +testerror() +{ + echo "Testing error code '$2'..." + echo "$1" | ./evalexpr + error="$(echo $?)" + [ "$2" -eq "$error" ] && echo "Succesful failure" || echo "Wrong error $error" +} + +clean() +{ + rm "$REF_OUT" "$TEST_OUT" +} + +# RPN + +echo "Tests for RPN:" +echo "======" + +testrpn "1 1 +" 2 +testrpn "5 2 2 ^ 3 + *" 35 +testrpn "10 6 9 3 + 0 11 - * / * 17 + 5 +" 22 +testrpn "3 4 5 * 3 + -" "-20" +testrpn "3 2 % 9 3 1 2 + * / -" 0 + +echo +echo "=============================================" +echo + +# Standard + +echo "Tests for standard notation:" +echo "======" + +testeval "1 + 1" +testeval " 1 + 1 +1 " +testeval "2 * 2" +testeval "5 * (2 + 4)" +testeval "5 * (2 % 4)" +testeval " 5 *(2 ^4) " +testeval " 5 *(2 ^4 " + +echo +echo "=============================================" +echo + +# Errors + +echo "Error tests:" +echo "======" + +testerror "" 0 +testerror "a+1" 1 +testerror "1%0" 3 + +echo "Testing error code '4'..." +./evalexpr --toto 2> /dev/null +echo $? + +# Cleanup + +clean diff --git a/graphs/piscine/evalexpr/tests/unit_tests.c b/graphs/piscine/evalexpr/tests/unit_tests.c new file mode 100644 index 0000000..ed445a0 --- /dev/null +++ b/graphs/piscine/evalexpr/tests/unit_tests.c @@ -0,0 +1,208 @@ +#include <criterion/criterion.h> +#include <criterion/assert.h> +#include <stddef.h> +#include <string.h> + +#include "../src/evalexpr.h" + +TestSuite(parse_number); + +Test(parse_number, parse_42) +{ + size_t o; + int actual = parse_number("42", &o); + cr_expect(actual == 42, "Attendu : %d, renvoyé : %d", 42, actual); + cr_expect(o == 1, "Décalage attendu : %d, renvoyé : %zu", 1, o); +} + +Test(parse_number, parse_4) +{ + size_t o; + int actual = parse_number("4", &o); + cr_expect(actual == 4, "Attendu : %d, renvoyé : %d", 4, actual); + cr_expect(o == 0, "Décalage attendu : %d, renvoyé : %zu", 0, o); +} + +TestSuite(my_pow); + +Test(my_pow, my_pow00) +{ + int actual = my_pow(0, 0); + cr_expect(actual == 1, "Attendu : %d, renvoyé : %d", 1, actual); +} + +Test(my_pow, my_pown0) +{ + int actual = my_pow(50, 0); + cr_expect(actual == 1, "Attendu : %d, renvoyé : %d", 1, actual); +} +Test(my_pow, my_pow0n) +{ + int actual = my_pow(0, 42); + cr_expect(actual == 0, "Attendu : %d, renvoyé : %d", 0, actual); +} +Test(my_pow, my_powab) +{ + int actual = my_pow(3,3); + cr_expect(actual == 27, "Attendu : %d, renvoyé : %d", 27, actual); +} +Test(my_pow, my_powab_2) +{ + int actual = my_pow(4, 2); + cr_expect(actual == 16, "Attendu : %d, renvoyé : %d", 16, actual); +} +Test(my_pow, my_powab_3) +{ + int actual = my_pow(10, 3); + cr_expect(actual == 1000, "Attendu : %d, renvoyé : %d", 1000, actual); +} +Test(my_pow, my_pow1n) +{ + int actual = my_pow(1, 50); + cr_expect(actual == 1, "Attendu : %d, renvoyé : %d", 1, actual); +} + +TestSuite(RPN); + +Test(RPN, evalrpn_easiest) +{ + const char test[] = "1 1 +"; + int expected = 0; + int retval; + int res = 2; + int actual = evalrpn(test, &retval); + cr_expect(actual == expected, "%s => Retour attendu : %d, renvoyé : %d", test, expected, actual); + cr_expect(retval == res, "%s => Résultat attendu : %d, reçu : %d", test, res, retval); +} +Test(RPN, evalrpn_35) +{ + const char test[] = "5 2 2 ^ 3 + *"; + int expected = 0; + int retval; + int res = 35; + int actual = evalrpn(test, &retval); + cr_expect(actual == expected, "%s => Retour attendu : %d, renvoyé : %d", test, expected, actual); + cr_expect(retval == res, "%s => Résultat attendu : %d, reçu : %d", test, res, retval); +} +Test(RPN, evalrpn_22) +{ + const char test[] = "10 6 9 3 + 0 11 - * / * 17 + 5 +"; + int expected = 0; + int retval; + int res = 22; + int actual = evalrpn(test, &retval); + cr_expect(actual == expected, "%s => Retour attendu : %d, renvoyé : %d", test, expected, actual); + cr_expect(retval == res, "%s => Résultat attendu : %d, reçu : %d", test, res, retval); +} +Test(RPN, evalrpn_minus20) +{ + const char test[] = "3 4 5 * 3 + -"; + int expected = 0; + int retval; + int res = -20; + int actual = evalrpn(test, &retval); + cr_expect(actual == expected, "%s => Retour attendu : %d, renvoyé : %d", test, expected, actual); + cr_expect(retval == res, "%s => Résultat attendu : %d, reçu : %d", test, res, retval); +} +Test(RPN, evalrpn_zero) +{ + const char test[] = "3 2 % 9 3 1 2 + * / -"; + int expected = 0; + int retval; + int res = 0; + int actual = evalrpn(test, &retval); + cr_expect(actual == expected, "%s => Retour attendu : %d, renvoyé : %d", test, expected, actual); + cr_expect(retval == res, "%s => Résultat attendu : %d, reçu : %d", test, res, retval); +} + +TestSuite(Precedence); + +Test(Precedence, parenthesis_above_all) +{ + struct token pleft = { PAR_LEFT, '(' }; + struct token pright = { PAR_RIGHT, ')' }; + struct token unplus = { UN_PLUS, '+' }; + struct token exp = { EXP, '^' }; + struct token mul = { MUL, '*' }; + struct token minus = { SUB, '-' }; + int eq = opcmp(&pleft, &pright); + int sup = opcmp(&pleft, &unplus); + int inf = opcmp(&unplus, &pright); + int parftw = opcmp(&pleft, &exp); + int par4ever = opcmp(&pright, &mul); + int paragain = opcmp(&pright, &minus); + cr_expect(eq == 0, "Wrong order (equal)"); + cr_expect(sup > 0, "Wrong order (>)"); + cr_expect(inf < 0, "Wrong order (<)"); + cr_expect(parftw > 0, "Wrong order (>)"); + cr_expect(par4ever > 0, "Wrong order (>)"); + cr_expect(paragain > 0, "Wrong order (>)"); +} + +Test(Precedence, other_precedence_tests) +{ + struct token exp = { EXP, '^' }; + struct token mul = { MUL, '*' }; + struct token unplus = { UN_PLUS, '+' }; + struct token minus = { SUB, '-' }; + struct token plus = { ADD, '+' }; + int eq = opcmp(&minus, &plus); + int sup = opcmp(&exp, &mul); + int inf = opcmp(&plus, &unplus); + + cr_expect(eq == 0, "Wrong order (equal)"); + cr_expect(sup > 0, "Wrong order (>)"); + cr_expect(inf < 0, "Wrong order (<)"); +} + +TestSuite(ShuntingTests); + +Test(ShuntingTests, shunt_simplest) +{ + char *rpn; + const char *expr = "1 + 1"; + int actual = shunting_yard(expr, &rpn); + cr_expect(actual == 0, "Expected shunting_yard return value %d, got %d", 0, actual); + cr_expect(strcmp(rpn, "1 1 +") == 0, "Expected '1 1 +', got %s", rpn); + free(rpn); +} + +Test(ShuntingTests, shunt_nico) +{ + char *rpn; + const char *expr = "1 + 1 + 1"; + int actual = shunting_yard(expr, &rpn); + cr_expect(actual == 0, "Expected shunting_yard return value %d, got %d", 0, actual); + cr_expect(strcmp(rpn, "1 1 + 1 +") == 0, "Expected '1 1 + 1 +', got %s", rpn); + free(rpn); +} + +Test(ShuntingTests, shunt_harderdaddy) +{ + char *rpn; + const char *expr = "5*(2^2+3)"; + int actual = shunting_yard(expr, &rpn); + cr_expect(actual == 0, "Expected shunting_yard return value %d, got %d", 0, actual); + cr_expect(strcmp(rpn, "5 2 2 ^ 3 + *") == 0, "Expected '5 2 2 ^ 3 + *', got %s", rpn); + free(rpn); +} + +Test(ShuntingTests, shunt_numbers) +{ + char *rpn; + const char *expr = "42 + 50"; + int actual = shunting_yard(expr, &rpn); + cr_expect(actual == 0, "Expected shunting_yard return value %d, got %d", 0, actual); + cr_expect(strcmp(rpn, "42 50 +") == 0, "Expected '42 50 +', got %s", rpn); + free(rpn); +} + +Test(ShuntingTests, shunt_mod) +{ + char *rpn; + const char *expr = "42 % 50"; + int actual = shunting_yard(expr, &rpn); + cr_expect(actual == 0, "Expected shunting_yard return value %d, got %d", 0, actual); + cr_expect(strcmp(rpn, "42 50 %") == 0, "Expected '42 50 +', got %s", rpn); + free(rpn); +} |
