#include "parser.h" #include "lexer.h" #include #include #include #include #include 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); } }