diff --git a/include/ast.h b/include/ast.h index 382cf3f..10fb4f3 100644 --- a/include/ast.h +++ b/include/ast.h @@ -4,65 +4,102 @@ #include "lexer.h" /* -expression → literal - | unary - | binary - | grouping ; -literal → NUMBER | STRING | "true" | "false" | "nil" ; -grouping → "(" expression ")" ; -unary → ( "-" | "!" ) expression ; -binary → expression operator expression ; -operator → "==" | "!=" | "<" | "<=" | ">" | ">=" - | "+" | "-" | "*" | "/" ; + expression → literal | unary | binary | grouping ; + literal → NUMBER | STRING | "true" | "false" | "nil" ; + grouping → "(" expression ")" ; + unary → ( "-" | "!" ) expression ; + binary → expression operator expression ; + operator → "==" | "!=" | "<" | "<=" | ">" | ">=" | "+" | "-" | "*" | "/" ; */ typedef enum { - BINARY, - UNARY, - LITERAL, - GROUPING, -} expr_type; + EXPR_ASSIGN, + EXPR_BINARY, + EXPR_CALL, + EXPR_GET, + EXPR_GROUPING, + EXPR_LITERAL, + EXPR_LOGICAL, + EXPR_SET, + EXPR_SUPER, + EXPR_THIS, + EXPR_UNARY, + EXPR_VARIABLE, +} expr_type_t; typedef enum { - VAL_BOOL, - VAL_NIL, - VAL_NUMBER, - VAL_STRING, + VAL_BOOL, + VAL_NIL, + VAL_NUMBER, + VAL_STRING, } value_type_t; typedef struct { - value_type_t type; - union { - int boolean; - double number; - char *string; - } as; + value_type_t type; + union { + int boolean; + double number; + char *string; + } as; } value_t; typedef struct expr_t { - expr_type type; - int line; - union { - struct { - token_t binary_op; - struct expr_t *left; - struct expr_t *right; - } binary; - struct { - token_t unary_op; - struct expr_t *right; - } unary; - struct { - value_t value; - } literal; + expr_type_t type; + int line; + union { + struct { + token_t name; + struct expr_t *value; + } assign; + struct { + token_t operator; + struct expr_t *left; + struct expr_t *right; + } binary; + struct { + struct expr_t *callee; + token_t paren; + struct expr_t **arguments; + } call; + struct { + struct expr_t *object; + token_t name; + } get; struct { struct expr_t *expression; } grouping; - } as; + struct { + value_t value; + } literal; + struct { + token_t operator; + struct expr_t *left; + struct expr_t *right; + } logical; + struct { + struct expr_t *object; + token_t name; + struct expr_t *value; + } set; + struct { + token_t keyword; + token_t method; + } super; + struct { + token_t keyword; + } this; + struct { + token_t operator; + struct expr_t *right; + } unary; + struct { + token_t name; + } variable; + } as; } expr_t; -expr_t *create_binary_expr(token_t *binary_op, expr_t *left, expr_t *right); -expr_t *create_unary_expr(token_t *unary_op, expr_t *right); +expr_t *create_binary_expr(token_t *operator, expr_t *left, expr_t *right); +expr_t *create_unary_expr(token_t *operator, expr_t *right); expr_t *create_literal_expr(token_t *token); expr_t *create_grouping_expr(expr_t *expression); void print_ast(expr_t *expr); diff --git a/include/interpreter.h b/include/interpreter.h index 230537f..9d3c03e 100644 --- a/include/interpreter.h +++ b/include/interpreter.h @@ -2,8 +2,10 @@ #define INTERPRETER_H #include "ast.h" +#include "stmt.h" value_t evaluate(expr_t *expr); void print_value(value_t *value); +void print_statements(stmt_array_t *array); #endif diff --git a/include/lexer.h b/include/lexer.h index b064980..f6f2e29 100644 --- a/include/lexer.h +++ b/include/lexer.h @@ -5,23 +5,23 @@ typedef enum { // Single-character tokens - LEFT_PAREN, RIGHT_PAREN, LEFT_BRACE, RIGHT_BRACE, - COMMA, DOT, MINUS, PLUS, SEMICOLON, SLASH, STAR, + TOKEN_LEFT_PAREN, TOKEN_RIGHT_PAREN, TOKEN_LEFT_BRACE, TOKEN_RIGHT_BRACE, + TOKEN_COMMA, TOKEN_DOT, TOKEN_MINUS, TOKEN_PLUS, TOKEN_SEMICOLON, + TOKEN_SLASH, TOKEN_STAR, // One or two character tokens - BANG, BANG_EQUAL, - EQUAL, EQUAL_EQUAL, - GREATER, GREATER_EQUAL, - LESS, LESS_EQUAL, + TOKEN_BANG, TOKEN_BANG_EQUAL, TOKEN_EQUAL, TOKEN_EQUAL_EQUAL, TOKEN_GREATER, + TOKEN_GREATER_EQUAL, TOKEN_LESS, TOKEN_LESS_EQUAL, // Literals - IDENTIFIER, STRING, NUMBER, + TOKEN_IDENTIFIER, TOKEN_STRING, TOKEN_NUMBER, // Keywords - AND, CLASS, ELSE, FALSE, FUN, FOR, IF, NIL, OR, - PRINT, RETURN, SUPER, THIS, TRUE, VAR, WHILE, + TOKEN_AND, TOKEN_CLASS, TOKEN_ELSE, TOKEN_FALSE, TOKEN_FUN, TOKEN_FOR, + TOKEN_IF, TOKEN_NIL, TOKEN_OR, TOKEN_PRINT, TOKEN_RETURN, TOKEN_SUPER, + TOKEN_THIS, TOKEN_TRUE, TOKEN_VAR, TOKEN_WHILE, - END_OF_FILE + TOKEN_EOF } token_type_t; typedef struct { diff --git a/include/parser.h b/include/parser.h index 78e91ce..004c476 100644 --- a/include/parser.h +++ b/include/parser.h @@ -2,21 +2,22 @@ #define PARSER_H /* -expression → equality ; -equality → comparison ( ( "!=" | "==" ) comparison )* ; -comparison → term ( ( ">" | ">=" | "<" | "<=" ) term )* ; -term → factor ( ( "-" | "+" ) factor )* ; -factor → unary ( ( "/" | "*" ) unary )* ; -unary → ( "!" | "-" ) unary - | primary ; -primary → NUMBER | STRING | "true" | "false" | "nil" - | "(" expression ")" ; +expression → equality ; +equality → comparison ( ( "!=" | "==" ) comparison )* ; +comparison → term ( ( ">" | ">=" | "<" | "<=" ) term )* ; +term → factor ( ( "-" | "+" ) factor )* ; +factor → unary ( ( "/" | "*" ) unary )* ; +unary → ( "!" | "-" ) unary | primary ; +primary → NUMBER | STRING | "true" | "false" | "nil" | "(" expression ")" ; */ #include "ast.h" #include "lexer.h" +#include "stmt.h" -expr_t *parse(token_t *tks); +stmt_array_t *parse(token_t *tks); +expr_t *parse_expr(token_t *tks); void free_expr(expr_t *expr); +void free_statements(stmt_array_t *array); #endif diff --git a/include/stmt.h b/include/stmt.h index 957f3d7..28ec994 100644 --- a/include/stmt.h +++ b/include/stmt.h @@ -2,64 +2,68 @@ #define STMT_H #include "ast.h" -#include "scanner.h" +#include "lexer.h" + +#define DEFAULT_STMTS_SIZE 512 + typedef enum { - STMT_BLOCK, - STMT_CLASS, - STMT_EXPR, - STMT_FUN, - STMT_IF, - STMT_PRINT, - STMT_VAR, - STMT_WHILE, - STMT_COUNT, -} StmtType; -typedef struct Stmt Stmt; -struct Stmt{ - StmtType type; - union { - struct { - Stmt **statements; - } block; - struct { - Token name; - Token superclass; - Stmt **methods; - } class; - struct { - Expr *expression; - } expr; - struct { - Token name; - TokenArray params; - Stmt **body; - } function; - struct { - Expr *condition; - Stmt *thenBranch; - Stmt *elseBranch; - } _if; - struct { - Expr *expression; - } print; - struct { - Token keyword; - Expr *value; - } _return; - struct { - Token name; - Expr *initializer; - } variable; - struct { - Expr *condition; - Stmt *body; - } _while; - } as; -}; + STMT_BLOCK, + STMT_CLASS, + STMT_EXPR, + STMT_FUN, + STMT_IF, + STMT_PRINT, + STMT_VAR, + STMT_WHILE, + STMT_COUNT, +} stmt_type_t; + +typedef struct stmt_t { + stmt_type_t type; + union { + struct { + struct stmt_t **statements; + } block; + struct { + token_t name; + token_t superclass; + struct stmt_t **methods; + } class; + struct { + expr_t *expression; + } expr; + struct { + token_t name; + array_t *params; + struct stmt_t **body; + } function; + struct { + expr_t *condition; + struct stmt_t *thenBranch; + struct stmt_t *elseBranch; + } _if; + struct { + expr_t *expression; + } print; + struct { + token_t keyword; + expr_t *value; + } _return; + struct { + token_t name; + expr_t *initializer; + } variable; + struct { + expr_t *condition; + struct stmt_t *body; + } _while; + } as; +} stmt_t; + typedef struct { - Stmt *statements; - int count; - int capacity; - bool hadError; -} StmtArray; + struct stmt_t *statements; + int length; + int capacity; +} stmt_array_t; + #endif diff --git a/src/ast.c b/src/ast.c index 98601f4..c03e8fb 100644 --- a/src/ast.c +++ b/src/ast.c @@ -5,29 +5,29 @@ #include "ast.h" #include "lexer.h" -expr_t *create_binary_expr(token_t *binary_op, expr_t *left, expr_t *right) +expr_t *create_binary_expr(token_t *operator, expr_t *left, expr_t *right) { expr_t *expr = malloc(sizeof(expr_t)); - expr->type = BINARY; - expr->line = binary_op->line; + expr->type = EXPR_BINARY; + expr->line = operator->line; expr->as.binary.left = left; expr->as.binary.right = right; - expr->as.binary.binary_op.type = binary_op->type; - char *bin_op_val = strdup(binary_op->value); - expr->as.binary.binary_op.value = bin_op_val; - expr->as.binary.binary_op.line = binary_op->line; + expr->as.binary.operator.type = operator->type; + char *bin_op_val = strdup(operator->value); + expr->as.binary.operator.value = bin_op_val; + expr->as.binary.operator.line = operator->line; return expr; } -expr_t *create_unary_expr(token_t *unary_op, expr_t *right) +expr_t *create_unary_expr(token_t *operator, expr_t *right) { expr_t *expr = malloc(sizeof(expr_t)); - expr->type = UNARY; - expr->line = unary_op->line; - expr->as.unary.unary_op.type = unary_op->type; - char *u_op_val = strdup(unary_op->value); - expr->as.unary.unary_op.value = u_op_val; - expr->as.unary.unary_op.line = unary_op->line; + expr->type = EXPR_UNARY; + expr->line = operator->line; + expr->as.unary.operator.type = operator->type; + char *u_op_val = strdup(operator->value); + expr->as.unary.operator.value = u_op_val; + expr->as.unary.operator.line = operator->line; expr->as.unary.right = right; return expr; } @@ -35,28 +35,28 @@ expr_t *create_unary_expr(token_t *unary_op, expr_t *right) expr_t *create_literal_expr(token_t *token) { expr_t *expr = malloc(sizeof(expr_t)); - expr->type = LITERAL; + expr->type = EXPR_LITERAL; expr->line = token->line; switch (token->type) { - case NUMBER: + case TOKEN_NUMBER: expr->as.literal.value.type = VAL_NUMBER; double num; sscanf(token->value, "%lf", &num); expr->as.literal.value.as.number = num; break; - case NIL: + case TOKEN_NIL: expr->as.literal.value.type = VAL_NIL; expr->as.literal.value.as.number = 0; break; - case TRUE: - case FALSE: + case TOKEN_TRUE: + case TOKEN_FALSE: expr->as.literal.value.type = VAL_BOOL; - expr->as.literal.value.as.boolean = token->type == TRUE; + expr->as.literal.value.as.boolean = token->type == TOKEN_TRUE; break; - case STRING: + case TOKEN_STRING: expr->as.literal.value.type = VAL_STRING; char *tkvalue = strdup(token->value); expr->as.literal.value.as.string = tkvalue; @@ -74,7 +74,7 @@ expr_t *create_grouping_expr(expr_t *expression) return NULL; } expr_t *expr = malloc(sizeof(expr_t)); - expr->type = GROUPING; + expr->type = EXPR_GROUPING; expr->line = expression->line; expr->as.grouping.expression = expression; return expr; @@ -84,7 +84,7 @@ void print_ast(expr_t *expr) { if (!expr) return; - if (expr->type == LITERAL) { + if (expr->type == EXPR_LITERAL) { switch (expr->as.literal.value.type) { case VAL_BOOL: printf("%s", expr->as.literal.value.as.boolean ? "true" : "false"); @@ -107,17 +107,17 @@ void print_ast(expr_t *expr) printf("%s", expr->as.literal.value.as.string); break; } - } else if (expr->type == BINARY) { - printf("(%s ", expr->as.binary.binary_op.value); + } else if (expr->type == EXPR_BINARY) { + printf("(%s ", expr->as.binary.operator.value); print_ast(expr->as.binary.left); printf(" "); print_ast(expr->as.binary.right); printf(")"); - } else if (expr->type == UNARY) { - printf("(%s ", expr->as.unary.unary_op.value); + } else if (expr->type == EXPR_UNARY) { + printf("(%s ", expr->as.unary.operator.value); print_ast(expr->as.unary.right); printf(")"); - } else if (expr->type == GROUPING) { + } else if (expr->type == EXPR_GROUPING) { printf("(group "); print_ast(expr->as.grouping.expression); printf(")"); diff --git a/src/interpreter.c b/src/interpreter.c index 1dec5c2..c8b58d0 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -31,7 +31,7 @@ void runtime_error(const char *message, int line) value_t visit_binary(expr_t *expr) { - token_type_t op_type = expr->as.binary.binary_op.type; + token_type_t op_type = expr->as.binary.operator.type; value_t right = evaluate(expr->as.binary.right); value_t left = evaluate(expr->as.binary.left); @@ -39,19 +39,19 @@ value_t visit_binary(expr_t *expr) if (left.type == VAL_NUMBER && right.type == VAL_NUMBER) { value_t result = {.type = VAL_NUMBER}; switch (op_type) { - case PLUS: + case TOKEN_PLUS: result.as.number = left.as.number + right.as.number; return result; - case MINUS: + case TOKEN_MINUS: result.as.number = left.as.number - right.as.number; return result; - case STAR: + case TOKEN_STAR: result.as.number = left.as.number * right.as.number; return result; - case SLASH: + case TOKEN_SLASH: if (right.as.number == 0) { runtime_error("Division by zero.", expr->line); } @@ -63,7 +63,7 @@ value_t visit_binary(expr_t *expr) } // Comparison - if (op_type == EQUAL_EQUAL || op_type == BANG_EQUAL) { + if (op_type == TOKEN_EQUAL_EQUAL || op_type == TOKEN_BANG_EQUAL) { int is_equal; if (left.type != right.type) { is_equal = 0; @@ -91,7 +91,7 @@ value_t visit_binary(expr_t *expr) } } value_t result = {.type = VAL_BOOL}; - result.as.boolean = op_type == EQUAL_EQUAL ? is_equal : !is_equal; + result.as.boolean = op_type == TOKEN_EQUAL_EQUAL ? is_equal : !is_equal; return result; } @@ -99,19 +99,19 @@ value_t visit_binary(expr_t *expr) if (left.type == VAL_NUMBER && right.type == VAL_NUMBER) { value_t result = {.type = VAL_BOOL }; switch (op_type) { - case GREATER: + case TOKEN_GREATER: result.as.boolean= left.as.number > right.as.number; return result; - case GREATER_EQUAL: + case TOKEN_GREATER_EQUAL: result.as.boolean = left.as.number >= right.as.number; return result; - case LESS: + case TOKEN_LESS: result.as.boolean = left.as.number < right.as.number; return result; - case LESS_EQUAL: + case TOKEN_LESS_EQUAL: result.as.boolean = left.as.number <= right.as.number; return result; @@ -121,7 +121,7 @@ value_t visit_binary(expr_t *expr) // String concatenation if (left.type == VAL_STRING && right.type == VAL_STRING) { - if (op_type == PLUS) { + if (op_type == TOKEN_PLUS) { value_t result = {.type = VAL_STRING}; size_t left_len = strlen(left.as.string); size_t right_len = strlen(right.as.string); @@ -133,7 +133,8 @@ value_t visit_binary(expr_t *expr) } // String/number comparisons - if ((left.type == VAL_STRING && right.type == VAL_NUMBER) || (left.type == VAL_NUMBER && right.type == VAL_STRING)) { + if ((left.type == VAL_STRING && right.type == VAL_NUMBER) || + (left.type == VAL_NUMBER && right.type == VAL_STRING)) { runtime_error("Operands must be numbers.", expr->line); } @@ -168,14 +169,14 @@ value_t visit_unary(expr_t *expr) { value_t operand = evaluate(expr->as.unary.right); - if (expr->as.unary.unary_op.type == MINUS) { + if (expr->as.unary.operator.type == TOKEN_MINUS) { if (operand.type == VAL_NUMBER) { value_t result = {.type = VAL_NUMBER, .as.number = -operand.as.number}; return result; } else { runtime_error("Operand must be a number.", expr->line); } - } else if (expr->as.unary.unary_op.type == BANG) { + } else if (expr->as.unary.operator.type == TOKEN_BANG) { value_t result = {.type = VAL_BOOL, .as.boolean = !is_truthy(&operand)}; return result; } @@ -190,16 +191,16 @@ value_t evaluate(expr_t *expr) return nil_value; } switch (expr->type) { - case LITERAL: + case EXPR_LITERAL: return visit_literal(expr); - case BINARY: + case EXPR_BINARY: return visit_binary(expr); - case UNARY: + case EXPR_UNARY: return visit_unary(expr); - case GROUPING: + case EXPR_GROUPING: return visit_grouping(expr); default: - errno = 65; + exit(65); break; } } @@ -231,3 +232,20 @@ void print_value(value_t *value) break; } } + +void print_statement(stmt_t stmt) +{ + if (stmt.type == STMT_PRINT) { + value_t obj = evaluate(stmt.as.print.expression); + print_value(&obj); +/* } else if (stmt.type == STMT_EXPR) { */ +/* value_t obj = evaluate(stmt.as.expr.expression); */ +/* print_value(&obj); */ + } +} +void print_statements(stmt_array_t *array) +{ + for (int i = 0; i < array->length; i++) { + print_statement(array->statements[i]); + } +} diff --git a/src/lexer.c b/src/lexer.c index 6495b63..9be2d52 100644 --- a/src/lexer.c +++ b/src/lexer.c @@ -7,35 +7,35 @@ #include "lexer.h" const keyword_map reserved_keywords[] = { - {"and", AND}, {"class", CLASS}, {"else", ELSE}, - {"false", FALSE}, {"fun", FUN}, {"for", FOR}, - {"if", IF}, {"nil", NIL}, {"or", OR}, - {"print", PRINT}, {"return", RETURN}, - {"super", SUPER}, {"this", THIS}, {"true", TRUE}, - {"var", VAR}, {"while", WHILE} + {"and", TOKEN_AND}, {"class", TOKEN_CLASS}, {"else", TOKEN_ELSE}, + {"false", TOKEN_FALSE}, {"fun", TOKEN_FUN}, {"for", TOKEN_FOR}, + {"if", TOKEN_IF}, {"nil", TOKEN_NIL}, {"or", TOKEN_OR}, + {"print", TOKEN_PRINT}, {"return", TOKEN_RETURN}, + {"super", TOKEN_SUPER}, {"this", TOKEN_THIS}, {"true", TOKEN_TRUE}, + {"var", TOKEN_VAR}, {"while", TOKEN_WHILE} }; const keyword_map regular_tokens[] = { - {"LEFT_PAREN", LEFT_PAREN}, {"RIGHT_PAREN", RIGHT_PAREN}, - {"LEFT_BRACE", LEFT_BRACE}, {"RIGHT_BRACE", RIGHT_BRACE}, - {"COMMA", COMMA}, {"DOT", DOT}, {"MINUS", MINUS}, - {"PLUS", PLUS}, {"SEMICOLON", SEMICOLON}, {"SLASH", SLASH}, - {"STAR", STAR}, {"BANG", BANG}, {"BANG_EQUAL", BANG_EQUAL}, - {"EQUAL", EQUAL}, {"EQUAL_EQUAL", EQUAL_EQUAL}, {"GREATER", GREATER}, - {"GREATER_EQUAL", GREATER_EQUAL}, {"LESS", LESS}, {"LESS_EQUAL", LESS_EQUAL}, - {"IDENTIFIER", IDENTIFIER}, {"STRING", STRING}, {"NUMBER", NUMBER}, - {"AND", AND}, {"CLASS", CLASS}, {"ELSE", ELSE}, {"FALSE", FALSE}, - {"FUN", FUN}, {"FOR", FOR}, {"IF", IF}, {"NIL", NIL}, - {"OR", OR}, {"PRINT", PRINT}, {"RETURN", RETURN}, - {"SUPER", SUPER}, {"THIS", THIS}, {"TRUE", TRUE}, - {"VAR", VAR}, {"WHILE", WHILE}, {"END_OF_FILE", END_OF_FILE} + {"LEFT_PAREN", TOKEN_LEFT_PAREN}, {"RIGHT_PAREN", TOKEN_RIGHT_PAREN}, + {"LEFT_BRACE", TOKEN_LEFT_BRACE}, {"RIGHT_BRACE", TOKEN_RIGHT_BRACE}, + {"COMMA", TOKEN_COMMA}, {"DOT", TOKEN_DOT}, {"MINUS", TOKEN_MINUS}, + {"PLUS", TOKEN_PLUS}, {"SEMICOLON", TOKEN_SEMICOLON}, {"SLASH", TOKEN_SLASH}, + {"STAR", TOKEN_STAR}, {"BANG", TOKEN_BANG}, {"BANG_EQUAL", TOKEN_BANG_EQUAL}, + {"EQUAL", TOKEN_EQUAL}, {"EQUAL_EQUAL", TOKEN_EQUAL_EQUAL}, {"GREATER", TOKEN_GREATER}, + {"GREATER_EQUAL", TOKEN_GREATER_EQUAL}, {"LESS", TOKEN_LESS}, {"LESS_EQUAL", TOKEN_LESS_EQUAL}, + {"IDENTIFIER", TOKEN_IDENTIFIER}, {"STRING", TOKEN_STRING}, {"NUMBER", TOKEN_NUMBER}, + {"AND", TOKEN_AND}, {"CLASS", TOKEN_CLASS}, {"ELSE", TOKEN_ELSE}, {"FALSE", TOKEN_FALSE}, + {"FUN", TOKEN_FUN}, {"FOR", TOKEN_FOR}, {"IF", TOKEN_IF}, {"NIL", TOKEN_NIL}, + {"OR", TOKEN_OR}, {"PRINT", TOKEN_PRINT}, {"RETURN", TOKEN_RETURN}, + {"SUPER", TOKEN_SUPER}, {"THIS", TOKEN_THIS}, {"TRUE", TOKEN_TRUE}, + {"VAR", TOKEN_VAR}, {"WHILE", TOKEN_WHILE}, {"END_OF_FILE", TOKEN_EOF} }; char *read_source(const char *filename) { FILE *file = fopen(filename, "r"); if (file == NULL) { - fprintf(stderr, "rd: Error reading file: %s\n", filename); + fprintf(stderr, "Error reading file: %s\n", filename); return NULL; } @@ -45,14 +45,14 @@ char *read_source(const char *filename) char *source = malloc(file_size + 1); if (source == NULL) { - fprintf(stderr, "rd: Error allocating memory\n"); + fprintf(stderr, "Memory allocation failed\n"); fclose(file); return NULL; } size_t bytes_read = fread(source, 1, file_size, file); if (bytes_read < file_size) { - fprintf(stderr, "rd: Error reading file contents\n"); + fprintf(stderr, "Error reading file contents\n"); free(source); fclose(file); return NULL; @@ -105,11 +105,11 @@ char *type_str(token_type_t type) void print_tokens(token_t *tokens) { - for (int i = 0; tokens[i].type != END_OF_FILE; i++) { + for (int i = 0; tokens[i].type != TOKEN_EOF; i++) { token_t token = tokens[i]; - if (token.type == STRING) { + if (token.type == TOKEN_STRING) { printf("STRING \"%s\" %s\n", token.value, token.value); - } else if (token.type == NUMBER) { + } else if (token.type == TOKEN_NUMBER) { double value = strtod(token.value, NULL); if (value == (int) value) { printf("NUMBER %s %d.0\n", token.value, (int) value); @@ -142,74 +142,71 @@ array_t *tokenize(char *filename) tokens->capacity = DEFAULT_TOKENS_SIZE; char *source = read_source(filename); - if (!source) { - return NULL; - } int line = 1; size_t source_len = strlen(source); if (source_len > 0) { for (int i = 0; i < source_len; i++) { switch (source[i]) { case '(': - token_add(tokens, token_gen(LEFT_PAREN, "(", line)); + token_add(tokens, token_gen(TOKEN_LEFT_PAREN, "(", line)); break; case ')': - token_add(tokens, token_gen(RIGHT_PAREN, ")", line)); + token_add(tokens, token_gen(TOKEN_RIGHT_PAREN, ")", line)); break; case '{': - token_add(tokens, token_gen(LEFT_BRACE, "{", line)); + token_add(tokens, token_gen(TOKEN_LEFT_BRACE, "{", line)); break; case '}': - token_add(tokens, token_gen(RIGHT_BRACE, "}", line)); + token_add(tokens, token_gen(TOKEN_RIGHT_BRACE, "}", line)); break; case '*': - token_add(tokens, token_gen(STAR, "*", line)); + token_add(tokens, token_gen(TOKEN_STAR, "*", line)); break; case '.': - token_add(tokens, token_gen(DOT, ".", line)); + token_add(tokens, token_gen(TOKEN_DOT, ".", line)); break; case ',': - token_add(tokens, token_gen(COMMA, ",", line)); + token_add(tokens, token_gen(TOKEN_COMMA, ",", line)); break; case '+': - token_add(tokens, token_gen(PLUS, "+", line)); + token_add(tokens, token_gen(TOKEN_PLUS, "+", line)); break; case '-': - token_add(tokens, token_gen(MINUS, "-", line)); + token_add(tokens, token_gen(TOKEN_MINUS, "-", line)); break; case ';': - token_add(tokens, token_gen(SEMICOLON, ";", line)); + token_add(tokens, token_gen(TOKEN_SEMICOLON, ";", line)); break; case '=': if (source[i + 1] == '=') { - token_add(tokens, token_gen(EQUAL_EQUAL, "==", line)); + token_add(tokens, token_gen(TOKEN_EQUAL_EQUAL, "==", line)); i++; } else { - token_add(tokens, token_gen(EQUAL, "=", line)); + token_add(tokens, token_gen(TOKEN_EQUAL, "=", line)); } break; case '!': if (source[i + 1] == '=') { - token_add(tokens, token_gen(BANG_EQUAL, "!=", line)); + token_add(tokens, token_gen(TOKEN_BANG_EQUAL, "!=", line)); i++; } else { - token_add(tokens, token_gen(BANG, "!", line)); + token_add(tokens, token_gen(TOKEN_BANG, "!", line)); } break; case '>': if (source[i + 1] == '=') { - token_add(tokens, token_gen(GREATER_EQUAL, ">=", line)); + token_add(tokens, token_gen(TOKEN_GREATER_EQUAL, ">=", line)); i++; } else { - token_add(tokens, token_gen(GREATER, ">", line)); + token_add(tokens, token_gen(TOKEN_GREATER, ">", line)); } break; case '<': if (source[i + 1] == '=') { - token_add(tokens, token_gen(LESS_EQUAL, "<=", line)); + token_add(tokens, token_gen(TOKEN_LESS_EQUAL, "<=", line)); i++; } else { - token_add(tokens, token_gen(LESS, "<", line)); + token_add(tokens, token_gen(TOKEN_LESS, "<", line)); } break; case '/': @@ -220,7 +217,7 @@ array_t *tokenize(char *filename) } i--; } else { - token_add(tokens, token_gen(SLASH, "/", line)); + token_add(tokens, token_gen(TOKEN_SLASH, "/", line)); } break; case ' ': @@ -246,7 +243,7 @@ array_t *tokenize(char *filename) char str[len + 1]; strncpy(str, &source[str_start], len); str[len] = 0; - token_add(tokens, token_gen(STRING, str, line)); + token_add(tokens, token_gen(TOKEN_STRING, str, line)); } break; @@ -277,7 +274,7 @@ array_t *tokenize(char *filename) } } if (!found) { - token_add(tokens, token_gen(IDENTIFIER, id, line)); + token_add(tokens, token_gen(TOKEN_IDENTIFIER, id, line)); } i--; break; @@ -296,7 +293,7 @@ array_t *tokenize(char *filename) char integer[len + 1]; strncpy(integer, iend, len); integer[len] = 0; - token_add(tokens, token_gen(NUMBER, integer, line)); + token_add(tokens, token_gen(TOKEN_NUMBER, integer, line)); i--; } else { @@ -306,7 +303,7 @@ array_t *tokenize(char *filename) } } } - token_add(tokens, token_gen(END_OF_FILE, "EOF", line)); + token_add(tokens, token_gen(TOKEN_EOF, "EOF", line)); free(source); return tokens; } diff --git a/src/parser.c b/src/parser.c index ecf5357..dd9a123 100644 --- a/src/parser.c +++ b/src/parser.c @@ -8,12 +8,11 @@ int current = 0; token_t *tokens; - expr_t *expression(void); void error(token_t *token, char *message) { - if (token->type == END_OF_FILE) { + if (token->type == TOKEN_EOF) { fprintf(stderr, "[line %d] at end: %s\n", token->line, message); } else { fprintf(stderr, "[line %d] at '%s': %s\n", token->line, token->value, message); @@ -26,25 +25,25 @@ void free_expr(expr_t *expr) if (!expr) return; switch (expr->type) { - case BINARY: - free(expr->as.binary.binary_op.value); + case EXPR_BINARY: + free(expr->as.binary.operator.value); free_expr(expr->as.binary.left); free_expr(expr->as.binary.right); free(expr); break; - case GROUPING: + case EXPR_GROUPING: free_expr(expr->as.grouping.expression); free(expr); break; - case UNARY: - free(expr->as.unary.unary_op.value); + case EXPR_UNARY: + free(expr->as.unary.operator.value); free_expr(expr->as.unary.right); free(expr); break; - case LITERAL: + case EXPR_LITERAL: if (expr->as.literal.value.type == VAL_STRING) { free(expr->as.literal.value.as.string); } @@ -56,24 +55,14 @@ void free_expr(expr_t *expr) } } -expr_t *parse(token_t *tks) -{ - tokens = tks; - if (errno == 65) { - return NULL; - } else { - return expression(); - } -} - token_t *peek(void) { return &tokens[current]; } -int isAtEnd(void) +int end(void) { - return tokens[current].type == END_OF_FILE; + return tokens[current].type == TOKEN_EOF; } token_t *previous(void) @@ -83,11 +72,10 @@ token_t *previous(void) void advance(void) { - if (!isAtEnd()) + if (!end()) current++; } - int check(token_type_t type) { if (tokens[current].type == type) { @@ -106,12 +94,13 @@ void consume(token_type_t type, char *message) { expr_t *primary(void) { - if (check(FALSE) || check(TRUE) || check(NIL) || check(NUMBER) || check(STRING)) { + if (check(TOKEN_FALSE) || check(TOKEN_TRUE) || check(TOKEN_NIL) || + check(TOKEN_NUMBER) || check(TOKEN_STRING)) { return create_literal_expr(previous()); } - if (check(LEFT_PAREN)) { + if (check(TOKEN_LEFT_PAREN)) { expr_t *expr = expression(); - consume(RIGHT_PAREN, "Expect ')' after expression."); + consume(TOKEN_RIGHT_PAREN, "Expect ')' after expression."); return create_grouping_expr(expr); } error(peek(), "Expect expression."); @@ -120,7 +109,7 @@ expr_t *primary(void) expr_t *unary(void) { - if (check(BANG) || check(MINUS)) { + if (check(TOKEN_BANG) || check(TOKEN_MINUS)) { token_t *operator = previous(); expr_t *right = unary(); return create_unary_expr(operator, right); @@ -133,7 +122,7 @@ expr_t *factor(void) { expr_t *expr = unary(); - while (check(SLASH) || check(STAR)) { + while (check(TOKEN_SLASH) || check(TOKEN_STAR)) { token_t *operator = previous(); expr_t *right = unary(); expr = create_binary_expr(operator, expr, right); @@ -146,7 +135,7 @@ expr_t *term(void) { expr_t *expr = factor(); - while (check(MINUS) || check(PLUS)) { + while (check(TOKEN_MINUS) || check(TOKEN_PLUS)) { token_t *operator = previous(); expr_t *right = factor(); expr = create_binary_expr(operator, expr, right); @@ -159,7 +148,8 @@ expr_t *comparison(void) { expr_t *expr = term(); - while (check(GREATER) || check(GREATER_EQUAL) || check(LESS) || check(LESS_EQUAL)) { + while (check(TOKEN_GREATER) || check(TOKEN_GREATER_EQUAL) || check(TOKEN_LESS) + || check(TOKEN_LESS_EQUAL)) { token_t *operator = previous(); expr_t *right = term(); expr = create_binary_expr(operator, expr, right); @@ -172,7 +162,7 @@ expr_t *equality(void) { expr_t *expr = comparison(); - while (check(BANG_EQUAL) || check(EQUAL_EQUAL)) { + while (check(TOKEN_BANG_EQUAL) || check(TOKEN_EQUAL_EQUAL)) { token_t *operator = previous(); expr_t *right = comparison(); expr = create_binary_expr(operator, expr, right); @@ -186,22 +176,99 @@ expr_t *expression(void) return equality(); } +stmt_t print_stmt(void) +{ + expr_t *value = expression(); + consume(TOKEN_SEMICOLON, "Expect ; after value."); + return (stmt_t) { + .type = STMT_PRINT, + .as.print.expression = value, + }; +} + +stmt_t expression_stmt(void) +{ + expr_t *expr = expression(); + consume(TOKEN_SEMICOLON, "Expect ; after expression."); + return (stmt_t) { + .type = STMT_EXPR, + .as.expr.expression = expr, + }; +} + +stmt_t statement(void) +{ + if (check(TOKEN_PRINT)) + return print_stmt(); + return expression_stmt(); +} + +void stmt_add(stmt_array_t *array, stmt_t stmt) +{ + if (array->length == array->capacity) { + array->capacity *= 2; + array->statements = realloc(array->statements, array->capacity * sizeof(stmt_t)); + } + array->statements[array->length++] = stmt; +} + +void free_statements(stmt_array_t *array) +{ + for (int i = 0; i < array->length; i++) { + if (array->statements[i].type == STMT_PRINT) { + free_expr(array->statements[i].as.print.expression); + } + if (array->statements[i].type == STMT_EXPR) { + free_expr(array->statements[i].as.expr.expression); + } + } + free(array->statements); + free(array); +} + +stmt_array_t *parse(token_t *tks) +{ + tokens = tks; + if (errno == 65) { + return NULL; + } else { + stmt_array_t *statements = malloc(sizeof(stmt_array_t)); + statements->statements = malloc(DEFAULT_STMTS_SIZE * sizeof(stmt_t)); + statements->length = 0; + statements->capacity = DEFAULT_STMTS_SIZE; + while (!end()) { + stmt_add(statements, statement()); + } + return statements; + } +} + +expr_t *parse_expr(token_t *tks) +{ + tokens = tks; + if (errno == 65) { + return NULL; + } else { + return expression(); + } +} + void synchronize(void) { advance(); - while (!isAtEnd()) { - if (previous()->type == SEMICOLON) return; + while (!end()) { + if (previous()->type == TOKEN_SEMICOLON) return; switch (peek()->type) { - case CLASS: - case FUN: - case VAR: - case FOR: - case IF: - case WHILE: - case PRINT: - case RETURN: + case TOKEN_CLASS: + case TOKEN_FUN: + case TOKEN_VAR: + case TOKEN_FOR: + case TOKEN_IF: + case TOKEN_WHILE: + case TOKEN_PRINT: + case TOKEN_RETURN: return; default: return; diff --git a/src/rd.c b/src/rd.c index a2f1567..5798e9e 100644 --- a/src/rd.c +++ b/src/rd.c @@ -11,21 +11,21 @@ int main(int argc, char **argv) { if (argc < 3) { - fprintf(stderr, "Usage: rd tokenize|parse|evaluate \n"); + fprintf(stderr, "Usage: rd tokenize|parse|evaluate|run \n"); return 1; } const char *command = argv[1]; - + + array_t *array = tokenize(argv[2]); + if (!array) { + return 1; + } if (!strcmp(command, "tokenize")) { - array_t *array = tokenize(argv[2]); - if (array) { - print_tokens(array->tokens); - free_array(array); - } + print_tokens(array->tokens); + free_array(array); } else if (!strcmp(command, "parse")) { - array_t *array = tokenize(argv[2]); - expr_t *expr = parse(array->tokens); + expr_t *expr = parse_expr(array->tokens); if (errno != 65) { print_ast(expr); printf("\n"); @@ -33,10 +33,18 @@ int main(int argc, char **argv) free_array(array); free_expr(expr); } else if (!strcmp(command, "evaluate")) { - array_t *array = tokenize(argv[2]); - expr_t *expr = parse(array->tokens); + expr_t *expr = parse_expr(array->tokens); value_t val = evaluate(expr); print_value(&val); + free_array(array); + free_expr(expr); + } else if (!strcmp(command, "run")) { + stmt_array_t *stmts = parse(array->tokens); + if (errno != 65) { + print_statements(stmts); + free_array(array); + free_statements(stmts); + } } else { fprintf(stderr, "Unknown command: %s\n", command); return 1;