commit da339c2
uint
·
2026-10-24 16:20:05 +0000 UTC
parent cf5e22d
Carry data pointer, implement public interface, add stupid birds example
M
expl.c
+102,
-60
1@@ -23,8 +23,8 @@ struct function {
2 expl_native native;
3 expl_node* args;
4 expl_node* body;
5+ void* data;
6 };
7-
8 struct environment {
9 char* name;
10 expl_value value;
11@@ -41,13 +41,14 @@ static int define(environment** env, const char* name, expl_value value);
12 static expl_node* expression(parser* p);
13 static expl_node* list(parser* p);
14 static expl_value* lookup(environment* env, const char* name);
15+expl_node* parse(const char* source);
16 static expl_node* value(parser* p, expl_type type);
17
18 static expl_value eval(expl_node* n, environment** env);
19 static expl_value eval_call(expl_node* args, environment** env);
20 static expl_value eval_fn(expl_node* args, environment** env);
21 static expl_value eval_user(function* f, int argc, expl_value* argv, environment** env);
22-static int register_native(environment** env, const char* name, expl_native fn);
23+static int register_native(environment** env, const char* name, expl_native fn, void* data);
24
25 static void skip_space(parser* p);
26 static char* _strndup(const char* src, size_t len);
27@@ -57,25 +58,6 @@ static expl_node* new_node(expl_type type);
28 static void free_node(expl_node* node);
29 static void free_environment(environment* env);
30
31-static expl_value
32-add(int argc, const expl_value* argv)
33-{
34- expl_value result = { 0 };
35- expl_value fail = { 0 };
36- int i;
37-
38- result.type = EXPL_VALUE_NUMBER;
39-
40- for (i = 0; i < argc; i++) {
41- if (argv[i].type != EXPL_VALUE_NUMBER)
42- return fail;
43-
44- result.as.number += argv[i].as.number;
45- }
46-
47- return result;
48-}
49-
50 static int
51 define(environment** env, const char* name, expl_value value)
52 {
53@@ -164,6 +146,32 @@ lookup(environment* env, const char* name)
54 return NULL;
55 }
56
57+expl_node*
58+parse(const char* source)
59+{
60+ parser p = { 0 };
61+ expl_node* head = NULL;
62+ expl_node** next = &head;
63+
64+ if (!source)
65+ return NULL;
66+ p.src = source;
67+
68+ skip_space(&p);
69+ while (!current_char(&p, '\0')) {
70+ *next = expression(&p);
71+ if (!*next) {
72+ free_node(head);
73+ return NULL;
74+ }
75+
76+ next = &(*next)->next;
77+ skip_space(&p);
78+ }
79+
80+ return head;
81+}
82+
83 static expl_node*
84 value(parser* p, expl_type type)
85 {
86@@ -295,7 +303,7 @@ eval_call(expl_node* n, environment** env)
87 /* call */
88 f = fn->as.function;
89 if (f->native)
90- result = f->native(argc, argv);
91+ result = f->native(argc, argv, f->data);
92 else
93 result = eval_user(f, argc, argv, env);
94
95@@ -367,7 +375,7 @@ eval_user(function* f, int argc, expl_value* argv, environment** env)
96 }
97
98 static int
99-register_native(environment** env, const char* name, expl_native fn)
100+register_native(environment** env, const char* name, expl_native fn, void* data)
101 {
102 function* f = malloc(sizeof(*f));
103 expl_value value = { 0 };
104@@ -378,6 +386,7 @@ register_native(environment** env, const char* name, expl_native fn)
105 f->native = fn;
106 f->args = NULL;
107 f->body = NULL;
108+ f->data = data;
109
110 value.type = EXPL_VALUE_FUNCTION;
111 value.as.function = f;
112@@ -493,36 +502,57 @@ free_environment(environment* env)
113 }
114 }
115
116-expl* expl_init(void);
117-void expl_close(expl* ctx);
118-int expl_register(expl* ctx, const char* name, expl_native fn);
119-expl_value expl_run(expl* ctx, const char* source);
120-void expl_print(const expl_node* node, int depth);
121+expl* expl_init(void)
122+{
123+ return calloc(1, sizeof(expl));
124+}
125
126-expl_node*
127-expl_parse(const char* source)
128+void expl_close(expl* ctx)
129 {
130- parser p = { 0 };
131- expl_node* head = NULL;
132- expl_node** next = &head;
133+ if (!ctx)
134+ return;
135
136- if (!source)
137- return NULL;
138- p.src = source;
139+ free_environment(ctx->env);
140+ free_node(ctx->programs);
141+ free(ctx);
142+}
143
144- skip_space(&p);
145- while (!current_char(&p, '\0')) {
146- *next = expression(&p);
147- if (!*next) {
148- free_node(head);
149- return NULL;
150- }
151+int
152+expl_register(expl* ctx, const char* name, expl_native fn, void* data)
153+{
154+ if (!ctx || !name || !fn)
155+ return 0;
156
157- next = &(*next)->next;
158- skip_space(&p);
159+ return register_native(&ctx->env, name, fn, data);
160+}
161+
162+expl_value
163+expl_run(expl* ctx, const char* source)
164+{
165+ expl_value result = { 0 };
166+ expl_node* program = NULL;
167+ expl_node* n = NULL;
168+
169+ if (!ctx || !source)
170+ return result;
171+
172+ program = parse(source);
173+ if (!program)
174+ return result;
175+
176+ for (n = program; n; n = n->next)
177+ result = eval(n, &ctx->env);
178+
179+ if (ctx->programs) {
180+ n = ctx->programs;
181+ while (n->next)
182+ n = n->next;
183+ n->next = program;
184 }
185+ else
186+ ctx->programs = program;
187
188- return head;
189+ return result;
190 }
191
192 void
193@@ -554,27 +584,39 @@ expl_print(const expl_node* node, int depth)
194 }
195
196 #if 1
197-int
198-main(void)
199+static expl_value
200+birds_who_hit_my_window(int argc, const expl_value* argv, void* data)
201 {
202- environment* env = NULL;
203- expl_node* program = NULL;
204- expl_node* n = NULL;
205+ int* count = (int*)data;
206 expl_value result = { 0 };
207
208- if (!register_native(&env, "+", add))
209- return EXIT_FAILURE;
210+ if (argc == 1 && argv[0].type == EXPL_VALUE_NUMBER)
211+ *count += (int)argv[0].as.number;
212
213- program = expl_parse(
214- "(fn add (x y) (+ x y))\n"
215- "(add 10 20)"
216- );
217+ result.type = EXPL_VALUE_NUMBER;
218+ result.as.number = *count;
219
220- for (n = program; n; n = n->next)
221- result = eval(n, &env);
222+ return result;
223+}
224+
225+#define FIND_THE_BIRDS \
226+"(fn foo (x) (birds_who_hit_window x))\n" \
227+"(foo 134)\n"
228+
229+int
230+main(void)
231+{
232+ int birds_who_hit_my_window_c = 0;
233+ expl* ctx = expl_init();
234+
235+ if (!ctx)
236+ return EXIT_FAILURE;
237
238- printf("%g\n", result.as.number);
239+ expl_register(ctx, "birds_who_hit_my_window", birds_who_hit_my_window, &birds_who_hit_my_window_c);
240+ expl_run(ctx, FIND_THE_BIRDS);
241+ printf("Stupid birds: %d\n", birds_who_hit_my_window_c);
242
243+ expl_close(ctx);
244 return EXIT_SUCCESS;
245 }
246 #endif
M
expl.h
+2,
-2
1@@ -37,7 +37,7 @@ typedef struct expl_node expl_node;
2 typedef struct expl_value expl_value;
3 typedef struct expl expl;
4
5-typedef expl_value (*expl_native)(int argc, const expl_value* argv);
6+typedef expl_value (*expl_native)(int argc, const expl_value* argv, void* data);
7
8 struct expl_node {
9 char* value;
10@@ -57,7 +57,7 @@ struct expl_value {
11
12 expl* expl_init(void);
13 void expl_close(expl* ctx);
14-int expl_register(expl* ctx, const char* name, expl_native fn);
15+int expl_register(expl* ctx, const char* name, expl_native fn, void* data);
16 expl_value expl_run(expl* ctx, const char* source);
17 void expl_print(const expl_node* node, int depth);
18