Add if statements, unary minus, and fix GC safe points
- Lexer: recognize 'if' as keyword (TOK_IF) - Parser: add NODE_IF with if_statement union, parse if/cond/body, handle unary minus in parse_term as 0 - expr - Eval: add NODE_IF evaluation, move GC to NODE_BLOCK level to avoid destroying temporary values during sub-expression evaluation
This commit is contained in:
4
projects/if.j
Normal file
4
projects/if.j
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
x = 20
|
||||||
|
if x < 10:
|
||||||
|
print x
|
||||||
|
print -300
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
x = 0
|
x = 0
|
||||||
while x < 100000000:
|
while x < 10000000:
|
||||||
x = x + 1
|
x = x + 1
|
||||||
print x
|
print x
|
||||||
|
|||||||
@@ -135,6 +135,8 @@ Token *tokenize(const char *source, int *token_count) {
|
|||||||
tokens[count++] = make_token(TOK_PRINT, word);
|
tokens[count++] = make_token(TOK_PRINT, word);
|
||||||
} else if (strcmp(word, "while") == 0) {
|
} else if (strcmp(word, "while") == 0) {
|
||||||
tokens[count++] = make_token(TOK_WHILE, word);
|
tokens[count++] = make_token(TOK_WHILE, word);
|
||||||
|
} else if (strcmp(word, "if") == 0) {
|
||||||
|
tokens[count++] = make_token(TOK_IF, word);
|
||||||
} else {
|
} else {
|
||||||
tokens[count++] = make_token(TOK_ID, word);
|
tokens[count++] = make_token(TOK_ID, word);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,10 @@ typedef struct ASTNode {
|
|||||||
struct ASTNode *cond;
|
struct ASTNode *cond;
|
||||||
struct ASTNode *body;
|
struct ASTNode *body;
|
||||||
} while_loop; // NODE_WHILE
|
} while_loop; // NODE_WHILE
|
||||||
|
struct {
|
||||||
|
struct ASTNode *cond;
|
||||||
|
struct ASTNode *body;
|
||||||
|
} if_statement; // NODE_IF
|
||||||
} data;
|
} data;
|
||||||
} ASTNode;
|
} ASTNode;
|
||||||
|
|
||||||
@@ -65,6 +69,15 @@ ASTNode *parse_term(Token *tokens) {
|
|||||||
node->data.string_val = tokens[pos].value;
|
node->data.string_val = tokens[pos].value;
|
||||||
pos++;
|
pos++;
|
||||||
return node;
|
return node;
|
||||||
|
} else if (tokens[pos].type == TOK_MINUS) {
|
||||||
|
pos++; // consumir '-'
|
||||||
|
ASTNode *term = parse_term(tokens);
|
||||||
|
ASTNode *neg = make_node(NODE_BINOP);
|
||||||
|
neg->data.binop.op = '-';
|
||||||
|
neg->data.binop.left = make_node(NODE_INT_LIT);
|
||||||
|
neg->data.binop.left->data.int_val = 0;
|
||||||
|
neg->data.binop.right = term;
|
||||||
|
return neg;
|
||||||
}
|
}
|
||||||
printf("ERROR: esperaba INT o ID, encontré tipo %d\n", tokens[pos].type);
|
printf("ERROR: esperaba INT o ID, encontré tipo %d\n", tokens[pos].type);
|
||||||
exit(1);
|
exit(1);
|
||||||
@@ -135,6 +148,33 @@ ASTNode *parse_statement(Token *tokens) {
|
|||||||
node->data.while_loop.body = body;
|
node->data.while_loop.body = body;
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tokens[pos].type == TOK_IF) {
|
||||||
|
pos++; // consumir if
|
||||||
|
ASTNode *cond = parse_expr(tokens);
|
||||||
|
pos++; // consumir :
|
||||||
|
pos++; // consumir NEWLINE
|
||||||
|
pos++; // consumir INDENT
|
||||||
|
|
||||||
|
// Parsear bloque de statements hasta DEDENT
|
||||||
|
ASTNode *body = make_node(NODE_BLOCK);
|
||||||
|
body->data.block.stmts = (ASTNode **)malloc(sizeof(ASTNode *) * 256);
|
||||||
|
body->data.block.count = 0;
|
||||||
|
while (tokens[pos].type != TOK_DEDENT) {
|
||||||
|
body->data.block.stmts[body->data.block.count++] =
|
||||||
|
parse_statement(tokens);
|
||||||
|
if (tokens[pos].type == TOK_NEWLINE) {
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pos++; // Consumir DEDENT
|
||||||
|
|
||||||
|
ASTNode *node = make_node(NODE_IF);
|
||||||
|
node->data.while_loop.cond = cond;
|
||||||
|
node->data.while_loop.body = body;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
printf("ERROR: statement inesperado\n");
|
printf("ERROR: statement inesperado\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@@ -215,6 +255,12 @@ void ast_print(ASTNode *node, const char *prefix, int is_last) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case NODE_IF:
|
||||||
|
printf("NODE_IF\n");
|
||||||
|
ast_print(node->data.while_loop.cond, new_prefix, 0);
|
||||||
|
ast_print(node->data.while_loop.body, new_prefix, 1);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
printf("UNKNOWN\n");
|
printf("UNKNOWN\n");
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -41,16 +41,8 @@ void env_set(Environment *env, const char *name, size_t value) {
|
|||||||
|
|
||||||
int step = 0;
|
int step = 0;
|
||||||
|
|
||||||
size_t eval(ASTNode *node, Environment *env, void *allocator, int debug, int gc) {
|
size_t eval(ASTNode *node, Environment *env, void *allocator, int debug,
|
||||||
|
int gc) {
|
||||||
// Run GC
|
|
||||||
if (gc) {
|
|
||||||
size_t roots[256];
|
|
||||||
for (int i = 0; i < env->count; i++) {
|
|
||||||
roots[i] = env->vars[i].value;
|
|
||||||
}
|
|
||||||
gc_collect(allocator, roots, env->count);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (debug > 0) {
|
if (debug > 0) {
|
||||||
step++;
|
step++;
|
||||||
@@ -101,6 +93,15 @@ size_t eval(ASTNode *node, Environment *env, void *allocator, int debug, int gc)
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
case NODE_BLOCK:
|
case NODE_BLOCK:
|
||||||
|
// Run GC
|
||||||
|
if (gc) {
|
||||||
|
size_t roots[256];
|
||||||
|
for (int i = 0; i < env->count; i++) {
|
||||||
|
roots[i] = env->vars[i].value;
|
||||||
|
}
|
||||||
|
gc_collect(allocator, roots, env->count);
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < node->data.block.count; i++)
|
for (int i = 0; i < node->data.block.count; i++)
|
||||||
eval(node->data.block.stmts[i], env, allocator, debug, gc);
|
eval(node->data.block.stmts[i], env, allocator, debug, gc);
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user