Support variable syntax
This commit is contained in:
parent
9818c21097
commit
dc566b4345
5 changed files with 58 additions and 8 deletions
|
@ -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
|
||||
|
|
|
@ -15,7 +15,6 @@ typedef enum {
|
|||
STMT_PRINT,
|
||||
STMT_VAR,
|
||||
STMT_WHILE,
|
||||
STMT_COUNT,
|
||||
} stmt_type_t;
|
||||
|
||||
typedef struct stmt_t {
|
||||
|
|
13
src/ast.c
13
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)
|
||||
|
|
|
@ -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)
|
||||
|
|
41
src/parser.c
41
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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue