matemateak/src/parser.c
2023-03-25 00:00:41 +01:00

328 lines
8.3 KiB
C

#include "parser.h"
#include "lexer.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Expr* error_expr(Position pos, const char* message)
{
Expr* node = malloc(sizeof(Expr));
*node = (Expr) {
.type = ExprTypeError,
.error = (ErrorExpr) {
.pos = pos,
.message = strndup(message, strlen(message)),
},
};
return node;
}
Expr* int_expr(int64_t value)
{
Expr* node = malloc(sizeof(Expr));
*node = (Expr) {
.type = ExprTypeInt,
.int_expr = (IntExpr) {
.value = value,
},
};
return node;
}
Expr* unary_expr(UnaryExprType type, Expr* subject)
{
Expr* node = malloc(sizeof(Expr));
*node = (Expr) {
.type = ExprTypeUnary,
.unary = (UnaryExpr) {
.type = type,
.subject = subject,
},
};
return node;
}
Expr* binary_expr(BinaryExprType type, Expr* left, Expr* right)
{
Expr* node = malloc(sizeof(Expr));
*node = (Expr) {
.type = ExprTypeBinary,
.binary = (BinaryExpr) {
.type = type,
.left = left,
.right = right,
},
};
return node;
}
typedef struct {
const char* text;
size_t length;
Lexer* lexer;
Token current;
} Parser;
bool parser_done(Parser* parser)
{
return parser->current.type == TokenTypeEof;
}
bool parser_current_is(Parser* parser, TokenType type)
{
return !parser_done(parser) && parser->current.type == type;
}
void parser_step(Parser* parser)
{
parser->current = lexer_next(parser->lexer);
}
Position parser_pos(Parser* parser)
{
return (Position) {
.index = parser->current.index,
.line = parser->current.line,
.col = parser->current.col,
};
}
Expr* parser_expr(Parser* parser);
Expr* parser_unknown_token_error(Parser* parser)
{
char buffer[128] = { 0 };
snprintf(
buffer, 128, "unknown char '%c'", parser->text[parser->current.index]
);
return error_expr(parser_pos(parser), buffer);
}
Expr* parser_operand(Parser* parser)
{
if (parser_current_is(parser, TokenTypeInt)) {
char buffer[24];
strncpy(
buffer, &parser->text[parser->current.index], parser->current.length
);
parser_step(parser);
return int_expr(atol(buffer));
} else if (parser_current_is(parser, TokenTypeEof)) {
Position pos = parser_pos(parser);
parser_step(parser);
return error_expr(pos, "unexpected end-of-file");
} else {
Expr* error = parser_unknown_token_error(parser);
parser_step(parser);
return error;
}
}
Expr* parser_group(Parser* parser)
{
if (parser_current_is(parser, TokenTypeLParen)) {
parser_step(parser);
Expr* value = parser_expr(parser);
if (!parser_current_is(parser, TokenTypeRParen)) {
parser_step(parser);
return error_expr(parser_pos(parser), "expected ')'");
}
parser_step(parser);
return value;
} else {
return parser_operand(parser);
}
}
Expr* parser_unary(Parser* parser)
{
if (parser_current_is(parser, TokenTypeMinus)) {
parser_step(parser);
return unary_expr(UnaryExprTypeNegate, parser_group(parser));
} else {
return parser_group(parser);
}
}
Expr* parser_multiply_divide(Parser* parser)
{
Expr* left = parser_unary(parser);
while (!parser_done(parser)) {
if (parser_current_is(parser, TokenTypeAsterisk)) {
parser_step(parser);
Expr* right = parser_unary(parser);
left = binary_expr(BinaryExprTypeMultiply, left, right);
} else if (parser_current_is(parser, TokenTypeSlash)) {
parser_step(parser);
Expr* right = parser_unary(parser);
left = binary_expr(BinaryExprTypeDivide, left, right);
} else {
break;
}
}
return left;
}
Expr* parser_add_subtract(Parser* parser)
{
Expr* left = parser_multiply_divide(parser);
while (!parser_done(parser)) {
if (parser_current_is(parser, TokenTypePlus)) {
parser_step(parser);
Expr* right = parser_multiply_divide(parser);
left = binary_expr(BinaryExprTypeAdd, left, right);
} else if (parser_current_is(parser, TokenTypeMinus)) {
parser_step(parser);
Expr* right = parser_multiply_divide(parser);
left = binary_expr(BinaryExprTypeSubtract, left, right);
} else {
break;
}
}
return left;
}
Expr* parser_expr(Parser* parser) { return parser_add_subtract(parser); }
Expr* parse(Lexer* lexer, const char* text, size_t length)
{
Parser parser = {
.text = text,
.length = length,
.lexer = lexer,
.current = lexer_next(lexer),
};
return parser_expr(&parser);
}
void free_expr(Expr* expr)
{
switch (expr->type) {
case ExprTypeError:
free(expr->error.message);
break;
case ExprTypeInt:
break;
case ExprTypeUnary:
free_expr(expr->unary.subject);
break;
case ExprTypeBinary:
free_expr(expr->binary.left);
free_expr(expr->binary.right);
break;
default:
fprintf(
stderr,
"panic: unexhausted value ./%s:%d %s()\n",
__FILE__,
__LINE__,
__func__
);
exit(1);
}
}
const char* unary_expr_type_to_string(UnaryExprType type)
{
switch (type) {
case UnaryExprTypeNegate:
return "Negate";
default:
fprintf(
stderr,
"panic: unexhausted value ./%s:%d %s()\n",
__FILE__,
__LINE__,
__func__
);
exit(1);
}
}
const char* binary_expr_type_to_string(BinaryExprType type)
{
switch (type) {
case BinaryExprTypeAdd:
return "Add";
case BinaryExprTypeSubtract:
return "Subtract";
case BinaryExprTypeMultiply:
return "Multiply";
case BinaryExprTypeDivide:
return "Divide";
default:
fprintf(
stderr,
"panic: unexhausted value ./%s:%d %s()\n",
__FILE__,
__LINE__,
__func__
);
exit(1);
}
}
char* expr_to_string(const Expr* expr)
{
switch (expr->type) {
case ExprTypeError: {
char formattet[65536];
snprintf(
formattet,
65536,
"Error { [%ld] %d:%d \"%s\" }",
expr->error.pos.index,
expr->error.pos.line,
expr->error.pos.col,
expr->error.message
);
return strndup(formattet, 65536);
}
case ExprTypeInt: {
char formattet[65536];
snprintf(formattet, 65536, "Int(%ld)", expr->int_expr.value);
return strndup(formattet, 65536);
}
case ExprTypeUnary: {
char* subject = expr_to_string(expr->unary.subject);
char formattet[65536];
snprintf(
formattet,
65536,
"Unary { type: %s, subject: %s }",
unary_expr_type_to_string(expr->unary.type),
subject
);
free(subject);
return strndup(formattet, 65536);
}
case ExprTypeBinary: {
char* left = expr_to_string(expr->binary.left);
char* right = expr_to_string(expr->binary.right);
char formattet[65536];
snprintf(
formattet,
65536,
"Binary { type: %s, left: %s, right: %s }",
binary_expr_type_to_string(expr->binary.type),
left,
right
);
free(left);
free(right);
return strndup(formattet, 65536);
}
default:
fprintf(
stderr,
"panic: unexhausted value ./%s:%d %s()\n",
__FILE__,
__LINE__,
__func__
);
exit(1);
}
}