diff --git a/lommereimar/calculator.c b/lommereimar/calculator.c new file mode 100644 index 0000000..9951fc6 --- /dev/null +++ b/lommereimar/calculator.c @@ -0,0 +1,149 @@ +#include +#include +#include +#include +#include +#include + +#include "calculator.h" + +FileIter fileiter(const char* filename) +{ + return (FileIter) { + .file = fopen(filename, "r"), + .done = false, + }; +} + +char fileiter_next(FileIter* file) +{ + if (file->done) + return '\0'; + int c = fgetc(file->file); + if (c == EOF) { + file->done = true; + return '\0'; + } else { + return (char)c; + } +} + +Lexer lexer(FileIter input_file) +{ + return (Lexer) { + .input_file = input_file, + .current = fileiter_next(&input_file), + .pos = (Position) { + .line = 1, + .col = 1, + }, + }; +} + +void lexer_step(Lexer* lexer) +{ + lexer->current = fileiter_next(&lexer->input_file); + if (lexer->current) { + lexer->pos.line++; + lexer->pos.col = 1; + } else { + lexer->pos.col++; + } +} + +Token lexer_single_token(Lexer* lexer, TokenType token_type) +{ + Position pos = lexer->pos; + lexer_step(lexer); + return (Token) { + .type = TokenTypePlus, + .pos = pos, + .value = NULL, + }; +} + +Token lexer_next(Lexer* lexer) +{ + if (isspace(lexer->current)) { + while (isspace(lexer->current)) + lexer_step(lexer); + return lexer_next(lexer); + } else if (isdigit(lexer->current)) { + Position pos = lexer->pos; + size_t i = 0; + char value[1234] = { 0 }; + while (isdigit(lexer->current)) { + value[i] = lexer->current; + lexer_step(lexer); + } + char* allocated_value = malloc(sizeof(char) * strlen(value) + 1); + strcpy(allocated_value, value); + return (Token) { + .type = TokenTypeInt, + .pos = pos, + .value = allocated_value, + }; + } else { + switch (lexer->current) { + case '+': + return lexer_single_token(lexer, TokenTypePlus); + case '-': + return lexer_single_token(lexer, TokenTypeMinus); + case '*': + return lexer_single_token(lexer, TokenTypeAsterisk); + case '/': + return lexer_single_token(lexer, TokenTypeSlash); + case '^': + return lexer_single_token(lexer, TokenTypeHat); + default: + return lexer_single_token(lexer, TokenTypeInvalidChar); + } + } +} + +Expr* allocate_expr(Expr data) +{ + Expr* expr = malloc(sizeof(Expr)); + *expr = data; + return expr; +} + +Parser parser(Lexer lexer) +{ + return (Parser) { + .lexer = lexer, + .current = lexer_next(&lexer), + }; +} + +void parser_step(Parser* parser) +{ + parser->current = lexer_next(&parser->lexer); +} + +Expr* parser_parse_expr(Parser* parser) { return parser_parse_term(parser); } + +Expr* parser_parse_term(Parser* parser) +{ + // Grammar + // term -> factor (("+"|"-") factor):* + Position pos = parser->current.pos; + Expr* left = parser_parse_factor(parser); + for (;;) { + if (parser->current.type == TokenTypePlus) { + parser_step(parser); + Expr* right = parser_parse_factor(parser); + left = allocate_expr((Expr) { + .type = ExprTypeBinary, + .pos = pos, + .binary = (ExprBinary) { + .type = ExprBinaryTypeAdd, + .left = left, + .right = right, + }, + }); + } + } +} + +int main() { return EXIT_SUCCESS; } diff --git a/lommereimar/calculator.h b/lommereimar/calculator.h new file mode 100644 index 0000000..8f33aa2 --- /dev/null +++ b/lommereimar/calculator.h @@ -0,0 +1,115 @@ +#ifndef CALCULATOR_H +#define CALCULATOR_H + +typedef struct { + FILE* file; + bool done; +} FileIter; + +FileIter fileiter(const char* filename); + +char fileiter_next(FileIter* file); + +typedef struct { + int line; + int col; +} Position; + +typedef enum { + TokenTypeEof, + TokenTypeInvalidChar, + TokenTypeInt, + TokenTypePlus, + TokenTypeMinus, + TokenTypeAsterisk, + TokenTypeSlash, + TokenTypeHat, + TokenTypeLParen, + TokenTypeRParen, +} TokenType; + +typedef struct { + // optional + char* value; + TokenType type; + Position pos; +} Token; + +typedef struct { + FileIter input_file; + char current; + Position pos; +} Lexer; + +Lexer lexer(FileIter input_file); + +void lexer_step(Lexer* lexer); + +Token lexer_single_token(Lexer* lexer, TokenType token_type); + +Token lexer_next(Lexer* lexer); + +typedef enum { + ExprTypeEof, + ExprTypeError, + ExprTypeInt, + ExprTypeFloat, + ExprTypeUnary, + ExprTypeBinary, +} ExprType; + +typedef struct Expr Expr; + +typedef enum { + ExprBinaryTypeAdd, + ExprBinaryTypeSubtract, + ExprBinaryTypeMultiply, + ExprBinaryTypeDivide, + ExprBinaryTypeExponent, +} ExprBinaryType; + +typedef struct { + ExprBinaryType type; + Expr* left; + Expr* right; +} ExprBinary; + +typedef enum { + ExprUnaryTypeNegate, +} ExprUnaryType; + +typedef struct { + ExprUnaryType type; + Expr* subject; +} ExprUnary; + +struct Expr { + ExprType type; + Position pos; + union { + char* error_value; + int int_value; + float float_value; + ExprUnary unary; + ExprBinary binary; + }; +}; + +Expr* allocate_expr(Expr data); + +typedef struct { + Lexer lexer; + Token current; +} Parser; + +Parser parser(Lexer lexer); + +void parser_step(Parser* parser); + +Expr* parser_parse_expr(Parser* parser); + +Expr* parser_parse_term(Parser* parser); + +Expr* parser_parse_factor(Parser* parser); + +#endif