Skip to content

Instantly share code, notes, and snippets.

@zed
Created November 11, 2011 21:50
Show Gist options
  • Select an option

  • Save zed/1359412 to your computer and use it in GitHub Desktop.

Select an option

Save zed/1359412 to your computer and use it in GitHub Desktop.
// gcc -std=c99 -Wall -pedantic -Wextra *.c -lreadline && ./a.out
#include <limits.h> // INT_MAX
#include <stdio.h>
#include <stdlib.h> // strtol
#include <readline/readline.h>
// space = \s+
// skip one or more ' ' characters
// return a pointer to the first non-' ' character or NULL on error
// NOTE: there must be at least one space
// NOTE: '\t', '\f', '\v' are *NOT* considered to be a space character here
static const char*
space(const char* pc) {
if (! (pc && *pc == ' ')) return NULL; // error
++pc;
while(*pc == ' ') ++pc;
return pc;
}
// operator = [+-]
// parse operator and store it in *presult (either '+' or '-')
// return a pointer to the first character after the operator or NULL on error
static const char*
operator(const char* pc, int *presult) {
if (! (pc && presult)) return NULL; // error
if (*pc == '+' || *pc == '-') {
*presult = *pc;
return ++pc;
}
return NULL;
}
// number = -?\d+
// parse the string as an integer and store it in *presult
// return a pointer to the first character after the number or NULL on error
static const char*
number(const char* pc, int* presult) {
if (! (pc && presult)) return NULL; // error
int sign = 1;
if (*pc == '-') { //NOTE: strtol() is too permissive, take sign by hand
++pc;
sign = -1;
}
char *end = NULL;
long int result = strtol(pc, &end, 10);
if (end == pc || result < 0 || result > INT_MAX) return NULL;
*presult = sign*result;
return end; // ok
}
// expr = number (\s+ [+-] \s+ number)*
// parse and evaluate the expression; store the result in *presult
// return a pointer to '\0' or NULL on error
static const char*
expr(const char* pc, int* presult) {
if (! (pc && presult)) return NULL; // error
int a, op, b;
if (! (pc = number(pc, &a))) return NULL;
while (*pc != '\0') {
if (! (pc = space(pc))) return NULL;
if (! (pc = operator(pc, &op))) return NULL;
if (! (pc = space(pc))) return NULL;
if (! (pc = number(pc, &b))) return NULL;
// evaluate
if (op == '+') a += b; //NOTE: ignore overflow
else if (op == '-') a -= b;
else return NULL; // can't happen
}
*presult = a;
return pc; // ok
}
int main() {
char* line = NULL;
while ((line = readline("calc> ")) && *line != '\0') {
int result = 0;
if (! expr(line, &result)) exit(EXIT_FAILURE);
printf("%d\n", result);
free(line);
}
exit(EXIT_SUCCESS);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment