If statements, loops
This commit is contained in:
parent
8f122d3523
commit
56d5d9d84b
8 changed files with 302 additions and 83 deletions
|
@ -104,6 +104,7 @@ expr_t *create_literal_expr(token_t *token);
|
|||
expr_t *create_grouping_expr(expr_t *expression);
|
||||
expr_t *create_variable_expr(token_t *name);
|
||||
expr_t *create_assign_expr(expr_t *name, expr_t *value);
|
||||
expr_t *create_logical_expr(token_t *operator, expr_t *left, expr_t *right);
|
||||
void print_ast(expr_t *expr);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
void runtime_error(const char *message, int line);
|
||||
value_t evaluate(expr_t *expr, ht_t *env);
|
||||
void print_value(value_t *value);
|
||||
void print_value(value_t value);
|
||||
void evaluate_statements(stmt_array_t *array, ht_t *env);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,7 +7,9 @@
|
|||
#define DEFAULT_STMTS_SIZE 512
|
||||
|
||||
/*
|
||||
statement → exprStmt | printStmt | block ;
|
||||
statement → exprStmt | ifStmt | printStmt | block ;
|
||||
ifStmt → "if" "(" expression ")" statement
|
||||
( "else" statement )? ;
|
||||
block → "{" declaration* "}" ;
|
||||
*/
|
||||
|
||||
|
@ -25,7 +27,7 @@ typedef enum {
|
|||
typedef struct stmt_t stmt_t;
|
||||
|
||||
typedef struct {
|
||||
stmt_t *statements;
|
||||
stmt_t **statements;
|
||||
int length;
|
||||
int capacity;
|
||||
} stmt_array_t;
|
||||
|
@ -51,8 +53,8 @@ struct stmt_t {
|
|||
} function;
|
||||
struct {
|
||||
expr_t *condition;
|
||||
struct stmt_t *thenBranch;
|
||||
struct stmt_t *elseBranch;
|
||||
struct stmt_t *then_branch;
|
||||
struct stmt_t *else_branch;
|
||||
} _if;
|
||||
struct {
|
||||
expr_t *expression;
|
||||
|
|
25
src/ast.c
25
src/ast.c
|
@ -13,8 +13,7 @@ expr_t *create_binary_expr(token_t *operator, expr_t *left, expr_t *right)
|
|||
expr->as.binary.left = left;
|
||||
expr->as.binary.right = right;
|
||||
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.value = strdup(operator->value);
|
||||
expr->as.binary.operator.line = operator->line;
|
||||
return expr;
|
||||
}
|
||||
|
@ -25,8 +24,7 @@ expr_t *create_unary_expr(token_t *operator, expr_t *right)
|
|||
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.value = strdup(operator->value);
|
||||
expr->as.unary.operator.line = operator->line;
|
||||
expr->as.unary.right = right;
|
||||
return expr;
|
||||
|
@ -58,8 +56,7 @@ expr_t *create_literal_expr(token_t *token)
|
|||
|
||||
case TOKEN_STRING:
|
||||
expr->as.literal.value.type = VAL_STRING;
|
||||
char *tkvalue = strdup(token->value);
|
||||
expr->as.literal.value.as.string = tkvalue;
|
||||
expr->as.literal.value.as.string = strdup(token->value);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -86,8 +83,7 @@ expr_t *create_variable_expr(token_t *name)
|
|||
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.value = strdup(name->value);
|
||||
expr->as.variable.name.line = name->line;
|
||||
|
||||
return expr;
|
||||
|
@ -104,6 +100,19 @@ expr_t *create_assign_expr(expr_t *name, expr_t *value)
|
|||
return expr;
|
||||
}
|
||||
|
||||
expr_t *create_logical_expr(token_t *operator, expr_t *left, expr_t *right)
|
||||
{
|
||||
expr_t *expr = malloc(sizeof(expr_t));
|
||||
expr->type = EXPR_LOGICAL;
|
||||
expr->line = operator->line;
|
||||
expr->as.logical.left = left;
|
||||
expr->as.logical.right = right;
|
||||
expr->as.logical.operator.type = operator->type;
|
||||
expr->as.logical.operator.value = strdup(operator->value);
|
||||
expr->as.logical.operator.line = operator->line;
|
||||
return expr;
|
||||
}
|
||||
|
||||
void print_ast(expr_t *expr)
|
||||
{
|
||||
if (!expr)
|
||||
|
|
|
@ -84,12 +84,13 @@ void ht_replace(ht_t *ht, char *name, value_t value)
|
|||
break;
|
||||
}
|
||||
if (!strcmp(ht[probe_idx].name, name)) {
|
||||
ht[probe_idx].value.type = value.type;
|
||||
if (value.type == VAL_STRING) {
|
||||
if (ht[probe_idx].value.type == VAL_STRING) {
|
||||
free(ht[probe_idx].value.as.string);
|
||||
}
|
||||
ht[probe_idx].value.type = value.type;
|
||||
ht[probe_idx].value.as = value.as;
|
||||
if (value.type == VAL_STRING) {
|
||||
ht[probe_idx].value.as.string = strdup(value.as.string);
|
||||
} else {
|
||||
ht[probe_idx].value.as = value.as;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -140,17 +140,17 @@ value_t visit_binary(expr_t *expr, ht_t *env)
|
|||
|
||||
}
|
||||
|
||||
int is_truthy(value_t *value)
|
||||
int is_truthy(value_t value)
|
||||
{
|
||||
switch (value->type) {
|
||||
switch (value.type) {
|
||||
case VAL_NIL:
|
||||
return 0;
|
||||
|
||||
case VAL_BOOL:
|
||||
return value->as.boolean;
|
||||
return value.as.boolean;
|
||||
|
||||
case VAL_NUMBER:
|
||||
if (value->as.number == 0)
|
||||
if (value.as.number == 0)
|
||||
return 0;
|
||||
return 1;
|
||||
|
||||
|
@ -174,7 +174,7 @@ value_t visit_unary(expr_t *expr, ht_t *env)
|
|||
runtime_error("Operand must be a number.", expr->line);
|
||||
}
|
||||
} else if (expr->as.unary.operator.type == TOKEN_BANG) {
|
||||
value_t result = {.type = VAL_BOOL, .as.boolean = !is_truthy(&operand)};
|
||||
value_t result = {.type = VAL_BOOL, .as.boolean = !is_truthy(operand)};
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -198,6 +198,21 @@ value_t visit_assign(expr_t *expr, ht_t *env)
|
|||
return value;
|
||||
}
|
||||
|
||||
value_t visit_logical(expr_t *expr, ht_t *env)
|
||||
{
|
||||
value_t left = evaluate(expr->as.logical.left, env);
|
||||
|
||||
if (expr->as.logical.operator.type == TOKEN_OR) {
|
||||
if (is_truthy(left))
|
||||
return left;
|
||||
} else {
|
||||
if (!is_truthy(left))
|
||||
return left;
|
||||
}
|
||||
|
||||
return evaluate(expr->as.logical.right, env);
|
||||
}
|
||||
|
||||
value_t evaluate(expr_t *expr, ht_t *env)
|
||||
{
|
||||
if (!expr) {
|
||||
|
@ -217,17 +232,19 @@ value_t evaluate(expr_t *expr, ht_t *env)
|
|||
return visit_variable(expr, env);
|
||||
case EXPR_ASSIGN:
|
||||
return visit_assign(expr, env);
|
||||
case EXPR_LOGICAL:
|
||||
return visit_logical(expr, env);
|
||||
default:
|
||||
exit(65);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void print_value(value_t *value)
|
||||
void print_value(value_t value)
|
||||
{
|
||||
switch (value->type) {
|
||||
switch (value.type) {
|
||||
case VAL_BOOL:
|
||||
printf("%s\n", value->as.boolean == 1 ? "true" : "false");
|
||||
printf("%s\n", value.as.boolean == 1 ? "true" : "false");
|
||||
break;
|
||||
|
||||
case VAL_NIL:
|
||||
|
@ -235,14 +252,14 @@ void print_value(value_t *value)
|
|||
break;
|
||||
|
||||
case VAL_STRING:
|
||||
printf("%s\n", value->as.string);
|
||||
printf("%s\n", value.as.string);
|
||||
break;
|
||||
|
||||
case VAL_NUMBER:
|
||||
if (value->as.number == (int) value->as.number) {
|
||||
printf("%d\n", (int) value->as.number);
|
||||
if (value.as.number == (int) value.as.number) {
|
||||
printf("%d\n", (int) value.as.number);
|
||||
} else {
|
||||
printf("%g\n", value->as.number);
|
||||
printf("%g\n", value.as.number);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -260,28 +277,42 @@ void evaluate_block(stmt_array_t *array, ht_t *cur_env, ht_t *scope_env)
|
|||
cur_env = previous;
|
||||
}
|
||||
|
||||
void evaluate_statement(stmt_t stmt, ht_t *env)
|
||||
void evaluate_statement(stmt_t *stmt, ht_t *env)
|
||||
{
|
||||
switch (stmt.type) {
|
||||
case STMT_PRINT:;
|
||||
value_t obj = evaluate(stmt.as.print.expression, env);
|
||||
print_value(&obj);
|
||||
switch (stmt->type) {
|
||||
case STMT_IF:
|
||||
if (is_truthy(evaluate(stmt->as._if.condition, env))) {
|
||||
evaluate_statement(stmt->as._if.then_branch, env);
|
||||
} else if (stmt->as._if.else_branch) {
|
||||
evaluate_statement(stmt->as._if.else_branch, env);
|
||||
}
|
||||
break;
|
||||
|
||||
case STMT_PRINT:
|
||||
print_value(evaluate(stmt->as.print.expression, env));
|
||||
break;
|
||||
|
||||
case STMT_EXPR:
|
||||
evaluate(stmt.as.expr.expression, env);
|
||||
evaluate(stmt->as.expr.expression, env);
|
||||
break;
|
||||
|
||||
case STMT_VAR:;
|
||||
case STMT_VAR: {
|
||||
value_t value = {.type = VAL_NIL};
|
||||
if (stmt.as.variable.initializer) {
|
||||
value = evaluate(stmt.as.variable.initializer, env);
|
||||
if (stmt->as.variable.initializer) {
|
||||
value = evaluate(stmt->as.variable.initializer, env);
|
||||
}
|
||||
ht_add(env, stmt.as.variable.name.value, value);
|
||||
ht_add(env, stmt->as.variable.name.value, value);
|
||||
break;
|
||||
}
|
||||
|
||||
case STMT_BLOCK:
|
||||
evaluate_block(stmt.as.block.statements, env, ht_init(env));
|
||||
evaluate_block(stmt->as.block.statements, env, ht_init(env));
|
||||
break;
|
||||
|
||||
case STMT_WHILE:
|
||||
while (is_truthy(evaluate(stmt->as._while.condition, env))) {
|
||||
evaluate_statement(stmt->as._while.body, env);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
259
src/parser.c
259
src/parser.c
|
@ -10,7 +10,10 @@
|
|||
int current = 0;
|
||||
token_t *tokens;
|
||||
expr_t *expression(void);
|
||||
stmt_t declaration(void);
|
||||
stmt_t *expression_stmt(void);
|
||||
stmt_t *statement(void);
|
||||
stmt_t *var_declaration(void);
|
||||
stmt_t *declaration(void);
|
||||
void synchronize(void);
|
||||
|
||||
/*
|
||||
|
@ -68,6 +71,13 @@ void free_expr(expr_t *expr)
|
|||
free(expr);
|
||||
break;
|
||||
|
||||
case EXPR_LOGICAL:
|
||||
free(expr->as.logical.operator.value);
|
||||
free_expr(expr->as.logical.left);
|
||||
free_expr(expr->as.logical.right);
|
||||
free(expr);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -205,10 +215,38 @@ expr_t *equality(void)
|
|||
return expr;
|
||||
}
|
||||
|
||||
expr_t *assignment(void)
|
||||
expr_t *and(void)
|
||||
{
|
||||
expr_t *expr = equality();
|
||||
|
||||
while (check(TOKEN_AND)) {
|
||||
token_t *operator = peek();
|
||||
advance();
|
||||
expr_t *right = equality();
|
||||
expr = create_logical_expr(operator, expr, right);
|
||||
}
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
expr_t *or(void)
|
||||
{
|
||||
expr_t *expr = and();
|
||||
|
||||
while (check(TOKEN_OR)) {
|
||||
token_t *operator = peek();
|
||||
advance();
|
||||
expr_t *right = and();
|
||||
expr = create_logical_expr(operator, expr, right);
|
||||
}
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
expr_t *assignment(void)
|
||||
{
|
||||
expr_t *expr = or();
|
||||
|
||||
if (check(TOKEN_EQUAL)) {
|
||||
token_t *equals = peek();
|
||||
advance();
|
||||
|
@ -228,47 +266,170 @@ expr_t *expression(void)
|
|||
return assignment();
|
||||
}
|
||||
|
||||
void stmt_add(stmt_array_t *array, stmt_t 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 = realloc(array->statements, array->capacity * sizeof(stmt_t *));
|
||||
}
|
||||
array->statements[array->length++] = stmt;
|
||||
}
|
||||
|
||||
void free_statement(stmt_t *stmt)
|
||||
{
|
||||
if (!stmt) {
|
||||
return;
|
||||
}
|
||||
if (stmt->type == STMT_PRINT) {
|
||||
free_expr(stmt->as.print.expression);
|
||||
free(stmt);
|
||||
} else if (stmt->type == STMT_EXPR) {
|
||||
free_expr(stmt->as.expr.expression);
|
||||
free(stmt);
|
||||
} else if (stmt->type == STMT_VAR) {
|
||||
free(stmt->as.variable.name.value);
|
||||
free_expr(stmt->as.variable.initializer);
|
||||
free(stmt);
|
||||
} else if (stmt->type == STMT_BLOCK) {
|
||||
free_statements(stmt->as.block.statements);
|
||||
free(stmt);
|
||||
} else if (stmt->type == STMT_IF) {
|
||||
free_expr(stmt->as._if.condition);
|
||||
free_statement(stmt->as._if.then_branch);
|
||||
free_statement(stmt->as._if.else_branch);
|
||||
free(stmt);
|
||||
} else if (stmt->type == STMT_WHILE) {
|
||||
free_expr(stmt->as._while.condition);
|
||||
free_statement(stmt->as._while.body);
|
||||
free(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);
|
||||
}
|
||||
if (array->statements[i].type == STMT_VAR) {
|
||||
free(array->statements[i].as.variable.name.value);
|
||||
free_expr(array->statements[i].as.variable.initializer);
|
||||
}
|
||||
if (array->statements[i].type == STMT_BLOCK) {
|
||||
free_statements(array->statements[i].as.block.statements);
|
||||
}
|
||||
free_statement(array->statements[i]);
|
||||
}
|
||||
free(array->statements);
|
||||
free(array);
|
||||
}
|
||||
|
||||
stmt_t print_stmt(void)
|
||||
stmt_t *for_stmt(void)
|
||||
{
|
||||
consume(TOKEN_LEFT_PAREN, "Expect '(' after 'for'.");
|
||||
stmt_t *initializer = NULL;
|
||||
if (check(TOKEN_SEMICOLON)) {
|
||||
advance();
|
||||
} else if (check(TOKEN_VAR)) {
|
||||
advance();
|
||||
initializer = var_declaration();
|
||||
} else {
|
||||
initializer = expression_stmt();
|
||||
}
|
||||
|
||||
expr_t *condition = NULL;
|
||||
if (!check(TOKEN_SEMICOLON)) {
|
||||
condition = expression();
|
||||
}
|
||||
consume(TOKEN_SEMICOLON, "Expect ';' after loop condition.");
|
||||
|
||||
expr_t *increment = NULL;
|
||||
if (!check(TOKEN_RIGHT_PAREN)) {
|
||||
increment = expression();
|
||||
}
|
||||
consume(TOKEN_RIGHT_PAREN, "Expect ')' after for clauses.");
|
||||
|
||||
stmt_t *body = statement();
|
||||
if (increment) {
|
||||
stmt_t *body_incremented = malloc(sizeof(stmt_t));
|
||||
body_incremented->type = STMT_BLOCK;
|
||||
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;
|
||||
stmt_add(statements, body);
|
||||
body_incremented->as.block.statements = statements;
|
||||
|
||||
stmt_t *stmt = malloc(sizeof(stmt_t));
|
||||
stmt->type = STMT_EXPR;
|
||||
stmt->as.expr.expression = increment;
|
||||
stmt_add(statements, stmt);
|
||||
body = body_incremented;
|
||||
}
|
||||
if (!condition) {
|
||||
token_t tok;
|
||||
tok.type = TOKEN_TRUE;
|
||||
tok.value = strdup("true");
|
||||
tok.line = -1;
|
||||
condition = create_literal_expr(&tok);
|
||||
}
|
||||
stmt_t *stmt = malloc(sizeof(stmt_t));
|
||||
stmt->type = STMT_WHILE;
|
||||
stmt->as._while.condition = condition;
|
||||
stmt->as._while.body = body;
|
||||
|
||||
body = stmt;
|
||||
|
||||
if (initializer) {
|
||||
stmt_t *body_initialized = malloc(sizeof(stmt_t));
|
||||
body_initialized->type = STMT_BLOCK;
|
||||
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;
|
||||
stmt_add(statements, initializer);
|
||||
stmt_add(statements, body);
|
||||
body_initialized->as.block.statements = statements;
|
||||
body = body_initialized;
|
||||
}
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
stmt_t *if_stmt(void)
|
||||
{
|
||||
consume(TOKEN_LEFT_PAREN, "Expect '(' after 'if'.");
|
||||
expr_t *cond = expression();
|
||||
consume(TOKEN_RIGHT_PAREN, "Expect ')' after if condition.");
|
||||
stmt_t *then_branch = statement();
|
||||
stmt_t *else_branch = NULL;
|
||||
if (check(TOKEN_ELSE)) {
|
||||
advance();
|
||||
else_branch = statement();
|
||||
}
|
||||
stmt_t *stmt = malloc(sizeof(stmt_t));
|
||||
stmt->type = STMT_IF;
|
||||
stmt->as._if.condition = cond;
|
||||
stmt->as._if.then_branch = then_branch;
|
||||
stmt->as._if.else_branch = else_branch;
|
||||
return stmt;
|
||||
}
|
||||
|
||||
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 *stmt = malloc(sizeof(stmt_t));
|
||||
stmt->type = STMT_PRINT;
|
||||
stmt->as.print.expression = value;
|
||||
return stmt;
|
||||
}
|
||||
|
||||
stmt_t block_stmt(void)
|
||||
stmt_t *while_stmt(void)
|
||||
{
|
||||
consume(TOKEN_LEFT_PAREN, "Expect '(' after 'while'.");
|
||||
expr_t *condition = expression();
|
||||
consume(TOKEN_RIGHT_PAREN, "Expect ')' after condition.");
|
||||
stmt_t *body = statement();
|
||||
|
||||
stmt_t *stmt = malloc(sizeof(stmt_t));
|
||||
stmt->type = STMT_WHILE;
|
||||
stmt->as._while.condition = condition;
|
||||
stmt->as._while.body = body;
|
||||
return stmt;
|
||||
}
|
||||
|
||||
stmt_t *block_stmt(void)
|
||||
{
|
||||
stmt_array_t *statements = malloc(sizeof(stmt_array_t));
|
||||
statements->statements = malloc(DEFAULT_STMTS_SIZE * sizeof(stmt_t));
|
||||
|
@ -281,28 +442,41 @@ stmt_t block_stmt(void)
|
|||
}
|
||||
|
||||
consume(TOKEN_RIGHT_BRACE, "Expect '}' after block.");
|
||||
return (stmt_t) {
|
||||
.type = STMT_BLOCK,
|
||||
.as.block.statements = statements,
|
||||
};
|
||||
|
||||
stmt_t *stmt = malloc(sizeof(stmt_t));
|
||||
stmt->type = STMT_BLOCK;
|
||||
stmt->as.block.statements = statements;
|
||||
return stmt;
|
||||
}
|
||||
|
||||
stmt_t expression_stmt(void)
|
||||
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 *stmt = malloc(sizeof(stmt_t));
|
||||
stmt->type = STMT_EXPR;
|
||||
stmt->as.expr.expression = expr;
|
||||
return stmt;
|
||||
}
|
||||
|
||||
stmt_t statement(void)
|
||||
stmt_t *statement(void)
|
||||
{
|
||||
if (check(TOKEN_FOR)) {
|
||||
advance();
|
||||
return for_stmt();
|
||||
}
|
||||
if (check(TOKEN_IF)) {
|
||||
advance();
|
||||
return if_stmt();
|
||||
}
|
||||
if (check(TOKEN_PRINT)) {
|
||||
advance();
|
||||
return print_stmt();
|
||||
}
|
||||
if (check(TOKEN_WHILE)) {
|
||||
advance();
|
||||
return while_stmt();
|
||||
}
|
||||
if (check(TOKEN_LEFT_BRACE)) {
|
||||
advance();
|
||||
return block_stmt();
|
||||
|
@ -310,7 +484,7 @@ stmt_t statement(void)
|
|||
return expression_stmt();
|
||||
}
|
||||
|
||||
stmt_t var_declaration(void)
|
||||
stmt_t *var_declaration(void)
|
||||
{
|
||||
token_t *name = consume(TOKEN_IDENTIFIER, "Expect variable name.");
|
||||
|
||||
|
@ -321,16 +495,17 @@ stmt_t var_declaration(void)
|
|||
}
|
||||
|
||||
consume(TOKEN_SEMICOLON, "Expect ';' after variable declaration.");
|
||||
return (stmt_t) {
|
||||
.type = STMT_VAR,
|
||||
.as.variable.name.type = name->type,
|
||||
.as.variable.name.value = strdup(name->value),
|
||||
.as.variable.name.line = name->line,
|
||||
.as.variable.initializer = initializer,
|
||||
};
|
||||
|
||||
stmt_t *stmt = malloc(sizeof(stmt_t));
|
||||
stmt->type = STMT_VAR;
|
||||
stmt->as.variable.name.type = name->type;
|
||||
stmt->as.variable.name.value = strdup(name->value);
|
||||
stmt->as.variable.name.line = name->line;
|
||||
stmt->as.variable.initializer = initializer;
|
||||
return stmt;
|
||||
}
|
||||
|
||||
stmt_t declaration(void)
|
||||
stmt_t *declaration(void)
|
||||
{
|
||||
if (check(TOKEN_VAR)) {
|
||||
advance();
|
||||
|
|
2
src/rd.c
2
src/rd.c
|
@ -35,7 +35,7 @@ int main(int argc, char **argv)
|
|||
} else if (!strcmp(command, "evaluate")) {
|
||||
expr_t *expr = parse_expr(array->tokens);
|
||||
value_t val = evaluate(expr, NULL);
|
||||
print_value(&val);
|
||||
print_value(val);
|
||||
free_array(array);
|
||||
free_expr(expr);
|
||||
} else if (!strcmp(command, "run")) {
|
||||
|
|
Loading…
Reference in a new issue