diff --git a/include/ast.h b/include/ast.h index 10fb4f3..e853408 100644 --- a/include/ast.h +++ b/include/ast.h @@ -102,6 +102,7 @@ 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); +expr_t *create_variable_expr(token_t *name); void print_ast(expr_t *expr); #endif diff --git a/include/stmt.h b/include/stmt.h index 28ec994..24a6ae6 100644 --- a/include/stmt.h +++ b/include/stmt.h @@ -15,7 +15,6 @@ typedef enum { STMT_PRINT, STMT_VAR, STMT_WHILE, - STMT_COUNT, } stmt_type_t; typedef struct stmt_t { diff --git a/src/ast.c b/src/ast.c index c03e8fb..56c61b5 100644 --- a/src/ast.c +++ b/src/ast.c @@ -80,6 +80,19 @@ expr_t *create_grouping_expr(expr_t *expression) return expr; } +expr_t *create_variable_expr(token_t *name) +{ + expr_t *expr = malloc(sizeof(expr_t)); + expr->type = EXPR_VARIABLE; + expr->line = name->line; + expr->as.variable.name.type = name->type; + char *name_val = strdup(name->value); + expr->as.variable.name.value = name_val; + expr->as.variable.name.line = name->line; + + return expr; +} + void print_ast(expr_t *expr) { if (!expr) diff --git a/src/interpreter.c b/src/interpreter.c index c8b58d0..a2db5fa 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -133,9 +133,10 @@ 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); + } runtime_error("Operands must be two numbers or two strings.", expr->line); @@ -238,9 +239,8 @@ 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); */ + } else if (stmt.type == STMT_EXPR) { + evaluate(stmt.as.expr.expression); } } void print_statements(stmt_array_t *array) diff --git a/src/parser.c b/src/parser.c index dd9a123..e29f6e8 100644 --- a/src/parser.c +++ b/src/parser.c @@ -9,6 +9,7 @@ int current = 0; token_t *tokens; expr_t *expression(void); +void synchronize(void); void error(token_t *token, char *message) { @@ -18,6 +19,7 @@ void error(token_t *token, char *message) fprintf(stderr, "[line %d] at '%s': %s\n", token->line, token->value, message); } errno = 65; + synchronize(); } void free_expr(expr_t *expr) @@ -86,10 +88,13 @@ int check(token_type_t type) } } -void consume(token_type_t type, char *message) { +token_t *consume(token_type_t type, char *message) { if (!check(type)) { error(peek(), message); + } else { + return peek(); } + return NULL; } expr_t *primary(void) @@ -98,6 +103,11 @@ expr_t *primary(void) check(TOKEN_NUMBER) || check(TOKEN_STRING)) { return create_literal_expr(previous()); } + + if (check(TOKEN_IDENTIFIER)) { + return create_variable_expr(previous()); + } + if (check(TOKEN_LEFT_PAREN)) { expr_t *expr = expression(); consume(TOKEN_RIGHT_PAREN, "Expect ')' after expression."); @@ -203,6 +213,33 @@ stmt_t statement(void) return expression_stmt(); } +stmt_t var_declaration(void) +{ + token_t *name = consume(TOKEN_IDENTIFIER, "Expect variable name."); + + expr_t *initializer; + if (check(TOKEN_EQUAL)) { + initializer = expression(); + } + + consume(TOKEN_SEMICOLON, "Expect ';' after variable declaration."); + return (stmt_t) { + .type = STMT_VAR, + .as.variable.name.type = name->type, + .as.variable.name.value = name->value, + .as.variable.name.line = name->line, + .as.variable.initializer = initializer, + }; +} + +stmt_t declaration(void) +{ + if (check(TOKEN_VAR)) + return var_declaration(); + + return statement(); +} + void stmt_add(stmt_array_t *array, stmt_t stmt) { if (array->length == array->capacity) { @@ -237,7 +274,7 @@ stmt_array_t *parse(token_t *tks) statements->length = 0; statements->capacity = DEFAULT_STMTS_SIZE; while (!end()) { - stmt_add(statements, statement()); + stmt_add(statements, declaration()); } return statements; }