Skip to content

Instantly share code, notes, and snippets.

@cpq
Last active August 29, 2015 14:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cpq/d76674d406d4d4362e14 to your computer and use it in GitHub Desktop.
Save cpq/d76674d406d4d4362e14 to your computer and use it in GitHub Desktop.
Arithmetic expression evaluator. Demonstrates how to write recursive descent parser in C.
// Copyright (c) 2014 Sergey Lyubka. All rights reserved.
// Arithmetic expression evaluator.
//
// Compilation: cc -o eval_arith eval_arith.c
// Usage: ./eval_arith "2 - 3 * ( 4 - 2.7 * 11.5 ) + 1.78"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
struct parser {
const unsigned char *pc;
};
static double parse_expr(struct parser *p);
static void fail(const char *message) {
fprintf(stderr, "FAILURE: %s\n", message);
exit(EXIT_FAILURE);
}
static void skip_whitespaces(struct parser *p) {
while (*p->pc != '\0' && isspace(*p->pc)) p->pc++;
}
static double parse_prim(struct parser *p) {
double result = 0;
skip_whitespaces(p);
if (*p->pc == '(') {
p->pc++;
result = parse_expr(p);
skip_whitespaces(p);
if (*p->pc != ')') {
fail("closing ')' expected");
}
p->pc++;
} else if (isdigit(*p->pc)) {
char *end;
result = strtod((const char *) p->pc, &end);
p->pc = (unsigned const char *) end;
} else {
fail("number expected");
}
skip_whitespaces(p);
return result;
}
static double parse_unary(struct parser *p) {
skip_whitespaces(p);
if (*p->pc == '-') {
p->pc++;
return -parse_prim(p);
} else {
return parse_prim(p);
}
}
static double parse_term(struct parser *p) {
double result = parse_unary(p);
while (*p->pc == '*' || *p->pc == '/') {
int op = *p->pc++;
double val = parse_unary(p);
result *= op == '*' ? val : 1.0 / val;
}
return result;
}
static double parse_expr(struct parser *p) {
double result = parse_term(p);
while (*p->pc == '+' || *p->pc == '-') {
int op = *p->pc++;
double val = parse_term(p);
result += op == '+' ? val : -val;
}
return result;
}
// Grammar:
// expr: term [ add_op term ] *
// term: prim [ mul_op prim ] *
// unary: [-] prim
// prim: number | ( expr )
int main(int argc, const char *argv[]) {
struct parser parser;
parser.pc = (unsigned char *) argv[1];
if (argc != 2) {
fail("Usage: eval_expr <arithmetic_expression>");
} else {
double result = parse_expr(&parser);
printf("Result: [%.*s] -> [%lg]\n",
(int) ((char *) parser.pc - argv[1]), argv[1], result);
}
return EXIT_SUCCESS;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment