Variable assign, printing

This commit is contained in:
Night Kaly 2025-01-16 00:04:09 +00:00
parent 1d297cf0f0
commit 4a0f325634
Signed by: night0721
SSH key fingerprint: SHA256:B/hgVwUoBpx5vdNsXl9w8XwZljA9766uk6T4ubZp5HM
8 changed files with 232 additions and 22 deletions

View file

@ -103,6 +103,7 @@ 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);
expr_t *create_assign_expr(token_t *name, expr_t *value);
void print_ast(expr_t *expr);
#endif

21
include/env.h Normal file
View file

@ -0,0 +1,21 @@
#ifndef ENV_H
#define ENV_H
#include "ast.h"
#include "lexer.h"
typedef struct {
char *name;
value_t value;
} ht_t;
#define DEFAULT_HT_SIZE 50
ht_t *ht_init(void);
void ht_add(ht_t *ht, char *name, value_t value);
value_t *ht_get(ht_t *ht, token_t *name);
void ht_replace(ht_t *ht, char *name, value_t value);
void ht_assign(ht_t *ht, token_t *name, value_t value);
void ht_free(ht_t *ht);
#endif

View file

@ -4,6 +4,7 @@
#include "ast.h"
#include "stmt.h"
void runtime_error(const char *message, int line);
value_t evaluate(expr_t *expr);
void print_value(value_t *value);
void print_statements(stmt_array_t *array);

View file

