├── README.md ├── sieve.kv ├── debug_print.h ├── kvstdlib.h ├── sanity.kv ├── kvstdlib.c ├── kvlang_internals.h ├── LICENSE └── main.c /README.md: -------------------------------------------------------------------------------- 1 | # keyva-lang 2 | The KeyVa programming language 3 | -------------------------------------------------------------------------------- /sieve.kv: -------------------------------------------------------------------------------- 1 | p[2]=2 2 | 3 | n = 3 4 | 5 | while len(p) < 10 6 | divisible = 0 7 | for i in p 8 | if mod(n, i) == 0 9 | divisible = 1 10 | end 11 | end 12 | 13 | if divisible == 0 14 | p[n]=n 15 | end 16 | n = n + 1 17 | end 18 | 19 | for i in p 20 | print(i) 21 | end -------------------------------------------------------------------------------- /debug_print.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (C) 2024 Gary Sims 4 | * 5 | */ 6 | 7 | #ifndef DEBUG_PRINT_H 8 | #define DEBUG_PRINT_H 9 | 10 | #include 11 | 12 | // Define DEBUG to enable debug prints 13 | // You can define DEBUG via compiler flags (e.g., -DDEBUG) instead of here 14 | #ifndef DEBUG 15 | #ifdef NDEBUG 16 | #define DEBUG 0 17 | #else 18 | #define DEBUG 1 19 | #endif 20 | #endif 21 | 22 | #if DEBUG 23 | 24 | // Variadic macro for debug printing with contextual information 25 | #define DEBUG_PRINT(fmt, ...) \ 26 | fprintf(stderr, "DEBUG: %s:%d:%s(): " fmt "\n", \ 27 | __FILE__, __LINE__, __func__, ##__VA_ARGS__) 28 | 29 | #else 30 | 31 | // When DEBUG is not defined, define DEBUG_PRINT as a no-op 32 | #define DEBUG_PRINT(fmt, ...) ((void)0) 33 | 34 | #endif 35 | 36 | #endif // DEBUG_PRINT_H 37 | -------------------------------------------------------------------------------- /kvstdlib.h: -------------------------------------------------------------------------------- 1 | 2 | /* SPDX-License-Identifier: GPL-2.0-only */ 3 | /* 4 | * Copyright (C) 2024 Gary Sims 5 | * 6 | */ 7 | 8 | #ifndef KVSTDLIB_H 9 | #define KVSTDLIB_H 10 | 11 | #include "kvlang_internals.h" 12 | 13 | /* Define a standard lib function type */ 14 | typedef FunctionReturn (*kvstdlib_func_t)(ASTNode *arg); 15 | 16 | /* Forward declarations of standard lib functions */ 17 | FunctionReturn kvstdlib_len(ASTNode *arg); 18 | FunctionReturn kvstdlib_key(ASTNode *arg); 19 | FunctionReturn kvstdlib_mod(ASTNode *arg); 20 | FunctionReturn kvstdlib_bar(ASTNode *arg); 21 | 22 | /* Structure to associate a string with its function */ 23 | typedef struct { 24 | const char *name; 25 | kvstdlib_func_t func; 26 | } kvstdlib_lookup_entry_t; 27 | 28 | /* Array of name/callback pairs */ 29 | static const kvstdlib_lookup_entry_t kvstdlib_lookup_table[] = { 30 | { "len", kvstdlib_len }, 31 | { "key", kvstdlib_key }, 32 | { "mod", kvstdlib_mod }, 33 | { "bar", kvstdlib_bar }, 34 | { NULL, NULL } /* Sentinel to mark the end of the array */ 35 | }; 36 | 37 | 38 | #endif /* KVSTDLIB_H */ 39 | -------------------------------------------------------------------------------- /sanity.kv: -------------------------------------------------------------------------------- 1 | def this_is_a_function(a, b) 2 | return a+b 3 | end 4 | 5 | def another_function(x) 6 | return x 7 | end 8 | 9 | def function_zero() 10 | print("This is function_zero") 11 | end 12 | 13 | passed = 0 14 | this_is_a_function(22, 33) 15 | f = this_is_a_function(10, 20) 16 | if f == 30 17 | print("PASS 1") 18 | passed = passed + 1 19 | end 20 | 21 | f = another_function(42) 22 | f = another_function(f) 23 | if f == 42 24 | print("PASS 2") 25 | passed = passed + 1 26 | end 27 | 28 | r=2 29 | if r < 5 30 | print("PASS 3") 31 | passed = passed + 1 32 | else 33 | print("FAIL 3") 34 | end 35 | r=7 36 | if r < 5 37 | print("FAIL 4") 38 | else 39 | print("PASS 4") 40 | passed = passed + 1 41 | end 42 | x = 10 43 | x["a"] = 11 44 | x["bob"] = 12 45 | for i in x 46 | if i == 10 47 | print("PASS 5") 48 | passed = passed + 1 49 | end 50 | if i == 11 51 | print("PASS 6") 52 | passed = passed + 1 53 | end 54 | if i == 12 55 | print("PASS 7") 56 | passed = passed + 1 57 | end 58 | end 59 | q=0 60 | t[q]=0 61 | if t[0] == 0 62 | print("PASS 8") 63 | passed = passed + 1 64 | end 65 | c = 0 66 | while c < 10 67 | c = c + 1 68 | end 69 | if c == 10 70 | print("PASS 9") 71 | passed = passed + 1 72 | end 73 | c = 0 74 | while c < 10 75 | c = c + 1 76 | cend = c 77 | end 78 | if cend == 10 79 | print("PASS 10") 80 | passed = passed + 1 81 | end 82 | for i in x 83 | t2 = i 84 | end 85 | if t2 == 12 86 | print("PASS 11") 87 | passed = passed + 1 88 | end 89 | def f1() 90 | x["a"]=11 91 | x["b"]=22 92 | return x 93 | end 94 | z = f1() 95 | if z["a"] == 11 96 | print("PASS 12") 97 | passed = passed + 1 98 | end 99 | if z["b"] == 12 100 | print("PASS 12") 101 | passed = passed + 1 102 | end 103 | if passed == 12 104 | print("ALL TESTS PASSED") 105 | end 106 | -------------------------------------------------------------------------------- /kvstdlib.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (C) 2024 Gary Sims 4 | * 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // #define NDEBUG 1 13 | #define DEBUG 1 14 | #include "debug_print.h" 15 | 16 | #include "kvlang_internals.h" 17 | 18 | #include "kvstdlib.h" 19 | 20 | FunctionReturn kvstdlib_len(ASTNode *arg) { 21 | FunctionReturn result = {0}; 22 | 23 | // len requires exactly one argument 24 | if (arg == NULL || arg->right != NULL) { 25 | printf("Error: len() requires exactly one argument\n"); 26 | result.has_return = 1; 27 | result.type = RESULT_NUMBER; 28 | result.number_value = 0; 29 | return result; 30 | } 31 | 32 | EvalResult arg_val; 33 | if (!evaluate_expression(arg, &arg_val, EVAL_PRINT)) { 34 | printf("Error: Failed to evaluate argument in len()\n"); 35 | result.has_return = 1; 36 | result.type = RESULT_NUMBER; 37 | result.number_value = 0; 38 | return result; 39 | } 40 | 41 | int length = 0; 42 | switch (arg_val.type) { 43 | case RESULT_ASSOC_ARRAY: 44 | // Just return array size 45 | length = arg_val.array_value->size; 46 | break; 47 | case RESULT_NUMBER: 48 | case RESULT_STRING: 49 | // Treat numbers and strings as arrays of length 1 50 | length = 1; 51 | break; 52 | default: 53 | // Unknown type, return 0 54 | length = 0; 55 | break; 56 | } 57 | 58 | result.has_return = 1; 59 | result.type = RESULT_NUMBER; 60 | result.number_value = length; 61 | return result; 62 | } 63 | 64 | FunctionReturn kvstdlib_key(ASTNode *arg) { 65 | FunctionReturn result = {0}; 66 | result.has_return = 1; 67 | 68 | // Requires exactly one argument 69 | if (arg == NULL || arg->right != NULL) { 70 | printf("Error: key() requires exactly one argument\n"); 71 | result.type = RESULT_STRING; 72 | strcpy(result.string_value, ""); 73 | return result; 74 | } 75 | 76 | if(arg->type == AST_IDENTIFIER) { 77 | Variable *var = get_variable(arg->data.identifier); 78 | if (var != NULL) { 79 | result.type = RESULT_STRING; 80 | strcpy(result.string_value, var->array.pairs[0].key); 81 | return result; 82 | } 83 | } else if(arg->type == AST_ARRAY_ACCESS) { 84 | EvalResult key_result; 85 | if (!evaluate_expression(arg->left, &key_result, EVAL_ARITHMETIC)) { 86 | printf("Error: Failed to evaluate array index\n"); 87 | result.type = RESULT_STRING; 88 | strcpy(result.string_value, ""); 89 | return result; 90 | } 91 | if (key_result.type != RESULT_STRING && key_result.type != RESULT_NUMBER) { 92 | printf("Error: Array index must be a string or number\n"); 93 | result.type = RESULT_STRING; 94 | strcpy(result.string_value, ""); 95 | return result; 96 | } 97 | 98 | // Convert numeric index to string if necessary 99 | if (key_result.type == RESULT_NUMBER) { 100 | snprintf(result.string_value, MAX_TOKEN_LENGTH, "%g", key_result.number_value); 101 | } else { 102 | strcpy(result.string_value, key_result.string_value); 103 | } 104 | result.type = RESULT_STRING; 105 | return result; 106 | } 107 | 108 | // Default 109 | result.has_return = 1; 110 | result.type = RESULT_STRING; 111 | strcpy(result.string_value, ""); 112 | return result; 113 | } 114 | 115 | FunctionReturn kvstdlib_mod(ASTNode *arg) { 116 | FunctionReturn result = {0}; 117 | result.has_return = 1; 118 | 119 | // Requires exactly one argument 120 | if (arg == NULL || arg->right == NULL) { 121 | printf("Error: mod() requires exactly two argument\n"); 122 | result.type = RESULT_NUMBER; 123 | result.number_value = 0; 124 | return result; 125 | } 126 | 127 | EvalResult arg_val1; 128 | if (!evaluate_expression(arg, &arg_val1, EVAL_ARITHMETIC)) { 129 | printf("Error: Failed to evaluate 1st argument in mod()\n"); 130 | result.type = RESULT_NUMBER; 131 | result.number_value = 0; 132 | return result; 133 | } 134 | 135 | EvalResult arg_val2; 136 | if (!evaluate_expression(arg->right, &arg_val2, EVAL_ARITHMETIC)) { 137 | printf("Error: Failed to evaluate 2nd argument in mod()\n"); 138 | result.type = RESULT_NUMBER; 139 | result.number_value = 0; 140 | return result; 141 | } 142 | 143 | if(arg_val1.type!=RESULT_NUMBER || arg_val2.type!=RESULT_NUMBER) { 144 | result.type = RESULT_NUMBER; 145 | result.number_value = 0; 146 | return result; 147 | } 148 | 149 | result.type = RESULT_NUMBER; 150 | result.number_value = ((int) arg_val1.number_value) % ((int) arg_val2.number_value); 151 | return result; 152 | } 153 | 154 | FunctionReturn kvstdlib_bar(ASTNode *arg) { 155 | FunctionReturn result = {0}; 156 | result.has_return = 1; 157 | return result; 158 | } 159 | -------------------------------------------------------------------------------- /kvlang_internals.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (C) 2024 Gary Sims 4 | * 5 | */ 6 | 7 | #ifndef KVLANGINTERNALS_H 8 | #define KVLANGINTERNALS_H 9 | 10 | #define MAX_LINE_LENGTH 1024 11 | #define MAX_TOKEN_LENGTH 256 12 | #define MAX_TOKENS_PER_LINE 100 13 | #define MAX_TOKENS MAX_TOKENS_PER_LINE 14 | #define MAX_FUNC_PARAMS 10 15 | 16 | // Token definitions 17 | typedef enum { 18 | TOKEN_EOF, 19 | TOKEN_IDENTIFIER, 20 | TOKEN_NUMBER, 21 | TOKEN_STRING, 22 | TOKEN_KEYWORD, 23 | TOKEN_OPERATOR, 24 | TOKEN_DELIMITER, 25 | TOKEN_COMMENT, 26 | TOKEN_UNKNOWN 27 | } TokenType; 28 | 29 | typedef enum { 30 | EVAL_ARITHMETIC, // For arithmetic expressions 31 | EVAL_PRINT // For the print function 32 | } EvalContext; 33 | 34 | typedef struct { 35 | TokenType type; 36 | char value[MAX_TOKEN_LENGTH]; 37 | } Token; 38 | 39 | typedef enum { 40 | AST_PRINT = 0, // 0 41 | AST_LITERAL, // 1 42 | AST_IDENTIFIER, // 2 43 | AST_ASSIGNMENT, // 3 44 | AST_ARRAY_ACCESS, // 4 45 | AST_BINARY_OP, // 5 46 | AST_IF_STATEMENT, // 6 47 | AST_BLOCK, // 7 48 | AST_FOR_STATEMENT, // 8 49 | AST_WHILE_STATEMENT, // 9 50 | AST_FUNCTION_DEFINITION, // 10 51 | AST_FUNCTION_CALL, // 11 52 | AST_RETURN_STATEMENT, // 12 53 | // ... other AST node types ... 54 | } ASTNodeType; 55 | 56 | typedef enum { 57 | OP_ADD, 58 | OP_SUBTRACT, 59 | OP_MULTIPLY, 60 | OP_DIVIDE, 61 | OP_LESS_THAN, 62 | OP_GREATER_THAN, 63 | OP_EQUAL, 64 | OP_NOT_EQUAL, 65 | OP_LESS_EQUAL, 66 | OP_GREATER_EQUAL, 67 | // ... other operators ... 68 | } OperatorType; 69 | 70 | struct ASTNode; 71 | 72 | typedef struct { 73 | char name[MAX_TOKEN_LENGTH]; 74 | struct ASTNode *parameters; // Linked list of parameter identifiers 75 | struct ASTNode *body; // Block of statements 76 | } FunctionDefinition; 77 | 78 | typedef struct { 79 | char name[MAX_TOKEN_LENGTH]; 80 | struct ASTNode *arguments; // Linked list of expressions for arguments 81 | } FunctionCall; 82 | 83 | typedef struct { 84 | struct ASTNode *expression; // Expression to return 85 | } ReturnStatement; 86 | 87 | typedef struct ASTNode { 88 | ASTNodeType type; 89 | struct ASTNode *left; 90 | struct ASTNode *right; 91 | struct ASTNode *nextblock; 92 | union { 93 | // For binary operators 94 | OperatorType operator; 95 | // For literals and identifiers 96 | char string_value[MAX_TOKEN_LENGTH]; 97 | char identifier[MAX_TOKEN_LENGTH]; 98 | // For function definitions 99 | FunctionDefinition func_def; 100 | // For function calls 101 | FunctionCall func_call; 102 | // For return statements 103 | ReturnStatement ret_stmt; 104 | // For if statements 105 | struct { 106 | struct ASTNode *condition; 107 | struct ASTNode *then_branch; 108 | struct ASTNode *else_branch; 109 | } if_stmt; 110 | // For for statements 111 | struct { 112 | char loop_var[MAX_TOKEN_LENGTH]; // Name of the loop variable 113 | struct ASTNode *expression; // Expression that should yield an array 114 | struct ASTNode *body; // Block of statements 115 | } for_stmt; 116 | struct { 117 | struct ASTNode *condition; // The condition expression 118 | struct ASTNode *body; // The block of statements to execute 119 | } while_stmt; 120 | 121 | } data; 122 | } ASTNode; 123 | 124 | typedef struct { 125 | char key[MAX_TOKEN_LENGTH]; 126 | char value[MAX_TOKEN_LENGTH]; 127 | } KeyValuePair; 128 | 129 | typedef struct { 130 | KeyValuePair *pairs; 131 | int size; 132 | int capacity; 133 | } AssocArray; 134 | 135 | typedef struct { 136 | char name[MAX_TOKEN_LENGTH]; 137 | AssocArray array; 138 | } Variable; 139 | 140 | typedef enum { 141 | RESULT_STRING, 142 | RESULT_NUMBER, 143 | RESULT_ASSOC_ARRAY 144 | } ResultType; 145 | 146 | typedef struct { 147 | ResultType type; 148 | union { 149 | char string_value[MAX_TOKEN_LENGTH]; 150 | double number_value; 151 | AssocArray *array_value; 152 | }; 153 | } EvalResult; 154 | 155 | 156 | typedef struct { 157 | char name[MAX_TOKEN_LENGTH]; 158 | struct ASTNode *parameters; 159 | struct ASTNode *body; 160 | } FunctionEntry; 161 | 162 | typedef struct { 163 | int has_return; 164 | ResultType type; 165 | union { 166 | char string_value[MAX_TOKEN_LENGTH]; 167 | double number_value; 168 | AssocArray *array_value; 169 | }; 170 | // char return_value[MAX_TOKEN_LENGTH]; // store number or string 171 | // int return_is_number; 172 | // If you have a Value struct, store it instead 173 | } FunctionReturn; 174 | 175 | 176 | // Function declarations 177 | void tokenize_line(const char *line, Token tokens[], int *token_count); 178 | void duplicate_assoc_array(AssocArray *dup, AssocArray *array); 179 | void parse_and_execute(Token tokens[], int token_count); 180 | ASTNode* parse_print_statement(Token tokens[], int *pos, int token_count); 181 | void execute_ast(ASTNode *node); 182 | ASTNode* parse_comparison(Token tokens[], int *pos, int token_count); 183 | int evaluate_expression(ASTNode *node, EvalResult *result, EvalContext context); 184 | void evaluate_and_print(ASTNode *node); 185 | void free_ast(ASTNode *node); 186 | ASTNode* parse_assignment_statement(Token tokens[], int *pos, int token_count); 187 | ASTNode* parse_term(Token tokens[], int *pos, int token_count); 188 | ASTNode* parse_factor(Token tokens[], int *pos, int token_count); 189 | ASTNode* parse_expression(Token tokens[], int *pos, int token_count); 190 | ASTNode* parse_additive(Token tokens[], int *pos, int token_count); 191 | void execute_assignment(ASTNode *node); 192 | Variable* get_variable(const char *name); 193 | char* get_variable_value(const char *name); 194 | void set_variable_value(const char *name, const char *key, const char *value); 195 | void clear_variable_assoc_array(const char *name); 196 | ASTNode* parse_if_statement(Token tokens[], int *pos, int token_count); 197 | ASTNode* parse_statement(Token tokens[], int *pos, int token_count); 198 | ASTNode* parse_block(Token tokens[], int *pos, int token_count); 199 | ASTNode* parse_for_statement(Token tokens[], int *pos, int token_count); 200 | ASTNode* parse_while_statement(Token tokens[], int *pos, int token_count); 201 | ASTNode* parse_function_call(Token tokens[], int *pos, int token_count); 202 | void execute_block(ASTNode *node); 203 | FunctionReturn execute_ast_with_return(ASTNode *node); 204 | FunctionReturn execute_block_with_return(ASTNode *node); 205 | FunctionReturn execute_function_call(ASTNode *call_node); 206 | ASTNode* parse_return_statement(Token tokens[], int *pos, int token_count); 207 | ASTNode* parse_function_definition(Token tokens[], int *pos, int token_count); 208 | 209 | #endif /* KVLANGINTERNALS_H */ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (C) 2024 Gary Sims 4 | * 5 | */ 6 | 7 | /* 8 | * Build instructions: 9 | * 10 | * gcc -O3 -o keyva main.c kvstdlib.c 11 | * 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #define NDEBUG 1 20 | //#define DEBUG 1 21 | #include "debug_print.h" 22 | 23 | #include "kvlang_internals.h" 24 | 25 | #include "kvstdlib.h" 26 | 27 | #define MAX_FUNCTIONS 100 28 | FunctionEntry functions[MAX_FUNCTIONS]; 29 | int function_count = 0; 30 | 31 | #define MAX_VARIABLES 100 32 | Variable variables[MAX_VARIABLES]; 33 | int variable_count = 0; 34 | 35 | // Keyword, operator, and delimiter definitions 36 | const char *keywords[] = { 37 | "def", "return", "end", "if", "else", "print", "for", "in", "while", NULL 38 | }; 39 | 40 | const char *operators[] = { 41 | "+", "-", "*", "/", "=", "<", ">", "<=", ">=", "==", "!=", NULL 42 | }; 43 | 44 | const char *delimiters = "(),[]"; 45 | 46 | int is_keyword(const char *str) { 47 | for (int i = 0; keywords[i] != NULL; i++) { 48 | if (strcmp(str, keywords[i]) == 0) 49 | return 1; 50 | } 51 | return 0; 52 | } 53 | 54 | int is_operator_char(char c) { 55 | return strchr("+-*/=<>!", c) != NULL; 56 | } 57 | 58 | int is_operator(const char *str) { 59 | for (int i = 0; operators[i] != NULL; i++) { 60 | if (strcmp(str, operators[i]) == 0) 61 | return 1; 62 | } 63 | return 0; 64 | } 65 | 66 | int is_delimiter_char(char c) { 67 | return strchr(delimiters, c) != NULL; 68 | } 69 | 70 | void tokenize_line(const char *line, Token tokens[], int *token_count) { 71 | int pos = 0; 72 | int length = strlen(line); 73 | *token_count = 0; 74 | 75 | while (pos < length) { 76 | char c = line[pos]; 77 | 78 | // Skip whitespace 79 | if (isspace(c)) { 80 | pos++; 81 | continue; 82 | } 83 | 84 | // Comments 85 | if (c == '#') { 86 | // Rest of the line is a comment 87 | Token token; 88 | token.type = TOKEN_COMMENT; 89 | strncpy(token.value, line + pos, MAX_TOKEN_LENGTH - 1); 90 | token.value[MAX_TOKEN_LENGTH - 1] = '\0'; 91 | tokens[(*token_count)++] = token; 92 | break; // Ignore rest of the line 93 | } 94 | 95 | // String literals 96 | if (c == '"' || c == '\'') { 97 | char quote = c; 98 | int start = ++pos; 99 | while (pos < length && line[pos] != quote) { 100 | pos++; 101 | } 102 | if (pos >= length) { 103 | printf("Error: Unterminated string literal\n"); 104 | return; 105 | } 106 | Token token; 107 | token.type = TOKEN_STRING; 108 | int str_length = pos - start; 109 | strncpy(token.value, line + start, str_length); 110 | token.value[str_length] = '\0'; 111 | tokens[(*token_count)++] = token; 112 | pos++; // Skip closing quote 113 | continue; 114 | } 115 | 116 | // Numbers 117 | if (isdigit(c)) { 118 | int start = pos; 119 | while (pos < length && isdigit(line[pos])) { 120 | pos++; 121 | } 122 | Token token; 123 | token.type = TOKEN_NUMBER; 124 | int num_length = pos - start; 125 | strncpy(token.value, line + start, num_length); 126 | token.value[num_length] = '\0'; 127 | tokens[(*token_count)++] = token; 128 | continue; 129 | } 130 | 131 | // Identifiers and keywords 132 | if (isalpha(c) || c == '_') { 133 | int start = pos; 134 | while (pos < length && (isalnum(line[pos]) || line[pos] == '_')) { 135 | pos++; 136 | } 137 | int id_length = pos - start; 138 | char id[MAX_TOKEN_LENGTH]; 139 | strncpy(id, line + start, id_length); 140 | id[id_length] = '\0'; 141 | 142 | Token token; 143 | if (is_keyword(id)) { 144 | token.type = TOKEN_KEYWORD; 145 | } else { 146 | token.type = TOKEN_IDENTIFIER; 147 | } 148 | strcpy(token.value, id); 149 | tokens[(*token_count)++] = token; 150 | continue; 151 | } 152 | 153 | // Operators 154 | if (is_operator_char(c)) { 155 | int start = pos; 156 | while (pos < length && is_operator_char(line[pos])) { 157 | pos++; 158 | } 159 | int op_length = pos - start; 160 | char op[MAX_TOKEN_LENGTH]; 161 | strncpy(op, line + start, op_length); 162 | op[op_length] = '\0'; 163 | 164 | // Check if it's a valid operator 165 | if (is_operator(op)) { 166 | Token token; 167 | token.type = TOKEN_OPERATOR; 168 | strcpy(token.value, op); 169 | tokens[(*token_count)++] = token; 170 | } else { 171 | printf("Error: Unknown operator '%s'\n", op); 172 | } 173 | continue; 174 | } 175 | 176 | // Delimiters 177 | if (is_delimiter_char(c)) { 178 | Token token; 179 | token.type = TOKEN_DELIMITER; 180 | token.value[0] = c; 181 | token.value[1] = '\0'; 182 | tokens[(*token_count)++] = token; 183 | pos++; 184 | continue; 185 | } 186 | 187 | // Unknown character 188 | printf("Error: Unknown character '%c'\n", c); 189 | pos++; 190 | } 191 | } 192 | 193 | void init_assoc_array(AssocArray *array) { 194 | array->size = 0; 195 | array->capacity = 4; // Initial capacity 196 | array->pairs = (KeyValuePair *)malloc(sizeof(KeyValuePair) * array->capacity); 197 | } 198 | 199 | void free_assoc_array(AssocArray *array) { 200 | free(array->pairs); 201 | array->pairs = NULL; 202 | array->size = 0; 203 | array->capacity = 0; 204 | } 205 | 206 | void duplicate_assoc_array(AssocArray *dup, AssocArray *array) { 207 | dup->capacity = array->capacity; 208 | dup->size = array->size; 209 | dup->pairs = (KeyValuePair *)malloc(sizeof(KeyValuePair) * array->capacity); 210 | memcpy(dup->pairs, array->pairs, sizeof(KeyValuePair) * array->capacity); 211 | } 212 | 213 | void set_assoc_array_value(AssocArray *array, const char *key, const char *value) { 214 | // Check if key exists 215 | for (int i = 0; i < array->size; i++) { 216 | if (strcmp(array->pairs[i].key, key) == 0) { 217 | strcpy(array->pairs[i].value, value); 218 | return; 219 | } 220 | } 221 | // Add new key-value pair 222 | if (array->size == array->capacity) { 223 | array->capacity *= 2; 224 | array->pairs = (KeyValuePair *)realloc(array->pairs, sizeof(KeyValuePair) * array->capacity); 225 | } 226 | strcpy(array->pairs[array->size].key, key); 227 | strcpy(array->pairs[array->size].value, value); 228 | array->size++; 229 | } 230 | 231 | char* get_assoc_array_value(AssocArray *array, const char *key) { 232 | for (int i = 0; i < array->size; i++) { 233 | if (strcmp(array->pairs[i].key, key) == 0) { 234 | return array->pairs[i].value; 235 | } 236 | } 237 | return NULL; // Key not found 238 | } 239 | 240 | char* get_first_assoc_array_value(AssocArray *array) { 241 | return array->pairs[0].value; 242 | } 243 | 244 | ASTNode* parse_array_access(Token tokens[], int *pos, int token_count) { 245 | // tokens[*pos] should be an identifier 246 | if (tokens[*pos].type != TOKEN_IDENTIFIER) { 247 | printf("Error: Expected identifier for array access\n"); 248 | return NULL; 249 | } 250 | ASTNode *node = (ASTNode*)malloc(sizeof(ASTNode)); 251 | node->type = AST_ARRAY_ACCESS; 252 | node->left = NULL; 253 | node->right = NULL; 254 | node->nextblock = NULL; 255 | // DEBUG_PRINT("Add AST_ARRAY_ACCESS Node of %d", node->type); 256 | strcpy(node->data.identifier, tokens[*pos].value); 257 | (*pos)++; 258 | 259 | // Expect '[' 260 | if (*pos < token_count && tokens[*pos].type == TOKEN_DELIMITER && tokens[*pos].value[0] == '[') { 261 | (*pos)++; 262 | // Parse the key expression inside brackets 263 | ASTNode *key_expr = parse_expression(tokens, pos, token_count); 264 | if (key_expr == NULL) { 265 | printf("Error: Expected expression inside '[]'\n"); 266 | free_ast(node); 267 | return NULL; 268 | } 269 | node->left = key_expr; 270 | node->right = NULL; 271 | node->nextblock = NULL; 272 | 273 | // Expect ']' 274 | if (*pos < token_count && tokens[*pos].type == TOKEN_DELIMITER && tokens[*pos].value[0] == ']') { 275 | (*pos)++; 276 | return node; 277 | } else { 278 | printf("Error: Expected ']' after array index\n"); 279 | free_ast(node); 280 | return NULL; 281 | } 282 | } else { 283 | printf("Error: Expected '[' after identifier for array access\n"); 284 | free_ast(node); 285 | return NULL; 286 | } 287 | } 288 | 289 | ASTNode* parse_assignment_statement(Token tokens[], int *pos, int token_count) { 290 | // Expect an identifier 291 | if (tokens[*pos].type == TOKEN_IDENTIFIER) { 292 | ASTNode *target = NULL; 293 | 294 | // Check for array access (e.g., a["lemon"]) 295 | if ((*pos + 1) < token_count && tokens[*pos + 1].type == TOKEN_DELIMITER && tokens[*pos + 1].value[0] == '[') { 296 | target = parse_array_access(tokens, pos, token_count); 297 | } else { 298 | // Simple identifier 299 | target = (ASTNode*)malloc(sizeof(ASTNode)); 300 | target->type = AST_IDENTIFIER; 301 | // DEBUG_PRINT("Add AST_IDENTIFIER Node of %d", target->type); 302 | strcpy(target->data.identifier, tokens[*pos].value); 303 | target->left = target->right = NULL; 304 | target->nextblock = NULL; 305 | (*pos)++; 306 | } 307 | 308 | // Expect '=' operator 309 | if (*pos < token_count && tokens[*pos].type == TOKEN_OPERATOR && strcmp(tokens[*pos].value, "=") == 0) { 310 | (*pos)++; 311 | // Parse the expression on the right-hand side 312 | ASTNode *expr = parse_expression(tokens, pos, token_count); 313 | if (expr == NULL) { 314 | printf("Error: Expected expression after '='\n"); 315 | free_ast(target); 316 | return NULL; 317 | } 318 | // Create assignment node 319 | ASTNode *node = (ASTNode*)malloc(sizeof(ASTNode)); 320 | node->type = AST_ASSIGNMENT; 321 | // DEBUG_PRINT("Add AST_ASSIGNMENT Node of %d", node->type); 322 | node->left = target; 323 | node->right = expr; 324 | node->nextblock = NULL; 325 | return node; 326 | } else { 327 | printf("Error: Expected '=' after identifier\n"); 328 | free_ast(target); 329 | return NULL; 330 | } 331 | } 332 | return NULL; 333 | } 334 | 335 | 336 | void parse_and_execute(Token tokens[], int token_count) { 337 | int pos = 0; 338 | 339 | while (pos < token_count) { 340 | ASTNode *node = parse_statement(tokens, &pos, token_count); 341 | if (node != NULL) { 342 | execute_ast(node); 343 | free_ast(node); 344 | } else { 345 | // Skip the rest of the line on error 346 | break; 347 | } 348 | } 349 | } 350 | 351 | ASTNode* parse_phrase(Token tokens[], int *pos, int token_count) { 352 | if (*pos >= token_count) { 353 | printf("Error: Unexpected end of input in term\n"); 354 | return NULL; 355 | } 356 | 357 | Token token = tokens[*pos]; 358 | 359 | if (token.type == TOKEN_NUMBER || token.type == TOKEN_STRING) { 360 | // Literal 361 | ASTNode *node = (ASTNode*)malloc(sizeof(ASTNode)); 362 | if (node == NULL) { 363 | printf("Error: Memory allocation failed\n"); 364 | return NULL; 365 | } 366 | node->type = AST_LITERAL; 367 | // DEBUG_PRINT("Add AST_LITERAL Node of %d", node->type); 368 | node->left = NULL; 369 | node->right = NULL; 370 | node->nextblock = NULL; 371 | strcpy(node->data.string_value, token.value); 372 | (*pos)++; 373 | return node; 374 | } else if (token.type == TOKEN_IDENTIFIER) { 375 | // Check for array access 376 | if ((*pos + 1) < token_count && 377 | tokens[*pos + 1].type == TOKEN_DELIMITER && 378 | tokens[*pos + 1].value[0] == '[') { 379 | return parse_array_access(tokens, pos, token_count); 380 | } else if ((*pos + 1) < token_count && 381 | tokens[*pos + 1].type == TOKEN_DELIMITER && 382 | tokens[*pos + 1].value[0] == '(') { 383 | // Function call 384 | char ident[MAX_TOKEN_LENGTH]; 385 | strcpy(ident, tokens[*pos].value); 386 | (*pos)++; 387 | 388 | // Parse arguments 389 | (*pos)++; 390 | ASTNode *arg_list = NULL; 391 | ASTNode **current = &arg_list; 392 | while (*pos < token_count && !(tokens[*pos].type == TOKEN_DELIMITER && tokens[*pos].value[0] == ')')) { 393 | ASTNode *arg = parse_expression(tokens, pos, token_count); 394 | if (arg == NULL) { 395 | printf("Error: Expected expression in function call arguments\n"); 396 | free_ast(arg_list); 397 | return NULL; 398 | } 399 | *current = arg; 400 | current = &arg->right; 401 | 402 | // Check for comma 403 | if (*pos < token_count && tokens[*pos].type == TOKEN_DELIMITER && tokens[*pos].value[0] == ',') { 404 | (*pos)++; 405 | } 406 | } 407 | 408 | // Expect ')' 409 | if (*pos >= token_count || !(tokens[*pos].type == TOKEN_DELIMITER && tokens[*pos].value[0] == ')')) { 410 | printf("Error: Expected ')' after function call arguments\n"); 411 | //free_ast(arg_list); 412 | return NULL; 413 | } 414 | (*pos)++; 415 | 416 | // Create function call node 417 | ASTNode *call_node = (ASTNode*)malloc(sizeof(ASTNode)); 418 | call_node->type = AST_FUNCTION_CALL; 419 | // DEBUG_PRINT("Add AST_FUNCTION_CALL Node of %d", call_node->type); 420 | call_node->left = call_node->right = NULL; 421 | call_node->nextblock = NULL; 422 | strcpy(call_node->data.func_call.name, ident); 423 | call_node->data.func_call.arguments = arg_list; 424 | //call_node->data.func_call.arguments = NULL; 425 | return call_node; 426 | } else { 427 | // Simple identifier 428 | ASTNode *node = (ASTNode*)malloc(sizeof(ASTNode)); 429 | if (node == NULL) { 430 | printf("Error: Memory allocation failed\n"); 431 | return NULL; 432 | } 433 | node->type = AST_IDENTIFIER; 434 | // DEBUG_PRINT("Add AST_IDENTIFIER Node of %d", node->type); 435 | node->left = NULL; 436 | node->right = NULL; 437 | node->nextblock = NULL; 438 | strcpy(node->data.identifier, token.value); 439 | (*pos)++; 440 | return node; 441 | } 442 | } else if (token.type == TOKEN_DELIMITER && token.value[0] == '(') { 443 | // Parenthesized expression 444 | (*pos)++; 445 | ASTNode *node = parse_expression(tokens, pos, token_count); 446 | if (node == NULL) { 447 | return NULL; 448 | } 449 | if (*pos >= token_count || 450 | tokens[*pos].type != TOKEN_DELIMITER || 451 | tokens[*pos].value[0] != ')') { 452 | printf("Error: Expected ')' after expression\n"); 453 | free_ast(node); 454 | return NULL; 455 | } 456 | (*pos)++; 457 | return node; 458 | } 459 | 460 | printf("Error: Unexpected token '%s' in term\n", token.value); 461 | return NULL; 462 | } 463 | 464 | // ASTNode* parse_comparison(Token tokens[], int *pos, int token_count) { 465 | // ASTNode *left = parse_phrase(tokens, pos, token_count); 466 | // if (left == NULL) { 467 | // return NULL; 468 | // } 469 | 470 | // while (*pos < token_count) { 471 | // Token token = tokens[*pos]; 472 | 473 | // OperatorType op_type; 474 | // int is_comparison = 0; 475 | 476 | // if (token.type == TOKEN_OPERATOR) { 477 | // if (strcmp(token.value, "<") == 0) { 478 | // op_type = OP_LESS_THAN; 479 | // is_comparison = 1; 480 | // } else if (strcmp(token.value, ">") == 0) { 481 | // op_type = OP_GREATER_THAN; 482 | // is_comparison = 1; 483 | // } else if (strcmp(token.value, "==") == 0) { 484 | // op_type = OP_EQUAL; 485 | // is_comparison = 1; 486 | // } else if (strcmp(token.value, "!=") == 0) { 487 | // op_type = OP_NOT_EQUAL; 488 | // is_comparison = 1; 489 | // } else if (strcmp(token.value, "<=") == 0) { 490 | // op_type = OP_LESS_EQUAL; 491 | // is_comparison = 1; 492 | // } else if (strcmp(token.value, ">=") == 0) { 493 | // op_type = OP_GREATER_EQUAL; 494 | // is_comparison = 1; 495 | // } 496 | // } 497 | 498 | // if (!is_comparison) { 499 | // break; // No more comparison operators 500 | // } 501 | 502 | // (*pos)++; // Consume operator 503 | // ASTNode *right = parse_phrase(tokens, pos, token_count); 504 | // if (right == NULL) { 505 | // free_ast(left); 506 | // return NULL; 507 | // } 508 | 509 | // // Create binary operation node 510 | // ASTNode *op_node = (ASTNode*)malloc(sizeof(ASTNode)); 511 | // op_node->type = AST_BINARY_OP; 512 | // // DEBUG_PRINT("Add AST_BINARY_OP Node of %d", op_node->type); 513 | // op_node->data.operator = op_type; 514 | // op_node->left = left; 515 | // op_node->right = right; 516 | // op_node->nextblock = NULL; 517 | 518 | // left = op_node; // Update left node for the next iteration 519 | // } 520 | 521 | // return left; 522 | // } 523 | 524 | // ASTNode* parse_expression(Token tokens[], int *pos, int token_count) { 525 | // ASTNode *left = parse_comparison(tokens, pos, token_count); 526 | // if (left == NULL) { 527 | // return NULL; 528 | // } 529 | 530 | // while (*pos < token_count) { 531 | // Token token = tokens[*pos]; 532 | 533 | // if (token.type == TOKEN_OPERATOR && (strcmp(token.value, "+") == 0 || strcmp(token.value, "-") == 0)) { 534 | // OperatorType op_type = (strcmp(token.value, "+") == 0) ? OP_ADD : OP_SUBTRACT; 535 | // (*pos)++; // Consume operator 536 | // ASTNode *right = parse_comparison(tokens, pos, token_count); 537 | // if (right == NULL) { 538 | // free_ast(left); 539 | // return NULL; 540 | // } 541 | 542 | // // Create binary operation node 543 | // ASTNode *op_node = (ASTNode*)malloc(sizeof(ASTNode)); 544 | // op_node->type = AST_BINARY_OP; 545 | // // DEBUG_PRINT("Add AST_BINARY_OP Node of %d", op_node->type); 546 | // op_node->data.operator = op_type; 547 | // op_node->left = left; 548 | // op_node->right = right; 549 | // op_node->nextblock = NULL; 550 | 551 | // left = op_node; // Update left node for the next iteration 552 | // } else { 553 | // break; // No more operators at this precedence level 554 | // } 555 | // } 556 | 557 | // return left; 558 | // } 559 | 560 | ASTNode* parse_expression(Token tokens[], int *pos, int token_count) { 561 | // comparisons have the lowest precedence after arithmetic 562 | return parse_comparison(tokens, pos, token_count); 563 | } 564 | 565 | ASTNode* parse_comparison(Token tokens[], int *pos, int token_count) { 566 | ASTNode *left = parse_additive(tokens, pos, token_count); 567 | if (left == NULL) { 568 | return NULL; 569 | } 570 | 571 | while (*pos < token_count && tokens[*pos].type == TOKEN_OPERATOR) { 572 | OperatorType op_type; 573 | int is_comparison = 0; 574 | 575 | if (strcmp(tokens[*pos].value, "<") == 0) { 576 | op_type = OP_LESS_THAN; 577 | is_comparison = 1; 578 | } else if (strcmp(tokens[*pos].value, ">") == 0) { 579 | op_type = OP_GREATER_THAN; 580 | is_comparison = 1; 581 | } else if (strcmp(tokens[*pos].value, "<=") == 0) { 582 | op_type = OP_LESS_EQUAL; 583 | is_comparison = 1; 584 | } else if (strcmp(tokens[*pos].value, ">=") == 0) { 585 | op_type = OP_GREATER_EQUAL; 586 | is_comparison = 1; 587 | } else if (strcmp(tokens[*pos].value, "==") == 0) { 588 | op_type = OP_EQUAL; 589 | is_comparison = 1; 590 | } else if (strcmp(tokens[*pos].value, "!=") == 0) { 591 | op_type = OP_NOT_EQUAL; 592 | is_comparison = 1; 593 | } 594 | 595 | if (!is_comparison) { 596 | // Not a comparison operator 597 | break; 598 | } 599 | 600 | (*pos)++; // consume operator 601 | ASTNode *right = parse_additive(tokens, pos, token_count); 602 | if (right == NULL) { 603 | free_ast(left); 604 | return NULL; 605 | } 606 | 607 | ASTNode *op_node = (ASTNode*)malloc(sizeof(ASTNode)); 608 | op_node->type = AST_BINARY_OP; 609 | op_node->data.operator = op_type; 610 | op_node->left = left; 611 | op_node->right = right; 612 | 613 | left = op_node; // chain comparisons if multiple 614 | } 615 | 616 | return left; 617 | } 618 | 619 | ASTNode* parse_additive(Token tokens[], int *pos, int token_count) { 620 | ASTNode *left = parse_term(tokens, pos, token_count); 621 | if (left == NULL) { 622 | return NULL; 623 | } 624 | 625 | while (*pos < token_count && tokens[*pos].type == TOKEN_OPERATOR) { 626 | if (strcmp(tokens[*pos].value, "+") == 0 || strcmp(tokens[*pos].value, "-") == 0) { 627 | OperatorType op_type; 628 | if (strcmp(tokens[*pos].value, "+") == 0) { 629 | op_type = OP_ADD; 630 | } else { 631 | op_type = OP_SUBTRACT; 632 | } 633 | 634 | (*pos)++; // Consume operator 635 | ASTNode *right = parse_term(tokens, pos, token_count); 636 | if (right == NULL) { 637 | free_ast(left); 638 | return NULL; 639 | } 640 | 641 | ASTNode *op_node = (ASTNode*)malloc(sizeof(ASTNode)); 642 | op_node->type = AST_BINARY_OP; 643 | op_node->data.operator = op_type; 644 | op_node->left = left; 645 | op_node->right = right; 646 | 647 | left = op_node; // Update left node 648 | } else { 649 | break; 650 | } 651 | } 652 | 653 | return left; 654 | } 655 | 656 | ASTNode* parse_term(Token tokens[], int *pos, int token_count) { 657 | ASTNode *left = parse_factor(tokens, pos, token_count); 658 | if (left == NULL) { 659 | return NULL; 660 | } 661 | 662 | while (*pos < token_count && tokens[*pos].type == TOKEN_OPERATOR) { 663 | if (strcmp(tokens[*pos].value, "*") == 0 || strcmp(tokens[*pos].value, "/") == 0) { 664 | OperatorType op_type; 665 | if (strcmp(tokens[*pos].value, "*") == 0) { 666 | op_type = OP_MULTIPLY; 667 | } else { 668 | op_type = OP_DIVIDE; 669 | } 670 | 671 | (*pos)++; // Consume operator 672 | ASTNode *right = parse_factor(tokens, pos, token_count); 673 | if (right == NULL) { 674 | free_ast(left); 675 | return NULL; 676 | } 677 | 678 | ASTNode *op_node = (ASTNode*)malloc(sizeof(ASTNode)); 679 | op_node->type = AST_BINARY_OP; 680 | op_node->data.operator = op_type; 681 | op_node->left = left; 682 | op_node->right = right; 683 | 684 | left = op_node; // Continue chaining 685 | } else { 686 | break; 687 | } 688 | } 689 | 690 | return left; 691 | } 692 | 693 | // ASTNode* parse_factor(Token tokens[], int *pos, int token_count) { 694 | // if (*pos >= token_count) { 695 | // printf("Error: Unexpected end of input in factor\n"); 696 | // return NULL; 697 | // } 698 | 699 | // Token token = tokens[*pos]; 700 | 701 | // // Parenthesized expression 702 | // if (token.type == TOKEN_DELIMITER && token.value[0] == '(') { 703 | // (*pos)++; 704 | // ASTNode *node = parse_expression(tokens, pos, token_count); 705 | // if (node == NULL) { 706 | // return NULL; 707 | // } 708 | // // Expect ')' 709 | // if (*pos >= token_count || tokens[*pos].type != TOKEN_DELIMITER || tokens[*pos].value[0] != ')') { 710 | // printf("Error: Expected ')' after expression\n"); 711 | // free_ast(node); 712 | // return NULL; 713 | // } 714 | // (*pos)++; 715 | // return node; 716 | // } 717 | 718 | // // Number or String literal 719 | // if (token.type == TOKEN_NUMBER || token.type == TOKEN_STRING) { 720 | // ASTNode *node = (ASTNode*)malloc(sizeof(ASTNode)); 721 | // node->type = AST_LITERAL; 722 | // node->left = node->right = NULL; 723 | // strcpy(node->data.string_value, token.value); 724 | // (*pos)++; 725 | // return node; 726 | // } 727 | 728 | // // Identifier or Function call 729 | // if (token.type == TOKEN_IDENTIFIER) { 730 | // char ident[MAX_TOKEN_LENGTH]; 731 | // strcpy(ident, token.value); 732 | // (*pos)++; 733 | 734 | // // Check for function call 735 | // if (*pos < token_count && tokens[*pos].type == TOKEN_DELIMITER && tokens[*pos].value[0] == '(') { 736 | // (*pos)++; 737 | // // Parse arguments 738 | // ASTNode *arg_list = NULL; 739 | // ASTNode **current = &arg_list; 740 | // while (*pos < token_count && !(tokens[*pos].type == TOKEN_DELIMITER && tokens[*pos].value[0] == ')')) { 741 | // ASTNode *arg = parse_expression(tokens, pos, token_count); 742 | // if (arg == NULL) { 743 | // free_ast(arg_list); 744 | // return NULL; 745 | // } 746 | // *current = arg; 747 | // current = &arg->right; 748 | 749 | // // Check for comma 750 | // if (*pos < token_count && tokens[*pos].type == TOKEN_DELIMITER && tokens[*pos].value[0] == ',') { 751 | // (*pos)++; 752 | // } 753 | // } 754 | 755 | // // Expect ')' 756 | // if (*pos >= token_count || !(tokens[*pos].type == TOKEN_DELIMITER && tokens[*pos].value[0] == ')')) { 757 | // printf("Error: Expected ')' after function call arguments\n"); 758 | // free_ast(arg_list); 759 | // return NULL; 760 | // } 761 | // (*pos)++; 762 | 763 | // // Create function call node 764 | // ASTNode *call_node = (ASTNode*)malloc(sizeof(ASTNode)); 765 | // call_node->type = AST_FUNCTION_CALL; 766 | // call_node->left = call_node->right = NULL; 767 | // strcpy(call_node->data.func_call.name, ident); 768 | // call_node->data.func_call.arguments = arg_list; 769 | // return call_node; 770 | // } else { 771 | // // Just a variable (identifier) 772 | // ASTNode *node = (ASTNode*)malloc(sizeof(ASTNode)); 773 | // node->type = AST_IDENTIFIER; 774 | // node->left = node->right = NULL; 775 | // strcpy(node->data.identifier, ident); 776 | // return node; 777 | // } 778 | // } 779 | 780 | // printf("Error: Unexpected token '%s' in factor\n", token.value); 781 | // return NULL; 782 | // } 783 | 784 | ASTNode* parse_factor(Token tokens[], int *pos, int token_count) { 785 | if (*pos >= token_count) { 786 | printf("Error: Unexpected end of input in factor\n"); 787 | return NULL; 788 | } 789 | 790 | Token token = tokens[*pos]; 791 | 792 | // Parenthesized expression 793 | if (token.type == TOKEN_DELIMITER && token.value[0] == '(') { 794 | (*pos)++; 795 | ASTNode *node = parse_expression(tokens, pos, token_count); 796 | if (node == NULL) return NULL; 797 | 798 | // Expect ')' 799 | if (*pos >= token_count || tokens[*pos].type != TOKEN_DELIMITER || tokens[*pos].value[0] != ')') { 800 | printf("Error: Expected ')' after expression\n"); 801 | free_ast(node); 802 | return NULL; 803 | } 804 | (*pos)++; 805 | return node; 806 | } 807 | 808 | // Number or String literal 809 | if (token.type == TOKEN_NUMBER || token.type == TOKEN_STRING) { 810 | ASTNode *node = (ASTNode*)malloc(sizeof(ASTNode)); 811 | node->type = AST_LITERAL; 812 | node->left = node->right = NULL; 813 | strcpy(node->data.string_value, token.value); 814 | (*pos)++; 815 | return node; 816 | } 817 | 818 | // Identifier or Function call or Array access 819 | if (token.type == TOKEN_IDENTIFIER) { 820 | char ident[MAX_TOKEN_LENGTH]; 821 | strcpy(ident, token.value); 822 | (*pos)++; 823 | 824 | // Check for function call (identifier followed by '(') 825 | if (*pos < token_count && tokens[*pos].type == TOKEN_DELIMITER && tokens[*pos].value[0] == '(') { 826 | (*pos)++; 827 | // Parse arguments 828 | ASTNode *arg_list = NULL; 829 | ASTNode **current = &arg_list; 830 | while (*pos < token_count && !(tokens[*pos].type == TOKEN_DELIMITER && tokens[*pos].value[0] == ')')) { 831 | ASTNode *arg = parse_expression(tokens, pos, token_count); 832 | if (arg == NULL) { 833 | free_ast(arg_list); 834 | return NULL; 835 | } 836 | *current = arg; 837 | current = &arg->right; 838 | 839 | // Check for comma 840 | if (*pos < token_count && tokens[*pos].type == TOKEN_DELIMITER && tokens[*pos].value[0] == ',') { 841 | (*pos)++; 842 | } 843 | } 844 | 845 | // Expect ')' 846 | if (*pos >= token_count || !(tokens[*pos].type == TOKEN_DELIMITER && tokens[*pos].value[0] == ')')) { 847 | printf("Error: Expected ')' after function call arguments\n"); 848 | free_ast(arg_list); 849 | return NULL; 850 | } 851 | (*pos)++; 852 | 853 | // Create function call node 854 | ASTNode *call_node = (ASTNode*)malloc(sizeof(ASTNode)); 855 | call_node->type = AST_FUNCTION_CALL; 856 | call_node->left = call_node->right = NULL; 857 | strcpy(call_node->data.func_call.name, ident); 858 | call_node->data.func_call.arguments = arg_list; 859 | return call_node; 860 | } 861 | 862 | // Check for array access (identifier followed by '[') 863 | if (*pos < token_count && tokens[*pos].type == TOKEN_DELIMITER && tokens[*pos].value[0] == '[') { 864 | (*pos)++; 865 | // Parse the index expression inside [] 866 | ASTNode *index_expr = parse_expression(tokens, pos, token_count); 867 | if (index_expr == NULL) { 868 | return NULL; 869 | } 870 | 871 | // Expect ']' 872 | if (*pos >= token_count || tokens[*pos].type != TOKEN_DELIMITER || tokens[*pos].value[0] != ']') { 873 | printf("Error: Expected ']' after array index\n"); 874 | free_ast(index_expr); 875 | return NULL; 876 | } 877 | (*pos)++; 878 | 879 | // Create AST_ARRAY_ACCESS node 880 | ASTNode *access_node = (ASTNode*)malloc(sizeof(ASTNode)); 881 | access_node->type = AST_ARRAY_ACCESS; 882 | strcpy(access_node->data.identifier, ident); 883 | access_node->left = index_expr; 884 | access_node->right = NULL; 885 | return access_node; 886 | } 887 | 888 | // Just a variable (identifier) 889 | ASTNode *node = (ASTNode*)malloc(sizeof(ASTNode)); 890 | node->type = AST_IDENTIFIER; 891 | node->left = node->right = NULL; 892 | strcpy(node->data.identifier, ident); 893 | return node; 894 | } 895 | 896 | printf("Error: Unexpected token '%s' in factor\n", token.value); 897 | return NULL; 898 | } 899 | 900 | ASTNode* parse_print_statement(Token tokens[], int *pos, int token_count) { 901 | if (tokens[*pos].type == TOKEN_KEYWORD && strcmp(tokens[*pos].value, "print") == 0) { 902 | (*pos)++; 903 | if (*pos < token_count && tokens[*pos].type == TOKEN_DELIMITER && tokens[*pos].value[0] == '(') { 904 | (*pos)++; 905 | // Parse the expression inside the parentheses 906 | ASTNode *expr = parse_expression(tokens, pos, token_count); 907 | if (expr == NULL) { 908 | printf("Error: Expected expression after 'print('\n"); 909 | return NULL; 910 | } 911 | if (*pos < token_count && tokens[*pos].type == TOKEN_DELIMITER && tokens[*pos].value[0] == ')') { 912 | (*pos)++; 913 | // Successfully parsed 'print' statement 914 | ASTNode *node = (ASTNode*)malloc(sizeof(ASTNode)); 915 | node->type = AST_PRINT; 916 | // DEBUG_PRINT("Add AST_PRINT Node of %d", node->type); 917 | node->left = expr; // Expression to print 918 | node->right = NULL; 919 | node->nextblock = NULL; 920 | return node; 921 | } else { 922 | printf("Error: Expected ')' after expression\n"); 923 | free_ast(expr); 924 | return NULL; 925 | } 926 | } else { 927 | printf("Error: Expected '(' after 'print'\n"); 928 | return NULL; 929 | } 930 | } 931 | return NULL; 932 | } 933 | 934 | ASTNode* parse_if_statement(Token tokens[], int *pos, int token_count) { 935 | if (tokens[*pos].type == TOKEN_KEYWORD && strcmp(tokens[*pos].value, "if") == 0) { 936 | (*pos)++; 937 | // Parse the condition expression 938 | ASTNode *condition = parse_expression(tokens, pos, token_count); 939 | if (condition == NULL) { 940 | printf("Error: Expected condition after 'if'\n"); 941 | return NULL; 942 | } 943 | // Parse the 'then' branch 944 | ASTNode *then_branch = parse_block(tokens, pos, token_count); 945 | if (then_branch == NULL) { 946 | printf("Error: Expected block after 'if' condition\n"); 947 | free_ast(condition); 948 | return NULL; 949 | } 950 | // Check for 'else' clause 951 | ASTNode *else_branch = NULL; 952 | if (*pos < token_count && tokens[*pos].type == TOKEN_KEYWORD && strcmp(tokens[*pos].value, "else") == 0) { 953 | (*pos)++; 954 | else_branch = parse_block(tokens, pos, token_count); 955 | if (else_branch == NULL) { 956 | printf("Error: Expected block after 'else'\n"); 957 | free_ast(condition); 958 | free_ast(then_branch); 959 | return NULL; 960 | } 961 | } 962 | // Expect 'end' keyword 963 | if (*pos < token_count && tokens[*pos].type == TOKEN_KEYWORD && strcmp(tokens[*pos].value, "end") == 0) { 964 | (*pos)++; 965 | // Create the if statement node 966 | ASTNode *node = (ASTNode*)malloc(sizeof(ASTNode)); 967 | node->type = AST_IF_STATEMENT; 968 | // DEBUG_PRINT("Add AST_IF_STATEMENT Node of %d", node->type); 969 | node->left = NULL; 970 | node->right = NULL; 971 | node->nextblock = NULL; 972 | node->data.if_stmt.condition = condition; 973 | node->data.if_stmt.then_branch = then_branch; 974 | node->data.if_stmt.else_branch = else_branch; 975 | return node; 976 | } else { 977 | printf("Error: Expected 'end' after 'if' statement\n"); 978 | free_ast(condition); 979 | free_ast(then_branch); 980 | if (else_branch) free_ast(else_branch); 981 | return NULL; 982 | } 983 | } 984 | return NULL; 985 | } 986 | 987 | ASTNode* parse_for_statement(Token tokens[], int *pos, int token_count) { 988 | // Expect 'for' 989 | if (*pos < token_count && tokens[*pos].type == TOKEN_KEYWORD && strcmp(tokens[*pos].value, "for") == 0) { 990 | (*pos)++; 991 | 992 | // Expect identifier for loop variable 993 | if (*pos >= token_count || tokens[*pos].type != TOKEN_IDENTIFIER) { 994 | printf("Error: Expected identifier after 'for'\n"); 995 | return NULL; 996 | } 997 | char loop_var[MAX_TOKEN_LENGTH]; 998 | strcpy(loop_var, tokens[*pos].value); 999 | (*pos)++; 1000 | 1001 | // Expect 'in' 1002 | if (*pos >= token_count || tokens[*pos].type != TOKEN_KEYWORD || strcmp(tokens[*pos].value, "in") != 0) { 1003 | printf("Error: Expected 'in' after loop variable\n"); 1004 | return NULL; 1005 | } 1006 | (*pos)++; 1007 | 1008 | // Parse expression that should yield an array 1009 | ASTNode *expr = parse_expression(tokens, pos, token_count); 1010 | if (expr == NULL) { 1011 | printf("Error: Expected expression after 'in'\n"); 1012 | return NULL; 1013 | } 1014 | 1015 | // Parse the block of statements until 'end' 1016 | ASTNode *body = parse_block(tokens, pos, token_count); 1017 | if (body == NULL) { 1018 | printf("Error: Expected block after 'for' statement\n"); 1019 | free_ast(expr); 1020 | return NULL; 1021 | } 1022 | 1023 | // Expect 'end' 1024 | if (*pos >= token_count || tokens[*pos].type != TOKEN_KEYWORD || strcmp(tokens[*pos].value, "end") != 0) { 1025 | printf("Error: Expected 'end' after 'for' block\n"); 1026 | free_ast(expr); 1027 | free_ast(body); 1028 | return NULL; 1029 | } 1030 | (*pos)++; 1031 | 1032 | // Create the for statement node 1033 | ASTNode *node = (ASTNode*)malloc(sizeof(ASTNode)); 1034 | node->type = AST_FOR_STATEMENT; 1035 | // DEBUG_PRINT("Add AST_FOR_STATEMENT Node of %d", node->type); 1036 | node->left = node->right = NULL; 1037 | node->nextblock = NULL; 1038 | strcpy(node->data.for_stmt.loop_var, loop_var); 1039 | node->data.for_stmt.expression = expr; 1040 | node->data.for_stmt.body = body; 1041 | return node; 1042 | } 1043 | 1044 | return NULL; // Not a for statement 1045 | } 1046 | 1047 | ASTNode* parse_while_statement(Token tokens[], int *pos, int token_count) { 1048 | if (*pos < token_count && tokens[*pos].type == TOKEN_KEYWORD && strcmp(tokens[*pos].value, "while") == 0) { 1049 | (*pos)++; 1050 | 1051 | // Parse the condition expression 1052 | ASTNode *condition = parse_expression(tokens, pos, token_count); 1053 | if (condition == NULL) { 1054 | printf("Error: Expected condition after 'while'\n"); 1055 | return NULL; 1056 | } 1057 | 1058 | // Parse the block of statements until 'end' 1059 | ASTNode *body = parse_block(tokens, pos, token_count); 1060 | if (body == NULL) { 1061 | printf("Error: Expected block after 'while' condition\n"); 1062 | free_ast(condition); 1063 | return NULL; 1064 | } 1065 | 1066 | // Expect 'end' 1067 | if (*pos >= token_count || tokens[*pos].type != TOKEN_KEYWORD || strcmp(tokens[*pos].value, "end") != 0) { 1068 | printf("Error: Expected 'end' after 'while' block\n"); 1069 | free_ast(condition); 1070 | free_ast(body); 1071 | return NULL; 1072 | } 1073 | (*pos)++; 1074 | 1075 | // Create the while statement node 1076 | ASTNode *node = (ASTNode*)malloc(sizeof(ASTNode)); 1077 | node->type = AST_WHILE_STATEMENT; 1078 | // DEBUG_PRINT("Add AST_WHILE_STATEMENT Node of %d", node->type); 1079 | node->left = node->right = NULL; 1080 | node->nextblock = NULL; 1081 | node->data.while_stmt.condition = condition; 1082 | node->data.while_stmt.body = body; 1083 | return node; 1084 | } 1085 | 1086 | return NULL; // Not a while statement 1087 | } 1088 | 1089 | ASTNode* parse_function_definition(Token tokens[], int *pos, int token_count) { 1090 | if (*pos < token_count && tokens[*pos].type == TOKEN_KEYWORD && strcmp(tokens[*pos].value, "def") == 0) { 1091 | (*pos)++; 1092 | // Expect function name 1093 | if (*pos >= token_count || tokens[*pos].type != TOKEN_IDENTIFIER) { 1094 | printf("Error: Expected function name after 'def'\n"); 1095 | return NULL; 1096 | } 1097 | 1098 | char func_name[MAX_TOKEN_LENGTH]; 1099 | strcpy(func_name, tokens[*pos].value); 1100 | (*pos)++; 1101 | 1102 | // Parse parameter list 1103 | // Expect '(' 1104 | if (*pos >= token_count || tokens[*pos].type != TOKEN_DELIMITER || tokens[*pos].value[0] != '(') { 1105 | printf("Error: Expected '(' after function name\n"); 1106 | return NULL; 1107 | } 1108 | (*pos)++; 1109 | 1110 | // Parse parameters (identifiers separated by commas) 1111 | ASTNode *param_list = NULL; 1112 | ASTNode **current = ¶m_list; 1113 | while (*pos < token_count && !(tokens[*pos].type == TOKEN_DELIMITER && tokens[*pos].value[0] == ')')) { 1114 | if (tokens[*pos].type == TOKEN_IDENTIFIER) { 1115 | ASTNode *param = (ASTNode*)malloc(sizeof(ASTNode)); 1116 | param->type = AST_IDENTIFIER; 1117 | // DEBUG_PRINT("Add AST_IDENTIFIER Node of %d", param->type); 1118 | strcpy(param->data.identifier, tokens[*pos].value); 1119 | param->left = param->right = NULL; 1120 | param->nextblock = NULL; 1121 | (*pos)++; 1122 | *current = param; 1123 | current = ¶m->right; 1124 | 1125 | // Check for comma 1126 | if (*pos < token_count && tokens[*pos].type == TOKEN_DELIMITER && tokens[*pos].value[0] == ',') { 1127 | (*pos)++; 1128 | continue; 1129 | } 1130 | } else { 1131 | printf("Error: Expected parameter name or ')' in function definition\n"); 1132 | free_ast(param_list); 1133 | return NULL; 1134 | } 1135 | } 1136 | 1137 | // Expect ')' 1138 | if (*pos >= token_count || tokens[*pos].type != TOKEN_DELIMITER || tokens[*pos].value[0] != ')') { 1139 | printf("Error: Expected ')' after parameters\n"); 1140 | free_ast(param_list); 1141 | return NULL; 1142 | } 1143 | (*pos)++; 1144 | 1145 | // Parse the body block until 'end' 1146 | ASTNode *body = parse_block(tokens, pos, token_count); 1147 | if (body == NULL) { 1148 | printf("Error: Expected block after function definition\n"); 1149 | free_ast(param_list); 1150 | return NULL; 1151 | } 1152 | 1153 | // Expect 'end' 1154 | if (*pos >= token_count || tokens[*pos].type != TOKEN_KEYWORD || strcmp(tokens[*pos].value, "end") != 0) { 1155 | printf("Error: Expected 'end' after function body\n"); 1156 | free_ast(param_list); 1157 | free_ast(body); 1158 | return NULL; 1159 | } 1160 | (*pos)++; 1161 | 1162 | // Create function definition node 1163 | ASTNode *node = (ASTNode*)malloc(sizeof(ASTNode)); 1164 | node->type = AST_FUNCTION_DEFINITION; 1165 | // DEBUG_PRINT("Add AST_FUNCTION_DEFINITION Node of %d", node->type); 1166 | node->left = node->right = NULL; 1167 | node->nextblock = NULL; 1168 | strcpy(node->data.func_def.name, func_name); 1169 | node->data.func_def.parameters = param_list; 1170 | node->data.func_def.body = body; 1171 | 1172 | // After creating the AST_FUNCTION_DEFINITION node in parse_function_definition: 1173 | if (function_count < MAX_FUNCTIONS) { 1174 | strcpy(functions[function_count].name, node->data.func_def.name); 1175 | functions[function_count].parameters = node->data.func_def.parameters; 1176 | functions[function_count].body = node->data.func_def.body; 1177 | function_count++; 1178 | } else { 1179 | printf("Error: Too many functions defined\n"); 1180 | } 1181 | return node; 1182 | } 1183 | 1184 | return NULL; 1185 | } 1186 | 1187 | ASTNode* parse_return_statement(Token tokens[], int *pos, int token_count) { 1188 | if (*pos < token_count && tokens[*pos].type == TOKEN_KEYWORD && strcmp(tokens[*pos].value, "return") == 0) { 1189 | (*pos)++; 1190 | // Parse expression after return 1191 | ASTNode *expr = parse_expression(tokens, pos, token_count); 1192 | if (expr == NULL) { 1193 | // No expression means return 0 1194 | // We'll handle this by setting expr to a literal 0 node 1195 | ASTNode *zero_node = (ASTNode*)malloc(sizeof(ASTNode)); 1196 | zero_node->type = AST_LITERAL; 1197 | // DEBUG_PRINT("Add AST_LITERAL Node of %d", zero_node->type); 1198 | zero_node->left = zero_node->right = NULL; 1199 | zero_node->nextblock = NULL; 1200 | strcpy(zero_node->data.string_value, "0"); 1201 | expr = zero_node; 1202 | } 1203 | ASTNode *node = (ASTNode*)malloc(sizeof(ASTNode)); 1204 | node->type = AST_RETURN_STATEMENT; 1205 | // DEBUG_PRINT("Add AST_RETURN_STATEMENT Node of %d", node->type); 1206 | node->left = node->right = NULL; 1207 | node->nextblock = NULL; 1208 | node->data.ret_stmt.expression = expr; 1209 | return node; 1210 | } 1211 | return NULL; 1212 | } 1213 | 1214 | ASTNode* parse_function_call(Token tokens[], int *pos, int token_count) { 1215 | if (tokens[*pos].type == TOKEN_IDENTIFIER) { 1216 | if ((*pos + 1) < token_count && 1217 | tokens[*pos + 1].type == TOKEN_DELIMITER && 1218 | tokens[*pos + 1].value[0] == '(') { 1219 | // Function call 1220 | char ident[MAX_TOKEN_LENGTH]; 1221 | strcpy(ident, tokens[*pos].value); 1222 | (*pos)++; 1223 | 1224 | // Parse arguments 1225 | (*pos)++; 1226 | ASTNode *arg_list = NULL; 1227 | ASTNode **current = &arg_list; 1228 | while (*pos < token_count && !(tokens[*pos].type == TOKEN_DELIMITER && tokens[*pos].value[0] == ')')) { 1229 | ASTNode *arg = parse_expression(tokens, pos, token_count); 1230 | if (arg == NULL) { 1231 | printf("Error: Expected expression in function call arguments\n"); 1232 | free_ast(arg_list); 1233 | return NULL; 1234 | } 1235 | *current = arg; 1236 | current = &arg->right; 1237 | 1238 | // Check for comma 1239 | if (*pos < token_count && tokens[*pos].type == TOKEN_DELIMITER && tokens[*pos].value[0] == ',') { 1240 | (*pos)++; 1241 | } 1242 | } 1243 | 1244 | // Expect ')' 1245 | if (*pos >= token_count || !(tokens[*pos].type == TOKEN_DELIMITER && tokens[*pos].value[0] == ')')) { 1246 | printf("Error: Expected ')' after function call arguments\n"); 1247 | //free_ast(arg_list); 1248 | return NULL; 1249 | } 1250 | (*pos)++; 1251 | 1252 | // Create function call node 1253 | ASTNode *call_node = (ASTNode*)malloc(sizeof(ASTNode)); 1254 | call_node->type = AST_FUNCTION_CALL; 1255 | // DEBUG_PRINT("Add AST_FUNCTION_CALL Node of %d", call_node->type); 1256 | call_node->left = call_node->right = NULL; 1257 | call_node->nextblock = NULL; 1258 | strcpy(call_node->data.func_call.name, ident); 1259 | call_node->data.func_call.arguments = arg_list; 1260 | //call_node->data.func_call.arguments = NULL; 1261 | return call_node; 1262 | } 1263 | } 1264 | 1265 | return NULL; // Not a function call 1266 | } 1267 | 1268 | ASTNode* parse_statement(Token tokens[], int *pos, int token_count) { 1269 | ASTNode *node = NULL; 1270 | 1271 | if (*pos >= token_count) return NULL; 1272 | // DEBUG_PRINT(">>> %s", tokens[*pos].value); 1273 | // Check if it's a for statement 1274 | node = parse_for_statement(tokens, pos, token_count); 1275 | if (node != NULL) { 1276 | return node; 1277 | } 1278 | 1279 | // Try to parse an 'if' statement 1280 | node = parse_if_statement(tokens, pos, token_count); 1281 | if (node != NULL) { 1282 | return node; 1283 | } 1284 | 1285 | // Try while statement 1286 | node = parse_while_statement(tokens, pos, token_count); 1287 | if (node != NULL) return node; 1288 | 1289 | // Try to parse a function definition 1290 | node = parse_function_definition(tokens, pos, token_count); 1291 | if (node != NULL) { 1292 | return node; 1293 | } 1294 | 1295 | // Try to parse a return in a function 1296 | node = parse_return_statement(tokens, pos, token_count); 1297 | if (node != NULL) { 1298 | return node; 1299 | } 1300 | 1301 | // Try to parse a function call 1302 | // Note this must be tried before parse_assignment_statement() as both 1303 | // start with an TOKEN_IDENTIFIER 1304 | node = parse_function_call(tokens, pos, token_count); 1305 | if (node != NULL) { 1306 | return node; 1307 | } 1308 | 1309 | // Try to parse a 'print' statement 1310 | node = parse_print_statement(tokens, pos, token_count); 1311 | if (node != NULL) { 1312 | return node; 1313 | } 1314 | 1315 | // Try to parse an assignment statement 1316 | node = parse_assignment_statement(tokens, pos, token_count); 1317 | if (node != NULL) { 1318 | return node; 1319 | } 1320 | 1321 | // Unrecognized statement 1322 | printf("Error: Unrecognized statement starting with '%s'\n", tokens[*pos].value); 1323 | return NULL; 1324 | } 1325 | 1326 | ASTNode* parse_block(Token tokens[], int *pos, int token_count) { 1327 | ASTNode *statements = NULL; // This will be a linked list of statements 1328 | ASTNode **current = &statements; 1329 | 1330 | while (*pos < token_count) { 1331 | if (tokens[*pos].type == TOKEN_KEYWORD && 1332 | (strcmp(tokens[*pos].value, "else") == 0 || strcmp(tokens[*pos].value, "end") == 0)) { 1333 | // End of the block 1334 | break; 1335 | } 1336 | 1337 | ASTNode *stmt = parse_statement(tokens, pos, token_count); 1338 | if (stmt == NULL) { 1339 | printf("Error: Failed to parse statement in block\n"); 1340 | free_ast(statements); 1341 | return NULL; 1342 | } 1343 | 1344 | *current = stmt; 1345 | //current = &(stmt->right); // Use the 'right' pointer to link statements 1346 | current = &(stmt->nextblock); // Use the 'nextblock' pointer to link statements 1347 | } 1348 | 1349 | return statements; 1350 | } 1351 | 1352 | void execute_if_statement(ASTNode *node) { 1353 | if (node == NULL || node->type != AST_IF_STATEMENT) return; 1354 | 1355 | EvalResult condition_result; 1356 | if (!evaluate_expression(node->data.if_stmt.condition, &condition_result, EVAL_ARITHMETIC)) { 1357 | printf("Error: Failed to evaluate condition in if statement\n"); 1358 | return; 1359 | } 1360 | 1361 | // Interpret any non-zero number as true 1362 | int condition_true = 0; 1363 | if (condition_result.type == RESULT_NUMBER) { 1364 | condition_true = (condition_result.number_value != 0); 1365 | } else if (condition_result.type == RESULT_STRING) { 1366 | // Empty string is false, non-empty string is true 1367 | condition_true = (strlen(condition_result.string_value) > 0); 1368 | } else { 1369 | printf("Error: Invalid condition type in if statement\n"); 1370 | return; 1371 | } 1372 | 1373 | if (condition_true) { 1374 | // Execute the then branch 1375 | execute_block(node->data.if_stmt.then_branch); 1376 | } else if (node->data.if_stmt.else_branch != NULL) { 1377 | // Execute the else branch 1378 | execute_block(node->data.if_stmt.else_branch); 1379 | } 1380 | } 1381 | 1382 | void execute_for_statement(ASTNode *node) { 1383 | if (node == NULL || node->type != AST_FOR_STATEMENT) return; 1384 | // DEBUG_PRINT("execute_for_statement"); 1385 | // Evaluate the expression to get the array 1386 | EvalResult result; 1387 | if (!evaluate_expression(node->data.for_stmt.expression, &result, EVAL_PRINT)) { 1388 | printf("Error: Failed to evaluate expression in for statement\n"); 1389 | return; 1390 | } 1391 | // DEBUG_PRINT("result.type %d", result.type); 1392 | AssocArray temp_array; 1393 | init_assoc_array(&temp_array); 1394 | 1395 | if (result.type == RESULT_ASSOC_ARRAY) { 1396 | // Use the existing associative array 1397 | // We'll just reference result.array_value directly 1398 | } else if (result.type == RESULT_STRING) { 1399 | // Wrap the single string in an associative array 1400 | set_assoc_array_value(&temp_array, "", result.string_value); 1401 | result.type = RESULT_ASSOC_ARRAY; 1402 | result.array_value = &temp_array; 1403 | } else if (result.type == RESULT_NUMBER) { 1404 | // Convert the number to a string and wrap it 1405 | char num_str[MAX_TOKEN_LENGTH]; 1406 | snprintf(num_str, MAX_TOKEN_LENGTH, "%g", result.number_value); 1407 | set_assoc_array_value(&temp_array, "", num_str); 1408 | result.type = RESULT_ASSOC_ARRAY; 1409 | result.array_value = &temp_array; 1410 | } else { 1411 | printf("Error: For loop expression must be a variable or array\n"); 1412 | return; 1413 | } 1414 | 1415 | // Now we have an associative array in result.array_value 1416 | AssocArray *array = result.array_value; 1417 | 1418 | // Iterate over each key-value pair in the array 1419 | for (int i = 0; i < array->size; i++) { 1420 | // Assign the value to the loop variable 1421 | set_variable_value(node->data.for_stmt.loop_var, array->pairs[i].key, array->pairs[i].value); 1422 | 1423 | // Execute the body 1424 | // DEBUG_PRINT("About to execute_block"); 1425 | execute_block(node->data.for_stmt.body); 1426 | 1427 | // Clear the loop_var before each iteration 1428 | clear_variable_assoc_array(node->data.for_stmt.loop_var); 1429 | } 1430 | 1431 | // If we used a temporary array, free it 1432 | if (result.array_value == &temp_array) { 1433 | free_assoc_array(&temp_array); 1434 | } 1435 | } 1436 | 1437 | void execute_while_statement(ASTNode *node) { 1438 | if (node == NULL || node->type != AST_WHILE_STATEMENT) return; 1439 | 1440 | while (1) { 1441 | EvalResult condition_result; 1442 | // Evaluate condition in arithmetic context (to handle numbers easily) 1443 | if (!evaluate_expression(node->data.while_stmt.condition, &condition_result, EVAL_ARITHMETIC)) { 1444 | printf("Error: Failed to evaluate condition in while statement\n"); 1445 | return; 1446 | } 1447 | 1448 | int condition_true = 0; 1449 | if (condition_result.type == RESULT_NUMBER) { 1450 | condition_true = (condition_result.number_value != 0); 1451 | } else if (condition_result.type == RESULT_STRING) { 1452 | // Empty string = false, non-empty = true 1453 | condition_true = (strlen(condition_result.string_value) > 0); 1454 | } else { 1455 | // Associative arrays, or other types: treat as true if non-empty? 1456 | // For simplicity, treat arrays as true if they have at least one element. 1457 | // If you want different logic, define it here. 1458 | if (condition_result.type == RESULT_ASSOC_ARRAY) { 1459 | condition_true = (condition_result.array_value->size > 0); 1460 | } else { 1461 | condition_true = 0; // Treat as false 1462 | } 1463 | } 1464 | 1465 | if (!condition_true) { 1466 | break; // Exit loop if condition is false 1467 | } 1468 | 1469 | // Execute the body block 1470 | execute_block(node->data.while_stmt.body); 1471 | } 1472 | } 1473 | 1474 | void execute_block(ASTNode *node) { 1475 | while (node != NULL) { 1476 | // DEBUG_PRINT("execute_block type %d", node->type); 1477 | // DEBUG_PRINT("execute_block left %p", node->left); 1478 | // DEBUG_PRINT("execute_block right %p", node->right); 1479 | execute_ast(node); 1480 | //node = node->right; // Move to the next statement in the block 1481 | node = node->nextblock; // Move to the next statement in the block 1482 | } 1483 | } 1484 | 1485 | void execute_ast(ASTNode *node) 1486 | { 1487 | if (node == NULL) 1488 | return; 1489 | 1490 | // printf("execute_ast %d\n", node->type); 1491 | 1492 | switch (node->type) { 1493 | case AST_PRINT: 1494 | // Evaluate the expression and print the result 1495 | evaluate_and_print(node->left); 1496 | break; 1497 | case AST_ASSIGNMENT: 1498 | execute_assignment(node); 1499 | break; 1500 | case AST_IF_STATEMENT: 1501 | execute_if_statement(node); 1502 | break; 1503 | case AST_BLOCK: 1504 | execute_block(node); 1505 | break; 1506 | case AST_FOR_STATEMENT: 1507 | execute_for_statement(node); 1508 | break; 1509 | case AST_WHILE_STATEMENT: 1510 | execute_while_statement(node); 1511 | break; 1512 | case AST_FUNCTION_DEFINITION: 1513 | // Already handled at parse time; no run-time needed unless we allow redef. 1514 | break; 1515 | case AST_FUNCTION_CALL: { 1516 | FunctionReturn call_res = execute_function_call(node); 1517 | // If called as a statement, ignore return value 1518 | break; 1519 | } 1520 | default: 1521 | printf("Error: While executing the AST - Unknown AST node type (%d)\n", node->type); 1522 | break; 1523 | } 1524 | } 1525 | 1526 | FunctionReturn execute_ast_with_return(ASTNode *node) { 1527 | FunctionReturn result = {0}; 1528 | if (node == NULL) return result; 1529 | 1530 | switch (node->type) { 1531 | // handle statements 1532 | case AST_PRINT: 1533 | evaluate_and_print(node->left); 1534 | break; 1535 | case AST_ASSIGNMENT: 1536 | execute_assignment(node); 1537 | break; 1538 | // case AST_IF_STATEMENT: 1539 | // return execute_if_statement_with_return(node); 1540 | // case AST_FOR_STATEMENT: 1541 | // return execute_for_statement_with_return(node); 1542 | // case AST_WHILE_STATEMENT: 1543 | // return execute_while_statement_with_return(node); 1544 | case AST_FUNCTION_DEFINITION: 1545 | // Already handled at parse time; no run-time needed unless we allow redef. 1546 | break; 1547 | case AST_FUNCTION_CALL: { 1548 | FunctionReturn call_res = execute_function_call(node); 1549 | // If called as a statement, ignore return value 1550 | break; 1551 | } 1552 | case AST_RETURN_STATEMENT: { 1553 | // Evaluate the return expression 1554 | EvalResult val; 1555 | if (!evaluate_expression(node->data.ret_stmt.expression, &val, EVAL_ARITHMETIC)) { 1556 | printf("Error: Failed to evaluate return expression\n"); 1557 | // return 0 by default 1558 | result.has_return = 1; 1559 | //result.return_is_number = 1; 1560 | result.type = RESULT_NUMBER; 1561 | result.number_value = 0; 1562 | //strcpy(result.return_value, "0"); 1563 | return result; 1564 | } 1565 | result.has_return = 1; 1566 | if (val.type == RESULT_NUMBER) { 1567 | //result.return_is_number = 1; 1568 | result.type = RESULT_NUMBER; 1569 | //snprintf(result.return_value, MAX_TOKEN_LENGTH, "%g", val.number_value); 1570 | result.number_value = val.number_value; 1571 | } else if (val.type == RESULT_STRING) { 1572 | //result.return_is_number = 0; 1573 | result.type = RESULT_STRING; 1574 | strcpy(result.string_value, val.string_value); 1575 | } else if (val.type == RESULT_ASSOC_ARRAY) { 1576 | //result.return_is_number = 0; 1577 | result.type = RESULT_ASSOC_ARRAY; 1578 | result.array_value = (AssocArray *) malloc(sizeof(AssocArray)); // Where does this get freed? 1579 | duplicate_assoc_array(result.array_value, val.array_value); 1580 | } else { 1581 | // If other, decide how to return them 1582 | // For simplicity, return "0" 1583 | // result.return_is_number = 1; 1584 | // strcpy(result.return_value, "0"); 1585 | result.type = RESULT_NUMBER; 1586 | result.number_value = 0; 1587 | } 1588 | return result; 1589 | } 1590 | default: 1591 | printf("Error: While executing the AST (with return) - Unknown AST node type\n"); 1592 | DEBUG_PRINT("node->type %d", node->type); 1593 | break; 1594 | } 1595 | return result; 1596 | } 1597 | 1598 | int evaluate_expression(ASTNode *node, EvalResult *result, EvalContext context) { 1599 | if (node == NULL) return 0; 1600 | DEBUG_PRINT("evaluate_expression node->type %d", node->type); 1601 | switch (node->type) { 1602 | case AST_LITERAL: 1603 | // Check if it's a number 1604 | if (isdigit(node->data.string_value[0]) || (node->data.string_value[0] == '-' && isdigit(node->data.string_value[1]))) { 1605 | result->type = RESULT_NUMBER; 1606 | result->number_value = atof(node->data.string_value); 1607 | } else { 1608 | result->type = RESULT_STRING; 1609 | strcpy(result->string_value, node->data.string_value); 1610 | } 1611 | return 1; 1612 | case AST_IDENTIFIER: { 1613 | Variable *var = get_variable(node->data.identifier); 1614 | if (var != NULL) { 1615 | if (context == EVAL_ARITHMETIC) { 1616 | // if (var->array.size == 1 && strcmp(var->array.pairs[0].key, "") == 0) { 1617 | // // Always use the default key "" for arithmetic expressions 1618 | if (var->array.size == 1) { 1619 | // Always use the only key 1620 | // char *value = get_assoc_array_value(&var->array, ""); 1621 | char *value = get_first_assoc_array_value(&var->array); 1622 | if (value != NULL) { 1623 | // Determine if value is a number 1624 | if (isdigit(value[0]) || (value[0] == '-' && isdigit(value[1]))) { 1625 | result->type = RESULT_NUMBER; 1626 | result->number_value = atof(value); 1627 | } else { 1628 | result->type = RESULT_STRING; 1629 | strcpy(result->string_value, value); 1630 | } 1631 | return 1; 1632 | } else { 1633 | printf("Error: Variable '%s' has no default value and cannot be used in expressions\n", node->data.identifier); 1634 | return 0; 1635 | } 1636 | } else { 1637 | // Return the associative array 1638 | result->type = RESULT_ASSOC_ARRAY; 1639 | result->array_value = &var->array; 1640 | return 1; 1641 | } 1642 | } else if (context == EVAL_PRINT) { 1643 | // For printing, return the entire associative array or the default value 1644 | // if (var->array.size == 1 && strcmp(var->array.pairs[0].key, "") == 0) { 1645 | // // Only default key, treat as simple variable 1646 | if (var->array.size == 1) { 1647 | // Only item, treat as simple variable 1648 | result->type = RESULT_STRING; 1649 | strcpy(result->string_value, var->array.pairs[0].value); 1650 | } else { 1651 | // Multiple keys, return the associative array 1652 | result->type = RESULT_ASSOC_ARRAY; 1653 | result->array_value = &var->array; 1654 | } 1655 | return 1; 1656 | } 1657 | } else { 1658 | printf("Error: Undefined variable '%s'\n", node->data.identifier); 1659 | return 0; 1660 | } 1661 | } 1662 | 1663 | case AST_ARRAY_ACCESS: { 1664 | EvalResult key_result; 1665 | if (!evaluate_expression(node->left, &key_result, EVAL_ARITHMETIC)) { 1666 | printf("Error: Failed to evaluate array index\n"); 1667 | DEBUG_PRINT("Error: Failed to evaluate array index"); 1668 | return 0; 1669 | } 1670 | if (key_result.type != RESULT_STRING && key_result.type != RESULT_NUMBER) { 1671 | printf("Error: Array index must be a string or number\n"); 1672 | return 0; 1673 | } 1674 | 1675 | // Convert numeric index to string if necessary 1676 | char key[MAX_TOKEN_LENGTH]; 1677 | if (key_result.type == RESULT_NUMBER) { 1678 | snprintf(key, MAX_TOKEN_LENGTH, "%g", key_result.number_value); 1679 | } else { 1680 | strcpy(key, key_result.string_value); 1681 | } 1682 | 1683 | Variable *var = get_variable(node->data.identifier); 1684 | if (var == NULL) { 1685 | printf("Error: Undefined variable '%s'\n", node->data.identifier); 1686 | return 0; 1687 | } 1688 | 1689 | char *value = get_assoc_array_value(&var->array, key); 1690 | if (value != NULL) { 1691 | // Determine if value is a number 1692 | if (isdigit(value[0]) || (value[0] == '-' && isdigit(value[1]))) { 1693 | result->type = RESULT_NUMBER; 1694 | result->number_value = atof(value); 1695 | } else { 1696 | result->type = RESULT_STRING; 1697 | strcpy(result->string_value, value); 1698 | } 1699 | return 1; 1700 | } else { 1701 | printf("Error: Key '%s' not found in variable '%s'\n", key, node->data.identifier); 1702 | return 0; 1703 | } 1704 | } 1705 | 1706 | case AST_BINARY_OP: { 1707 | EvalResult left_result, right_result; 1708 | // For relational operators, we need to determine the context 1709 | EvalContext op_context = (node->data.operator == OP_ADD || node->data.operator == OP_SUBTRACT || 1710 | node->data.operator == OP_MULTIPLY || node->data.operator == OP_DIVIDE) 1711 | ? EVAL_ARITHMETIC : context; 1712 | 1713 | if (!evaluate_expression(node->left, &left_result, op_context)) { 1714 | return 0; 1715 | } 1716 | if (!evaluate_expression(node->right, &right_result, op_context)) { 1717 | return 0; 1718 | } 1719 | 1720 | // Handle arithmetic and relational operators 1721 | if (left_result.type == RESULT_NUMBER && right_result.type == RESULT_NUMBER) { 1722 | switch (node->data.operator) { 1723 | case OP_ADD: 1724 | result->type = RESULT_NUMBER; 1725 | result->number_value = left_result.number_value + right_result.number_value; 1726 | return 1; 1727 | case OP_SUBTRACT: 1728 | result->type = RESULT_NUMBER; 1729 | result->number_value = left_result.number_value - right_result.number_value; 1730 | return 1; 1731 | case OP_MULTIPLY: 1732 | result->type = RESULT_NUMBER; 1733 | result->number_value = left_result.number_value * right_result.number_value; 1734 | return 1; 1735 | case OP_DIVIDE: 1736 | result->type = RESULT_NUMBER; 1737 | result->number_value = left_result.number_value / right_result.number_value; 1738 | return 1; 1739 | case OP_LESS_THAN: 1740 | result->type = RESULT_NUMBER; 1741 | result->number_value = (left_result.number_value < right_result.number_value) ? 1 : 0; 1742 | return 1; 1743 | case OP_GREATER_THAN: 1744 | result->type = RESULT_NUMBER; 1745 | result->number_value = (left_result.number_value > right_result.number_value) ? 1 : 0; 1746 | return 1; 1747 | case OP_EQUAL: 1748 | result->type = RESULT_NUMBER; 1749 | result->number_value = (left_result.number_value == right_result.number_value) ? 1 : 0; 1750 | return 1; 1751 | case OP_NOT_EQUAL: 1752 | result->type = RESULT_NUMBER; 1753 | result->number_value = (left_result.number_value != right_result.number_value) ? 1 : 0; 1754 | return 1; 1755 | case OP_LESS_EQUAL: 1756 | result->type = RESULT_NUMBER; 1757 | result->number_value = (left_result.number_value <= right_result.number_value) ? 1 : 0; 1758 | return 1; 1759 | case OP_GREATER_EQUAL: 1760 | result->type = RESULT_NUMBER; 1761 | result->number_value = (left_result.number_value >= right_result.number_value) ? 1 : 0; 1762 | return 1; 1763 | // Handle other operators... 1764 | default: 1765 | printf("Error: Unsupported operator\n"); 1766 | return 0; 1767 | } 1768 | } else { 1769 | printf("Error: Both operands must be numbers for arithmetic or relational operations\n"); 1770 | return 0; 1771 | } 1772 | } 1773 | case AST_FUNCTION_CALL: { 1774 | FunctionReturn call_res = execute_function_call(node); 1775 | // TODO the return value is IMPORTANT! 1776 | if(call_res.has_return == 0) { 1777 | result->type = RESULT_NUMBER; 1778 | result->number_value = 0; 1779 | } else { 1780 | if(call_res.type == RESULT_NUMBER) { 1781 | result->type = RESULT_NUMBER; 1782 | result->number_value = call_res.number_value; 1783 | } else if (call_res.type == RESULT_ASSOC_ARRAY) { 1784 | result->type = RESULT_ASSOC_ARRAY; 1785 | result->array_value = call_res.array_value; 1786 | } else { 1787 | result->type = RESULT_STRING; 1788 | strcpy(result->string_value, call_res.string_value); 1789 | } 1790 | } 1791 | return 1; 1792 | break; 1793 | } 1794 | 1795 | default: 1796 | printf("Error: While evaluating expression - Unknown AST node type\n"); 1797 | DEBUG_PRINT("DEBUG: While evaluating expression - Unknown AST node type (%d)\n", node->type); 1798 | break; 1799 | } 1800 | } 1801 | 1802 | void clear_variable_assoc_array(const char *name) { 1803 | Variable *var = NULL; 1804 | // Check if variable exists 1805 | for (int i = 0; i < variable_count; i++) { 1806 | if (strcmp(variables[i].name, name) == 0) { 1807 | var = &variables[i]; 1808 | break; 1809 | } 1810 | } 1811 | 1812 | if (var != NULL) { 1813 | free_assoc_array(&var->array); 1814 | init_assoc_array(&var->array); 1815 | } 1816 | 1817 | } 1818 | 1819 | void set_variable_assoc_array(const char *name, AssocArray *array_value) { 1820 | Variable *var = NULL; 1821 | // Check if variable exists 1822 | for (int i = 0; i < variable_count; i++) { 1823 | if (strcmp(variables[i].name, name) == 0) { 1824 | var = &variables[i]; 1825 | break; 1826 | } 1827 | } 1828 | 1829 | if (var == NULL) { 1830 | // Create new variable 1831 | if (variable_count >= MAX_VARIABLES) { 1832 | printf("Error: Maximum number of variables reached\n"); 1833 | return; 1834 | } 1835 | strcpy(variables[variable_count].name, name); 1836 | init_assoc_array(&variables[variable_count].array); 1837 | var = &variables[variable_count]; 1838 | variable_count++; 1839 | } else { 1840 | // Free existing array 1841 | free_assoc_array(&var->array); 1842 | init_assoc_array(&var->array); 1843 | } 1844 | 1845 | // Copy the associative array 1846 | for (int i = 0; i < array_value->size; i++) { 1847 | set_assoc_array_value(&var->array, array_value->pairs[i].key, array_value->pairs[i].value); 1848 | } 1849 | } 1850 | 1851 | #define MAX_SCOPES 100 1852 | 1853 | // Global variables tracking scopes 1854 | // Variable variables[MAX_VARIABLES]; 1855 | // int variable_count = 0; 1856 | Variable scope_variables_stack[MAX_SCOPES][MAX_VARIABLES]; 1857 | int scope_count_stack[MAX_SCOPES]; 1858 | int scope_depth = 0; 1859 | 1860 | // push_scope saves the current variable_count on a stack 1861 | void push_scope() { 1862 | if (scope_depth >= MAX_SCOPES) { 1863 | printf("Error: Scope stack overflow\n"); 1864 | return; 1865 | } 1866 | // Record the current variables 1867 | memcpy(&scope_variables_stack[scope_depth], variables, sizeof(Variable) * MAX_VARIABLES); 1868 | scope_count_stack[scope_depth++] = variable_count; 1869 | variable_count = 0; 1870 | } 1871 | 1872 | // pop_scope restores variable_count to the value it had at the last push_scope 1873 | void pop_scope() { 1874 | if (scope_depth <= 0) { 1875 | printf("Error: Scope stack underflow\n"); 1876 | return; 1877 | } 1878 | 1879 | int variable_count = scope_count_stack[--scope_depth]; 1880 | memcpy(variables, &scope_variables_stack[scope_depth], sizeof(Variable) * MAX_VARIABLES); 1881 | } 1882 | 1883 | void execute_assignment(ASTNode *node) { 1884 | if (node == NULL || node->type != AST_ASSIGNMENT) return; 1885 | DEBUG_PRINT("execute_assignment"); 1886 | ASTNode *target = node->left; 1887 | ASTNode *expr = node->right; 1888 | 1889 | // Evaluate the expression 1890 | EvalResult result; 1891 | if (!evaluate_expression(expr, &result, EVAL_ARITHMETIC)) { 1892 | printf("Error: Failed to evaluate expression in assignment\n"); 1893 | DEBUG_PRINT("Error: Failed to evaluate expression in assignment"); 1894 | return; 1895 | } 1896 | 1897 | DEBUG_PRINT("target->type %d result.type %d", target->type, result.type); 1898 | if (target->type == AST_IDENTIFIER) { 1899 | // Simple variable assignment 1900 | if (result.type == RESULT_STRING) { 1901 | set_variable_value(target->data.identifier, NULL, result.string_value); 1902 | } else if (result.type == RESULT_NUMBER) { 1903 | char num_str[MAX_TOKEN_LENGTH]; 1904 | // DEBUG_PRINT("result.number_value %f", result.number_value); 1905 | snprintf(num_str, MAX_TOKEN_LENGTH, "%g", result.number_value); 1906 | set_variable_value(target->data.identifier, NULL, num_str); 1907 | } else if (result.type == RESULT_ASSOC_ARRAY) { 1908 | set_variable_assoc_array(target->data.identifier, result.array_value); 1909 | } 1910 | } else if (target->type == AST_ARRAY_ACCESS) { 1911 | // Array element assignment 1912 | EvalResult key_result; 1913 | if (!evaluate_expression(target->left, &key_result, EVAL_PRINT)) { 1914 | printf("Error: Failed to evaluate array index\n"); 1915 | DEBUG_PRINT("Error: Failed to evaluate array index"); 1916 | return; 1917 | } 1918 | if ( (key_result.type != RESULT_STRING) && (key_result.type != RESULT_NUMBER) ){ 1919 | printf("Assignment Error: Array index must be a string or number\n"); 1920 | return; 1921 | } 1922 | char key_str[MAX_TOKEN_LENGTH]; 1923 | if (key_result.type == RESULT_NUMBER) { 1924 | snprintf(key_str, MAX_TOKEN_LENGTH, "%g", key_result.number_value); 1925 | } else { 1926 | strcpy(key_str, key_result.string_value); 1927 | } 1928 | if (result.type == RESULT_STRING) { 1929 | set_variable_value(target->data.identifier, key_str, result.string_value); 1930 | } else if (result.type == RESULT_NUMBER) { 1931 | char num_str[MAX_TOKEN_LENGTH]; 1932 | snprintf(num_str, MAX_TOKEN_LENGTH, "%g", result.number_value); 1933 | set_variable_value(target->data.identifier, key_str, num_str); 1934 | } else if (result.type == RESULT_ASSOC_ARRAY) { 1935 | printf("Error: Cannot assign an associative array to an array element\n"); 1936 | } 1937 | } else { 1938 | printf("Error: Invalid assignment target\n"); 1939 | } 1940 | } 1941 | 1942 | int find_function(const char *name) { 1943 | for (int i = 0; i < function_count; i++) { 1944 | if (strcmp(functions[i].name, name) == 0) { 1945 | return i; 1946 | } 1947 | } 1948 | return -1; // Not found 1949 | } 1950 | 1951 | void set_variable_from_eval_result(const char *name, EvalResult *result) { 1952 | if (result->type == RESULT_NUMBER) { 1953 | char num_str[MAX_TOKEN_LENGTH]; 1954 | snprintf(num_str, MAX_TOKEN_LENGTH, "%g", result->number_value); 1955 | set_variable_value(name, NULL, num_str); 1956 | } else if (result->type == RESULT_STRING) { 1957 | set_variable_value(name, NULL, result->string_value); 1958 | } else if (result->type == RESULT_ASSOC_ARRAY) { 1959 | // Assign entire associative array to the variable 1960 | set_variable_assoc_array(name, result->array_value); 1961 | } else { 1962 | // Unknown or unsupported type, default to "0" 1963 | set_variable_value(name, NULL, "0"); 1964 | } 1965 | } 1966 | 1967 | FunctionReturn execute_function_call(ASTNode *call_node) { 1968 | 1969 | // Check for built-in functions first 1970 | for (int i = 0; kvstdlib_lookup_table[i].name != NULL; i++) { 1971 | if (strcmp(kvstdlib_lookup_table[i].name, call_node->data.func_call.name) == 0) { 1972 | if (kvstdlib_lookup_table[i].func) { 1973 | return kvstdlib_lookup_table[i].func(call_node->data.func_call.arguments); 1974 | } 1975 | } 1976 | } 1977 | 1978 | // If not a built-in, proceed with user-defined functions 1979 | FunctionReturn result = {0}; 1980 | 1981 | int idx = find_function(call_node->data.func_call.name); 1982 | if (idx < 0) { 1983 | printf("Error: Undefined function '%s'\n", call_node->data.func_call.name); 1984 | // return default 0 1985 | result.has_return = 1; 1986 | // result.return_is_number = 1; 1987 | // strcpy(result.return_value, "0"); 1988 | result.type = RESULT_NUMBER; 1989 | result.number_value = 0; 1990 | return result; 1991 | } 1992 | 1993 | // Evaluate arguments 1994 | ASTNode *param = functions[idx].parameters; 1995 | ASTNode *arg = call_node->data.func_call.arguments; 1996 | 1997 | EvalResult args[MAX_FUNC_PARAMS]; 1998 | int argc = 0; 1999 | 2000 | while (param != NULL && arg != NULL) { 2001 | EvalResult arg_val; 2002 | if (!evaluate_expression(arg, &arg_val, EVAL_ARITHMETIC)) { 2003 | printf("Error: Failed to evaluate argument\n"); 2004 | pop_scope(); 2005 | result.has_return = 1; 2006 | // result.return_is_number = 1; 2007 | // strcpy(result.return_value, "0"); 2008 | result.type = RESULT_NUMBER; 2009 | result.number_value = 0; 2010 | return result; 2011 | } 2012 | 2013 | args[argc++] = arg_val; 2014 | param = param->right; 2015 | arg = arg->right; 2016 | } 2017 | 2018 | 2019 | // Push a new scope 2020 | push_scope(); 2021 | 2022 | param = functions[idx].parameters; 2023 | int i = 0; 2024 | while (iidentifier 2027 | set_variable_from_eval_result(param->data.identifier, &args[i++]); 2028 | param = param->right; 2029 | } 2030 | 2031 | // If fewer arguments than parameters or vice versa, decide how to handle 2032 | // For now, missing arguments -> empty string 2033 | while (param != NULL) { 2034 | set_variable_value(param->data.identifier, NULL, "0"); 2035 | param = param->right; 2036 | } 2037 | 2038 | // Execute the function body 2039 | // Modify execute_block or a similar function to return a structure with return info 2040 | FunctionReturn body_ret = execute_block_with_return(functions[idx].body); 2041 | 2042 | pop_scope(); 2043 | 2044 | if (!body_ret.has_return) { 2045 | // No return encountered, return 0 2046 | body_ret.has_return = 1; 2047 | // body_ret.return_is_number = 1; 2048 | // strcpy(body_ret.return_value, "0"); 2049 | body_ret.type = RESULT_NUMBER; 2050 | body_ret.number_value = 0; 2051 | } 2052 | 2053 | return body_ret; 2054 | } 2055 | 2056 | FunctionReturn execute_block_with_return(ASTNode *node) { 2057 | FunctionReturn result = {0}; 2058 | while (node != NULL) { 2059 | FunctionReturn stmt_result = execute_ast_with_return(node); 2060 | if (stmt_result.has_return) { 2061 | return stmt_result; // bubble up the return 2062 | } 2063 | node = node->nextblock; 2064 | } 2065 | return result; // no return encountered 2066 | } 2067 | 2068 | void print_assoc_array(AssocArray *array) { 2069 | printf("{"); 2070 | for (int i = 0; i < array->size; i++) { 2071 | // Print key-value pairs 2072 | printf("\"%s\": \"%s\"", array->pairs[i].key, array->pairs[i].value); 2073 | if (i < array->size - 1) { 2074 | printf(", "); 2075 | } 2076 | } 2077 | printf("}\n"); 2078 | } 2079 | 2080 | void evaluate_and_print(ASTNode *node) { 2081 | EvalResult result; 2082 | if (evaluate_expression(node, &result, EVAL_PRINT)) { 2083 | if (result.type == RESULT_STRING) { 2084 | printf("%s\n", result.string_value); 2085 | } else if (result.type == RESULT_NUMBER) { 2086 | printf("%g\n", result.number_value); 2087 | } else if (result.type == RESULT_ASSOC_ARRAY) { 2088 | print_assoc_array(result.array_value); 2089 | } 2090 | } 2091 | } 2092 | 2093 | void set_variable_value(const char *name, const char *key, const char *value) { 2094 | Variable *var = NULL; 2095 | // Check if variable exists 2096 | for (int i = 0; i < variable_count; i++) { 2097 | if (strcmp(variables[i].name, name) == 0) { 2098 | var = &variables[i]; 2099 | break; 2100 | } 2101 | } 2102 | 2103 | if (var == NULL) { 2104 | // Create new variable 2105 | if (variable_count >= MAX_VARIABLES) { 2106 | printf("Error: Maximum number of variables reached\n"); 2107 | return; 2108 | } 2109 | strcpy(variables[variable_count].name, name); 2110 | init_assoc_array(&variables[variable_count].array); 2111 | var = &variables[variable_count]; 2112 | variable_count++; 2113 | } 2114 | 2115 | if (key == NULL) { 2116 | // Assign to default key 2117 | set_assoc_array_value(&var->array, "", value); 2118 | } else { 2119 | // Assign to specified key 2120 | set_assoc_array_value(&var->array, key, value); 2121 | } 2122 | } 2123 | 2124 | Variable* get_variable(const char *name) { 2125 | for (int i = 0; i < variable_count; i++) { 2126 | if (strcmp(variables[i].name, name) == 0) { 2127 | return &variables[i]; 2128 | } 2129 | } 2130 | return NULL; // Variable not found 2131 | } 2132 | 2133 | char* get_variable_value(const char *name) { 2134 | // Lookup variable 2135 | for (int i = 0; i < variable_count; i++) { 2136 | if (strcmp(variables[i].name, name) == 0) { 2137 | // Get value from default key 2138 | char *value = get_assoc_array_value(&variables[i].array, ""); 2139 | if (value != NULL) { 2140 | return value; 2141 | } else { 2142 | // If no default key, return a representation of the array 2143 | return "[Associative Array]"; 2144 | } 2145 | } 2146 | } 2147 | return NULL; // Variable not found 2148 | } 2149 | 2150 | 2151 | void free_ast(ASTNode *node) { 2152 | if (node == NULL) return; 2153 | free_ast(node->left); 2154 | free_ast(node->right); 2155 | free_ast(node->nextblock); 2156 | free(node); 2157 | } 2158 | 2159 | int starts_with_keyword(const char *line, const char *keyword) { 2160 | int len = strlen(keyword); 2161 | // Skip leading whitespace 2162 | while (*line && isspace(*line)) { 2163 | line++; 2164 | } 2165 | return strncmp(line, keyword, len) == 0 && (line[len] == '\0' || isspace(line[len])); 2166 | } 2167 | 2168 | int main(int argc, char *argv[]) { 2169 | if (argc > 1) { 2170 | // Run script file 2171 | const char *filename = argv[1]; 2172 | FILE *file = fopen(filename, "r"); 2173 | if (!file) { 2174 | printf("Error: Could not open file '%s'\n", filename); 2175 | return 1; 2176 | } 2177 | 2178 | char line[MAX_LINE_LENGTH]; 2179 | char buffer[MAX_LINE_LENGTH * 1000]; // Adjust size as needed 2180 | buffer[0] = '\0'; 2181 | 2182 | while (fgets(line, sizeof(line), file)) { 2183 | strcat(buffer, line); 2184 | } 2185 | fclose(file); 2186 | 2187 | // Tokenize, parse, and execute the buffer 2188 | Token tokens[MAX_TOKENS * 100]; // Adjust size as needed 2189 | int token_count = 0; 2190 | tokenize_line(buffer, tokens, &token_count); 2191 | parse_and_execute(tokens, token_count); 2192 | } else { 2193 | char line[MAX_LINE_LENGTH]; 2194 | char buffer[MAX_LINE_LENGTH * 100]; // Adjust size as needed 2195 | buffer[0] = '\0'; // Initialize buffer 2196 | int in_block = 0; // Flag to indicate if we're inside a block 2197 | 2198 | printf("Welcome to keyva-lang REPL\n"); 2199 | while (1) { 2200 | // Display prompt based on block depth 2201 | if (in_block > 0) { 2202 | printf("... "); // Indicate continuation 2203 | } else { 2204 | printf("> "); 2205 | } 2206 | if (fgets(line, sizeof(line), stdin) == NULL) break; 2207 | 2208 | // Remove trailing newline character 2209 | line[strcspn(line, "\n")] = '\0'; 2210 | 2211 | // Check for exit command 2212 | if (strcmp(line, "exit") == 0 || strcmp(line, "quit") == 0) { 2213 | break; 2214 | } 2215 | 2216 | // Append line to buffer 2217 | strcat(buffer, line); 2218 | strcat(buffer, "\n"); // Keep newlines to maintain line numbers 2219 | 2220 | // Check for block-opening keywords 2221 | if (starts_with_keyword(line, "if")) { 2222 | in_block++; 2223 | } 2224 | 2225 | // Check for block-opening keywords 2226 | if (starts_with_keyword(line, "for")) { 2227 | in_block++; 2228 | } 2229 | 2230 | // Check for block-opening keywords 2231 | if (starts_with_keyword(line, "def")) { 2232 | in_block++; 2233 | } 2234 | 2235 | // Check for block-closing keyword 2236 | if (starts_with_keyword(line, "end")) { 2237 | in_block--; 2238 | if (in_block < 0) { 2239 | printf("Error: Unmatched 'end' detected\n"); 2240 | buffer[0] = '\0'; 2241 | in_block = 0; 2242 | continue; 2243 | } 2244 | } 2245 | 2246 | // If not inside a block, process the buffer 2247 | if (in_block == 0) { 2248 | // Tokenize, parse, and execute the buffer 2249 | Token tokens[MAX_TOKENS]; 2250 | int token_count = 0; 2251 | tokenize_line(buffer, tokens, &token_count); 2252 | parse_and_execute(tokens, token_count); 2253 | 2254 | // Clear the buffer 2255 | buffer[0] = '\0'; 2256 | } 2257 | } 2258 | 2259 | return 0; 2260 | } 2261 | 2262 | return 0; 2263 | } 2264 | 2265 | --------------------------------------------------------------------------------