Created
November 11, 2011 21:50
-
-
Save zed/1359412 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // 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