backup
This commit is contained in:
+16
-22
@@ -5,30 +5,24 @@
|
|||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
config_t *config_create(void);
|
void config_create(void);
|
||||||
void free_node(node_t *node);
|
void init_builtin_functions(void);
|
||||||
void config_destroy(config_t *config);
|
|
||||||
int handle_map_key(config_t *config, node_t **args, int arg_count);
|
|
||||||
int handle_define(config_t *config, node_t **args, int arg_count);
|
|
||||||
int execute_function_call(config_t *config, node_t *call);
|
|
||||||
int config_parse_string(config_t *config, const char *input);
|
|
||||||
int config_parse_file(config_t *config, const char *filename);
|
|
||||||
|
|
||||||
const char *config_get_key_mapping(config_t *config, const char *key_combo);
|
int handle_map_key(node_t **args, int arg_count);
|
||||||
node_t *find_variable(config_t *config, const char *name);
|
int handle_define(node_t **args, int arg_count);
|
||||||
|
int handle_function(node_t **args, int arg_count);
|
||||||
|
|
||||||
const char *config_get_string(config_t *config, const char *path,
|
int execute_function_call(node_t *call);
|
||||||
const char *default_value);
|
int config_parse_string(const char *input);
|
||||||
int config_get_int(config_t *config, const char *path, int default_value);
|
int config_parse_file(const char *filename);
|
||||||
double config_get_double(config_t *config, const char *path,
|
|
||||||
double default_value);
|
|
||||||
bool config_get_bool(config_t *config, const char *path, bool default_value);
|
|
||||||
void config_print_all(config_t *config);
|
|
||||||
|
|
||||||
static struct {
|
const char *config_get_key_mapping(const char *key_combo);
|
||||||
const char *name;
|
node_t *find_variable(const char *name);
|
||||||
int (*handler)(config_t *config, node_t **args, int arg_count);
|
|
||||||
} builtin_functions[] = {
|
const char *config_get_string(const char *path, const char *default_value);
|
||||||
{"map-key", handle_map_key}, {"define", handle_define}, {NULL, NULL}};
|
int config_get_int(const char *path, int default_value);
|
||||||
|
double config_get_double(const char *path, double default_value);
|
||||||
|
bool config_get_bool(const char *path, bool default_value);
|
||||||
|
void config_print_all(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+72
-21
@@ -1,12 +1,7 @@
|
|||||||
#ifndef DATA_H_PARSER
|
#ifndef DATA_H_PARSER
|
||||||
#define DATA_H_PARSER
|
#define DATA_H_PARSER
|
||||||
|
|
||||||
#include "define.h"
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
// Token types for lexical analysis
|
// Token types for lexical analysis
|
||||||
|
|
||||||
@@ -26,7 +21,7 @@ typedef enum {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
token_type_t type;
|
token_type_t type;
|
||||||
char value[MAX_TOKEN_LENGTH];
|
char *value;
|
||||||
int line;
|
int line;
|
||||||
int column;
|
int column;
|
||||||
} token_t;
|
} token_t;
|
||||||
@@ -37,23 +32,28 @@ typedef enum {
|
|||||||
NODE_STRING,
|
NODE_STRING,
|
||||||
NODE_NUMBER,
|
NODE_NUMBER,
|
||||||
NODE_BOOLEAN,
|
NODE_BOOLEAN,
|
||||||
NODE_FUNCTION_REF, // %function-name
|
NODE_FUNCTION_REF, // %function-name
|
||||||
NODE_FUNCTION_CALL // ,function-name()
|
NODE_FUNCTION_CALL, // ,function-name()
|
||||||
|
NODE_LIST
|
||||||
} node_type_t;
|
} node_type_t;
|
||||||
|
|
||||||
typedef struct node {
|
typedef struct node {
|
||||||
node_type_t type;
|
node_type_t type;
|
||||||
union {
|
union {
|
||||||
char symbol[MAX_SYMBOL_LENGTH];
|
char *symbol;
|
||||||
char string[MAX_STRING_LENGTH];
|
char *string;
|
||||||
double number;
|
double number;
|
||||||
bool boolean;
|
bool boolean;
|
||||||
char function_ref[MAX_SYMBOL_LENGTH];
|
char *function_ref;
|
||||||
struct {
|
struct {
|
||||||
char function_name[MAX_SYMBOL_LENGTH];
|
char *function_name;
|
||||||
struct node *args[MAX_ARGS];
|
struct node **args;
|
||||||
int arg_count;
|
int arg_count;
|
||||||
} call;
|
} call;
|
||||||
|
struct {
|
||||||
|
struct node **children;
|
||||||
|
int child_count;
|
||||||
|
} list;
|
||||||
} data;
|
} data;
|
||||||
} node_t;
|
} node_t;
|
||||||
|
|
||||||
@@ -79,22 +79,73 @@ typedef struct config_var {
|
|||||||
struct config_var *next;
|
struct config_var *next;
|
||||||
} config_var_t;
|
} config_var_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct config {
|
||||||
key_mapping_t *key_mappings;
|
key_mapping_t *key_mappings;
|
||||||
config_var_t *variables;
|
config_var_t *variables;
|
||||||
} config_t;
|
} config_t;
|
||||||
|
|
||||||
|
// Execution context for function calls
|
||||||
|
typedef struct exec_context {
|
||||||
|
struct {
|
||||||
|
char **names;
|
||||||
|
node_t **values;
|
||||||
|
int count;
|
||||||
|
} local_vars;
|
||||||
|
} exec_context_t;
|
||||||
|
|
||||||
|
typedef void (*command_func_t)(void);
|
||||||
|
|
||||||
|
typedef enum { FUNC_BUILTIN, FUNC_USER_DEFINED, FUNC_REGISTRY } function_type_t;
|
||||||
|
|
||||||
|
typedef struct unified_function {
|
||||||
|
char *name;
|
||||||
|
function_type_t type;
|
||||||
|
union {
|
||||||
|
// For built-in functions
|
||||||
|
struct {
|
||||||
|
int (*handler)(node_t **args, int arg_count);
|
||||||
|
bool eval_args; // Whether to evaluate arguments before calling
|
||||||
|
} builtin;
|
||||||
|
|
||||||
|
// For user-defined functions
|
||||||
|
struct {
|
||||||
|
char **parameters;
|
||||||
|
int param_count;
|
||||||
|
node_t *body;
|
||||||
|
} user_defined;
|
||||||
|
|
||||||
|
// For registry functions
|
||||||
|
struct {
|
||||||
|
command_func_t func;
|
||||||
|
} registry;
|
||||||
|
} data;
|
||||||
|
|
||||||
|
struct unified_function *next;
|
||||||
|
} unified_function_t;
|
||||||
|
|
||||||
void advance_char(lexer_t *lexer);
|
void advance_char(lexer_t *lexer);
|
||||||
void skip_whitespace(lexer_t *lexer);
|
void skip_whitespace(lexer_t *lexer);
|
||||||
void skip_comment(lexer_t *lexer);
|
void skip_comment(lexer_t *lexer);
|
||||||
node_t *create_node(node_type_t type);
|
|
||||||
node_t *create_symbol_node(const char *symbol);
|
|
||||||
node_t *create_string_node(const char *string);
|
|
||||||
node_t *create_number_node(double number);
|
|
||||||
node_t *create_boolean_node(bool value);
|
|
||||||
node_t *create_function_ref_node(const char *function_name);
|
|
||||||
node_t *create_function_call_node(const char *function_name);
|
|
||||||
|
|
||||||
void add_arg_to_call(node_t *call, node_t *args);
|
void add_arg_to_call(node_t *call, node_t *args);
|
||||||
|
void add_to_list(node_t *node, node_t *element);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef GLOBAL_CONFIG
|
||||||
|
|
||||||
|
unified_function_t *unified_functions = NULL;
|
||||||
|
int registry_count;
|
||||||
|
config_var_t variable_registry[256];
|
||||||
|
int var_registry_count;
|
||||||
|
|
||||||
|
config_t config;
|
||||||
|
#else
|
||||||
|
|
||||||
|
extern unified_function_t *unified_functions;
|
||||||
|
extern int registry_count;
|
||||||
|
extern config_var_t variable_registry[256];
|
||||||
|
extern int var_registry_count;
|
||||||
|
|
||||||
|
extern config_t config;
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#ifndef FUNCTION_H_
|
||||||
|
#define FUNCTION_H_
|
||||||
|
|
||||||
|
#include "data.h"
|
||||||
|
|
||||||
|
int register_builtin_function(const char *name, int (*handler)(node_t **, int),
|
||||||
|
bool eval_args);
|
||||||
|
int register_user_function(const char *name, char **parameters, int param_count,
|
||||||
|
node_t *body);
|
||||||
|
int register_registry_function(const char *name, command_func_t func);
|
||||||
|
|
||||||
|
int register_function(const char *name, command_func_t func);
|
||||||
|
|
||||||
|
unified_function_t *find_unified_function(const char *name);
|
||||||
|
|
||||||
|
node_t *execute_unified_function(exec_context_t *ctx, const char *name,
|
||||||
|
node_t **args, int arg_count);
|
||||||
|
|
||||||
|
command_func_t find_function(const char *name);
|
||||||
|
int execute_command(const char *name);
|
||||||
|
|
||||||
|
node_t *execute_function_call_in_context(exec_context_t *ctx, node_t *call);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
#define LEXER_H_
|
#define LEXER_H_
|
||||||
|
|
||||||
#include "data.h"
|
#include "data.h"
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
token_t next_token(lexer_t *lexer);
|
token_t next_token(lexer_t *lexer);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#ifndef NODE_T_
|
||||||
|
#define NODE_T_
|
||||||
|
|
||||||
|
#include "data.h"
|
||||||
|
|
||||||
|
node_t *create_node(node_type_t type);
|
||||||
|
node_t *create_symbol_node(const char *symbol);
|
||||||
|
node_t *create_string_node(const char *string);
|
||||||
|
node_t *create_number_node(double number);
|
||||||
|
node_t *create_boolean_node(bool value);
|
||||||
|
node_t *create_list_node(void);
|
||||||
|
node_t *create_function_ref_node(const char *function_name);
|
||||||
|
node_t *create_function_call_node(const char *function_name);
|
||||||
|
|
||||||
|
void free_node(node_t *node);
|
||||||
|
node_t *copy_node(node_t *src);
|
||||||
|
|
||||||
|
node_t *evaluate_node(exec_context_t *ctx, node_t *node);
|
||||||
|
|
||||||
|
#endif
|
||||||
+1
-1
@@ -2,10 +2,10 @@
|
|||||||
#define PARSER_H_
|
#define PARSER_H_
|
||||||
|
|
||||||
#include "data.h"
|
#include "data.h"
|
||||||
#include "lexer.h"
|
|
||||||
|
|
||||||
node_t *parse_atom(lexer_t *lexer, token_t *token);
|
node_t *parse_atom(lexer_t *lexer, token_t *token);
|
||||||
node_t *parse_function_call(lexer_t *lexer, const char *function_name);
|
node_t *parse_function_call(lexer_t *lexer, const char *function_name);
|
||||||
node_t *parse_statement(lexer_t *lexer);
|
node_t *parse_statement(lexer_t *lexer);
|
||||||
|
node_t *parse_expression(lexer_t *lexer, token_t *token);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -8,5 +8,10 @@
|
|||||||
,map-key("CTRL-w s h" %window-split-horizontal)
|
,map-key("CTRL-w s h" %window-split-horizontal)
|
||||||
,map-key("CTRL-w s v" %window-split-vertical)
|
,map-key("CTRL-w s v" %window-split-vertical)
|
||||||
|
|
||||||
|
,fun(saveQuit () (
|
||||||
|
,editorSave
|
||||||
|
,editorQuit
|
||||||
|
))
|
||||||
|
|
||||||
,define(theme "dark")
|
,define(theme "dark")
|
||||||
,define(auto-save true)
|
,define(auto-save true)
|
||||||
|
|||||||
@@ -1,38 +1,34 @@
|
|||||||
|
|
||||||
#include "src/data.h"
|
#define GLOBAL_EDITOR
|
||||||
#include "src/config_tools.h"
|
|
||||||
|
|
||||||
int main() {
|
#include "include/config_tools.h"
|
||||||
|
#include "include/data.h"
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
// Parse the configuration
|
// Parse the configuration
|
||||||
config_t *config = config_create();
|
config_create();
|
||||||
char *config_file = "init.bl";
|
char *config_file = "init.bl";
|
||||||
if (!config) {
|
|
||||||
fprintf(stderr, "Error: Failed to create config structure\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config_parse_file(config, config_file) != 0) {
|
if (config_parse_file(config_file) != 0) {
|
||||||
fprintf(stderr, "Error: Failed to parse config file\n");
|
fprintf(stderr, "Error: Failed to parse config file\n");
|
||||||
config_destroy(config);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Successfully parsed Lisp config file: %s\n\n", config_file);
|
printf("Successfully parsed Lisp config file: %s\n\n", config_file);
|
||||||
|
|
||||||
// Print all entries
|
// Print all entries
|
||||||
config_print_all(config);
|
config_print_all();
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
// Demonstrate usage
|
// Demonstrate usage
|
||||||
printf("Example usage:\n");
|
printf("Example usage:\n");
|
||||||
printf("CTRL-s maps to: %s\n", config_get_key_mapping(config, "CTRL-s"));
|
printf("CTRL-s maps to: %s\n", config_get_key_mapping("CTRL-s"));
|
||||||
printf("CTRL-f o maps to: %s\n", config_get_key_mapping(config, "CTRL-f o"));
|
printf("CTRL-f o maps to: %s\n", config_get_key_mapping("CTRL-f o"));
|
||||||
printf("Window width: %d\n", config_get_int(config, "window-width", 1024));
|
printf("Window width: %d\n", config_get_int("window-width", 1024));
|
||||||
printf("Theme: %s\n", config_get_string(config, "theme", "light"));
|
printf("Theme: %s\n", config_get_string("theme", "light"));
|
||||||
printf("Auto-save: %s\n",
|
printf("Auto-save: %s\n",
|
||||||
config_get_bool(config, "auto-save", false) ? "enabled" : "disabled");
|
config_get_bool("auto-save", false) ? "enabled" : "disabled");
|
||||||
printf("Font size: %d\n", config_get_int(config, "font-size", 12));
|
printf("Font size: %d\n", config_get_int("font-size", 12));
|
||||||
|
|
||||||
config_destroy(config);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
+145
-94
@@ -1,62 +1,29 @@
|
|||||||
|
|
||||||
#include "../include/config_tools.h"
|
#include "../include/config_tools.h"
|
||||||
|
#include "../include/function.h"
|
||||||
|
#include "../include/node.h"
|
||||||
|
#define GLOBAL_CONFIG
|
||||||
#include "../include/data.h"
|
#include "../include/data.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
config_t *config_create(void) {
|
void config_create(void) {
|
||||||
/*
|
/*
|
||||||
* @brief Initialize config structure
|
* @brief Initialize config structure
|
||||||
*/
|
*/
|
||||||
config_t *config = malloc(sizeof(config_t));
|
config.key_mappings = NULL;
|
||||||
if (config) {
|
config.variables = NULL;
|
||||||
config->key_mappings = NULL;
|
|
||||||
config->variables = NULL;
|
|
||||||
}
|
|
||||||
return config;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_node(node_t *node) {
|
void init_builtin_functions(void) {
|
||||||
int i;
|
register_builtin_function("map-key", handle_map_key, true);
|
||||||
if (!node)
|
register_builtin_function("define", handle_define, false); // Don't eval args
|
||||||
return;
|
register_builtin_function("func", handle_function, false); // Don't eval args
|
||||||
|
|
||||||
if (node->type == NODE_FUNCTION_CALL) {
|
|
||||||
for (i = 0; i < node->data.call.arg_count; i++) {
|
|
||||||
free_node(node->data.call.args[i]);
|
|
||||||
}
|
|
||||||
// free(node->data.call.args);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
void config_destroy(config_t *config) {
|
|
||||||
if (!config)
|
|
||||||
return;
|
|
||||||
|
|
||||||
key_mapping_t *mapping = config->key_mappings;
|
|
||||||
while (mapping) {
|
|
||||||
key_mapping_t *next = mapping->next;
|
|
||||||
free(mapping->key_combo);
|
|
||||||
free(mapping->function_name);
|
|
||||||
free(mapping);
|
|
||||||
mapping = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Free variables
|
|
||||||
config_var_t *var = config->variables;
|
|
||||||
while (var) {
|
|
||||||
config_var_t *next = var->next;
|
|
||||||
free(var->name);
|
|
||||||
free_node(var->value);
|
|
||||||
free(var);
|
|
||||||
var = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(config);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Built-in function handlers
|
// Built-in function handlers
|
||||||
int handle_map_key(config_t *config, node_t **args, int arg_count) {
|
int handle_map_key(node_t **args, int arg_count) {
|
||||||
if (arg_count != 2 || args[0]->type != NODE_STRING ||
|
if (arg_count != 2 || args[0]->type != NODE_STRING ||
|
||||||
args[1]->type != NODE_FUNCTION_REF) {
|
args[1]->type != NODE_FUNCTION_REF) {
|
||||||
fprintf(stderr, "Error: map-key requires (key_combo, function_ref)\n");
|
fprintf(stderr, "Error: map-key requires (key_combo, function_ref)\n");
|
||||||
@@ -69,48 +36,134 @@ int handle_map_key(config_t *config, node_t **args, int arg_count) {
|
|||||||
|
|
||||||
mapping->key_combo = strdup(args[0]->data.string);
|
mapping->key_combo = strdup(args[0]->data.string);
|
||||||
mapping->function_name = strdup(args[1]->data.function_ref);
|
mapping->function_name = strdup(args[1]->data.function_ref);
|
||||||
mapping->next = config->key_mappings;
|
mapping->next = config.key_mappings;
|
||||||
config->key_mappings = mapping;
|
config.key_mappings = mapping;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int handle_define(config_t *config, node_t **args, int arg_count) {
|
int handle_define(node_t **args, int arg_count) {
|
||||||
if (arg_count != 2 || args[0]->type != NODE_SYMBOL) {
|
|
||||||
fprintf(stderr, "Error: define requires (variable_name, value)\n");
|
if (arg_count != 2) {
|
||||||
|
fprintf(stderr, "Error: define requires exactly 2 arguments, got %d\n",
|
||||||
|
arg_count);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args[0]->type != NODE_SYMBOL) {
|
||||||
|
fprintf(
|
||||||
|
stderr,
|
||||||
|
"Error: define requires first argument to be a symbol, got type %d\n",
|
||||||
|
args[0]->type);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
config_var_t *var = malloc(sizeof(config_var_t));
|
config_var_t *var = malloc(sizeof(config_var_t));
|
||||||
if (!var)
|
if (!var) {
|
||||||
|
fprintf(stderr, "Error: Failed to allocate memory for variable\n");
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
var->name = strdup(args[0]->data.symbol);
|
var->name = strdup(args[0]->data.symbol);
|
||||||
var->value = args[1]; // Transfer ownership
|
if (!var->name) {
|
||||||
var->next = config->variables;
|
free(var);
|
||||||
config->variables = var;
|
fprintf(stderr, "Error: Failed to allocate memory for variable name\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var->value = copy_node(args[1]);
|
||||||
|
if (!var->value) {
|
||||||
|
free(var->name);
|
||||||
|
free(var);
|
||||||
|
fprintf(stderr, "Error: Failed to copy variable value\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var->next = config.variables;
|
||||||
|
config.variables = var;
|
||||||
|
|
||||||
|
// Verify it was stored
|
||||||
|
config_var_t *check = config.variables;
|
||||||
|
while (check) {
|
||||||
|
check = check->next;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int execute_function_call(config_t *config, node_t *call) {
|
int handle_function(node_t **args, int arg_count) {
|
||||||
if (call->type != NODE_FUNCTION_CALL)
|
if (arg_count != 3) {
|
||||||
|
fprintf(stderr, "Error: func requires exactly 3 arguments, got %d\n",
|
||||||
|
arg_count);
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
// Look for built-in function
|
if (args[0]->type != NODE_SYMBOL) {
|
||||||
for (int i = 0; builtin_functions[i].name; i++) {
|
fprintf(
|
||||||
if (strcmp(call->data.call.function_name, builtin_functions[i].name) == 0) {
|
stderr,
|
||||||
return builtin_functions[i].handler(config, call->data.call.args,
|
"Error: func requires first argument to be a symbol (function name)\n");
|
||||||
call->data.call.arg_count);
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args[1]->type != NODE_LIST) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Error: func requires second argument to be a list (parameters)\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare parameters
|
||||||
|
node_t *param_list = args[1];
|
||||||
|
int param_count = param_list->data.list.child_count;
|
||||||
|
char **parameters = NULL;
|
||||||
|
|
||||||
|
if (param_count > 0) {
|
||||||
|
parameters = malloc(sizeof(char *) * param_count);
|
||||||
|
if (!parameters)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (int i = 0; i < param_count; i++) {
|
||||||
|
if (param_list->data.list.children[i]->type != NODE_SYMBOL) {
|
||||||
|
fprintf(stderr, "Error: Function parameters must be symbols\n");
|
||||||
|
for (int j = 0; j < i; j++) {
|
||||||
|
free(parameters[j]);
|
||||||
|
}
|
||||||
|
free(parameters);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
parameters[i] = strdup(param_list->data.list.children[i]->data.symbol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stderr, "Error: Unknown function '%s'\n",
|
// Prepare body
|
||||||
call->data.call.function_name);
|
node_t *body = args[2];
|
||||||
|
if (body->type != NODE_LIST) {
|
||||||
|
node_t *wrapper = create_list_node();
|
||||||
|
add_to_list(wrapper, copy_node(body));
|
||||||
|
body = wrapper;
|
||||||
|
} else {
|
||||||
|
body = copy_node(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register the function
|
||||||
|
return register_user_function(args[0]->data.symbol, parameters, param_count,
|
||||||
|
body);
|
||||||
|
}
|
||||||
|
|
||||||
|
int execute_function_call(node_t *call) {
|
||||||
|
exec_context_t ctx = {0};
|
||||||
|
ctx.local_vars.names = NULL;
|
||||||
|
ctx.local_vars.values = NULL;
|
||||||
|
ctx.local_vars.count = 0;
|
||||||
|
|
||||||
|
node_t *result = execute_function_call_in_context(&ctx, call);
|
||||||
|
if (result) {
|
||||||
|
free_node(result);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int config_parse_string(config_t *config, const char *input) {
|
int config_parse_string(const char *input) {
|
||||||
lexer_t lexer = {0};
|
lexer_t lexer = {0};
|
||||||
lexer.input = input;
|
lexer.input = input;
|
||||||
lexer.pos = 0;
|
lexer.pos = 0;
|
||||||
@@ -119,7 +172,6 @@ int config_parse_string(config_t *config, const char *input) {
|
|||||||
lexer.current_char = input[0];
|
lexer.current_char = input[0];
|
||||||
|
|
||||||
while (lexer.current_char != '\0') {
|
while (lexer.current_char != '\0') {
|
||||||
printf("%c", lexer.current_char);
|
|
||||||
skip_whitespace(&lexer);
|
skip_whitespace(&lexer);
|
||||||
skip_comment(&lexer);
|
skip_comment(&lexer);
|
||||||
skip_whitespace(&lexer);
|
skip_whitespace(&lexer);
|
||||||
@@ -133,12 +185,13 @@ int config_parse_string(config_t *config, const char *input) {
|
|||||||
|
|
||||||
node_t *stmt = parse_statement(&lexer);
|
node_t *stmt = parse_statement(&lexer);
|
||||||
if (stmt) {
|
if (stmt) {
|
||||||
if (execute_function_call(config, stmt) != 0) {
|
if (execute_function_call(stmt) != 0) {
|
||||||
fprintf(stderr, "Error executing statement at line %d\n", lexer.line);
|
fprintf(stderr, "Error executing statement at line %d\n", lexer.line);
|
||||||
}
|
}
|
||||||
if (stmt->type != NODE_FUNCTION_CALL ||
|
if (stmt->type != NODE_FUNCTION_CALL ||
|
||||||
strcmp(stmt->data.call.function_name, "define") != 0) {
|
(strcmp(stmt->data.call.function_name, "define") != 0 &&
|
||||||
free_node(stmt); // Don't free if ownership was transferred to define
|
strcmp(stmt->data.call.function_name, "func") != 0)) {
|
||||||
|
free_node(stmt); // Don't free if ownership was transferred
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,7 +204,7 @@ int config_parse_string(config_t *config, const char *input) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int config_parse_file(config_t *config, const char *filename) {
|
int config_parse_file(const char *filename) {
|
||||||
FILE *file = fopen(filename, "r");
|
FILE *file = fopen(filename, "r");
|
||||||
long file_size = 0;
|
long file_size = 0;
|
||||||
char *content = NULL;
|
char *content = NULL;
|
||||||
@@ -175,7 +228,7 @@ int config_parse_file(config_t *config, const char *filename) {
|
|||||||
content[file_size] = '\0';
|
content[file_size] = '\0';
|
||||||
fclose(file);
|
fclose(file);
|
||||||
|
|
||||||
result = config_parse_string(config, content);
|
result = config_parse_string(content);
|
||||||
free(content);
|
free(content);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -183,8 +236,8 @@ int config_parse_file(config_t *config, const char *filename) {
|
|||||||
|
|
||||||
// Getter functions
|
// Getter functions
|
||||||
|
|
||||||
const char *config_get_key_mapping(config_t *config, const char *key_combo) {
|
const char *config_get_key_mapping(const char *key_combo) {
|
||||||
key_mapping_t *mapping = config->key_mappings;
|
key_mapping_t *mapping = config.key_mappings;
|
||||||
while (mapping) {
|
while (mapping) {
|
||||||
if (strcmp(mapping->key_combo, key_combo) == 0) {
|
if (strcmp(mapping->key_combo, key_combo) == 0) {
|
||||||
return mapping->function_name;
|
return mapping->function_name;
|
||||||
@@ -194,8 +247,8 @@ const char *config_get_key_mapping(config_t *config, const char *key_combo) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
node_t *find_variable(config_t *config, const char *name) {
|
node_t *find_variable(const char *name) {
|
||||||
config_var_t *var = config->variables;
|
config_var_t *var = config.variables;
|
||||||
while (var) {
|
while (var) {
|
||||||
if (strcmp(var->name, name) == 0) {
|
if (strcmp(var->name, name) == 0) {
|
||||||
return var->value;
|
return var->value;
|
||||||
@@ -205,58 +258,56 @@ node_t *find_variable(config_t *config, const char *name) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *config_get_string(config_t *config, const char *path,
|
const char *config_get_string(const char *path, const char *default_value) {
|
||||||
const char *default_value) {
|
node_t *node = find_variable(path);
|
||||||
node_t *node = find_variable(config, path);
|
|
||||||
if (node && node->type == NODE_STRING) {
|
if (node && node->type == NODE_STRING) {
|
||||||
return node->data.string;
|
return node->data.string;
|
||||||
}
|
}
|
||||||
return default_value;
|
return default_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
int config_get_int(config_t *config, const char *path, int default_value) {
|
int config_get_int(const char *path, int default_value) {
|
||||||
node_t *node = find_variable(config, path);
|
node_t *node = find_variable(path);
|
||||||
if (node && node->type == NODE_NUMBER) {
|
if (node && node->type == NODE_NUMBER) {
|
||||||
return (int)node->data.number;
|
return (int)node->data.number;
|
||||||
}
|
}
|
||||||
return default_value;
|
return default_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
double config_get_double(config_t *config, const char *path,
|
double config_get_double(const char *path, double default_value) {
|
||||||
double default_value) {
|
node_t *node = find_variable(path);
|
||||||
node_t *node = find_variable(config, path);
|
|
||||||
if (node && node->type == NODE_NUMBER) {
|
if (node && node->type == NODE_NUMBER) {
|
||||||
return node->data.number;
|
return node->data.number;
|
||||||
}
|
}
|
||||||
return default_value;
|
return default_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool config_get_bool(config_t *config, const char *path, bool default_value) {
|
bool config_get_bool(const char *path, bool default_value) {
|
||||||
node_t *node = find_variable(config, path);
|
node_t *node = find_variable(path);
|
||||||
if (node && node->type == NODE_BOOLEAN) {
|
if (node && node->type == NODE_BOOLEAN) {
|
||||||
return node->data.boolean;
|
return node->data.boolean;
|
||||||
}
|
}
|
||||||
return default_value;
|
return default_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void config_print_all(config_t *config) {
|
void config_print_all(void) {
|
||||||
printf("Key Mappings:\n");
|
printf("Key Mappings:\n");
|
||||||
printf("%-20s -> %s\n", "Key Combination", "Function");
|
printf("%-20s -> %s\n", "Key Combination", "Function\n");
|
||||||
printf("%-20s %s\n", "---------------", "--------");
|
printf("%-20s %s\n", "---------------", "--------\n");
|
||||||
|
|
||||||
key_mapping_t *mapping = config->key_mappings;
|
key_mapping_t *mapping = config.key_mappings;
|
||||||
while (mapping) {
|
while (mapping) {
|
||||||
printf("%-20s -> %s\n", mapping->key_combo, mapping->function_name);
|
printf("%-20s -> %s\n", mapping->key_combo, mapping->function_name);
|
||||||
mapping = mapping->next;
|
mapping = mapping->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("\nVariables:\n");
|
printf("\nVariables:\n");
|
||||||
printf("%-20s = %s\n", "Name", "Value");
|
printf("%-20s = %s\n", "Name", "Value\n");
|
||||||
printf("%-20s %s\n", "----", "-----");
|
printf("%-20s %s\n", "----", "-----\n");
|
||||||
|
|
||||||
config_var_t *var = config->variables;
|
config_var_t *var = config.variables;
|
||||||
while (var) {
|
while (var) {
|
||||||
printf("%-20s = ", var->name);
|
printf("%-20s = \n", var->name);
|
||||||
|
|
||||||
switch (var->value->type) {
|
switch (var->value->type) {
|
||||||
case NODE_STRING:
|
case NODE_STRING:
|
||||||
|
|||||||
+49
-57
@@ -1,5 +1,8 @@
|
|||||||
#include "../include/data.h"
|
#include "../include/data.h"
|
||||||
#include "../include/define.h"
|
#include "../include/define.h"
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
void advance_char(lexer_t *lexer) {
|
void advance_char(lexer_t *lexer) {
|
||||||
@@ -27,74 +30,63 @@ void skip_comment(lexer_t *lexer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Node creation functions
|
node_t *create_list_node(void) {
|
||||||
node_t *create_node(node_type_t type) {
|
|
||||||
node_t *node = malloc(sizeof(node_t));
|
node_t *node = malloc(sizeof(node_t));
|
||||||
if (!node)
|
if (!node) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
memset(node, 0, sizeof(node_t));
|
|
||||||
node->type = type;
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
node_t *create_symbol_node(const char *symbol) {
|
|
||||||
node_t *node = create_node(NODE_SYMBOL);
|
|
||||||
if (node) {
|
|
||||||
strncpy(node->data.symbol, symbol, MAX_SYMBOL_LENGTH - 1);
|
|
||||||
node->data.symbol[MAX_SYMBOL_LENGTH - 1] = '\0';
|
|
||||||
}
|
}
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
node_t *create_string_node(const char *string) {
|
node->type = NODE_LIST;
|
||||||
node_t *node = create_node(NODE_STRING);
|
node->data.list.child_count = 0;
|
||||||
if (node) {
|
node->data.list.children = NULL;
|
||||||
strncpy(node->data.string, string, MAX_STRING_LENGTH - 1);
|
|
||||||
node->data.string[MAX_STRING_LENGTH - 1] = '\0';
|
|
||||||
}
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
node_t *create_number_node(double number) {
|
|
||||||
node_t *node = create_node(NODE_NUMBER);
|
|
||||||
if (node) {
|
|
||||||
node->data.number = number;
|
|
||||||
}
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
node_t *create_boolean_node(bool value) {
|
|
||||||
node_t *node = create_node(NODE_BOOLEAN);
|
|
||||||
if (node) {
|
|
||||||
node->data.boolean = value;
|
|
||||||
}
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
node_t *create_function_ref_node(const char *function_name) {
|
|
||||||
node_t *node = create_node(NODE_FUNCTION_REF);
|
|
||||||
if (node) {
|
|
||||||
strncpy(node->data.function_ref, function_name, MAX_SYMBOL_LENGTH - 1);
|
|
||||||
node->data.function_ref[MAX_SYMBOL_LENGTH - 1] = '\0';
|
|
||||||
}
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
node_t *create_function_call_node(const char *function_name) {
|
|
||||||
node_t *node = create_node(NODE_FUNCTION_CALL);
|
|
||||||
if (node) {
|
|
||||||
strncpy(node->data.call.function_name, function_name,
|
|
||||||
MAX_SYMBOL_LENGTH - 1);
|
|
||||||
node->data.call.function_name[MAX_SYMBOL_LENGTH - 1] = '\0';
|
|
||||||
node->data.call.arg_count = 0;
|
|
||||||
}
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_arg_to_call(node_t *call, node_t *arg) {
|
void add_arg_to_call(node_t *call, node_t *arg) {
|
||||||
if (call->type == NODE_FUNCTION_CALL &&
|
if (call->type == NODE_FUNCTION_CALL &&
|
||||||
call->data.call.arg_count < MAX_ARGS) {
|
call->data.call.arg_count < MAX_ARGS) {
|
||||||
|
call->data.call.args =
|
||||||
|
(node_t **)realloc(call->data.call.args,
|
||||||
|
(call->data.call.arg_count + 1) * sizeof(node_t *));
|
||||||
call->data.call.args[call->data.call.arg_count++] = arg;
|
call->data.call.args[call->data.call.arg_count++] = arg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void add_to_list(node_t *list, node_t *element) {
|
||||||
|
node_t **new_children = NULL;
|
||||||
|
if (!list || !element) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure this is actually a list node
|
||||||
|
if (list->type != NODE_LIST) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this is the first element
|
||||||
|
if (list->data.list.children == NULL) {
|
||||||
|
|
||||||
|
fprintf(stderr, "DEBUG : child number 0 added\n");
|
||||||
|
list->data.list.children = malloc(sizeof(node_t *));
|
||||||
|
if (!list->data.list.children) {
|
||||||
|
return; // Memory allocation failed
|
||||||
|
}
|
||||||
|
list->data.list.children[0] = element;
|
||||||
|
list->data.list.child_count = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reallocate to add new element
|
||||||
|
new_children = realloc(list->data.list.children,
|
||||||
|
sizeof(node_t *) * (list->data.list.child_count + 1));
|
||||||
|
if (!new_children) {
|
||||||
|
return; // Memory allocation failed
|
||||||
|
}
|
||||||
|
|
||||||
|
list->data.list.children = new_children;
|
||||||
|
list->data.list.children[list->data.list.child_count] = element;
|
||||||
|
list->data.list.child_count++;
|
||||||
|
fprintf(stderr, "DEBUG : child number %d added\n",
|
||||||
|
list->data.list.child_count);
|
||||||
|
}
|
||||||
|
|||||||
+215
@@ -0,0 +1,215 @@
|
|||||||
|
#include "../include/function.h"
|
||||||
|
#include "../include/data.h"
|
||||||
|
#include "../include/node.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
int register_builtin_function(const char *name,
|
||||||
|
int (*handler)(node_t **args, int arg_count),
|
||||||
|
bool eval_args) {
|
||||||
|
unified_function_t *func = malloc(sizeof(unified_function_t));
|
||||||
|
if (!func)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
func->name = strdup(name);
|
||||||
|
func->type = FUNC_BUILTIN;
|
||||||
|
func->data.builtin.handler = handler;
|
||||||
|
func->data.builtin.eval_args = eval_args;
|
||||||
|
func->next = unified_functions;
|
||||||
|
unified_functions = func;
|
||||||
|
fprintf(stderr, "%s succefully added\n", name);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int register_user_function(const char *name, char **parameters, int param_count,
|
||||||
|
node_t *body) {
|
||||||
|
unified_function_t *func = malloc(sizeof(unified_function_t));
|
||||||
|
if (!func)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
func->name = strdup(name);
|
||||||
|
func->type = FUNC_USER_DEFINED;
|
||||||
|
func->data.user_defined.parameters = parameters;
|
||||||
|
func->data.user_defined.param_count = param_count;
|
||||||
|
func->data.user_defined.body = body;
|
||||||
|
func->next = unified_functions;
|
||||||
|
unified_functions = func;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int register_registry_function(const char *name, command_func_t c_func) {
|
||||||
|
unified_function_t *func = malloc(sizeof(unified_function_t));
|
||||||
|
if (!func)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
func->name = strdup(name);
|
||||||
|
func->type = FUNC_REGISTRY;
|
||||||
|
func->data.registry.func = c_func;
|
||||||
|
func->next = unified_functions;
|
||||||
|
unified_functions = func;
|
||||||
|
fprintf(stderr, "DEBIG : %s added\n", name);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int register_function(const char *name, command_func_t func) {
|
||||||
|
return register_registry_function(name, func);
|
||||||
|
}
|
||||||
|
|
||||||
|
unified_function_t *find_unified_function(const char *name) {
|
||||||
|
unified_function_t *func = unified_functions;
|
||||||
|
while (func) {
|
||||||
|
// fprintf(stderr, "%s\n", func->name);
|
||||||
|
if (strcmp(func->name, name) == 0) {
|
||||||
|
return func;
|
||||||
|
}
|
||||||
|
func = func->next;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
node_t *execute_unified_function(exec_context_t *ctx, const char *name,
|
||||||
|
node_t **args, int arg_count) {
|
||||||
|
unified_function_t *func = find_unified_function(name);
|
||||||
|
if (!func) {
|
||||||
|
fprintf(stderr, "Error: Unknown function '%s'\n", name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (func->type) {
|
||||||
|
case FUNC_BUILTIN: {
|
||||||
|
node_t **eval_args = args;
|
||||||
|
|
||||||
|
// Evaluate arguments if needed
|
||||||
|
if (func->data.builtin.eval_args) {
|
||||||
|
eval_args = malloc(sizeof(node_t *) * arg_count);
|
||||||
|
if (!eval_args)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (int i = 0; i < arg_count; i++) {
|
||||||
|
eval_args[i] = evaluate_node(ctx, args[i]);
|
||||||
|
if (!eval_args[i]) {
|
||||||
|
// Clean up on failure
|
||||||
|
for (int j = 0; j < i; j++) {
|
||||||
|
free_node(eval_args[j]);
|
||||||
|
}
|
||||||
|
free(eval_args);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = func->data.builtin.handler(eval_args, arg_count);
|
||||||
|
|
||||||
|
// Clean up evaluated arguments if we allocated them
|
||||||
|
if (func->data.builtin.eval_args) {
|
||||||
|
for (int i = 0; i < arg_count; i++) {
|
||||||
|
free_node(eval_args[i]);
|
||||||
|
}
|
||||||
|
free(eval_args);
|
||||||
|
}
|
||||||
|
|
||||||
|
return create_boolean_node(result == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
case FUNC_USER_DEFINED: {
|
||||||
|
fprintf(stderr, "DEBUG : BODY length %d\n",
|
||||||
|
func->data.user_defined.body->data.list.child_count);
|
||||||
|
if (func->data.user_defined.param_count != arg_count) {
|
||||||
|
fprintf(stderr, "Error: Function '%s' expects %d arguments, got %d\n",
|
||||||
|
name, func->data.user_defined.param_count, arg_count);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new execution context
|
||||||
|
exec_context_t new_ctx = *ctx;
|
||||||
|
|
||||||
|
if (func->data.user_defined.param_count > 0) {
|
||||||
|
new_ctx.local_vars.count = func->data.user_defined.param_count;
|
||||||
|
new_ctx.local_vars.names =
|
||||||
|
malloc(sizeof(char *) * func->data.user_defined.param_count);
|
||||||
|
new_ctx.local_vars.values =
|
||||||
|
malloc(sizeof(node_t *) * func->data.user_defined.param_count);
|
||||||
|
|
||||||
|
for (int i = 0; i < func->data.user_defined.param_count; i++) {
|
||||||
|
new_ctx.local_vars.names[i] = func->data.user_defined.parameters[i];
|
||||||
|
new_ctx.local_vars.values[i] = evaluate_node(ctx, args[i]);
|
||||||
|
if (!new_ctx.local_vars.values[i]) {
|
||||||
|
// Clean up on failure
|
||||||
|
for (int j = 0; j < i; j++) {
|
||||||
|
free_node(new_ctx.local_vars.values[j]);
|
||||||
|
}
|
||||||
|
free(new_ctx.local_vars.names);
|
||||||
|
free(new_ctx.local_vars.values);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "DEBUG : body %s\n",
|
||||||
|
func->data.user_defined.body->data.symbol);
|
||||||
|
node_t *result = evaluate_node(&new_ctx, func->data.user_defined.body);
|
||||||
|
|
||||||
|
// Clean up context
|
||||||
|
if (func->data.user_defined.param_count > 0) {
|
||||||
|
for (int i = 0; i < func->data.user_defined.param_count; i++) {
|
||||||
|
free_node(new_ctx.local_vars.values[i]);
|
||||||
|
}
|
||||||
|
free(new_ctx.local_vars.names);
|
||||||
|
free(new_ctx.local_vars.values);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
case FUNC_REGISTRY: {
|
||||||
|
// Registry functions don't take arguments and don't return values
|
||||||
|
func->data.registry.func();
|
||||||
|
return create_boolean_node(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Error: Unknown function type for '%s'\n", name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int execute_command(const char *name) {
|
||||||
|
fprintf(stderr, "Looking for command %s\n", name);
|
||||||
|
unified_function_t *func = find_unified_function(name);
|
||||||
|
if (!func) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (func->type == FUNC_REGISTRY) {
|
||||||
|
func->data.registry.func();
|
||||||
|
return 0;
|
||||||
|
} else if (func->type == FUNC_USER_DEFINED) {
|
||||||
|
fprintf(stderr, "DEBUG ; user definned %s \n", name);
|
||||||
|
exec_context_t ctx = {0};
|
||||||
|
node_t *result = evaluate_node(&ctx, func->data.user_defined.body);
|
||||||
|
if (result) {
|
||||||
|
free_node(result);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute function call with context support
|
||||||
|
node_t *execute_function_call_in_context(exec_context_t *ctx, node_t *call) {
|
||||||
|
|
||||||
|
if (call->type != NODE_FUNCTION_CALL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
fprintf(stderr, "DEBUG : Call in context %s\n",
|
||||||
|
call->data.call.function_name);
|
||||||
|
|
||||||
|
return execute_unified_function(ctx, call->data.call.function_name,
|
||||||
|
call->data.call.args,
|
||||||
|
call->data.call.arg_count);
|
||||||
|
}
|
||||||
+17
-5
@@ -1,5 +1,9 @@
|
|||||||
#include "../include/lexer.h"
|
#include "../include/lexer.h"
|
||||||
|
#include "../include/define.h"
|
||||||
|
#include <ctype.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/ucontext.h>
|
||||||
|
|
||||||
token_t next_token(lexer_t *lexer) {
|
token_t next_token(lexer_t *lexer) {
|
||||||
token_t token = {0};
|
token_t token = {0};
|
||||||
@@ -25,15 +29,18 @@ token_t next_token(lexer_t *lexer) {
|
|||||||
// Comma (function call indicator)
|
// Comma (function call indicator)
|
||||||
if (lexer->current_char == ',') {
|
if (lexer->current_char == ',') {
|
||||||
token.type = TOKEN_COMMA;
|
token.type = TOKEN_COMMA;
|
||||||
|
token.value = (char *)malloc(2 * sizeof(char));
|
||||||
token.value[0] = ',';
|
token.value[0] = ',';
|
||||||
token.value[1] = '\0';
|
token.value[1] = '\0';
|
||||||
advance_char(lexer);
|
advance_char(lexer);
|
||||||
|
fprintf(stderr, "DEBUG : next token = ,\n");
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Percent (function reference indicator)
|
// Percent (function reference indicator)
|
||||||
if (lexer->current_char == '%') {
|
if (lexer->current_char == '%') {
|
||||||
token.type = TOKEN_PERCENT;
|
token.type = TOKEN_PERCENT;
|
||||||
|
token.value = (char *)malloc(2 * sizeof(char));
|
||||||
token.value[0] = '%';
|
token.value[0] = '%';
|
||||||
token.value[1] = '\0';
|
token.value[1] = '\0';
|
||||||
advance_char(lexer);
|
advance_char(lexer);
|
||||||
@@ -43,16 +50,20 @@ token_t next_token(lexer_t *lexer) {
|
|||||||
// Parentheses
|
// Parentheses
|
||||||
if (lexer->current_char == '(') {
|
if (lexer->current_char == '(') {
|
||||||
token.type = TOKEN_LPAREN;
|
token.type = TOKEN_LPAREN;
|
||||||
|
token.value = (char *)malloc(2 * sizeof(char));
|
||||||
token.value[0] = '(';
|
token.value[0] = '(';
|
||||||
token.value[1] = '\0';
|
token.value[1] = '\0';
|
||||||
advance_char(lexer);
|
advance_char(lexer);
|
||||||
|
fprintf(stderr, "DEBUG : next token = (\n");
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lexer->current_char == ')') {
|
if (lexer->current_char == ')') {
|
||||||
token.type = TOKEN_RPAREN;
|
token.type = TOKEN_RPAREN;
|
||||||
|
token.value = (char *)malloc(2 * sizeof(char));
|
||||||
token.value[0] = ')';
|
token.value[0] = ')';
|
||||||
token.value[1] = '\0';
|
token.value[1] = '\0';
|
||||||
|
fprintf(stderr, "DEBUG : next token = )\n");
|
||||||
advance_char(lexer);
|
advance_char(lexer);
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
@@ -63,8 +74,8 @@ token_t next_token(lexer_t *lexer) {
|
|||||||
advance_char(lexer); // Skip opening quote
|
advance_char(lexer); // Skip opening quote
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (lexer->current_char != '"' && lexer->current_char != '\0' &&
|
while (lexer->current_char != '"' && lexer->current_char != '\0') {
|
||||||
i < MAX_TOKEN_LENGTH - 1) {
|
token.value = (char *)realloc(token.value, (i + 1) * sizeof(char));
|
||||||
if (lexer->current_char == '\\' && lexer->input[lexer->pos + 1] != '\0') {
|
if (lexer->current_char == '\\' && lexer->input[lexer->pos + 1] != '\0') {
|
||||||
advance_char(lexer);
|
advance_char(lexer);
|
||||||
switch (lexer->current_char) {
|
switch (lexer->current_char) {
|
||||||
@@ -107,8 +118,8 @@ token_t next_token(lexer_t *lexer) {
|
|||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (
|
while (
|
||||||
(isalnum(lexer->current_char) || strchr("-+._", lexer->current_char)) &&
|
(isalnum(lexer->current_char) || strchr("-+._", lexer->current_char))) {
|
||||||
i < MAX_TOKEN_LENGTH - 1) {
|
token.value = (char *)realloc(token.value, (i + 1) * sizeof(char));
|
||||||
token.value[i++] = lexer->current_char;
|
token.value[i++] = lexer->current_char;
|
||||||
advance_char(lexer);
|
advance_char(lexer);
|
||||||
}
|
}
|
||||||
@@ -127,6 +138,7 @@ token_t next_token(lexer_t *lexer) {
|
|||||||
token.type = TOKEN_NUMBER;
|
token.type = TOKEN_NUMBER;
|
||||||
} else {
|
} else {
|
||||||
token.type = TOKEN_SYMBOL;
|
token.type = TOKEN_SYMBOL;
|
||||||
|
fprintf(stderr, "DEBUG : next token = %s\n", token.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return token;
|
return token;
|
||||||
@@ -134,7 +146,7 @@ token_t next_token(lexer_t *lexer) {
|
|||||||
|
|
||||||
// Error case
|
// Error case
|
||||||
token.type = TOKEN_ERROR;
|
token.type = TOKEN_ERROR;
|
||||||
snprintf(token.value, MAX_TOKEN_LENGTH, "Unexpected character '%c'",
|
snprintf(token.value, MAX_TOKEN_LENGTH - 1, "Unexpected character '%c'",
|
||||||
lexer->current_char);
|
lexer->current_char);
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|||||||
+223
@@ -0,0 +1,223 @@
|
|||||||
|
#include "../include/node.h"
|
||||||
|
#include "../include/config_tools.h"
|
||||||
|
#include "../include/define.h"
|
||||||
|
#include "../include/function.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/ucontext.h>
|
||||||
|
|
||||||
|
// Node creation functions
|
||||||
|
node_t *create_node(node_type_t type) {
|
||||||
|
node_t *node = malloc(sizeof(node_t));
|
||||||
|
if (!node)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
memset(node, 0, sizeof(node_t));
|
||||||
|
node->type = type;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
node_t *create_symbol_node(const char *symbol) {
|
||||||
|
node_t *node = create_node(NODE_SYMBOL);
|
||||||
|
if (node) {
|
||||||
|
node->data.symbol = (char *)malloc((MAX_SYMBOL_LENGTH - 1) * sizeof(char));
|
||||||
|
strncpy(node->data.symbol, symbol, MAX_SYMBOL_LENGTH - 1);
|
||||||
|
node->data.symbol[MAX_SYMBOL_LENGTH - 1] = '\0';
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
node_t *create_string_node(const char *string) {
|
||||||
|
node_t *node = create_node(NODE_STRING);
|
||||||
|
if (node) {
|
||||||
|
node->data.string = (char *)malloc((MAX_STRING_LENGTH - 1) * sizeof(char));
|
||||||
|
strncpy(node->data.string, string, MAX_STRING_LENGTH - 1);
|
||||||
|
node->data.string[MAX_STRING_LENGTH - 1] = '\0';
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
node_t *create_number_node(double number) {
|
||||||
|
node_t *node = create_node(NODE_NUMBER);
|
||||||
|
if (node) {
|
||||||
|
node->data.number = number;
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
node_t *create_boolean_node(bool value) {
|
||||||
|
node_t *node = create_node(NODE_BOOLEAN);
|
||||||
|
if (node) {
|
||||||
|
node->data.boolean = value;
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
node_t *create_function_ref_node(const char *function_name) {
|
||||||
|
node_t *node = create_node(NODE_FUNCTION_REF);
|
||||||
|
if (node) {
|
||||||
|
node->data.function_ref =
|
||||||
|
(char *)malloc((MAX_SYMBOL_LENGTH - 1) * sizeof(char));
|
||||||
|
strncpy(node->data.function_ref, function_name, MAX_SYMBOL_LENGTH - 1);
|
||||||
|
node->data.function_ref[MAX_SYMBOL_LENGTH - 1] = '\0';
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
node_t *create_function_call_node(const char *function_name) {
|
||||||
|
node_t *node = create_node(NODE_FUNCTION_CALL);
|
||||||
|
if (node) {
|
||||||
|
node->data.call.function_name =
|
||||||
|
(char *)malloc((MAX_SYMBOL_LENGTH - 1) * sizeof(char));
|
||||||
|
strncpy(node->data.call.function_name, function_name,
|
||||||
|
MAX_SYMBOL_LENGTH - 1);
|
||||||
|
node->data.call.function_name[MAX_SYMBOL_LENGTH - 1] = '\0';
|
||||||
|
node->data.call.arg_count = 0;
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
node_t *copy_node(node_t *src) {
|
||||||
|
if (!src)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
node_t *copy = malloc(sizeof(node_t));
|
||||||
|
if (!copy)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
copy->type = src->type;
|
||||||
|
|
||||||
|
switch (src->type) {
|
||||||
|
case NODE_STRING:
|
||||||
|
copy->data.string = strdup(src->data.string);
|
||||||
|
break;
|
||||||
|
case NODE_NUMBER:
|
||||||
|
copy->data.number = src->data.number;
|
||||||
|
break;
|
||||||
|
case NODE_BOOLEAN:
|
||||||
|
copy->data.boolean = src->data.boolean;
|
||||||
|
break;
|
||||||
|
case NODE_SYMBOL:
|
||||||
|
copy->data.symbol = strdup(src->data.symbol);
|
||||||
|
break;
|
||||||
|
case NODE_FUNCTION_REF:
|
||||||
|
copy->data.function_ref = strdup(src->data.function_ref);
|
||||||
|
break;
|
||||||
|
case NODE_LIST:
|
||||||
|
copy->data.list.child_count = src->data.list.child_count;
|
||||||
|
copy->data.list.children =
|
||||||
|
malloc(sizeof(node_t *) * src->data.list.child_count);
|
||||||
|
for (int i = 0; i < src->data.list.child_count; i++) {
|
||||||
|
copy->data.list.children[i] = copy_node(src->data.list.children[i]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NODE_FUNCTION_CALL:
|
||||||
|
copy->data.call.function_name = strdup(src->data.call.function_name);
|
||||||
|
copy->data.call.arg_count = src->data.call.arg_count;
|
||||||
|
copy->data.call.args = malloc(sizeof(node_t *) * src->data.call.arg_count);
|
||||||
|
for (int i = 0; i < src->data.call.arg_count; i++) {
|
||||||
|
copy->data.call.args[i] = copy_node(src->data.call.args[i]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
free(copy);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_node(node_t *node) {
|
||||||
|
int i;
|
||||||
|
if (!node)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (node->type == NODE_FUNCTION_CALL) {
|
||||||
|
for (i = 0; i < node->data.call.arg_count; i++) {
|
||||||
|
free_node(node->data.call.args[i]);
|
||||||
|
}
|
||||||
|
free(node->data.call.args);
|
||||||
|
} else if (node->type == NODE_LIST) {
|
||||||
|
for (i = 0; i < node->data.list.child_count; i++) {
|
||||||
|
free_node(node->data.list.children[i]);
|
||||||
|
}
|
||||||
|
free(node->data.list.children);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free string data if present
|
||||||
|
if (node->type == NODE_STRING && node->data.string) {
|
||||||
|
free(node->data.string);
|
||||||
|
} else if (node->type == NODE_SYMBOL && node->data.symbol) {
|
||||||
|
free(node->data.symbol);
|
||||||
|
} else if (node->type == NODE_FUNCTION_REF && node->data.function_ref) {
|
||||||
|
free(node->data.function_ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Evaluate a node in the given context
|
||||||
|
node_t *evaluate_node(exec_context_t *ctx, node_t *node) {
|
||||||
|
fprintf(stderr, "DEBUG : evalute node type %d\n", node->type);
|
||||||
|
if (!node)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
switch (node->type) {
|
||||||
|
case NODE_STRING:
|
||||||
|
case NODE_NUMBER:
|
||||||
|
case NODE_BOOLEAN:
|
||||||
|
case NODE_FUNCTION_REF:
|
||||||
|
return copy_node(node);
|
||||||
|
|
||||||
|
case NODE_SYMBOL: {
|
||||||
|
// Look up variable
|
||||||
|
for (int i = 0; i < ctx->local_vars.count; i++) {
|
||||||
|
if (strcmp(ctx->local_vars.names[i], node->data.symbol) == 0) {
|
||||||
|
return copy_node(ctx->local_vars.values[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
node_t *var = find_variable(node->data.symbol);
|
||||||
|
if (var) {
|
||||||
|
return copy_node(var);
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "Error: Undefined variable '%s'\n", node->data.symbol);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
case NODE_FUNCTION_CALL:
|
||||||
|
fprintf(stderr, "DEBUG: function call : %s\n",
|
||||||
|
node->data.call.function_name);
|
||||||
|
return execute_function_call_in_context(ctx, node);
|
||||||
|
|
||||||
|
case NODE_LIST: {
|
||||||
|
// Execute all expressions in list and return last result
|
||||||
|
node_t *result = NULL;
|
||||||
|
fprintf(stderr, "DEBUG : child count %d\n", node->data.list.child_count);
|
||||||
|
for (int i = 0; i < node->data.list.child_count; i++) {
|
||||||
|
fprintf(stderr, "DEBUG : child number %d\n", i);
|
||||||
|
node_t *child = node->data.list.children[i];
|
||||||
|
if (result) {
|
||||||
|
free_node(result);
|
||||||
|
}
|
||||||
|
// Evaluate child and handle function calls
|
||||||
|
if (child->type == NODE_FUNCTION_CALL) {
|
||||||
|
result = execute_function_call_in_context(ctx, child);
|
||||||
|
} else {
|
||||||
|
result = evaluate_node(ctx, child);
|
||||||
|
}
|
||||||
|
if (!result) {
|
||||||
|
fprintf(stderr, "Error evaluating list element %d\n", i);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Error: Cannot evaluate node type %d\n", node->type);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
+174
-14
@@ -1,6 +1,28 @@
|
|||||||
#include "../include/parser.h"
|
#include "../include/parser.h"
|
||||||
|
#include "../include/lexer.h"
|
||||||
|
#include "../include/node.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
node_t *parse_atom(lexer_t *lexer, token_t *token) {
|
node_t *parse_atom(lexer_t *lexer, token_t *token) {
|
||||||
|
// Variable
|
||||||
|
node_t *list = NULL;
|
||||||
|
size_t saved_pos = 0;
|
||||||
|
int saved_line = 0;
|
||||||
|
int saved_column = 0;
|
||||||
|
char saved_char = '\000';
|
||||||
|
|
||||||
|
token_t peek;
|
||||||
|
token_t func_name;
|
||||||
|
token_t next;
|
||||||
|
token_t func_token;
|
||||||
|
|
||||||
|
node_t *call = NULL;
|
||||||
|
node_t *arg = NULL;
|
||||||
|
node_t *element = NULL;
|
||||||
|
|
||||||
|
// Code
|
||||||
switch (token->type) {
|
switch (token->type) {
|
||||||
case TOKEN_SYMBOL:
|
case TOKEN_SYMBOL:
|
||||||
return create_symbol_node(token->value);
|
return create_symbol_node(token->value);
|
||||||
@@ -14,29 +36,169 @@ node_t *parse_atom(lexer_t *lexer, token_t *token) {
|
|||||||
case TOKEN_BOOLEAN:
|
case TOKEN_BOOLEAN:
|
||||||
return create_boolean_node(strcmp(token->value, "true") == 0);
|
return create_boolean_node(strcmp(token->value, "true") == 0);
|
||||||
|
|
||||||
|
case TOKEN_LPAREN: {
|
||||||
|
fprintf(stderr, "DEBUG : list parsing\n");
|
||||||
|
list = create_list_node();
|
||||||
|
|
||||||
|
// Look ahead to see if this is a function call or just a list
|
||||||
|
saved_pos = lexer->pos;
|
||||||
|
saved_line = lexer->line;
|
||||||
|
saved_column = lexer->column;
|
||||||
|
saved_char = lexer->current_char;
|
||||||
|
|
||||||
|
peek = next_token(lexer);
|
||||||
|
|
||||||
|
// If first token is a comma, this is a function call
|
||||||
|
if (peek.type == TOKEN_COMMA) {
|
||||||
|
func_name = next_token(lexer);
|
||||||
|
|
||||||
|
if (func_name.type == TOKEN_SYMBOL) {
|
||||||
|
call = create_function_call_node(func_name.value);
|
||||||
|
|
||||||
|
// Parse arguments until closing paren
|
||||||
|
next = next_token(lexer);
|
||||||
|
while (next.type != TOKEN_RPAREN && next.type != TOKEN_EOF) {
|
||||||
|
arg = NULL;
|
||||||
|
|
||||||
|
if (next.type == TOKEN_PERCENT) {
|
||||||
|
// Function reference argument
|
||||||
|
func_token = next_token(lexer);
|
||||||
|
if (func_token.type == TOKEN_SYMBOL) {
|
||||||
|
arg = create_function_ref_node(func_token.value);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Parse the argument expression recursively
|
||||||
|
arg = parse_expression(lexer, &next);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg) {
|
||||||
|
add_arg_to_call(call, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
next = next_token(lexer);
|
||||||
|
|
||||||
|
// Skip commas between arguments
|
||||||
|
while (next.type == TOKEN_COMMA) {
|
||||||
|
next = next_token(lexer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return call;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, parse as a regular list
|
||||||
|
// Restore lexer state
|
||||||
|
lexer->pos = saved_pos;
|
||||||
|
lexer->line = saved_line;
|
||||||
|
lexer->column = saved_column;
|
||||||
|
lexer->current_char = saved_char;
|
||||||
|
|
||||||
|
// Parse elements in the list
|
||||||
|
while (1) {
|
||||||
|
// Skip whitespace and comments
|
||||||
|
skip_whitespace(lexer);
|
||||||
|
skip_comment(lexer);
|
||||||
|
skip_whitespace(lexer);
|
||||||
|
|
||||||
|
// Check if we're at the end of the list
|
||||||
|
if (lexer->current_char == ')') {
|
||||||
|
// Consume the closing paren
|
||||||
|
lexer->pos++;
|
||||||
|
lexer->column++;
|
||||||
|
if (lexer->pos < strlen(lexer->input)) {
|
||||||
|
lexer->current_char = lexer->input[lexer->pos];
|
||||||
|
} else {
|
||||||
|
lexer->current_char = '\0';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lexer->current_char == '\0') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the next element
|
||||||
|
element = parse_statement(lexer);
|
||||||
|
if (element) {
|
||||||
|
add_to_list(list, element);
|
||||||
|
} else {
|
||||||
|
// If we couldn't parse anything, advance one character to avoid
|
||||||
|
// infinite loop
|
||||||
|
lexer->pos++;
|
||||||
|
lexer->column++;
|
||||||
|
if (lexer->pos < strlen(lexer->input)) {
|
||||||
|
lexer->current_char = lexer->input[lexer->pos];
|
||||||
|
} else {
|
||||||
|
lexer->current_char = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
case TOKEN_PERCENT: {
|
case TOKEN_PERCENT: {
|
||||||
// Parse function reference: %function-name
|
// Parse function reference: %function-name
|
||||||
token_t next = next_token(lexer);
|
next = next_token(lexer);
|
||||||
if (next.type == TOKEN_SYMBOL) {
|
if (next.type == TOKEN_SYMBOL) {
|
||||||
return create_function_ref_node(next.value);
|
return create_function_ref_node(next.value);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case TOKEN_COMMA: {
|
||||||
|
// Function call at top level: ,function-name
|
||||||
|
func_token = next_token(lexer);
|
||||||
|
if (func_token.type == TOKEN_SYMBOL) {
|
||||||
|
return create_function_call_node(func_token.value);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
node_t *parse_expression(lexer_t *lexer, token_t *token) {
|
||||||
|
if (!token) {
|
||||||
|
token_t current = next_token(lexer);
|
||||||
|
return parse_expression(lexer, ¤t);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if this is a function call
|
||||||
|
if (token->type == TOKEN_COMMA) {
|
||||||
|
token_t func_token = next_token(lexer);
|
||||||
|
if (func_token.type == TOKEN_SYMBOL) {
|
||||||
|
return parse_function_call(lexer, func_token.value);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise parse as atom
|
||||||
|
return parse_atom(lexer, token);
|
||||||
|
}
|
||||||
|
|
||||||
node_t *parse_function_call(lexer_t *lexer, const char *function_name) {
|
node_t *parse_function_call(lexer_t *lexer, const char *function_name) {
|
||||||
node_t *call = create_function_call_node(function_name);
|
node_t *call = create_function_call_node(function_name);
|
||||||
if (!call)
|
if (!call)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
// Look for opening parenthesis (optional)
|
||||||
|
size_t saved_pos = lexer->pos;
|
||||||
|
int saved_line = lexer->line;
|
||||||
|
int saved_column = lexer->column;
|
||||||
|
char saved_char = lexer->current_char;
|
||||||
|
|
||||||
token_t token = next_token(lexer);
|
token_t token = next_token(lexer);
|
||||||
|
|
||||||
if (token.type != TOKEN_LPAREN) {
|
if (token.type != TOKEN_LPAREN) {
|
||||||
// Function call without parentheses - no arguments
|
// No parentheses, restore position and return call with no args
|
||||||
printf("no paren\n");
|
lexer->pos = saved_pos;
|
||||||
|
lexer->line = saved_line;
|
||||||
|
lexer->column = saved_column;
|
||||||
|
lexer->current_char = saved_char;
|
||||||
return call;
|
return call;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,15 +214,21 @@ node_t *parse_function_call(lexer_t *lexer, const char *function_name) {
|
|||||||
arg = create_function_ref_node(func_token.value);
|
arg = create_function_ref_node(func_token.value);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Regular argument
|
// Parse argument expression
|
||||||
arg = parse_atom(lexer, &token);
|
arg = parse_expression(lexer, &token);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arg) {
|
if (arg) {
|
||||||
add_arg_to_call(call, arg);
|
add_arg_to_call(call, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get next token
|
||||||
token = next_token(lexer);
|
token = next_token(lexer);
|
||||||
|
|
||||||
|
// Skip commas between arguments
|
||||||
|
while (token.type == TOKEN_COMMA) {
|
||||||
|
token = next_token(lexer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return call;
|
return call;
|
||||||
@@ -73,13 +241,5 @@ node_t *parse_statement(lexer_t *lexer) {
|
|||||||
|
|
||||||
token_t token = next_token(lexer);
|
token_t token = next_token(lexer);
|
||||||
|
|
||||||
if (token.type == TOKEN_COMMA) {
|
return parse_expression(lexer, &token);
|
||||||
// Function call: ,function-name(args)
|
|
||||||
token_t func_token = next_token(lexer);
|
|
||||||
if (func_token.type == TOKEN_SYMBOL) {
|
|
||||||
return parse_function_call(lexer, func_token.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user