Skip to content

Commit

Permalink
feat: handle early return in function #9
Browse files Browse the repository at this point in the history
  • Loading branch information
zestones committed Dec 30, 2024
1 parent 3ec5b34 commit 86aa109
Show file tree
Hide file tree
Showing 14 changed files with 170 additions and 23 deletions.
42 changes: 36 additions & 6 deletions example/compilation/to-remove.txt
Original file line number Diff line number Diff line change
@@ -1,13 +1,43 @@
PROG

var i : int;
var n : int;
var fib : int;
var fib_1 : int;
var fib_2 : int;

for (i := 5; i > 0; i--) {
print("i=%d\n", i);

func fibonacci(num : int) -> int {
var i: int;
if (num <= 1) { return num; }

fib_1 := 1;
fib_2 := 0;

for (i := 2; i <= num; i++) {
fib := fib_1 + fib_2;
fib_2 := fib_1;
fib_1 := fib;
}

return fib_1;
}

print("--> i=%d\n", i);

i++;
proc display_fibonacci(num : int, result : int) {
print("Fibonacci number at position %d is %d\n", num, result);
}

proc main() {
print("Enter the position in Fibonacci sequence: ");
input("%d", n);


if (n < 0) {
print("Fibonacci is undefined for negative numbers.\n");
} else {
fib := fibonacci(n);
display_fibonacci(n, fib);
}
}

print("--> i=%d\n", i);
main();
43 changes: 43 additions & 0 deletions example/interpretation/iter_fibo.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
PROG

var n : int;
var fib : int;
var fib_1 : int;
var fib_2 : int;


func fibonacci(num : int) -> int {
var i: int;
if (num <= 1) { return num; }

fib_1 := 1;
fib_2 := 0;

for (i := 2; i <= num; i++) {
fib := fib_1 + fib_2;
fib_2 := fib_1;
fib_1 := fib;
}

return fib_1;
}


proc display_fibonacci(num : int, result : int) {
print("Fibonacci number at position %d is %d\n", num, result);
}

proc main() {
print("Enter the position in Fibonacci sequence: ");
input("%d", n);


if (n < 0) {
print("Fibonacci is undefined for negative numbers.\n");
} else {
fib := fibonacci(n);
display_fibonacci(n, fib);
}
}

main();
11 changes: 11 additions & 0 deletions example/interpretation/recursive.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
PROG

func main(n: int) -> int {
if (n < 1) {
return 0;
}

return main(n - 1);
}

print("%d\n", main(2));
2 changes: 0 additions & 2 deletions src/data/region_table.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,6 @@ void fprintf_region_table(FILE* out) {
sprintf(index_str, "%d", i);
sprintf(size_str, "%d", region_table[i].size);
sprintf(nis_str, "%d", region_table[i].nis);
// TODO: print in a file ?
// sprintf(ast_str, "%d", region_table[i].ast);

print_table_row(out,
4,
Expand Down
16 changes: 11 additions & 5 deletions src/parser/grammar.y
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "../symbol_table/declaration/declaration_table.h"
#include "../symbol_table/lexeme/lexeme_table.h"
#include "../symbol_table/hash/hash_table.h"
#include "../symbol_table/utility.h"
#include "../data/region_table.h"

#include "parser.h"
Expand Down Expand Up @@ -148,18 +149,17 @@ function_declaration: FUNCTION IDENTIFIER {
declaration_func_start();
} OPEN_PARENTHESIS parameter_list CLOSE_PARENTHESIS RETURN_TYPE type {
update_declaration_func_return_type($8);
} START declaration_list statement_list return_statement END {
} START declaration_list statement_list END {
$$ = construct_node(A_FUNCTION_DECLARATION, $2, find_declaration_index_by_nature($2, TYPE_FUNC));

Node *nodes[] = { $5, $11, $12, $13 };
add_chain($$, nodes, 4);
Node *nodes[] = { $5, $11, $12 };
add_chain($$, nodes, 3);

update_region_ast(peek_region(), $$);
declaration_func_proc_end();

// Keep the declaration in the region
$$ = construct_node(A_FUNCTION_DECLARATION, $2, find_declaration_index_by_nature($2, TYPE_FUNC));
check_func_prototype($8, $13);
}
;

Expand Down Expand Up @@ -386,6 +386,7 @@ statement: assignment_statement SEMICOLON {
| for_statement { $$ = $1; }
| print_statement { $$ = $1; }
| input_statement { $$ = $1; }
| return_statement{ $$ = $1; }
;

assignment_statement: IDENTIFIER { check_variable_definition($1); } OPAFF expression {
Expand Down Expand Up @@ -444,9 +445,14 @@ inc_dec_statement: IDENTIFIER DECREMENT {
}
;

return_statement: RETURN_VALUE expression SEMICOLON {
return_statement: RETURN_VALUE expression SEMICOLON {
if (!peek_region()) {
set_error_type(&error, SYNTAX_ERROR);
yyerror("Return statement is not allowed outside of a function.");
}
$$ = construct_node_default(A_RETURN_STATEMENT);
add_child($$, $2);
check_func_prototype(get_func_return_type(find_function_index_by_region(peek_region())), $$);
}
;

Expand Down
13 changes: 13 additions & 0 deletions src/symbol_table/declaration/declaration_table.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,19 @@ int find_declaration_index(int index);
*/
int find_declaration_index_by_nature(int tlex_index, Nature nature);

/**
* @brief Finds the index of a function declaration based on the execution region.
*
* This function searches the declaration table for a function (`TYPE_FUNC`) whose
* execution region matches the provided `region_index`. It traverses the linked list
* of declarations and returns the index of the matching function, if found.
*
* @param region_index The region index to match against the function's execution region.
* @return The index of the function declaration in the declaration table if a match is found.
* Returns `NULL_VALUE` if no matching function is found.
*/
int find_function_index_by_region(int region_index);

/**
* @brief Gets the nature of a declaration.
*
Expand Down
17 changes: 17 additions & 0 deletions src/symbol_table/declaration/name_association.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,20 @@ int find_declaration_index(int tlex_index) {
int find_declaration_index_by_nature(int tlex_index, Nature nature) {
return find_declaration_in_stack(tlex_index, nature);
}

int find_function_index_by_region(int region_index) {
Declaration *declaration_table = get_declaration_table();
int index = 4; // Start at the first entry in the declaration table

// TODO: optimize this search
while (index != MAX_DECLARATION_COUNT) {
if (declaration_table[index].nature == TYPE_FUNC &&
declaration_table[index].execution == region_index) {
return index; // Found the function with the matching region
}

index++;
}

return NULL_VALUE;
}
6 changes: 6 additions & 0 deletions src/symbol_table/utility.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,4 +108,10 @@ int get_struct_nth_field_lexicographic(int struct_declaration, int nth_field) {
int get_struct_field_count(int struct_declaration) {
int struct_representation = get_declaration_description(struct_declaration);
return get_representation_value(struct_representation);
}


int get_func_return_type(int func_declaration) {
int func_representation = get_declaration_description(func_declaration);
return get_representation_value(func_representation);
}
3 changes: 3 additions & 0 deletions src/symbol_table/utility.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,7 @@ int get_struct_nth_field_execution(int declaration_type, int nth);
int get_struct_nth_field_declaration(int struct_declaration, int nth_field); // TODO: rename type -> declaration
int get_struct_nth_field_lexicographic(int struct_declaration, int nth_field);


int get_func_return_type(int func_declaration);

#endif // __UTILITY_H__
4 changes: 4 additions & 0 deletions src/virtual_machine/core/execution.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ vm_cell get_variable_cell(int index_declaration) {
return get_cell_from_stack_frame(frame, address);
}

vm_cell get_return_cell() {
return get_stack_frame_by_id(peek_execution_stack().dynamic_link)->region_value;
}

void handle_variable_affectation(int index_declaration, vm_cell cell) {
int address = get_variable_address(index_declaration);
int region = get_declaration_region(index_declaration);
Expand Down
12 changes: 12 additions & 0 deletions src/virtual_machine/core/execution.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,18 @@ vm_cell get_struct_cell(Node *struct_access);
*/
vm_cell get_array_cell(Node *arra_access);

/**
* @brief Retrieves the return value cell from the current function's stack frame.
*
* This function accesses the stack frame of the currently executing function
* by using the dynamic link to locate its stack frame. It then retrieves the
* `region_value` field, which represents the memory location for storing
* the return value of the function.
*
* @return The `vm_cell` containing the return value location for the current function.
*/
vm_cell get_return_cell();

/**
* @brief Updates the memory cell of a variable with a new value.
*
Expand Down
7 changes: 4 additions & 3 deletions src/virtual_machine/interpreter/condition/condition.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,21 @@ void execute_condition(AST ast) {
while (current_node != NULL) {
vm_cell condition = resolve_boolean_expression(current_node->child);

if (current_node->type == A_IF_ELSE_IF || current_node->type == A_IF_ELSE) {
if (current_node->type == A_IF_ELSE_IF || current_node->type == A_IF_ELSE || A_IF) {
if (condition.value.boolean) {
resolve_statement_list(current_node->child->sibling->child);
break;
}

// Move to the next branch (else if or else)
Node *next_branch = current_node->child->sibling->sibling;
if (current_node->type == A_IF_ELSE && next_branch && next_branch->child) {
if ((current_node->type == A_IF_ELSE || A_IF) && next_branch && next_branch->child) {
resolve_statement_list(next_branch->child);
break;
}
current_node = next_branch;
} else {
}
else {
printf("Unexpected node type: %d\n", current_node->type);
break;
}
Expand Down
5 changes: 4 additions & 1 deletion src/virtual_machine/interpreter/expression/expression.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,10 @@ vm_cell resolve_expression(Node *expression) {
case A_FUNC_PROC_CALL_STATEMENT: {
execute_func_proc_call(expression);
stack_frame current_frame = peek_execution_stack();
return current_frame.region_value;
vm_cell cell = current_frame.region_value;
// Clear the region value after execution to continue to resolve statement list
peek_execution_stack_as_mutable()->region_value = construct_vm_cell(NULL_VALUE, NULL);
return cell;
}

default:
Expand Down
12 changes: 6 additions & 6 deletions src/virtual_machine/interpreter/interpreter.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ static void resolve_declaration_list(Node *declaration_list) {
}

void resolve_statement_list(AST statement_list) {
if (statement_list == NULL) return;
if (statement_list == NULL || get_return_cell().is_initialized) return;

switch (statement_list->type) {
case A_ASSIGNMENT_STATEMENT:
Expand Down Expand Up @@ -64,6 +64,11 @@ void resolve_statement_list(AST statement_list) {
break;
}

case A_RETURN_STATEMENT: {
handle_function_return_value(resolve_expression(statement_list->child));
break;
}

default:
resolve_statement_list(statement_list->child);
resolve_statement_list(statement_list->sibling);
Expand Down Expand Up @@ -104,11 +109,6 @@ static void interpret_ast(AST ast) {
else interpret_ast(ast->child);
break;

case A_RETURN_STATEMENT: {
handle_function_return_value(resolve_expression(ast->child));
break;
}

default: {
interpret_ast(ast->child);
interpret_ast(ast->sibling);
Expand Down

0 comments on commit 86aa109

Please sign in to comment.