162 lines
3.9 KiB
C
162 lines
3.9 KiB
C
#include "calculator.h"
|
|
#include <ctype.h>
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
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; }
|