Skip to content

Commit

Permalink
Implement calculator error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
breiters committed Nov 19, 2024
1 parent 15eff12 commit 88b3b67
Showing 1 changed file with 48 additions and 33 deletions.
81 changes: 48 additions & 33 deletions src/calculator_exptree.c
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
#include <bstrlib.h>
#include <bstrlib_helper.h>
#include <perfgroup.h> /* CounterList */
#include "calculator_exptree.h"
#include <perfgroup.h> /* CounterList */
#include <ctype.h> /* isspace */
#include <errno.h> /* errno */
#include <math.h> /* NAN / isnan */
#include <stdio.h> /* printf / fprintf */
#include <stdlib.h> /* malloc / free */
#include <string.h> /* strncmp / strlen */

#include <ctype.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef NAN
# define NAN (0.0/0.0)
#endif

#define NODE_NULL_VALUE NAN
#define NODE_NULL_OPERATOR '\0'

struct exptree_node {
struct exptree_node *left; // Left child
Expand All @@ -24,9 +30,6 @@ static struct exptree_node *_make_expression_tree(const char **expr);
static struct exptree_node *_make_term_tree(const char **expr);
static struct exptree_node *_make_factor_tree(const char **expr);

#define NODE_NULL_VALUE 0.0
#define NODE_NULL_OPERATOR '\0'

static void _skip_spaces(const char **expr)
{
while (isspace(**expr)) {
Expand All @@ -52,33 +55,31 @@ static struct exptree_node *_make_value_node(double value)
// Set counter and create a leaf node
static struct exptree_node *_make_counter_node(char *counter)
{
struct exptree_node *node =
(struct exptree_node *)malloc(sizeof(struct exptree_node));
struct exptree_node *node = malloc(sizeof(struct exptree_node));
if (!node) {
return NULL;
}
*node = (struct exptree_node){.left = NULL,
.right = NULL,
.value = NODE_NULL_VALUE,
.counter_name = counter,
.operator= NODE_NULL_OPERATOR };
.operator = NODE_NULL_OPERATOR };
return node;
}

// Parse an operator and create an operator node
static struct exptree_node *
_make_operator_node(char operator, struct exptree_node *left, struct exptree_node *right)
{
struct exptree_node *node =
(struct exptree_node *)malloc(sizeof(struct exptree_node));
struct exptree_node *node = malloc(sizeof(struct exptree_node));
if (!node) {
return NULL;
}
*node = (struct exptree_node){.left = left,
.right = right,
.value = NODE_NULL_VALUE,
.counter_name = NULL,
.operator= operator};
.operator = operator};
return node;
}

Expand All @@ -100,9 +101,10 @@ static struct exptree_node *_make_factor_tree(const char **expr)
return subtree;
} else {
char *endptr;
errno = 0;
double value = strtod(*expr, &endptr);
if (*expr == endptr) {
// no conversion performed
// No conversion performed
char *counter_name;
if (sscanf(*expr, " %m[^()+-*/ \n] %*s", &counter_name) == 1) {
*expr += strlen(counter_name);
Expand All @@ -111,6 +113,9 @@ static struct exptree_node *_make_factor_tree(const char **expr)
fprintf(stderr, "Error: Could not parse: %s\n", *expr);
exit(EXIT_FAILURE);
}
} else if (errno) {
/* Underflow or Overflow */
/* value is DBL_MIN / HUGE_VAL (TODO: is this ok?) */
}
*expr = endptr;
return _make_value_node(value);
Expand All @@ -124,7 +129,7 @@ static struct exptree_node *_make_term_tree(const char **expr)
while (1) {
_skip_spaces(expr);
if (**expr == '*' || **expr == '/') {
char operator= ** expr;
char operator = **expr;
(*expr)++;
struct exptree_node *right = _make_factor_tree(expr);
left = _make_operator_node(operator, left, right);
Expand All @@ -142,7 +147,7 @@ static struct exptree_node *_make_expression_tree(const char **expr)
while (1) {
_skip_spaces(expr);
if (**expr == '+' || **expr == '-') {
char operator= ** expr;
char operator = **expr;
(*expr)++;
struct exptree_node *right = _make_term_tree(expr);
left = _make_operator_node(operator, left, right);
Expand Down Expand Up @@ -204,7 +209,7 @@ void free_expression_tree(struct exptree_node *node)
free(node);
}

// Get node value
// Gets node's value (returns NAN on error)
static double _get_value(const struct exptree_node *node, const CounterList *clist)
{
if (!node->counter_name) {
Expand All @@ -219,33 +224,43 @@ static double _get_value(const struct exptree_node *node, const CounterList *cli
const char *cname = bdata(clist->cnames->entry[ctr]);

if (len == strlen(cname) && !strncmp(node->counter_name, cname, len)) {
const char *val_str = bdata(clist->cvalues->entry[ctr]);
/* TODO: why are counter values stored as strings instead of unsigned long
* long ? */
double val = strtod(val_str, NULL);
/* TODO error handling of strtod */
return val;
const char *value_str = bdata(clist->cvalues->entry[ctr]);
/* TODO: why are counter values stored as strings instead of
* unsigned long long ? */

char *endptr;
errno = 0;
double value = strtod(value_str, &endptr);
if (value_str == endptr) {
// no conversion performed
fprintf(stderr, "Error: no conversion performed on %s\n", value_str);
return NODE_NULL_VALUE;
} else if (errno) {
/* Underflow or Overflow */
/* value is DBL_MIN / HUGE_VAL (TODO: is this ok?) */
}
return value;
}
}

fprintf(stderr, "Error: counter not found: %s\n", node->counter_name);
return NODE_NULL_VALUE; // TODO: error handling
return NODE_NULL_VALUE;
}

// Evaluate the expression tree recursively
// Evaluates the expression tree recursively (returns NAN on error)
double evaluate_expression_tree(const struct exptree_node *node, const CounterList *clist)
{
// TODO: maybe return NAN to indicate error ?
// need to check for NULL in child node evaluation in this case
if (!node) {
return 0.0;
return NODE_NULL_VALUE;
}

// If it's a leaf node (number/counter), return its value
if (node->operator== NODE_NULL_OPERATOR) {
if (node->operator == NODE_NULL_OPERATOR) {
return _get_value(node, clist);
}

// If it's not a leaf node, it must have two child (may change in case of unary operators)

// Recursively evaluate left and right subtrees
double val_left = evaluate_expression_tree(node->left, clist);
double val_right = evaluate_expression_tree(node->right, clist);
Expand All @@ -261,11 +276,11 @@ double evaluate_expression_tree(const struct exptree_node *node, const CounterLi
case '/':
if (val_right == 0.0) {
fprintf(stderr, "Error: Division by zero\n");
exit(EXIT_FAILURE);
return NODE_NULL_VALUE;
}
return val_left / val_right;
default:
fprintf(stderr, "Error: Unknown operator '%c'\n", node->operator);
exit(EXIT_FAILURE);
return NODE_NULL_VALUE;
}
}

0 comments on commit 88b3b67

Please sign in to comment.