lommereimar: add lommereimar
This commit adds the required files for the LommeReimar project. It is very good and nice. also incomplete.
This commit is contained in:
parent
29abedb032
commit
f4b2d113f7
149
lommereimar/calculator.c
Normal file
149
lommereimar/calculator.c
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
#include <ctype.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#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; }
|
115
lommereimar/calculator.h
Normal file
115
lommereimar/calculator.h
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user