#include "calc.h" #include #include #include #include #include #include static inline bool isBinaryOp(TokenType tt); static inline ExprType binaryOpExprType(TokenType tt); static inline bool contains(char ch, const char* string); static inline int evalText(const char* text); int main(void) { while (true) { printf("> "); fflush(stdout); char line[128] = ""; fgets(line, 127, stdin); size_t line_length = strlen(line); line[--line_length] = '\0'; printf("line = \"%s\"\n", line); int result = evalText(line); printf("%d\n", result); } Expr* expr = binaryExprNew(ET_Add, intExprNew(-200), intExprNew(23)); exprPrint(expr); fputc('\n', stdout); int result = exprEval(expr); printf("%d\n", result); exprFree(expr); } static inline int evalText(const char* text) { Token tokens[128]; size_t tokens_size = lex(tokens, 128, text); Parser parser; parserConstruct(&parser, tokens, tokens_size); Expr* expr = parseExpr(&parser); if (!expr) return 0; int result = exprEval(expr); exprFree(expr); return result; } void parserConstruct(Parser* parser, Token* tokens, size_t tokens_size) { *parser = (Parser) { .tokens = tokens, .tokens_size = tokens_size, .i = 0, }; } void parserStep(Parser* parser) { parser->i += 1; } bool parserDone(const Parser* parser) { return parser->i >= parser->tokens_size; } Token parserCurrent(const Parser* parser) { return parser->tokens[parser->i]; } Expr* parseExpr(Parser* parser) { if (parserDone(parser)) { fprintf(stderr, "error: expected expr, got end-of-file\n"); return NULL; } Token tok = parserCurrent(parser); if (isBinaryOp(tok.type)) { parserStep(parser); Expr* left = parseExpr(parser); if (!left) return NULL; Expr* right = parseExpr(parser); if (!right) return NULL; ExprType et = binaryOpExprType(tok.type); return binaryExprNew(et, left, right); } else if (tok.type == TT_Int) { parserStep(parser); return intExprNew(tok.value); } else { parserStep(parser); fprintf(stderr, "error: expected expr\n"); return NULL; } } size_t lex(Token* tokens, size_t tokens_max_size, const char* text) { const size_t text_length = strlen(text); size_t tokens_i = 0; size_t i = 0; while (i < text_length && tokens_i < tokens_max_size) { while (contains(text[i], " \t\n")) { i++; } if (contains(text[i], "1234567890")) { char text_value[16] = ""; size_t j = 0; while (contains(text[i], "1234567890") && j < 15) { text_value[j] = text[i]; j++; i++; } tokens[tokens_i++] = (Token) { .type = TT_Int, .value = atoi(text_value) }; } else if (contains(text[i], "+-*/")) { char ch = text[i]; i++; tokens[tokens_i++] = (Token) { .type = (TokenType)ch, .value = 0, }; } else { char ch = text[i]; i++; fprintf(stderr, "error: illegal character '%c'\n", ch); } } return tokens_i; } static inline bool isBinaryOp(TokenType tt) { switch (tt) { case TT_Plus: case TT_Minus: case TT_Asterisk: case TT_Slash: return true; case TT_Int: default: return false; } } static inline ExprType binaryOpExprType(TokenType tt) { switch (tt) { case TT_Plus: return ET_Add; case TT_Minus: return ET_Subtract; case TT_Asterisk: return ET_Multiply; case TT_Slash: return ET_Divide; case TT_Int: break; } return 0; } static inline bool contains(char ch, const char* string) { for (size_t i = 0; i < strlen(string); ++i) { if (string[i] == ch) { return true; } } return false; }