fix parser
This commit is contained in:
		
							parent
							
								
									813f14a3d4
								
							
						
					
					
						commit
						9177a1cd24
					
				
							
								
								
									
										10
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								Makefile
									
									
									
									
									
								
							@ -1,6 +1,8 @@
 | 
			
		||||
 | 
			
		||||
CC = gcc
 | 
			
		||||
 | 
			
		||||
TARGET = matemateak
 | 
			
		||||
 | 
			
		||||
CFLAGS = -std=c17 -Wall -Wextra -Wpedantic -Wconversion
 | 
			
		||||
LFLAGS = -lm
 | 
			
		||||
 | 
			
		||||
@ -9,15 +11,17 @@ HEADER_FILES = $(shell find src/ -name *.h)
 | 
			
		||||
 | 
			
		||||
OBJECT_FILES = $(patsubst %.c, %.o, $(C_FILES))
 | 
			
		||||
 | 
			
		||||
matemateak: $(OBJECT_FILES)
 | 
			
		||||
all: compile_flags.txt $(TARGET)
 | 
			
		||||
 | 
			
		||||
$(TARGET): $(OBJECT_FILES)
 | 
			
		||||
	$(CC) -o $@ $(LFLAGS) $^
 | 
			
		||||
 | 
			
		||||
%.o: %.c $(HEADER_FILES)
 | 
			
		||||
	$(CC) -c -o $@ $(CFLAGS) $<
 | 
			
		||||
 | 
			
		||||
compile_flags.txt:
 | 
			
		||||
	echo -xc $(C_FLAGS) | sed 's/\s\+/\n/g' > compile_flags.txt
 | 
			
		||||
	echo -xc $(CFLAGS) | sed 's/\s\+/\n/g' > compile_flags.txt
 | 
			
		||||
 | 
			
		||||
clean:
 | 
			
		||||
	$(RM) $(OBJECT_FILES) matemateak
 | 
			
		||||
	$(RM) $(OBJECT_FILES) $(TARGET)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										70
									
								
								src/lexer.c
									
									
									
									
									
								
							
							
						
						
									
										70
									
								
								src/lexer.c
									
									
									
									
									
								
							@ -1,7 +1,19 @@
 | 
			
		||||
