Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // (Public domain, created by Ryan Johnson)
- // A simple recursive descent calculator in C.
- // compile with `cc -lm calc.c`
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdarg.h>
- #include <inttypes.h>
- #include <ctype.h>
- #include <math.h>
- typedef double f64;
- typedef struct {
- int type;
- f64 num;
- } Token;
- // The current token.
- Token curr;
- // Exit with an error
- void error(const char *fmt, ...) {
- va_list list;
- va_start(list, fmt);
- vfprintf(stderr, fmt, list);
- fputc('\n', stderr);
- exit(1);
- }
- // Get the next token from stdin
- Token next(void) {
- for (;;) {
- int c = getchar();
- if (isdigit(c)) {
- f64 num = 0;
- do num = num * 10 + (c - '0');
- while (isdigit(c = getchar()));
- ungetc(c, stdin);
- curr.type = 'n';
- curr.num = num;
- return curr;
- }
- if (isspace(c))
- continue;
- switch (c) {
- case '+':
- case '-':
- case '*':
- case '/':
- case '%':
- case '^':
- case '(':
- case ')':
- case EOF:
- curr.type = c;
- return curr;
- }
- if (isprint(c))
- error("Unexpected character: \"%c\"", (char)c);
- else
- error("Unexpected character: 0x%2X", (unsigned int)c);
- }
- }
- // Return the current Token as a string.
- const char *str_type(void) {
- switch (curr.type) {
- case '+':
- return "'+'";
- case '-':
- return "'-'";
- case '*':
- return "'*'";
- case '/':
- return "'/'";
- case '%':
- return "'%'";
- case '^':
- return "'^'";
- case 'n':
- return "number";
- case EOF:
- return "EOF";
- }
- return NULL;
- }
- // Production Rules:
- // Add -> Mul (("+" | "-") Mul)*
- // Mul -> Unary (("*" | "/" | "%") Unary)*
- // Unary -> ("+" | "-")? Exp
- // Exp -> Primary ("^" Exp)?
- // Primary -> Number | "(" Add ")"
- f64 p_add(void);
- f64 p_mul(void);
- f64 p_unary(void);
- f64 p_exp(void);
- f64 p_primary(void);
- f64 p_add(void) {
- f64 v = p_mul();
- for (;;) {
- if (curr.type == '+') {
- next();
- v += p_mul();
- } else if (curr.type == '-') {
- next();
- v -= p_mul();
- } else break;
- }
- return v;
- }
- f64 p_mul(void) {
- f64 v = p_unary();
- for (;;) {
- if (curr.type == '*') {
- next();
- v *= p_unary();
- } else if (curr.type == '/') {
- next();
- v /= p_unary();
- } else if (curr.type == '%') {
- next();
- v = fmod(v, p_unary());
- } else break;
- }
- return v;
- }
- f64 p_unary(void) {
- if (curr.type == '+') {
- next();
- return p_exp();
- } else if (curr.type == '-') {
- next();
- return -p_exp();
- }
- return p_exp();
- }
- f64 p_exp(void) {
- f64 v = p_primary();
- if (curr.type == '^') {
- next();
- return pow(v, p_exp());
- }
- return v;
- }
- f64 p_primary(void) {
- f64 v;
- switch (curr.type) {
- case 'n':
- v = curr.num;
- next();
- return v;
- case '(':
- next();
- v = p_add();
- if (curr.type != ')')
- error("Expected ')', found %s", str_type());
- next();
- return v;
- }
- error("Unexpected %s", str_type());
- }
- int main(void) {
- next();
- printf("%.2f\n", p_add());
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement