#include "calculator.h" #include #include #include #include #include #include LommereimarFileIter lommereimar_fileiter(const char* filename) { return (LommereimarFileIter) { .file = fopen(filename, "r"), .done = false, }; } char lommereimar_fileiter_next(LommereimarFileIter* file) { if (file->done) return '\0'; int c = fgetc(file->file); if (c == EOF) { file->done = true; return '\0'; } else { return (char)c; } } LommereimarLexer lommereimar_lexer(LommereimarFileIter input_file) { return (LommereimarLexer) { .input_file = input_file, .current = lommereimar_fileiter_next(&input_file), .pos = (LommereimarPosition) { .line = 1, .col = 1, }, }; } void lommereimar_lexer_step(LommereimarLexer* lexer) { lexer->current = lommereimar_fileiter_next(&lexer->input_file); if (lexer->current) { lexer->pos.line++; lexer->pos.col = 1; } else { lexer->pos.col++; } } #define lexer_step lommereimar_lexer_step LommereimarToken lommereimar_lexer_single_token( LommereimarLexer* lexer, LommereimarTokenType token_type ) { LommereimarPosition pos = lexer->pos; lommereimar_lexer_step(lexer); return (LommereimarToken) { .type = token_type, .pos = pos, .value = NULL, }; } #define single_token lommereimar_lexer_single_token LommereimarToken lommereimar_lexer_next(LommereimarLexer* lexer) { if (isspace(lexer->current)) { while (isspace(lexer->current)) lommereimar_lexer_step(lexer); return lommereimar_lexer_next(lexer); } else if (isdigit(lexer->current)) { LommereimarPosition pos = lexer->pos; size_t i = 0; char value[1234] = { 0 }; while (isdigit(lexer->current)) { value[i] = lexer->current; lommereimar_lexer_step(lexer); } char* allocated_value = malloc(sizeof(char) * strlen(value) + 1); strcpy(allocated_value, value); return (LommereimarToken) { .type = LommereimarTokenTypeInt, .pos = pos, .value = allocated_value, }; } else { switch (lexer->current) { case '+': return single_token(lexer, LommereimarTokenTypePlus); case '-': return single_token(lexer, LommereimarTokenTypeMinus); case '*': return single_token(lexer, LommereimarTokenTypeAsterisk); case '/': return single_token(lexer, LommereimarTokenTypeSlash); case '^': return single_token(lexer, LommereimarTokenTypeHat); default: return single_token(lexer, LommereimarTokenTypeInvalidChar); } } } LommereimarExpr* lommereimar_allocate_expr(LommereimarExpr data) { LommereimarExpr* expr = malloc(sizeof(LommereimarExpr)); *expr = data; return expr; } #define allocate_expr lommereimar_allocate_expr LommereimarParser lommereimar_parser(LommereimarLexer lexer) { return (LommereimarParser) { .lexer = lexer, .current = lommereimar_lexer_next(&lexer), }; } void lommereimar_parser_step(LommereimarParser* parser) { parser->current = lommereimar_lexer_next(&parser->lexer); } #define parser_step lommereimar_parser_step LommereimarExpr* lommereimar_parser_parse_expr(LommereimarParser* parser) { return lommereimar_parser_parse_term(parser); } LommereimarExpr* lommereimar_parser_parse_term(LommereimarParser* parser) { // Grammar // term -> factor (("+"|"-") factor):* LommereimarPosition pos = parser->current.pos; LommereimarExpr* left = lommereimar_parser_parse_factor(parser); for (;;) { if (parser->current.type == LommereimarTokenTypePlus) { parser_step(parser); LommereimarExpr* right = lommereimar_parser_parse_factor(parser); left = allocate_expr((LommereimarExpr) { .type = LommereimarExprTypeBinary, .pos = pos, .binary = (LommereimarExprBinary) { .type = LommereimarExprBinaryTypeAdd, .left = left, .right = right, }, }); } } } int main(void) { return EXIT_SUCCESS; }