#include "lexer.h"
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
char* strndup(const char* value, size_t length)
 | 
			
		||||
{
 | 
			
		||||
    size_t string_length = strlen(value);
 | 
			
		||||
    if (string_length >= length)
 | 
			
		||||
        string_length = length;
 | 
			
		||||
    char* allocated = malloc(sizeof(char) * (string_length + 1));
 | 
			
		||||
    strncpy(allocated, value, string_length);
 | 
			
		||||
    return allocated;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool lexer_done(const Lexer* lexer) { return lexer->index >= lexer->length; }
 | 
			
		||||
 | 
			
		||||
char lexer_current(const Lexer* lexer) { return lexer->text[lexer->index]; }
 | 
			
		||||
@ -149,10 +161,66 @@ const char* token_type_to_string(TokenType type)
 | 
			
		||||
            return "LParen";
 | 
			
		||||
        case TokenTypeRParen:
 | 
			
		||||
            return "RParen";
 | 
			
		||||
        default:
 | 
			
		||||
            fprintf(
 | 
			
		||||
                stderr,
 | 
			
		||||
                "panic: unexhausted value ./%s:%d %s()\n",
 | 
			
		||||
                __FILE__,
 | 
			
		||||
                __LINE__,
 | 
			
		||||
                __func__
 | 
			
		||||
            );
 | 
			
		||||
            exit(1);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
char* token_to_string(Token* token, const char* text)
 | 
			
		||||
{
 | 
			
		||||
    // frick it late
 | 
			
		||||
    char value[32] = { 0 };
 | 
			
		||||
    size_t value_i = 0;
 | 
			
		||||
    for (size_t i = 0; i < token->length && i < 32; i++) {
 | 
			
		||||
        char c = text[token->index + i];
 | 
			
		||||
        switch (c) {
 | 
			
		||||
            case '\\':
 | 
			
		||||
                value[value_i++] = '\\';
 | 
			
		||||
                value[value_i++] = '\\';
 | 
			
		||||
                break;
 | 
			
		||||
            case '\t':
 | 
			
		||||
                value[value_i++] = '\\';
 | 
			
		||||
                value[value_i++] = 't';
 | 
			
		||||
                break;
 | 
			
		||||
            case '\r':
 | 
			
		||||
                value[value_i++] = '\\';
 | 
			
		||||
                value[value_i++] = 'r';
 | 
			
		||||
                break;
 | 
			
		||||
            case '\n':
 | 
			
		||||
                value[value_i++] = '\\';
 | 
			
		||||
                value[value_i++] = 'n';
 | 
			
		||||
                break;
 | 
			
		||||
            case '\0':
 | 
			
		||||
                value[value_i++] = '\\';
 | 
			
		||||
                value[value_i++] = '0';
 | 
			
		||||
                break;
 | 
			
		||||
            case '\"':
 | 
			
		||||
                value[value_i++] = '\\';
 | 
			
		||||
                value[value_i++] = '\"';
 | 
			
		||||
                break;
 | 
			
		||||
            default:
 | 
			
		||||
                value[value_i++] = c;
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    char formattet[128];
 | 
			
		||||
    snprintf(
 | 
			
		||||
        formattet,
 | 
			
		||||
        128,
 | 
			
		||||
        "Token { %11s [%3ld:%-3ld] %3d:%-3d \"%s\" }",
 | 
			
		||||
        token_type_to_string(token->type),
 | 
			
		||||
        token->index,
 | 
			
		||||
        token->length,
 | 
			
		||||
        token->line,
 | 
			
		||||
        token->line,
 | 
			
		||||
        value
 | 
			
		||||
    );
 | 
			
		||||
    return strndup(formattet, 128);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -3,6 +3,8 @@
 | 
			
		||||
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
 | 
			
		||||
char* strndup(const char* value, size_t length);
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    size_t index;
 | 
			
		||||
    int line, col;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										28
									
								
								src/main.c
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								src/main.c
									
									
									
									
									
								
							@ -1,4 +1,30 @@
 | 
			
		||||
#include "lexer.h"
 | 
			
		||||
#include "parser.h"
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
int main(void) { printf("hello world\n"); }
 | 
			
		||||
int main(void)
 | 
			
		||||
{
 | 
			
		||||
    char* text = "2 * (3 + 4)";
 | 
			
		||||
 | 
			
		||||
    Lexer lexer1;
 | 
			
		||||
    lexer(&lexer1, text, strlen(text));
 | 
			
		||||
    Token current_token = lexer_next(&lexer1);
 | 
			
		||||
    printf("tokens = [\n");
 | 
			
		||||
    while (current_token.type != TokenTypeEof) {
 | 
			
		||||
        char* token_string = token_to_string(¤t_token, text);
 | 
			
		||||
        printf("    %s,\n", token_string);
 | 
			
		||||
        free(token_string);
 | 
			
		||||
        current_token = lexer_next(&lexer1);
 | 
			
		||||
    }
 | 
			
		||||
    printf("]\n");
 | 
			
		||||
 | 
			
		||||
    Lexer lexer2;
 | 
			
		||||
    lexer(&lexer2, text, strlen(text));
 | 
			
		||||
    Expr* ast = parse(&lexer2, text, strlen(text));
 | 
			
		||||
    char* ast_string = expr_to_string(ast);
 | 
			
		||||
    printf("ast = %s\n", ast_string);
 | 
			
		||||
    free(ast_string);
 | 
			
		||||
    free_expr(ast);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										194
									
								
								src/parser.c
									
									
									
									
									
								
							
							
						
						
									
										194
									
								
								src/parser.c
									
									
									
									
									
								
							@ -13,7 +13,7 @@ Expr* error_expr(Position pos, const char* message)
 | 
			
		||||
        .type = ExprTypeError,
 | 
			
		||||
        .error = (ErrorExpr) {
 | 
			
		||||
            .pos = pos,
 | 
			
		||||
            .message = strdup(message),
 | 
			
		||||
            .message = strndup(message, strlen(message)),
 | 
			
		||||
        },
 | 
			
		||||
    };
 | 
			
		||||
    return node;
 | 
			
		||||
@ -89,37 +89,7 @@ Position parser_pos(Parser* parser)
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Expr* parser_error(Parser* parser, const char* message)
 | 
			
		||||
{
 | 
			
		||||
    size_t line_width = 0;
 | 
			
		||||
    for (size_t i = 0;
 | 
			
		||||
         i < parser->length && parser->text[parser->current.index + i] != '\r'
 | 
			
		||||
         && parser->text[parser->current.index + i] != '\n';
 | 
			
		||||
         ++i)
 | 
			
		||||
        line_width = i;
 | 
			
		||||
 | 
			
		||||
    char line[512] = { 0 };
 | 
			
		||||
 | 
			
		||||
    char underline_indent[512] = { 0 };
 | 
			
		||||
    if (line_width > 0)
 | 
			
		||||
        memset(underline_indent, ' ', line_width - 1);
 | 
			
		||||
 | 
			
		||||
    char underline[512] = { '^', 0 };
 | 
			
		||||
    memset(underline, '^', parser->current.length);
 | 
			
		||||
 | 
			
		||||
    char formatted[512 * 4];
 | 
			
		||||
    snprintf(
 | 
			
		||||
        formatted,
 | 
			
		||||
        512 * 4,
 | 
			
		||||
        "error: %s\n     |\n %-4d|%s\n     |%s%s\n",
 | 
			
		||||
        message,
 | 
			
		||||
        parser->current.line,
 | 
			
		||||
        line,
 | 
			
		||||
        underline_indent,
 | 
			
		||||
        underline
 | 
			
		||||
    );
 | 
			
		||||
    return error_expr(parser_pos(parser), formatted);
 | 
			
		||||
}
 | 
			
		||||
Expr* parser_expr(Parser* parser);
 | 
			
		||||
 | 
			
		||||
Expr* parser_unknown_token_error(Parser* parser)
 | 
			
		||||
{
 | 
			
		||||
@ -127,15 +97,22 @@ Expr* parser_unknown_token_error(Parser* parser)
 | 
			
		||||
    snprintf(
 | 
			
		||||
        buffer, 128, "unknown char '%c'", parser->text[parser->current.index]
 | 
			
		||||
    );
 | 
			
		||||
    return parser_error(parser, buffer);
 | 
			
		||||
    return error_expr(parser_pos(parser), buffer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Expr* parser_operand(Parser* parser)
 | 
			
		||||
{
 | 
			
		||||
    if (parser_current_is(parser, TokenTypeInt)) {
 | 
			
		||||
        return NULL;
 | 
			
		||||
        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)) {
 | 
			
		||||
        return parser_error(parser, "unexpected end-of-file");
 | 
			
		||||
        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);
 | 
			
		||||
@ -143,13 +120,29 @@ Expr* parser_operand(Parser* parser)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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_operand(parser));
 | 
			
		||||
        return unary_expr(UnaryExprTypeNegate, parser_group(parser));
 | 
			
		||||
    } else {
 | 
			
		||||
        return parser_operand(parser);
 | 
			
		||||
        return parser_group(parser);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -206,5 +199,130 @@ Expr* parse(Lexer* lexer, const char* text, size_t length)
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
{
 | 
			
		||||
    printf("expr->type == %d\n", expr->type);
 | 
			
		||||
    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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -56,5 +56,6 @@ struct Expr {
 | 
			
		||||
 | 
			
		||||
Expr* parse(Lexer* lexer, const char* text, size_t length);
 | 
			
		||||
void free_expr(Expr* expr);
 | 
			
		||||
char* expr_to_string(const Expr* expr);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user