@ -6,6 +6,12 @@
#define DEFAULT_STMTS_SIZE 512
/*
program statement* EOF ;
statement exprStmt | printStmt ;
exprStmt expression ";" ;
printStmt "print" expression ";" ;
*/
typedef enum {
STMT_BLOCK,
STMT_CLASS,

View file

@ -93,6 +93,19 @@ expr_t *create_variable_expr(token_t *name)
return expr;
}
expr_t *create_assign_expr(token_t *name, expr_t *value)
{
expr_t *expr = malloc(sizeof(expr_t));
expr->type = EXPR_ASSIGN;
expr->line = name->line;
expr->as.assign.name.type = name->type;
expr->as.assign.name.value = name->value;
expr->as.assign.name.line = name->line;
expr->as.assign.value = value;
return expr;
}
void print_ast(expr_t *expr)
{
if (!expr)

93
src/env.c Normal file
View file

@ -0,0 +1,93 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "env.h"
#include "interpreter.h"
ht_t *ht_init(void)
{
ht_t *ht = malloc(sizeof(ht_t) * DEFAULT_HT_SIZE);
for (int i = 0; i < DEFAULT_HT_SIZE; i++) {
ht[i].name = NULL;
}
return ht;
}
unsigned int hash(char *key)
{
unsigned int h = 0;
for (; *key; key++)
h = 31 * h + *key;
return h;
}
void ht_add(ht_t *ht, char *name, value_t value)
{
unsigned int idx = hash(name) % DEFAULT_HT_SIZE;
/* Linear probing for collision resolution */
for (int i = 0; i < DEFAULT_HT_SIZE; i++) {
int probe_idx = (idx + i) % DEFAULT_HT_SIZE;
if (!ht[probe_idx].name) {
ht[probe_idx].name = name;
memcpy(&ht[probe_idx].value, &value, sizeof(value));
return;
} else {
ht_replace(ht, name, value);
return;
}
}
}
value_t *ht_get(ht_t *ht, token_t *name)
{
unsigned int idx = hash(name->value) % DEFAULT_HT_SIZE;
/* Linear probing to search for the key */
for (int i = 0; i < DEFAULT_HT_SIZE; i++) {
int probe_idx = (idx + i) % DEFAULT_HT_SIZE;
if (ht[probe_idx].name && !strcmp(ht[probe_idx].name, name->value))
return &ht[probe_idx].value;
}
char err[512];
snprintf(err, 512, "Undefined variable '%s'.", name->value);
runtime_error(err, name->line);
return NULL;
}
void ht_replace(ht_t *ht, char *name, value_t value)
{
unsigned int idx = hash(name) % DEFAULT_HT_SIZE;
for (int i = 0; i < DEFAULT_HT_SIZE; i++) {
int probe_idx = (idx + i) % DEFAULT_HT_SIZE;
if (!ht[probe_idx].name)
break;
if (!strcmp(ht[probe_idx].name, name)) {
memcpy(&ht[probe_idx].value, &value, sizeof(value));
return;
}
}
}
void ht_assign(ht_t *ht, token_t *name, value_t value)
{
if (ht_get(ht, name)) {
ht_replace(ht, name->value, value);
return;
}
char err[512];
snprintf(err, 512, "Undefined variable '%s'.", name->value);
runtime_error(err, name->line);
}
void ht_free(ht_t *ht)
{
for (int i = 0; i < DEFAULT_HT_SIZE; i++) {
if (ht[i].value.type != VAL_NIL) {
free(ht[i].name);
}
}
free(ht);
}

View file

@ -4,13 +4,11 @@
#include <errno.h>
#include "ast.h"
#include "env.h"
#include "interpreter.h"
#include "lexer.h"
value_t visit_literal(expr_t *expr);
value_t visit_grouping(expr_t *expr);
value_t visit_binary(expr_t *expr);
value_t visit_unary(expr_t *expr);
ht_t *ht;
value_t visit_literal(expr_t *expr)
{
@ -184,6 +182,23 @@ value_t visit_unary(expr_t *expr)
return (value_t){.type = VAL_NIL};
}
value_t visit_variable(expr_t *expr)
{
value_t *val = ht_get(ht, &expr->as.variable.name);
if (val) {
return *val;
} else {
return (value_t) {.type = VAL_NIL};
}
}
value_t visit_assign(expr_t *expr)
{
value_t value = evaluate(expr->as.assign.value);
ht_assign(ht, &expr->as.assign.name, value);
return value;
}
value_t evaluate(expr_t *expr)
{
if (!expr) {
@ -199,6 +214,10 @@ value_t evaluate(expr_t *expr)
return visit_unary(expr);
case EXPR_GROUPING:
return visit_grouping(expr);
case EXPR_VARIABLE:
return visit_variable(expr);
case EXPR_ASSIGN:
return visit_assign(expr);
default:
exit(65);
break;
@ -240,10 +259,18 @@ void print_statement(stmt_t stmt)
print_value(&obj);
} else if (stmt.type == STMT_EXPR) {
evaluate(stmt.as.expr.expression);
} else if (stmt.type == STMT_VAR) {
value_t value = {.type = VAL_NIL};
if (stmt.as.variable.initializer) {
value = evaluate(stmt.as.variable.initializer);
}
ht_add(ht, stmt.as.variable.name.value, value);
}
}
void print_statements(stmt_array_t *array)
{
ht = ht_init();
for (int i = 0; i < array->length; i++) {
print_statement(array->statements[i]);
}

View file

@ -11,6 +11,9 @@ token_t *tokens;
expr_t *expression(void);
void synchronize(void);
/*
* Syntax error
*/
void error(token_t *token, char *message)
{
if (token->type == TOKEN_EOF) {
@ -51,6 +54,16 @@ void free_expr(expr_t *expr)
}
free(expr);
break;
case EXPR_VARIABLE:
free(expr->as.variable.name.value);
free(expr);
break;
case EXPR_ASSIGN:
free(expr->as.assign.name.value);
free_expr(expr->as.assign.value);
break;
default:
break;
@ -80,19 +93,17 @@ void advance(void)
int check(token_type_t type)
{
if (tokens[current].type == type) {
advance();
return 1;
} else {
return 0;
}
return tokens[current].type == type;
}
token_t *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();
token_t *tok = peek();
advance();
return tok;
}
return NULL;
}
@ -101,14 +112,19 @@ expr_t *primary(void)
{
if (check(TOKEN_FALSE) || check(TOKEN_TRUE) || check(TOKEN_NIL) ||
check(TOKEN_NUMBER) || check(TOKEN_STRING)) {
return create_literal_expr(previous());
token_t *tok = peek();
advance();
return create_literal_expr(tok);
}
if (check(TOKEN_IDENTIFIER)) {
return create_variable_expr(previous());
token_t *tok = peek();
advance();
return create_variable_expr(tok);
}
if (check(TOKEN_LEFT_PAREN)) {
advance();
expr_t *expr = expression();
consume(TOKEN_RIGHT_PAREN, "Expect ')' after expression.");
return create_grouping_expr(expr);
@ -120,7 +136,8 @@ expr_t *primary(void)
expr_t *unary(void)
{
if (check(TOKEN_BANG) || check(TOKEN_MINUS)) {
token_t *operator = previous();
token_t *operator = peek();
advance();
expr_t *right = unary();
return create_unary_expr(operator, right);
}
@ -133,7 +150,8 @@ expr_t *factor(void)
expr_t *expr = unary();
while (check(TOKEN_SLASH) || check(TOKEN_STAR)) {
token_t *operator = previous();
token_t *operator = peek();
advance();
expr_t *right = unary();
expr = create_binary_expr(operator, expr, right);
}
@ -146,7 +164,8 @@ expr_t *term(void)
expr_t *expr = factor();
while (check(TOKEN_MINUS) || check(TOKEN_PLUS)) {
token_t *operator = previous();
token_t *operator = peek();
advance();
expr_t *right = factor();
expr = create_binary_expr(operator, expr, right);
}
@ -160,7 +179,8 @@ expr_t *comparison(void)
while (check(TOKEN_GREATER) || check(TOKEN_GREATER_EQUAL) || check(TOKEN_LESS)
|| check(TOKEN_LESS_EQUAL)) {
token_t *operator = previous();
token_t *operator = peek();
advance();
expr_t *right = term();
expr = create_binary_expr(operator, expr, right);
}
@ -173,7 +193,8 @@ expr_t *equality(void)
expr_t *expr = comparison();
while (check(TOKEN_BANG_EQUAL) || check(TOKEN_EQUAL_EQUAL)) {
token_t *operator = previous();
token_t *operator = peek();
advance();
expr_t *right = comparison();
expr = create_binary_expr(operator, expr, right);
}
@ -181,9 +202,28 @@ expr_t *equality(void)
return expr;
}
expr_t *assignment(void)
{
expr_t *expr = equality();
if (check(TOKEN_EQUAL)) {
token_t *equals = peek();
advance();
expr_t *value = assignment();
if (expr->type == EXPR_VARIABLE) {
token_t name = expr->as.variable.name;
return create_assign_expr(&name, value);
}
error(equals, "Invalid assignment target.");
}
return expr;
}
expr_t *expression(void)
{
return equality();
return assignment();
}
stmt_t print_stmt(void)
@ -208,8 +248,10 @@ stmt_t expression_stmt(void)
stmt_t statement(void)
{
if (check(TOKEN_PRINT))
if (check(TOKEN_PRINT)) {
advance();
return print_stmt();
}
return expression_stmt();
}
@ -219,6 +261,7 @@ stmt_t var_declaration(void)
expr_t *initializer = NULL;
if (check(TOKEN_EQUAL)) {
advance();
initializer = expression();
}
@ -234,8 +277,10 @@ stmt_t var_declaration(void)
stmt_t declaration(void)
{
if (check(TOKEN_VAR))
if (check(TOKEN_VAR)) {
advance();
return var_declaration();
}
return statement();
}
@ -258,6 +303,9 @@ void free_statements(stmt_array_t *array)
if (array->statements[i].type == STMT_EXPR) {
free_expr(array->statements[i].as.expr.expression);
}
if (array->statements[i].type == STMT_VAR) {
free_expr(array->statements[i].as.variable.initializer);
}
}
free(array->statements);
free(array);