git @ Cat's Eye Technologies Bhuna / d91294c
Initial import of Bhuna 0.1 sources. catseye 13 years ago
57 changed file(s) with 4683 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 Program ::= {Statement}.
1 Block ::= Statement | "{" {Statement} "}".
2 Statement ::= (Control | Command | Assignment | Block) [";"].
3
4 Control ::= "if" Expr<0> Block ["else" Block]
5 | "while" Expr<0> Block.
6
7 Command ::= VarExpr Expr<0> {"," Expr<0>}
8 Assignment ::= ["local"] VarExpr "=" Expr<0>.
9
10 Expr<N> ::= Expr<N+1> {Op<N> Expr<N+1>}.
11 Expr<4> ::= Primitive.
12
13 Op<0> ::= "&" | "|".
14 Op<1> ::= ">" | "<" | ">=" | "<=" | "=" | "!=".
15 Op<2> ::= "+" | "-".
16 Op<3> ::= "*" | "/" | "%".
17
18 Primitive ::= "(" Expr<0> ")"
19 | "!" Primitive
20 | VarExpr
21 | Block [[2]]
22 | FunName "(" [Expr<0> {"," Expr<0>}] ")"
23 | Literal.
24
25 Literal ::= "[" [Literal {"," Literal}] "]"
26 | <<symbol>> [[3]]
27 | <<number>>.
28
29 VarExpr ::= Var {"[" Expr<0> "]"}.
30 Var ::= <<symbol>>. [[4]]
31
32 Footnotes:
33
34 [[2]]: Only blocks enclosed in braces are valid here.
35 [[3]]: Must start with lowercase letter.
36 [[4]]: Must start with Uppercase letter.
0 Bottles = 99
1 if Bottles > 0 {
2 print Bottles, " bottles of beer on the wall,", EoL,
3 Bottles, " bottles of beer,", EoL,
4 "Take one down, pass it around,", EoL,
5 Bottles - 1, " bottles of beer on the wall.", EoL, EoL
6 Bottles = Bottles - 1
7 }
8
0 Bottles = 9999
1 while Bottles > 0 {
2 Print Bottles, " bottles of beer on the wall,", EoL,
3 Bottles, " bottles of beer,", EoL,
4 "Take one down, pass it around,", EoL,
5 Bottles - 1, " bottles of beer on the wall.", EoL, EoL
6 Bottles = Bottles - 1
7 }
8
0 #!/usr/local/bin/lua
1
2 bottles = 9999
3 while (bottles > 0) do
4 print(bottles, "bottles of beer on the wall,")
5 print(bottles, "bottles of beer,")
6 print("Take none down, pass none around,")
7 print(bottles - 1, "bottles of beer on the wall.");
8 print("");
9 bottles = bottles - 1
10 end
0 #!/usr/bin/perl
1
2 $bottles = 9999;
3 while ($bottles > 0) {
4 print "$bottles bottles of beer on the wall,\n";
5 print "$bottles bottles of beer,\n";
6 print "Take none down, pass none around,\n";
7 $bottles = $bottles - 1;
8 print "$bottles bottles of beer on the wall.\n";
9 print "\n";
10 }
0 F = {
1 Print "hello from f", EoL
2 Print Arg, EoL
3 Print "goodbye from f", EoL
4 Return [119,123] // Index(Arg, 1)
5 }
6
7 G = F([1,2,3],[4,5,6])
8 Print G, EoL
9
0 G = {
1 Q = "hello"
2 F = {
3 Print Q
4 }
5 F
6 }
7
8 G
0 F = {
1 T = 123
2 Return { Return 17 }
3 }
4
5 Print F, EoL
6 Print F(), EoL
7 Print F()(), EoL
8 Print F()()(), EoL
0 F = {
1 Q = 17
2 Return { Return Q }
3 }
4 Print F()()
0 F = {
1 Level = Index(Arg, 1)
2 Print "Level is ", Level, EoL
3 Q = {
4 QLev = Index(Arg, 1)
5 Print "QLev is ", QLev, EoL
6 Print "(And Q thinks Level is ", Level, ")", EoL
7 if (QLev < 3)
8 Q QLev + 1
9 else
10 Print "This is as far as we go.", EoL
11 }
12 if Level < 3 {
13 F Level + 1
14 } else {
15 Print "At level three, woo!", EoL
16 Q(0)
17 }
18 }
19
20 F(0)
0 F = {
1 C = Index(Arg, 1)
2 C Index(Arg, 2)
3 C "cheese"
4 }
5
6 R = {
7 Print "R was called with ", Index(Arg, 1), EoL
8 }
9
10 F R, "Spam Spam Spam Spam wonderful Spam!"
11
0
1 Q = {}
2 P = {
3 Level = Arg[1]
4 if (Level > 0) {
5 Print "Calling Q at level ", Level, EoL
6 Q Level - 1
7 Print "Called Q, Exiting P at level ", Level, EoL
8 }
9 }
10 Q = {
11 Level = Arg.1
12 if (Level > 0) {
13 Print "Calling P at level ", Level, EoL
14 P Level - 1
15 Print "Called P, Exiting Q at level ", Level, EoL
16 }
17 }
18
19 P 10
0 F = {
1 Q = 17
2 G = {
3 Print "Q is ", Q, EoL
4 }
5 G;
6 Return G
7 }
8
9 G = F()
10 G;
11
12
0 F = {
1 Q = 17
2 G = {
3 Print "Q is ", Q, EoL
4 }
5 G;
6 Q = 23;
7 G;
8 Return G
9 }
10
11 G = F()
12 G;
13
14
0 F = 19
1
2 Foo = {
3 local F = 23
4 print F
5 }
6
7 Print F
8 Foo;
9 Print F
0 Foo = {
1 Print Arg
2 }
3
4 Foo 19, 23, 76;
0 Song = {
1 Bottles = 99
2
3 Sing = {
4 Print Bottles, " bottles of beer on the wall,", EoL,
5 Bottles, " bottles of beer,", EoL,
6 "Take none down, pass none around,", EoL,
7 Bottles, " bottles of beer on the wall.", EoL, EoL
8 }
9
10 while True Sing
11
12 }
13
14 Song
0 F = {
1 Q = 17
2 Return { Print Q }
3 }
4
5 while True {
6 G = F()
7 G;
8 }
9
0 Bottles = 99
1 while True {
2 Print Bottles, " bottles of beer on the wall,", EoL,
3 Bottles, " bottles of beer,", EoL,
4 "Take none down, pass none around,", EoL,
5 Bottles, " bottles of beer on the wall.", EoL, EoL
6 }
0 A = ["moe","larry","curly"]
1
2 B = Index(A, 1)
3
4 Print B
5
6 // B = [1,"hello","there"]
7 // Print A, EoL
8 // Print B, EoL
9 // B = A
10 // Print A, EoL
11 // Print B, EoL
12
0
1 F = {
2 Print "hello!"
3 }
4
5 G = {
6 Print "naff!"
7 }
8
9 H = G // does not dup the AST...
10 G = F // lost one ref to the AST...
11 F = G // my fears were unfounded
12
0 G = 3
1
2 R = {
3 if G > 0 {
4 G = G - 1
5 R
6 }
7 }
8
9 R
0
1 R = {
2 P = Arg[1]
3 Print "P is ", P, EoL
4 if (P > 0) R P - 1
5 Print "P is still ", P, EoL
6 }
7
8 R 2
0 A = 1
1 B = 2
2 A = B
3 // debug
4
0 local F = 100
1 while F > 20 {
2 local F = 10
3 print F
4 // global f = 3
5 }
6 print F
7
0 B = 100
1 Print B
2 B = B * 5
3 Print B
0 #include <stdio.h>
1
2 int main(int argc, char **argv)
3 {
4 int f = 100;
5
6 while (f > 20) {
7 int f = 10;
8 printf("%d", f);
9 }
10 printf("%d", f);
11
12 exit(0);
13 }
0 PROG= bhuna
1 SRCS= scan.c parse.c \
2 symbol.c ast.c \
3 mem.c \
4 list.c atom.c buffer.c closure.c dict.c value.c \
5 activation.c eval.c \
6 builtin.c \
7 main.c
8
9 CFLAGS+=-Wall -I/usr/local/include
10 .ifndef NODEBUG
11 CFLAGS+=-g -DDEBUG
12 .else
13 CFLAGS+=-DNDEBUG
14 .endif
15
16 NOMAN= y
17
18 # DESTDIR=/usr/local/sbin
19 strip: bhuna
20 strip bhuna
21 ls -lah bhuna
22 ls -la bhuna
23
24 .include <bsd.prog.mk>
0 #include <assert.h>
1 #include <stdlib.h>
2 #include <stdio.h>
3
4 #include "activation.h"
5
6 #include "mem.h"
7 #include "symbol.h"
8 #include "value.h"
9
10 #ifdef DEBUG
11 extern int trace_activations;
12 #endif
13
14 struct activation *
15 activation_new(struct symbol_table *stab, struct activation *enclosing)
16 {
17 struct activation *a;
18 struct symbol *sym;
19
20 a = bhuna_malloc(sizeof(struct activation));
21 a->alist = NULL;
22 activation_grab(enclosing);
23 a->enclosing = enclosing;
24 a->refcount = 1;
25
26 for (sym = stab->head; sym != NULL; sym = sym->next) {
27 struct alist *al;
28
29 al = bhuna_malloc(sizeof(struct alist));
30 al->next = a->alist;
31 al->sym = sym;
32 al->value = NULL;
33 a->alist = al;
34 }
35
36 #ifdef DEBUG
37 if (trace_activations > 1) {
38 printf("[ARC] created ");
39 activation_dump(a, -1);
40 printf("\n");
41 }
42 #endif
43
44 return(a);
45 }
46
47 void
48 activation_free(struct activation *a)
49 {
50 struct alist *next;
51
52 #ifdef DEBUG
53 if (trace_activations > 1) {
54 printf("[ARC] freeing ");
55 activation_dump(a, -1);
56 printf("\n");
57 }
58 #endif
59
60 assert(a->refcount == 0);
61 while (a->alist != NULL) {
62 next = a->alist->next;
63 value_release(a->alist->value);
64 bhuna_free(a->alist);
65 a->alist = next;
66 }
67 activation_release(a->enclosing);
68 bhuna_free(a);
69 }
70
71 /*** REFCOUNTERS ***/
72
73 void
74 activation_grab(struct activation *a)
75 {
76 if (a == NULL)
77 return;
78 a->refcount++;
79 #ifdef DEBUG
80 if (trace_activations > 1) {
81 printf("[ARC] ");
82 activation_dump(a, -1);
83 printf(" grabbed, refcount now %d\n", a->refcount);
84 }
85 #endif
86 }
87
88 void
89 activation_release(struct activation *a)
90 {
91 if (a == NULL)
92 return;
93 a->refcount--;
94 #ifdef DEBUG
95 if (trace_activations > 1) {
96 printf("[ARC] ");
97 activation_dump(a, -1);
98 printf(" released, refcount now %d\n", a->refcount);
99 }
100 #endif
101 if (a->refcount == 0)
102 activation_free(a);
103 }
104
105 static struct alist *
106 activation_find_sym(struct activation *a, struct symbol *sym)
107 {
108 struct alist *al;
109
110 for (al = a->alist; al != NULL; al = al->next) {
111 if (al->sym == sym)
112 return(al);
113 }
114
115 if (a->enclosing != NULL)
116 return(activation_find_sym(a->enclosing, sym));
117
118 return(NULL);
119 }
120
121 struct value *
122 activation_get_value(struct activation *a, struct symbol *sym)
123 {
124 struct alist *al;
125
126 al = activation_find_sym(a, sym);
127 assert(al != NULL);
128
129 return(al->value);
130 }
131
132 void
133 activation_set_value(struct activation *a, struct symbol *sym, struct value *v)
134 {
135 struct alist *al;
136
137 if ((al = activation_find_sym(a, sym)) == NULL) {
138 #ifdef DEBUG
139 if (trace_activations > 1) {
140 printf("WARNING: ");
141 symbol_dump(sym, 0);
142 printf(" (=");
143 value_print(v);
144 printf(") not found in ");
145 activation_dump(a, -1);
146 printf(", adding\n");
147 }
148 #endif
149
150 al = bhuna_malloc(sizeof(struct alist));
151 al->next = a->alist;
152 al->sym = sym;
153 al->value = NULL;
154 a->alist = al;
155 }
156
157 value_release(al->value);
158 value_grab(v);
159 al->value = v;
160 }
161
162 void
163 activation_dump(struct activation *a, int detail)
164 {
165 #ifdef DEBUG
166 struct alist *al;
167
168 printf("Activation/");
169 if (a == NULL) {
170 printf("(NULL)/");
171 return;
172 }
173 if (detail == -1) {
174 printf("%08lx", (unsigned long)a);
175 } else {
176 for (al = a->alist; al != NULL; al = al->next) {
177 symbol_dump(al->sym, 0);
178 if (detail) {
179 printf("=");
180 value_print(al->value);
181 }
182 printf(" ");
183 }
184 }
185 if (a->enclosing != NULL) {
186 printf(" --> ");
187 activation_dump(a->enclosing, detail);
188 }
189 printf("/");
190 #endif
191 }
0 struct symbol_table;
1 struct symbol;
2 struct value;
3
4 struct activation {
5 int refcount;
6 struct alist *alist;
7 struct activation *enclosing; /* lexically enclosing activation record */
8 };
9
10 struct alist {
11 struct alist *next;
12 struct symbol *sym;
13 struct value *value;
14 };
15
16
17 struct activation *activation_new(struct symbol_table *, struct activation *);
18 void activation_free(struct activation *);
19
20 void activation_grab(struct activation *);
21 void activation_release(struct activation *);
22
23 struct value *activation_get_value(struct activation *, struct symbol *);
24 void activation_set_value(struct activation *, struct symbol *, struct value *);
25
26 void activation_dump(struct activation *, int);
0 #include <stdio.h>
1 #include <stdlib.h>
2 #include <string.h>
3
4 #include "ast.h"
5 #include "list.h"
6 #include "symbol.h"
7 #include "value.h"
8
9 /***** constructors *****/
10
11 struct ast *
12 ast_new_sym(struct symbol *s)
13 {
14 struct ast *a;
15
16 a = malloc(sizeof(struct ast));
17 a->type = AST_SYM;
18
19 a->u.sym.sym = s;
20
21 return(a);
22 }
23
24 struct ast *
25 ast_new_value(struct value *v)
26 {
27 struct ast *a;
28
29 a = malloc(sizeof(struct ast));
30 a->type = AST_VALUE;
31
32 value_grab(v);
33 a->u.value.value = v;
34
35 return(a);
36 }
37
38 struct ast *
39 ast_new_scope(struct ast *body, struct symbol_table *local)
40 {
41 struct ast *a;
42
43 a = malloc(sizeof(struct ast));
44 a->type = AST_SCOPE;
45
46 a->u.scope.body = body;
47
48 a->u.scope.local = local;
49
50 return(a);
51 }
52
53 struct ast *
54 ast_new_apply(struct ast *fn, struct ast *args)
55 {
56 struct ast *a;
57
58 a = malloc(sizeof(struct ast));
59 a->type = AST_APPLY;
60
61 a->u.apply.left = fn;
62 a->u.apply.right = args;
63
64 return(a);
65 }
66
67 struct ast *
68 ast_new_arg(struct ast *left, struct ast *right)
69 {
70 struct ast *a;
71
72 a = malloc(sizeof(struct ast));
73 a->type = AST_ARG;
74
75 a->u.arg.left = left;
76 a->u.arg.right = right;
77
78 return(a);
79 }
80
81 struct ast *
82 ast_new_statement(struct ast *left, struct ast *right)
83 {
84 struct ast *a;
85
86 /*
87 if (left == NULL && right == NULL)
88 return(NULL);
89 if (left == NULL)
90 return(right);
91 if (right == NULL)
92 return(left);
93 */
94
95 a = malloc(sizeof(struct ast));
96 a->type = AST_STATEMENT;
97
98 a->u.statement.left = left;
99 a->u.statement.right = right;
100
101 return(a);
102 }
103
104 struct ast *
105 ast_new_assignment(struct ast *left, struct ast *right)
106 {
107 struct ast *a;
108
109 a = malloc(sizeof(struct ast));
110 a->type = AST_ASSIGNMENT;
111
112 a->u.assignment.left = left;
113 a->u.assignment.right = right;
114
115 return(a);
116 }
117
118 struct ast *
119 ast_new_conditional(struct ast *test, struct ast *yes, struct ast *no)
120 {
121 struct ast *a;
122
123 a = malloc(sizeof(struct ast));
124 a->type = AST_CONDITIONAL;
125
126 a->u.conditional.test = test;
127 a->u.conditional.yes = yes;
128 a->u.conditional.no = no;
129
130 return(a);
131 }
132
133 struct ast *
134 ast_new_while_loop(struct ast *test, struct ast *body)
135 {
136 struct ast *a;
137
138 a = malloc(sizeof(struct ast));
139 a->type = AST_WHILE_LOOP;
140
141 a->u.while_loop.test = test;
142 a->u.while_loop.body = body;
143
144 return(a);
145 }
146
147 void
148 ast_free(struct ast *a)
149 {
150 if (a == NULL) {
151 return;
152 }
153 switch (a->type) {
154 case AST_SYM:
155 break;
156 case AST_VALUE:
157 value_release(a->u.value.value);
158 break;
159 case AST_SCOPE:
160 ast_free(a->u.scope.body);
161 break;
162 case AST_APPLY:
163 ast_free(a->u.apply.left);
164 ast_free(a->u.apply.right);
165 break;
166 case AST_ARG:
167 ast_free(a->u.arg.left);
168 ast_free(a->u.arg.right);
169 break;
170 case AST_STATEMENT:
171 ast_free(a->u.statement.left);
172 ast_free(a->u.statement.right);
173 break;
174 case AST_ASSIGNMENT:
175 ast_free(a->u.assignment.left);
176 ast_free(a->u.assignment.right);
177 break;
178 case AST_CONDITIONAL:
179 ast_free(a->u.conditional.test);
180 ast_free(a->u.conditional.yes);
181 ast_free(a->u.conditional.no);
182 break;
183 case AST_WHILE_LOOP:
184 ast_free(a->u.while_loop.test);
185 ast_free(a->u.while_loop.body);
186 break;
187 }
188 free(a);
189 }
190
191 char *
192 ast_name(struct ast *a)
193 {
194 #ifdef DEBUG
195 if (a == NULL)
196 return("(null)");
197 switch (a->type) {
198 case AST_SYM:
199 return("AST_SYM");
200 case AST_VALUE:
201 return("AST_VALUE");
202 case AST_SCOPE:
203 return("AST_SCOPE");
204 case AST_APPLY:
205 return("AST_APPLY");
206 case AST_ARG:
207 return("AST_ARG");
208 case AST_STATEMENT:
209 return("AST_STATEMENT");
210 case AST_ASSIGNMENT:
211 return("AST_ASSIGNMENT");
212 case AST_CONDITIONAL:
213 return("AST_CONDITIONAL");
214 case AST_WHILE_LOOP:
215 return("AST_WHILE_LOOP");
216 }
217 #endif
218 return("AST_UNKNOWN??!?");
219 }
220
221 void
222 ast_dump(struct ast *a, int indent)
223 {
224 #ifdef DEBUG
225 int i;
226
227 if (a == NULL) {
228 return;
229 }
230 for (i = 0; i < indent; i++) printf(" ");
231 switch (a->type) {
232 case AST_SYM:
233 printf("symbol(");
234 symbol_dump(a->u.sym.sym, 0);
235 printf(")\n");
236 break;
237 case AST_VALUE:
238 printf("value(");
239 value_print(a->u.value.value);
240 printf(")\n");
241 break;
242 case AST_SCOPE:
243 printf("scope {\n");
244 symbol_table_dump(a->u.scope.local, 0);
245 /*symbol_table_dump(a->u.scope.trap, 0);*/
246 ast_dump(a->u.scope.body, indent + 1);
247 for (i = 0; i < indent; i++) printf(" "); printf("}\n");
248 break;
249 case AST_APPLY:
250 printf("apply {\n");
251 ast_dump(a->u.apply.left, indent + 1);
252 ast_dump(a->u.apply.right, indent + 1);
253 for (i = 0; i < indent; i++) printf(" "); printf("}\n");
254 break;
255 case AST_ARG:
256 printf("arg {\n");
257 ast_dump(a->u.arg.left, indent + 1);
258 ast_dump(a->u.arg.right, indent + 1);
259 for (i = 0; i < indent; i++) printf(" "); printf("}\n");
260 break;
261 case AST_STATEMENT:
262 printf("statement {\n");
263 ast_dump(a->u.statement.left, indent + 1);
264 ast_dump(a->u.statement.right, indent + 1);
265 for (i = 0; i < indent; i++) printf(" "); printf("}\n");
266 break;
267 case AST_ASSIGNMENT:
268 printf("assign {\n");
269 ast_dump(a->u.assignment.left, indent + 1);
270 ast_dump(a->u.assignment.right, indent + 1);
271 for (i = 0; i < indent; i++) printf(" "); printf("}\n");
272 break;
273 case AST_CONDITIONAL:
274 printf("conditional {\n");
275 ast_dump(a->u.conditional.test, indent + 1);
276 ast_dump(a->u.conditional.yes, indent + 1);
277 if (a->u.conditional.no != NULL)
278 ast_dump(a->u.conditional.no, indent + 1);
279 for (i = 0; i < indent; i++) printf(" "); printf("}\n");
280 break;
281 case AST_WHILE_LOOP:
282 printf("while {\n");
283 ast_dump(a->u.while_loop.test, indent + 1);
284 ast_dump(a->u.while_loop.body, indent + 1);
285 break;
286 }
287 #endif
288 }
0 #ifndef __AST_H_
1 #define __AST_H_
2
3 struct value;
4 struct symbol;
5 struct list;
6
7 struct ast_sym {
8 struct symbol *sym;
9 };
10
11 struct ast_value {
12 struct value *value;
13 };
14
15 struct ast_scope {
16 struct symbol_table *local;
17 struct ast *body;
18 };
19
20 struct ast_apply {
21 struct ast *left; /* ISA var(/...?) (fn/cmd) */
22 struct ast *right; /* ISA arg */
23 };
24
25 struct ast_arg {
26 struct ast *left; /* ISA arg/apply/var */
27 struct ast *right; /* ISA arg/apply/var */
28 };
29
30 struct ast_statement {
31 struct ast *left; /* ISA statement/apply */
32 struct ast *right; /* ISA statement/apply */
33 };
34
35 struct ast_assignment {
36 struct ast *left; /* ISA var */
37 struct ast *right; /* ISA apply/var */
38 };
39
40 struct ast_conditional {
41 struct ast *test; /* ISA apply/var */
42 struct ast *yes; /* ISA statement/apply */
43 struct ast *no; /* ISA statement/apply/NULL */
44 };
45
46 struct ast_while_loop {
47 struct ast *test; /* ISA apply/var */
48 struct ast *body; /* ISA statement/apply */
49 };
50
51 #define AST_SYM 1
52 #define AST_VALUE 2
53 #define AST_SCOPE 3
54 #define AST_APPLY 4
55 #define AST_ARG 5
56 #define AST_STATEMENT 6
57 #define AST_ASSIGNMENT 7
58 #define AST_CONDITIONAL 8
59 #define AST_WHILE_LOOP 9
60
61 union ast_union {
62 struct ast_sym sym;
63 struct ast_value value;
64 struct ast_scope scope;
65 struct ast_apply apply;
66 struct ast_arg arg;
67 struct ast_statement statement;
68 struct ast_assignment assignment;
69 struct ast_conditional conditional;
70 struct ast_while_loop while_loop;
71 };
72
73 struct ast {
74 int type;
75 union ast_union u;
76 };
77
78 struct ast *ast_new_sym(struct symbol *);
79 struct ast *ast_new_value(struct value *);
80 struct ast *ast_new_scope(struct ast *, struct symbol_table *);
81 struct ast *ast_new_apply(struct ast *, struct ast *);
82 struct ast *ast_new_arg(struct ast *, struct ast *);
83 struct ast *ast_new_statement(struct ast *, struct ast *);
84 struct ast *ast_new_assignment(struct ast *, struct ast *);
85 struct ast *ast_new_conditional(struct ast *, struct ast *, struct ast *);
86 struct ast *ast_new_while_loop(struct ast *, struct ast *);
87 void ast_free(struct ast *);
88
89 void ast_dump(struct ast *, int);
90 char *ast_name(struct ast *);
91
92 void ast_eval(struct ast *, struct value **);
93
94 #endif /* !__AST_H_ */
0 #include <string.h>
1 #include <stdlib.h>
2
3 #include "mem.h"
4 #include "atom.h"
5
6 static struct atom_entry *atom_entry_head = NULL;
7 static int next_atom = 0;
8
9 int
10 atom_resolve(char *lexeme)
11 {
12 struct atom_entry *ae;
13
14 /* find lexeme in atom table */
15 for (ae = atom_entry_head; ae != NULL; ae = ae->next) {
16 if (strcmp(ae->lexeme, lexeme) == 0)
17 return(ae->atom);
18 }
19 /* create new atom */
20 ae = bhuna_malloc(sizeof(struct atom_entry));
21 ae->next = atom_entry_head;
22 ae->lexeme = strdup(lexeme);
23 ae->atom = next_atom++;
24 atom_entry_head = ae;
25
26 return(ae->atom);
27 }
0 #ifndef __ATOM_H_
1 #define __ATOM_H_
2
3 struct atom_entry {
4 struct atom_entry *next;
5 char *lexeme;
6 int atom;
7 };
8
9 int atom_resolve(char *);
10
11 #endif /* !__ATOM_H_ */
0 /*
1 * Copyright (c) 2004 The DragonFly Project. All rights reserved.
2 *
3 * This code is derived from software contributed to The DragonFly Project
4 * by Chris Pressey <cpressey@catseye.mine.nu>.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 * 3. Neither the name of The DragonFly Project nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific, prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
30 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 /*
35 * extbuf.c
36 * $Id: buffer.c,v 1.1 2004/07/21 19:52:35 cpressey Exp $
37 * Routines to manipulate extensible buffers.
38 *
39 * Aura buffers are buffers that attempt to automatically expand
40 * when more data is written to them than they can initially hold.
41 * In addition, each extensible buffer contains a cursor from which
42 * its contents may be incrementally scanned.
43 */
44
45 #include <err.h>
46 #include <stdarg.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <sysexits.h>
51
52 #include "buffer.h"
53
54 /*
55 * Create a new extensible buffer with the given initial size.
56 */
57 struct aura_buffer *
58 aura_buffer_new(size_t size)
59 {
60 struct aura_buffer *e;
61
62 e = malloc(sizeof(struct aura_buffer));
63
64 e->len = 0;
65 e->size = size;
66 e->pos = 0;
67
68 e->buf = malloc(size);
69 e->buf[0] = '\0';
70
71 return(e);
72 }
73
74 /*
75 * Deallocate the memory used for an extensible buffer.
76 */
77 void
78 aura_buffer_free(struct aura_buffer *e)
79 {
80 if (e != NULL) {
81 if (e->buf != NULL)
82 free(e->buf);
83 free(e);
84 }
85 }
86
87 /*
88 * Return the underlying (static) buffer of an extensible buffer.
89 *
90 * NOTE that you should NEVER cache the returned pointer anywhere,
91 * as any further manipulation of the extensible buffer may cause
92 * it to be invalidated.
93 *
94 * ALSO NOTE that the buffer may contain embedded NULs, but will
95 * also be guaranteed to be NUL-terminated.
96 */
97 char *
98 aura_buffer_buf(struct aura_buffer *e)
99 {
100 return(e->buf);
101 }
102
103 /*
104 * Return the current length of the extensible buffer.
105 */
106 size_t
107 aura_buffer_len(struct aura_buffer *e)
108 {
109 return(e->len);
110 }
111
112 /*
113 * Return the current size of the extensible buffer. This is how
114 * big it's length may grow to before expanded.
115 */
116 size_t
117 aura_buffer_size(struct aura_buffer *e)
118 {
119 return(e->size);
120 }
121
122 /*
123 * Ensure that an extensible buffer's size is at least the given
124 * size. If it is not, it will be internally grown to that size.
125 * This does not affect the contents of the buffer in any way.
126 */
127 void
128 aura_buffer_ensure_size(struct aura_buffer *e, size_t size)
129 {
130 if (e->size >= size) return;
131 e->size = size;
132 if ((e->buf = realloc(e->buf, e->size)) == NULL) {
133 err(EX_UNAVAILABLE, "realloc()");
134 }
135 }
136
137 /*
138 * Set the contents of an extensible buffer from a regular (char *)
139 * buffer. The extensible buffer will grow if needed. Any existing
140 * contents of the extensible buffer are destroyed in this operation.
141 * Note that, because this requires that the length of the
142 * regular buffer be specified, it may safely contain NUL bytes.
143 */
144 void
145 aura_buffer_set(struct aura_buffer *e, char *buf, size_t length)
146 {
147 while ((length + 1) > e->size) {
148 e->size *= 2;
149 }
150 if ((e->buf = realloc(e->buf, e->size)) == NULL) {
151 err(EX_UNAVAILABLE, "realloc()");
152 }
153 memcpy(e->buf, buf, length);
154 e->len = length;
155 e->buf[e->len] = '\0';
156 }
157
158 /*
159 * Append the contents of a regular buffer to the end of the existing
160 * contents of an extensible buffer. The extensible buffer will grow
161 * if needed. Note that, because this requires that the length of the
162 * regular buffer be specified, it may safely contain NUL bytes.
163 */
164 void
165 aura_buffer_append(struct aura_buffer *e, char *buf, size_t length)
166 {
167 while (e->len + (length + 1) > e->size) {
168 e->size *= 2;
169 }
170 if ((e->buf = realloc(e->buf, e->size)) == NULL) {
171 err(EX_UNAVAILABLE, "realloc()");
172 }
173 memcpy(e->buf + e->len, buf, length);
174 e->len += length;
175 e->buf[e->len] = '\0';
176 }
177
178 /*
179 * Set the contents of an extensible buffer from an ASCIIZ string.
180 * This is identical to aura_buffer_set except that the length need not
181 * be specified, and the ASCIIZ string may not contain embedded NUL's.
182 */
183 void
184 aura_buffer_cpy(struct aura_buffer *e, char *s)
185 {
186 aura_buffer_set(e, s, strlen(s));
187 }
188
189 /*
190 * Append the contents of an ASCIIZ string to an extensible buffer.
191 * This is identical to aura_buffer_append except that the length need not
192 * be specified, and the ASCIIZ string may not contain embedded NUL's.
193 */
194 void
195 aura_buffer_cat(struct aura_buffer *e, char *s)
196 {
197 aura_buffer_append(e, s, strlen(s));
198 }
199
200 /*
201 * Append the entire contents of a text file to an extensible buffer.
202 */
203 int
204 aura_buffer_cat_file(struct aura_buffer *e, char *fmt, ...)
205 {
206 va_list args;
207 char *filename, line[1024];
208 FILE *f;
209
210 va_start(args, fmt);
211 vasprintf(&filename, fmt, args);
212 va_end(args);
213
214 if ((f = fopen(filename, "r")) == NULL)
215 return(0);
216
217 free(filename);
218
219 while (fgets(line, 1023, f) != NULL) {
220 aura_buffer_cat(e, line);
221 }
222
223 fclose(f);
224
225 return(1);
226 }
227
228 /*
229 * Append the entire output of a shell command to an extensible buffer.
230 */
231 int
232 aura_buffer_cat_pipe(struct aura_buffer *e, char *fmt, ...)
233 {
234 va_list args;
235 char *command, line[1024];
236 FILE *p;
237
238 va_start(args, fmt);
239 vasprintf(&command, fmt, args);
240 va_end(args);
241
242 if ((p = popen(command, "r")) == NULL)
243 return(0);
244
245 free(command);
246
247 while (fgets(line, 1023, p) != NULL) {
248 aura_buffer_cat(e, line);
249 }
250
251 pclose(p);
252
253 return(1);
254 }
255
256 /*** CURSORED FUNCTIONS ***/
257
258 /*
259 * Note that the cursor can be anywhere from the first character to
260 * one position _beyond_ the last character in the buffer.
261 */
262
263 int
264 aura_buffer_seek(struct aura_buffer *e, size_t pos)
265 {
266 if (pos <= e->size) {
267 e->pos = pos;
268 return(1);
269 } else {
270 return(0);
271 }
272 }
273
274 size_t
275 aura_buffer_tell(struct aura_buffer *e)
276 {
277 return(e->pos);
278 }
279
280 int
281 aura_buffer_eof(struct aura_buffer *e)
282 {
283 return(e->pos >= e->size);
284 }
285
286 char
287 aura_buffer_peek_char(struct aura_buffer *e)
288 {
289 return(e->buf[e->pos]);
290 }
291
292 char
293 aura_buffer_scan_char(struct aura_buffer *e)
294 {
295 return(e->buf[e->pos++]);
296 }
297
298 int
299 aura_buffer_compare(struct aura_buffer *e, char *s)
300 {
301 int i, pos;
302
303 for (i = 0, pos = e->pos; s[i] != '\0' && pos < e->size; i++, pos++) {
304 if (e->buf[pos] != s[i])
305 return(0);
306 }
307
308 if (pos <= e->size) {
309 return(pos);
310 } else {
311 return(0);
312 }
313 }
314
315 int
316 aura_buffer_expect(struct aura_buffer *e, char *s)
317 {
318 int pos;
319
320 if ((pos = aura_buffer_compare(e, s)) > 0) {
321 e->pos = pos;
322 return(1);
323 } else {
324 return(0);
325 }
326 }
327
328 void
329 aura_buffer_push(struct aura_buffer *e, void *src, size_t len)
330 {
331 aura_buffer_ensure_size(e, e->pos + len);
332 memcpy(e->buf + e->pos, src, len);
333 e->pos += len;
334 }
335
336 int
337 aura_buffer_pop(struct aura_buffer *e, void *dest, size_t len)
338 {
339 if (e->pos - len > 0) {
340 e->pos -= len;
341 memcpy(dest, e->buf + e->pos, len);
342 return(1);
343 } else {
344 return(0);
345 }
346 }
0 /*
1 * Copyright (c) 2004 The DragonFly Project. All rights reserved.
2 *
3 * This code is derived from software contributed to The DragonFly Project
4 * by Chris Pressey <cpressey@catseye.mine.nu>.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 * 3. Neither the name of The DragonFly Project nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific, prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
30 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 /*
35 * buffer.h
36 * $Id: buffer.h,v 1.1 2004/07/21 19:52:35 cpressey Exp $
37 */
38
39 #ifndef __AURA_BUFFER_H_
40 #define __AURA_BUFFER_H_
41
42 #include <stdlib.h>
43
44 struct aura_buffer {
45 char *buf;
46 size_t len;
47 size_t size;
48 size_t pos;
49 };
50
51 struct aura_buffer *aura_buffer_new(size_t);
52 void aura_buffer_free(struct aura_buffer *);
53 char *aura_buffer_buf(struct aura_buffer *);
54 size_t aura_buffer_len(struct aura_buffer *);
55 size_t aura_buffer_size(struct aura_buffer *);
56
57 void aura_buffer_ensure_size(struct aura_buffer *, size_t);
58 void aura_buffer_set(struct aura_buffer *, char *, size_t);
59 void aura_buffer_append(struct aura_buffer *, char *, size_t);
60
61 void aura_buffer_cpy(struct aura_buffer *, char *);
62 void aura_buffer_cat(struct aura_buffer *, char *);
63 int aura_buffer_cat_file(struct aura_buffer *, char *, ...);
64 int aura_buffer_cat_pipe(struct aura_buffer *, char *, ...);
65
66 int aura_buffer_seek(struct aura_buffer *, size_t);
67 size_t aura_buffer_tell(struct aura_buffer *);
68 int aura_buffer_eof(struct aura_buffer *);
69 char aura_buffer_peek_char(struct aura_buffer *);
70 char aura_buffer_scan_char(struct aura_buffer *);
71 int aura_buffer_compare(struct aura_buffer *, char *);
72 int aura_buffer_expect(struct aura_buffer *, char *);
73
74 void aura_buffer_push(struct aura_buffer *, void *, size_t);
75 int aura_buffer_pop(struct aura_buffer *, void *, size_t);
76
77 #endif /* !__AURA_BUFFER_H_ */
0 #include <stdio.h>
1 #include <stdlib.h>
2
3 #include "builtin.h"
4 #include "value.h"
5 #include "list.h"
6 #include "closure.h"
7
8 #include "symbol.h"
9
10 /*
11 * Built-in operations.
12 * Each of these allocates a new value and returns it,
13 * leaving the passed values untouched.
14 * The single parameter `arg' is always a value of type VALUE_LIST.
15 */
16
17 struct builtin_desc builtins[] = {
18 {"Print", builtin_print},
19 {"Return", builtin_return},
20 {"!", builtin_not},
21 {"&", builtin_and},
22 {"|", builtin_or},
23 {"=", builtin_equ},
24 {"!=", builtin_neq},
25 {">", builtin_gt},
26 {"<", builtin_lt},
27 {">=", builtin_gte},
28 {"<=", builtin_lte},
29 {"+", builtin_add},
30 {"-", builtin_sub},
31 {"*", builtin_mul},
32 {"/", builtin_div},
33 {"%", builtin_mod},
34 {"Index", builtin_index},
35 {NULL, NULL}
36 };
37
38 void
39 builtin_return(struct value **arg)
40 {
41 /* Deref the list. */
42 value_set_from_value(arg, (*arg)->v.l->value);
43 }
44
45 void
46 builtin_print(struct value **arg)
47 {
48 struct list *l;
49 struct value *v;
50
51 for (l = (*arg)->v.l; l != NULL; l = l->next) {
52 v = l->value;
53 switch (v->type) {
54 case VALUE_INTEGER:
55 printf("%d", v->v.i);
56 break;
57 case VALUE_BOOLEAN:
58 printf("%s", v->v.b ? "true" : "false");
59 break;
60 case VALUE_STRING:
61 printf("%s", v->v.s);
62 break;
63 case VALUE_LIST:
64 builtin_print(&v);
65 break;
66 case VALUE_STAB:
67 symbol_table_dump(v->v.stab, 1);
68 break;
69 case VALUE_ERROR:
70 printf("#ERR<%s>", v->v.e);
71 break;
72 case VALUE_BUILTIN:
73 printf("#FN<%08lx>", (unsigned long)v->v.f);
74 break;
75 case VALUE_CLOSURE:
76 closure_dump(v->v.k);
77 break;
78 case VALUE_SYMBOL:
79 symbol_dump(v->v.sym, 0);
80 break;
81 default:
82 printf("???unknown(%d)???", v->type);
83 break;
84 }
85 }
86 }
87
88 /*** logical ***/
89
90 void
91 builtin_not(struct value **arg)
92 {
93 struct value *v;
94
95 v = (*arg)->v.l->value;
96
97 if (v->type == VALUE_BOOLEAN) {
98 value_set_boolean(arg, !v->v.b);
99 } else {
100 value_set_error(arg, "type mismatch");
101 }
102 }
103
104 void
105 builtin_and(struct value **arg)
106 {
107 struct value *l, *r;
108
109 l = (*arg)->v.l->value;
110 r = (*arg)->v.l->next->value;
111
112 if (l->type == VALUE_BOOLEAN && r->type == VALUE_BOOLEAN) {
113 value_set_boolean(arg, l->v.b && r->v.b);
114 } else {
115 value_set_error(arg, "type mismatch");
116 }
117 }
118
119 void
120 builtin_or(struct value **arg)
121 {
122 struct value *l, *r;
123
124 l = (*arg)->v.l->value;
125 r = (*arg)->v.l->next->value;
126
127 if (l->type == VALUE_BOOLEAN && r->type == VALUE_BOOLEAN) {
128 value_set_boolean(arg, l->v.b || r->v.b);
129 } else {
130 value_set_error(arg, "type mismatch");
131 }
132 }
133
134 /*** comparison ***/
135
136 void
137 builtin_equ(struct value **arg)
138 {
139 struct value *l, *r;
140
141 l = (*arg)->v.l->value;
142 r = (*arg)->v.l->next->value;
143
144 if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) {
145 value_set_boolean(arg, l->v.i == r->v.i);
146 } else {
147 value_set_error(arg, "type mismatch");
148 }
149 }
150
151 void
152 builtin_neq(struct value **arg)
153 {
154 struct value *l, *r;
155
156 l = (*arg)->v.l->value;
157 r = (*arg)->v.l->next->value;
158
159 if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) {
160 value_set_boolean(arg, l->v.i != r->v.i);
161 } else {
162 value_set_error(arg, "type mismatch");
163 }
164 }
165
166 void
167 builtin_gt(struct value **arg)
168 {
169 struct value *l, *r;
170
171 l = (*arg)->v.l->value;
172 r = (*arg)->v.l->next->value;
173
174 if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) {
175 value_set_boolean(arg, l->v.i > r->v.i);
176 } else {
177 value_set_error(arg, "type mismatch");
178 }
179 }
180
181 void
182 builtin_lt(struct value **arg)
183 {
184 struct value *l, *r;
185
186 l = (*arg)->v.l->value;
187 r = (*arg)->v.l->next->value;
188
189 if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) {
190 value_set_boolean(arg, l->v.i < r->v.i);
191 } else {
192 value_set_error(arg, "type mismatch");
193 }
194 }
195
196 void
197 builtin_gte(struct value **arg)
198 {
199 struct value *l, *r;
200
201 l = (*arg)->v.l->value;
202 r = (*arg)->v.l->next->value;
203
204 if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) {
205 value_set_boolean(arg, l->v.i >= r->v.i);
206 } else {
207 value_set_error(arg, "type mismatch");
208 }
209 }
210
211 void
212 builtin_lte(struct value **arg)
213 {
214 struct value *l, *r;
215
216 l = (*arg)->v.l->value;
217 r = (*arg)->v.l->next->value;
218
219 if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) {
220 value_set_boolean(arg, l->v.i <= r->v.i);
221 } else {
222 value_set_error(arg, "type mismatch");
223 }
224 }
225
226 /*** arithmetic ***/
227
228 void
229 builtin_add(struct value **arg)
230 {
231 struct value *l, *r;
232
233 l = (*arg)->v.l->value;
234 r = (*arg)->v.l->next->value;
235
236 if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) {
237 value_set_integer(arg, l->v.i + r->v.i);
238 } else {
239 value_set_error(arg, "type mismatch");
240 }
241 }
242
243 void
244 builtin_mul(struct value **arg)
245 {
246 struct value *l, *r;
247
248 l = (*arg)->v.l->value;
249 r = (*arg)->v.l->next->value;
250
251 if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) {
252 value_set_integer(arg, l->v.i * r->v.i);
253 } else {
254 value_set_error(arg, "type mismatch");
255 }
256 }
257
258 void
259 builtin_sub(struct value **arg)
260 {
261 struct value *l, *r;
262
263 l = (*arg)->v.l->value;
264 r = (*arg)->v.l->next->value;
265
266 if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) {
267 value_set_integer(arg, l->v.i - r->v.i);
268 } else {
269 value_set_error(arg, "type mismatch");
270 }
271 }
272
273 void
274 builtin_div(struct value **arg)
275 {
276 struct value *l, *r;
277
278 l = (*arg)->v.l->value;
279 r = (*arg)->v.l->next->value;
280
281 if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) {
282 if (r->v.i == 0)
283 value_set_error(arg, "division by zero");
284 else
285 value_set_integer(arg, l->v.i / r->v.i);
286 } else {
287 value_set_error(arg, "type mismatch");
288 }
289 }
290
291 void
292 builtin_mod(struct value **arg)
293 {
294 struct value *l, *r;
295
296 l = (*arg)->v.l->value;
297 r = (*arg)->v.l->next->value;
298
299 if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) {
300 if (r->v.i == 0)
301 value_set_error(arg, "modulo by zero");
302 else
303 value_set_integer(arg, l->v.i % r->v.i);
304 } else {
305 value_set_error(arg, "type mismatch");
306 }
307 }
308
309 /*** list ***/
310
311 void
312 builtin_index(struct value **arg)
313 {
314 struct value *l, *r;
315 int count;
316 struct list *li;
317
318 l = (*arg)->v.l->value;
319 r = (*arg)->v.l->next->value;
320
321 if (l->type == VALUE_LIST && r->type == VALUE_INTEGER) {
322 li = l->v.l;
323 for (count = 1; l != NULL && count < r->v.i; count++)
324 li = li->next;
325 if (li == NULL)
326 value_set_error(arg, "no such element");
327 else
328 value_set_from_value(arg, li->value);
329 } else {
330 value_set_error(arg, "type mismatch");
331 }
332 }
0 #ifndef __BUILTIN_H_
1 #define __BUILTIN_H_
2
3 struct value;
4
5 struct builtin_desc {
6 char *name;
7 void (*fn)(struct value **);
8 };
9
10 extern struct builtin_desc builtins[];
11
12 void builtin_print(struct value **);
13
14 void builtin_return(struct value **);
15
16 void builtin_not(struct value **);
17 void builtin_and(struct value **);
18 void builtin_or(struct value **);
19
20 void builtin_equ(struct value **);
21 void builtin_neq(struct value **);
22 void builtin_gt(struct value **);
23 void builtin_lt(struct value **);
24 void builtin_gte(struct value **);
25 void builtin_lte(struct value **);
26
27 void builtin_add(struct value **);
28 void builtin_mul(struct value **);
29 void builtin_sub(struct value **);
30 void builtin_div(struct value **);
31 void builtin_mod(struct value **);
32
33 void builtin_index(struct value **);
34
35 #endif
0 #include <assert.h>
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 #include "mem.h"
5 #include "closure.h"
6 #include "symbol.h"
7 #include "ast.h"
8 #include "activation.h"
9
10 struct closure *
11 closure_new(struct ast *a, struct activation *ar)
12 {
13 struct closure *c;
14
15 assert(a->type == AST_SCOPE);
16
17 c = bhuna_malloc(sizeof(struct closure));
18 c->ast = a;
19 c->ar = ar;
20
21 return(c);
22 }
23
24 void
25 closure_free(struct closure *c)
26 {
27 activation_release(c->ar);
28 bhuna_free(c);
29 }
30
31 void
32 closure_dump(struct closure *c)
33 {
34 #ifdef DEBUG
35 printf("closure{");
36 ast_dump(c->ast, 0);
37 activation_dump(c->ar, 0);
38 printf("}");
39 #endif
40 }
0 #ifndef __CLOSURE_H_
1 #define __CLOSURE_H_
2
3 struct activation;
4 struct ast;
5
6 struct closure {
7 struct ast *ast;
8 struct activation *ar; /* env in which we were created */
9 };
10
11 struct closure *closure_new(struct ast *, struct activation *);
12 void closure_free(struct closure *);
13 void closure_dump(struct closure *);
14
15 #endif
0 /*
1 * Copyright (c) 2004 The DragonFly Project. All rights reserved.
2 *
3 * This code is derived from software contributed to The DragonFly Project
4 * by Chris Pressey <cpressey@catseye.mine.nu>.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 * 3. Neither the name of The DragonFly Project nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific, prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
30 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 /*
35 * dict.c
36 * $Id$
37 * Routines to manipulate Bhuna dictionaries.
38 */
39
40 #include <assert.h>
41 #include <stdlib.h>
42 #include <string.h>
43
44 #include "mem.h"
45
46 #include "dict.h"
47 #include "value.h"
48
49 /*** CONSTRUCTOR ***/
50
51 /*
52 * Create a new dictionary.
53 */
54 struct dict *
55 dict_new(void)
56 {
57 struct dict *d;
58 int i;
59
60 d = bhuna_malloc(sizeof(struct dict));
61 d->num_buckets = 31;
62 d->bucket = bhuna_malloc(sizeof(struct chain *) * d->num_buckets);
63 for (i = 0; i < d->num_buckets; i++) {
64 d->bucket[i] = NULL;
65 }
66 d->cursor = NULL;
67 d->cur_bucket = 0;
68
69 return(d);
70 }
71
72 /*** DESTRUCTORS ***/
73
74 static void
75 chain_free(struct chain *c)
76 {
77 assert(c != NULL);
78
79 value_release(c->key);
80 value_release(c->value);
81
82 bhuna_free(c);
83 }
84
85 void
86 dict_free(struct dict *d)
87 {
88 struct chain *c;
89 size_t bucket_no;
90
91 for (bucket_no = 0; bucket_no < d->num_buckets; bucket_no++) {
92 c = d->bucket[bucket_no];
93 while (c != NULL) {
94 d->bucket[bucket_no] = c->next;
95 chain_free(c);
96 c = d->bucket[bucket_no];
97 }
98 }
99 bhuna_free(d);
100 }
101
102 /*** UTILITIES ***/
103
104 /*
105 * Hash function, taken from "Compilers: Principles, Techniques, and Tools"
106 * by Aho, Sethi, & Ullman (a.k.a. "The Dragon Book", 2nd edition.)
107 */
108 static size_t
109 hashpjw(struct value *key, size_t table_size) {
110 char *p;
111 unsigned long int h = 0, g;
112
113 /*
114 * XXX ecks ecks ecks XXX
115 * This is naff... for certain values this will work.
116 * For others, it won't...
117 */
118 for (p = (char *)key; p - (char *)key < sizeof(struct value); p++) {
119 h = (h << 4) + (*p);
120 if ((g = h & 0xf0000000))
121 h = (h ^ (g >> 24)) ^ g;
122 }
123
124 return(h % table_size);
125 }
126
127 /*
128 * Create a new bucket (not called directly by client code.)
129 */
130 static struct chain *
131 chain_new(struct value *key, struct value *value)
132 {
133 struct chain *c;
134
135 c = bhuna_malloc(sizeof(struct chain));
136
137 c->next = NULL;
138 /* XXX grab? */
139 c->key = key;
140 c->value = value;
141
142 return(c);
143 }
144
145 /*
146 * Locate the bucket number a particular key would be located in, and the
147 * chain link itself if such a key exists (or NULL if it could not be found.)
148 */
149 static void
150 dict_locate(struct dict *d, struct value *key,
151 size_t *b_index, struct chain **c)
152 {
153 *b_index = hashpjw(key, d->num_buckets);
154 for (*c = d->bucket[*b_index]; *c != NULL; *c = (*c)->next) {
155 if (value_equal(key, (*c)->key))
156 break;
157 }
158 }
159
160 /*** OPERATIONS ***/
161
162 int dict_exists(struct dict *, struct value *);
163
164 /*
165 * Retrieve a value from a dictionary, given its key.
166 */
167 struct value *
168 dict_fetch(struct dict *d, struct value *k)
169 {
170 struct chain *c;
171 size_t i;
172
173 dict_locate(d, k, &i, &c);
174 if (c != NULL) {
175 /* XXX grab? */
176 return(c->value);
177 } else {
178 return(NULL);
179 }
180 }
181
182 /*
183 * Insert a value into a dictionary.
184 */
185 void
186 dict_store(struct dict *d, struct value *k, struct value *v)
187 {
188 struct chain *c;
189 size_t i;
190
191 dict_locate(d, k, &i, &c);
192 if (c == NULL) {
193 /* Chain does not exist, add a new one. */
194 c = chain_new(k, v);
195 c->next = d->bucket[i];
196 d->bucket[i] = c;
197 } else {
198 /* Chain already exists, replace the value. */
199 value_release(c->value);
200 c->value = v;
201 }
202 }
203
204 int
205 dict_exists(struct dict *d, struct value *key)
206 {
207 struct value *v;
208
209 v = dict_fetch(d, key);
210 return(v != NULL);
211 }
212
213 /*
214 * Finds the next bucket with data in it.
215 * If d->cursor == NULL after this, there is no more data.
216 */
217 static void
218 dict_advance(struct dict *d)
219 {
220 while (d->cursor == NULL) {
221 if (d->cur_bucket == d->num_buckets - 1) {
222 /* We're at eof. Do nothing. */
223 break;
224 } else {
225 d->cur_bucket++;
226 d->cursor = d->bucket[d->cur_bucket];
227 }
228 }
229 }
230
231 void
232 dict_rewind(struct dict *d)
233 {
234 d->cur_bucket = 0;
235 d->cursor = d->bucket[d->cur_bucket];
236 dict_advance(d);
237 }
238
239 int
240 dict_eof(struct dict *d)
241 {
242 return(d->cursor == NULL);
243 }
244
245 struct value *
246 dict_getkey(struct dict *d)
247 {
248 if (d->cursor == NULL) {
249 return(NULL);
250 } else {
251 /* XXX grab? */
252 return(d->cursor->key);
253 }
254 }
255
256 void
257 dict_next(struct dict *d)
258 {
259 if (d->cursor != NULL)
260 d->cursor = d->cursor->next;
261 dict_advance(d);
262 }
263
264 size_t
265 dict_size(struct dict *d)
266 {
267 struct chain *c;
268 int bucket_no;
269 size_t count = 0;
270
271 for (bucket_no = 0; bucket_no < d->num_buckets; bucket_no++) {
272 for (c = d->bucket[bucket_no]; c != NULL; c = c->next)
273 count++;
274 }
275
276 return(count);
277 }
0 /*
1 * Copyright (c) 2004 The DragonFly Project. All rights reserved.
2 *
3 * This code is derived from software contributed to The DragonFly Project
4 * by Chris Pressey <cpressey@catseye.mine.nu>.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 * 3. Neither the name of The DragonFly Project nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific, prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
30 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 /*
35 * dict.c
36 * $Id$
37 * Routines to manipulate Bhuna dictionaries.
38 */
39
40 #ifndef __DICT_H_
41 #define __DICT_H_
42
43 struct value;
44
45 struct dict {
46 struct chain **bucket;
47 struct chain *cursor;
48 int cur_bucket;
49 int num_buckets;
50 };
51
52 struct chain {
53 struct chain *next;
54 struct value *key;
55 struct value *value;
56 };
57
58 struct dict *dict_new(void);
59 void dict_free(struct dict *);
60
61 struct value *dict_fetch(struct dict *, struct value *);
62 int dict_exists(struct dict *, struct value *);
63 void dict_store(struct dict *, struct value *, struct value *);
64
65 void dict_rewind(struct dict *);
66 int dict_eof(struct dict *);
67 struct value *dict_getkey(struct dict *);
68 void dict_next(struct dict *);
69
70 size_t dict_size(struct dict *);
71
72 #endif /* !__DICT_H_ */
0 #include <assert.h>
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 #include "ast.h"
6 #include "value.h"
7 #include "symbol.h"
8 #include "list.h"
9 #include "closure.h"
10 #include "activation.h"
11
12 #ifdef DEBUG
13 extern int trace_assignments;
14 extern int trace_calls;
15 extern int trace_ast;
16 extern int trace_closures;
17 #endif
18
19 extern struct activation *current_ar;
20
21 /*** OPERATIONS ***/
22
23 /*
24 * Flatten arguments into a given list value.
25 */
26 static void
27 ast_flatten(struct ast *a, struct value **lvp)
28 {
29 struct value *v = NULL;
30
31 if (a == NULL)
32 return;
33
34 switch (a->type) {
35 case AST_ARG:
36 /*
37 * We go right-to-left here so that our list will
38 * be created the right way 'round.
39 */
40 ast_flatten(a->u.arg.right, lvp);
41 ast_flatten(a->u.arg.left, lvp);
42 break;
43 default:
44 ast_eval(a, &v);
45 value_list_append(lvp, v);
46 value_release(v);
47 }
48 }
49
50 /*** EVALUATOR ***/
51
52 /*
53 * a is roughly analogous to the program counter (PC.)
54 *
55 * v is roughly analogous to the accumulator (A) or top of stack (ToS).
56 */
57 void
58 ast_eval(struct ast *a, struct value **v)
59 {
60 struct symbol *sym;
61 struct value *l = NULL, *r = NULL, *lv = NULL;
62
63 if (a == NULL)
64 return;
65
66 #ifdef DEBUG
67 if (trace_ast) {
68 printf(">>> ENTERING %s[0x%08lx]\n", ast_name(a), (unsigned long)a);
69 }
70 #endif
71
72 switch (a->type) {
73 case AST_SYM:
74 lv = activation_get_value(current_ar, a->u.sym.sym);
75 if (lv == NULL) {
76 printf("*** undefined symbol: ");
77 symbol_dump(a->u.sym.sym, 0);
78 value_set_error(v, "undefined value");
79 } else {
80 value_set_from_value(v, lv);
81 }
82 break;
83 case AST_VALUE:
84 value_set_from_value(v, a->u.value.value);
85 if (*v != NULL && (*v)->type == VALUE_CLOSURE) {
86 /* XXX Freshen the closure. */
87 activation_release((*v)->v.k->ar);
88 activation_grab(current_ar);
89 (*v)->v.k->ar = current_ar;
90 }
91 break;
92 case AST_SCOPE:
93 /*
94 * pretty sure we don't need to do anything with the stab, here.
95 * although we may want to note somewhere that this is the
96 * most recently encountered stab.
97 */
98 ast_eval(a->u.scope.body, v);
99 break;
100 case AST_APPLY:
101 ast_eval(a->u.apply.left, &l);
102 ast_eval(a->u.apply.right, &r);
103 /*
104 * Make the RHS a list (in case it's not) for consistency.
105 */
106 if (r->type == VALUE_LIST) {
107 value_set_from_value(v, r);
108 } else {
109 value_set_list(v);
110 value_list_append(v, r);
111 }
112 value_release(r);
113
114 #ifdef DEBUG
115 if (trace_calls) {
116 printf("---> call:");
117 value_print(l);
118 printf("(");
119 value_print(*v);
120 printf(")\n");
121 }
122 #endif
123
124 /*** BEGIN value_call(l, v); ***/
125
126 if (l->type == VALUE_BUILTIN) {
127 l->v.f(v);
128 } else if (l->type == VALUE_CLOSURE) {
129 struct symbol_table *lstab;
130 struct activation *old_ar;
131
132 assert(l->v.k->ast->type == AST_SCOPE);
133 lstab = l->v.k->ast->u.scope.local;
134
135 /*
136 * Get a new activation record.
137 */
138 old_ar = current_ar;
139
140 /*
141 * Create a new activation record whose lexical
142 * link is the environment of the closure.
143 */
144 current_ar = activation_new(lstab, l->v.k->ar);
145
146 /*
147 * Populate the closure's trapped symbol table with
148 * values taken from the current activation.
149 */
150 /*
151 symbol_table_push_frame(l->v.k->ast->u.scope.trap);
152 */
153
154 /*
155 * Put the arguments into the symbol 'Arg' in the new frame.
156 */
157 sym = symbol_lookup(lstab, "Arg", 0);
158 assert(sym != NULL);
159 activation_set_value(current_ar, sym, *v);
160
161 /*
162 * Evaluate the closure.
163 */
164 ast_eval(l->v.k->ast, v);
165
166 /*
167 * Indicate that we're not longer using ar and that
168 * the refcounter can deallocate it if it wants.
169 */
170 activation_release(current_ar);
171
172 /*
173 * Restore the environment of the symbols to what it was
174 * before the closure was evaluated.
175 */
176 current_ar = old_ar;
177 } else {
178 value_set_error(v, "not executable");
179 }
180
181 /*** END value_call(l, v); ***/
182
183 #ifdef DEBUG
184 if (trace_calls) {
185 printf("<--- call done, retval=");
186 value_print(*v);
187 printf("\n");
188 }
189 #endif
190
191 value_release(l);
192 break;
193 case AST_ARG:
194 value_set_list(v);
195 ast_flatten(a, v);
196 break;
197 case AST_STATEMENT:
198 ast_eval(a->u.statement.left, &l);
199 value_release(l);
200 ast_eval(a->u.statement.right, v);
201 break;
202 case AST_ASSIGNMENT:
203 ast_eval(a->u.assignment.right, v);
204 if (a->u.assignment.left != NULL && a->u.assignment.left->type == AST_SYM) {
205 sym = a->u.assignment.left->u.sym.sym;
206 activation_set_value(current_ar, sym, *v);
207 #ifdef DEBUG
208 if (trace_assignments) {
209 symbol_dump(sym, 1);
210 printf("\n");
211 }
212 #endif
213 } else {
214 value_set_error(v, "bad lvalue");
215 }
216 break;
217 case AST_CONDITIONAL:
218 ast_eval(a->u.conditional.test, &l);
219 if (l == NULL || l->type != VALUE_BOOLEAN) {
220 value_set_error(v, "type mismatch");
221 } else {
222 if (l->v.b) {
223 ast_eval(a->u.conditional.yes, v);
224 } else if (a->u.conditional.no != NULL) {
225 ast_eval(a->u.conditional.no, v);
226 } else {
227 value_set_error(v, "missing else");
228 }
229 }
230 value_release(l);
231 break;
232 case AST_WHILE_LOOP:
233 for (;;) {
234 ast_eval(a->u.while_loop.test, &l);
235 if (l == NULL || l->type != VALUE_BOOLEAN) {
236 value_release(l);
237 value_set_error(v, "type mismatch");
238 break;
239 } else {
240 if (!l->v.b) {
241 /*
242 * `while' condition evaluated to false.
243 */
244 value_release(l);
245 break;
246 }
247 ast_eval(a->u.while_loop.body, v);
248 }
249 }
250 break;
251 }
252
253 #ifdef DEBUG
254 if (trace_ast) {
255 printf("<<< LEAVING %s[0x%08lx] w/value=", ast_name(a), (unsigned long)a);
256 value_print(*v);
257 printf("\n");
258 }
259 #endif
260 }
0 #include <assert.h>
1 #include <stdlib.h>
2 #include <stdio.h>
3
4 #include "mem.h"
5 #include "list.h"
6 #include "value.h"
7
8 void
9 list_cons(struct list **l, struct value *v)
10 {
11 struct list *n;
12
13 n = bhuna_malloc(sizeof(struct list));
14 value_grab(v);
15 n->value = v;
16 n->next = *l;
17 *l = n;
18 }
19
20 void
21 list_free(struct list **l)
22 {
23 struct list *next;
24
25 while ((*l) != NULL) {
26 next = (*l)->next;
27 value_release((*l)->value);
28 bhuna_free((*l));
29 (*l) = next;
30 }
31 }
32
33 size_t
34 list_length(struct list *l)
35 {
36 size_t i = 0;
37
38 while(l != NULL) {
39 i++;
40 l = l->next;
41 }
42
43 return(i);
44 }
45
46 /*
47 * Full comparison used here.
48 */
49 int
50 list_contains(struct list *l, struct value *v)
51 {
52 while (l != NULL) {
53 if (value_equal(l->value, v))
54 return(1);
55 l = l->next;
56 }
57
58 return(0);
59 }
60
61 void
62 list_dump(struct list *l)
63 {
64 printf("[");
65 while (l != NULL) {
66 value_print(l->value);
67 if (l->next != NULL)
68 printf(",");
69 l = l->next;
70 }
71 printf("]");
72 }
0 #ifndef __LIST_H_
1 #define __LIST_H_
2
3 #include <sys/types.h>
4
5 struct value;
6
7 struct list {
8 struct list *next;
9 struct value *value;
10 };
11
12 void list_cons(struct list **, struct value *);
13 void list_free(struct list **);
14 size_t list_length(struct list *);
15 int list_contains(struct list *, struct value *);
16
17 void list_dump(struct list *);
18
19 #endif /* !__LIST_H_ */
0 #include <assert.h>
1 #include <stdio.h>
2 #include <unistd.h>
3
4 #include "scan.h"
5 #include "parse.h"
6 #include "symbol.h"
7 #include "ast.h"
8 #include "builtin.h"
9 #include "value.h"
10 #include "activation.h"
11
12 #ifdef DEBUG
13 int trace_ast = 0;
14 int trace_activations = 0;
15 int trace_calls = 0;
16 int trace_assignments = 0;
17 int trace_refcounting = 0;
18 int trace_closures = 0;
19
20 int num_vars_created = 0;
21 int num_vars_grabbed = 0;
22 int num_vars_released = 0;
23 int num_vars_freed = 0;
24 int num_vars_cowed = 0;
25 int debug_frame = 0;
26 #endif
27
28 struct activation *global_ar;
29 struct activation *current_ar;
30
31 void
32 usage(char **argv)
33 {
34 fprintf(stderr, "Usage: %s "
35 #ifdef DEBUG
36 "[-acfknprstvz] "
37 #endif
38 "source\n",
39 argv[0]);
40 #ifdef DEBUG
41 fprintf(stderr, " -a: trace assignments\n");
42 fprintf(stderr, " -c: trace calls\n");
43 fprintf(stderr, " -f: trace frames\n");
44 fprintf(stderr, " -k: trace closures\n");
45 fprintf(stderr, " -n: don't actually run program\n");
46 fprintf(stderr, " -p: dump program AST before run\n");
47 fprintf(stderr, " -r: show reference counting stats (-rr = trace refcounting)\n");
48 fprintf(stderr, " -s: dump symbol table before run\n");
49 fprintf(stderr, " -t: trace AST transitions in evaluator\n");
50 fprintf(stderr, " -v: trace activation records\n");
51 fprintf(stderr, " -z: dump symbol table after run\n");
52 #endif
53 exit(1);
54 }
55
56 void
57 load_builtins(struct symbol_table *stab, struct builtin_desc *b)
58 {
59 int i;
60 struct value *v;
61 struct symbol *sym;
62
63 for (i = 0; b[i].name != NULL; i++) {
64 sym = symbol_define(stab, b[i].name, SYM_KIND_COMMAND);
65 v = value_new_builtin(b[i].fn);
66 activation_set_value(global_ar, sym, v);
67 value_release(v);
68 }
69
70 /* XXX */
71 sym = symbol_define(stab, "EoL", SYM_KIND_VARIABLE);
72 v = value_new_string("\n");
73 activation_set_value(global_ar, sym, v);
74 value_release(v);
75
76 sym = symbol_define(stab, "True", SYM_KIND_VARIABLE);
77 v = value_new_boolean(1);
78 activation_set_value(global_ar, sym, v);
79 value_release(v);
80
81 sym = symbol_define(stab, "False", SYM_KIND_VARIABLE);
82 v = value_new_boolean(0);
83 activation_set_value(global_ar, sym, v);
84 value_release(v);
85 }
86
87 int
88 main(int argc, char **argv)
89 {
90 char **real_argv = argv;
91 struct scan_st *sc;
92 struct symbol_table *stab;
93 struct ast *a;
94 struct value *v;
95 char *source = NULL;
96 int opt;
97 #ifdef DEBUG
98 int run_program = 1;
99 int dump_symbols_beforehand = 0;
100 int dump_symbols_afterwards = 0;
101 int dump_program = 0;
102 #define OPTS "acfknprstvz"
103 #define RUN_PROGRAM run_program
104 #else
105 #define OPTS ""
106 #define RUN_PROGRAM 1
107 #endif
108
109 #ifdef DEBUG
110 setvbuf(stdout, NULL, _IOLBF, 0);
111 #endif
112
113 /*
114 * Get command-line arguments.
115 */
116 while ((opt = getopt(argc, argv, OPTS)) != -1) {
117 switch(opt) {
118 #ifdef DEBUG
119 case 'a':
120 trace_assignments++;
121 break;
122 case 'c':
123 trace_calls++;
124 break;
125 case 'f':
126 debug_frame++;
127 break;
128 case 'k':
129 trace_closures++;
130 break;
131 case 'n':
132 run_program = 0;
133 break;
134 case 'p':
135 dump_program = 1;
136 break;
137 case 'r':
138 trace_refcounting++;
139 break;
140 case 's':
141 dump_symbols_beforehand = 1;
142 break;
143 case 't':
144 trace_ast++;
145 break;
146 case 'v':
147 trace_activations++;
148 break;
149 case 'z':
150 dump_symbols_afterwards = 1;
151 break;
152 #endif
153 case '?':
154 default:
155 usage(argv);
156 }
157 }
158 argc -= optind;
159 argv += optind;
160
161 if (*argv != NULL)
162 source = *argv;
163 else
164 usage(real_argv);
165
166 if ((sc = scan_open(source)) != NULL) {
167 stab = symbol_table_new(NULL);
168 global_ar = activation_new(stab, NULL);
169 load_builtins(stab, builtins);
170 a = parse_program(sc, stab);
171 scan_close(sc);
172 #ifdef DEBUG
173 if (dump_symbols_beforehand)
174 symbol_table_dump(stab, 1);
175 if (dump_program) {
176 ast_dump(a, 0);
177 }
178 #endif
179 if (sc->errors == 0 && RUN_PROGRAM) {
180 v = value_new_integer(76);
181 current_ar = global_ar;
182 ast_eval(a, &v);
183 value_release(v);
184 }
185 #ifdef DEBUG
186 if (dump_symbols_afterwards)
187 symbol_table_dump(stab, 1);
188 #endif
189 ast_free(a);
190 symbol_table_free(stab);
191 #ifdef DEBUG
192 if (trace_refcounting > 0) {
193 value_dump_global_table();
194 printf("Created: %8d\n", num_vars_created);
195 printf("Grabbed: %8d\n", num_vars_grabbed);
196 printf("Released: %8d\n", num_vars_released);
197 printf("Freed: %8d\n", num_vars_freed);
198 printf("CoW'ed: %8d\n", num_vars_cowed);
199 }
200 #endif
201 return(0);
202 } else {
203 fprintf(stderr, "Can't open `%s'\n", source);
204 return(1);
205 }
206 }
0 /*
1 * Copyright (c) 2004 The DragonFly Project. All rights reserved.
2 *
3 * This code is derived from software contributed to The DragonFly Project
4 * by Chris Pressey <cpressey@catseye.mine.nu>.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 * 3. Neither the name of The DragonFly Project nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific, prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
30 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 /*
35 * mem.c
36 * $Id$
37 * Bhuna memory management functions.
38 */
39
40 #include <assert.h>
41 #include <stdlib.h>
42 #include <string.h>
43
44 void *
45 bhuna_malloc(size_t size, char *what)
46 {
47 void *ptr;
48
49 ptr = malloc(size);
50 assert(ptr != NULL);
51 bzero(ptr, size);
52
53 return(ptr);
54 }
55
56 char *
57 bhuna_strdup(char *string)
58 {
59 char *ptr;
60
61 ptr = strdup(string);
62 assert(ptr != NULL);
63
64 return(ptr);
65 }
66
67 void
68 bhuna_free(void *ptr)
69 {
70 assert(ptr != NULL);
71 free(ptr);
72 }
0 /*
1 * Copyright (c) 2004 The DragonFly Project. All rights reserved.
2 *
3 * This code is derived from software contributed to The DragonFly Project
4 * by Chris Pressey <cpressey@catseye.mine.nu>.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 * 3. Neither the name of The DragonFly Project nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific, prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
30 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 /*
35 * mem.h
36 * $Id$
37 * Bhuna memory management functions and macros.
38 */
39
40 #ifndef __MEM_H_
41 #define __MEM_H_
42
43 #include <sys/types.h>
44
45 #ifdef DEBUG
46 void *bhuna_malloc(size_t);
47 char *bhuna_strdup(char *);
48 void bhuna_free(void *);
49 #else
50 #define bhuna_malloc(x) malloc(x)
51 #define bhuna_strdup(x) strdup(x)
52 #define bhuna_free(x) free(x)
53 #endif
54
55 #endif
0 /*
1 * Copyright (c)2004 Cat's Eye Technologies. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions
5 * are met:
6 *
7 * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 *
10 * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * Neither the name of Cat's Eye Technologies nor the names of its
16 * contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
24 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30 * OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32 /*
33 * parse.c
34 * Recursive-descent parser for Bhuna.
35 * $Id: parse.c 54 2004-04-23 22:51:09Z catseye $
36 */
37
38 #include <assert.h>
39 #include <ctype.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43
44 #include "scan.h"
45 #include "parse.h"
46 #include "symbol.h"
47 #include "value.h"
48 #include "atom.h"
49 #include "ast.h"
50
51 #define VAR_LOCAL 0
52 #define VAR_GLOBAL 1
53
54 #define VAR_MUST_EXIST 0
55 #define VAR_MAY_EXIST 1
56 #define VAR_MUST_NOT_EXIST 2
57
58 /* util */
59
60 struct ast *
61 ast_new_empty_list(struct symbol_table *stab)
62 {
63 struct value *v;
64 struct ast *a;
65
66 /*
67 * Optimization: make this one symbol once,
68 * share it as a global value...
69 */
70 v = value_new_list();
71 a = ast_new_value(v);
72 value_release(v);
73 return(a);
74 }
75
76 /* ---------------- TOP LEVEL ----------------*/
77
78 struct ast *
79 parse_program(struct scan_st *sc, struct symbol_table *stab)
80 {
81 struct ast *a = NULL;
82
83 while (sc->type != TOKEN_EOF) {
84 a = ast_new_statement(a, parse_statement(sc, stab));
85 }
86
87 return(a);
88 }
89
90 /*
91 * Caller must allocate *istab if they want us to have one.
92 * Otherwise they should set it to NULL, and we'll just use the one above.
93 */
94 struct ast *
95 parse_block(struct scan_st *sc, struct symbol_table *stab,
96 struct symbol_table **istab)
97 {
98 struct ast *a = NULL;
99 /* struct value *v;
100 struct symbol *sym; */
101
102 assert(*istab != NULL);
103
104 if (tokeq(sc, "{")) {
105 scan_expect(sc, "{");
106 while (tokne(sc, "}") && sc->type != TOKEN_EOF) {
107 a = ast_new_statement(a, parse_statement(sc, *istab));
108 }
109 scan_expect(sc, "}");
110 } else {
111 a = parse_statement(sc, *istab);
112 }
113
114 /*
115 * For housekeeping, we place a reference to this symbol table
116 * in an anonymous symbol in the overlying symbol table.
117 */
118 /*
119 if (!symbol_table_is_empty(*istab) != NULL) {
120 sym = symbol_define(stab, NULL, SYM_KIND_ANONYMOUS);
121 v = value_new_symbol_table(*istab);
122 symbol_set_value(sym, v);
123 value_release(v);
124 }
125 */
126
127 return(a);
128 }
129
130 struct ast *
131 parse_statement(struct scan_st *sc, struct symbol_table *stab)
132 {
133 struct symbol_table *istab;
134 struct ast *a, *l, *r;
135
136 if (tokeq(sc, "{")) {
137 istab = symbol_table_new(stab);
138 a = parse_block(sc, stab, &istab);
139 } else if (tokeq(sc, "if")) {
140 scan(sc);
141 a = parse_expr(sc, stab, 0);
142 istab = symbol_table_new(stab);
143 l = parse_block(sc, stab, &istab);
144 if (tokeq(sc, "else")) {
145 scan(sc);
146 istab = symbol_table_new(stab);
147 r = parse_block(sc, stab, &istab);
148 } else {
149 r = NULL;
150 }
151 a = ast_new_conditional(a, l, r);
152 } else if (tokeq(sc, "while")) {
153 scan(sc);
154 l = parse_expr(sc, stab, 0);
155 istab = symbol_table_new(stab);
156 r = parse_block(sc, stab, &istab);
157 a = ast_new_while_loop(l, r);
158 } else if (tokeq(sc, "local")) {
159 scan(sc);
160 a = parse_assignment(sc, stab);
161 } else {
162 if (symbol_lookup(stab, sc->token, VAR_GLOBAL) == NULL) {
163 /*
164 * Symbol doesn't exist at all - it MUST be
165 * an assignment, and it MUST be local.
166 */
167 a = parse_assignment(sc, stab);
168 } else {
169 a = parse_command(sc, stab);
170 }
171 }
172 if (tokeq(sc, ";"))
173 scan(sc);
174 return(a);
175 }
176
177 struct ast *
178 parse_assignment(struct scan_st *sc, struct symbol_table *stab)
179 {
180 struct symbol *sym;
181 struct ast *l, *r;
182
183 l = parse_var(sc, stab, &sym, VAR_LOCAL, VAR_MUST_NOT_EXIST);
184 scan_expect(sc, "=");
185 r = parse_expr(sc, stab, 0);
186 return(ast_new_assignment(l, r));
187 }
188
189 struct ast *
190 parse_command(struct scan_st *sc, struct symbol_table *stab)
191 {
192 struct symbol *sym;
193 struct ast *a, *l, *r;
194
195 a = parse_var(sc, stab, &sym, VAR_GLOBAL, VAR_MUST_EXIST);
196 if (tokeq(sc, "=")) {
197 /*
198 * Actually... it's an assignment to an already-existing variable.
199 */
200 scan(sc);
201 r = parse_expr(sc, stab, 0);
202 a = ast_new_assignment(a, r);
203 return(a);
204 }
205
206 if (tokne(sc, "}") && tokne(sc, ";") && sc->type != TOKEN_EOF) {
207 l = parse_expr(sc, stab, 0);
208 while (tokeq(sc, ",")) {
209 scan_expect(sc, ",");
210 r = parse_expr(sc, stab, 0);
211 l = ast_new_arg(l, r);
212 }
213 } else {
214 l = ast_new_empty_list(stab);
215 }
216 a = ast_new_apply(a, l);
217
218 return(a);
219 }
220
221 /* ------------------------- EXPRESSIONS ------------------------ */
222
223 int maxlevel = 3;
224
225 char *op[4][6] = {
226 { "&", "|", "", "", "", "" },
227 { "=", "!=", ">", "<", ">=", "<=" },
228 { "+", "-", "", "", "", "" },
229 { "*", "/", "%", "", "", "" }
230 };
231
232 struct ast *
233 parse_expr(struct scan_st *sc, struct symbol_table *stab, int level)
234 {
235 struct ast *l, *r;
236 struct symbol *sym;
237 int done = 0, i = 0;
238 char the_op[256];
239
240 if (level > maxlevel) {
241 l = parse_primitive(sc, stab);
242 return(l);
243 } else {
244 l = parse_expr(sc, stab, level + 1);
245 while (!done) {
246 done = 1;
247 for (i = 0; i < 6 && op[level][i][0] != '\0'; i++) {
248 if (tokeq(sc, op[level][i])) {
249 strlcpy(the_op, sc->token, 256);
250 scan(sc);
251 done = 0;
252 r = parse_expr(sc, stab, level + 1);
253 r = ast_new_arg(l, r);
254 sym = symbol_lookup(stab, the_op, 1);
255 l = ast_new_apply(ast_new_sym(sym), r);
256 break;
257 }
258 }
259 }
260 return(l);
261 }
262 }
263
264 struct ast *
265 parse_primitive(struct scan_st *sc, struct symbol_table *stab)
266 {
267 struct ast *a, *l, *r;
268 struct value *v;
269 struct symbol *sym;
270 struct symbol_table *istab;
271
272 if (tokeq(sc, "(")) {
273 scan(sc);
274 a = parse_expr(sc, stab, 0);
275 scan_expect(sc, ")");
276 } else if (tokeq(sc, "{")) {
277 istab = symbol_table_new(stab);
278 sym = symbol_define(istab, "Arg", SYM_KIND_VARIABLE);
279 a = parse_block(sc, stab, &istab);
280 a = ast_new_scope(a, istab);
281 v = value_new_closure(a, NULL);
282 a = ast_new_value(v);
283 value_release(v);
284 } else if (tokeq(sc, "!")) {
285 scan(sc);
286 a = parse_primitive(sc, stab);
287 sym = symbol_lookup(stab, "!", 1);
288 a = ast_new_apply(ast_new_sym(sym), a);
289 } else if (sc->type == TOKEN_BAREWORD && isupper(sc->token[0])) {
290 a = parse_var(sc, stab, &sym, VAR_GLOBAL, VAR_MUST_EXIST);
291 while (tokeq(sc, "(") || tokeq(sc, "[") || tokeq(sc, ".")) {
292 if (tokeq(sc, "(")) {
293 scan(sc);
294 if (tokne(sc, ")")) {
295 l = parse_expr(sc, stab, 0);
296 while (tokeq(sc, ",")) {
297 scan(sc);
298 r = parse_expr(sc, stab, 0);
299 l = ast_new_arg(l, r);
300 }
301 } else {
302 l = ast_new_empty_list(stab);
303 }
304 scan_expect(sc, ")");
305 a = ast_new_apply(a, l);
306 } else if (tokeq(sc, "[")) {
307 scan(sc);
308 r = parse_expr(sc, stab, 0);
309 scan_expect(sc, "]");
310 a = ast_new_arg(a, r);
311 sym = symbol_lookup(stab, "Index", VAR_GLOBAL);
312 a = ast_new_apply(ast_new_sym(sym), a);
313 } else if (tokeq(sc, ".")) {
314 scan(sc);
315 r = parse_literal(sc, stab);
316 a = ast_new_arg(a, r);
317 sym = symbol_lookup(stab, "Index", VAR_GLOBAL);
318 a = ast_new_apply(ast_new_sym(sym), a);
319 }
320 }
321 } else {
322 a = parse_literal(sc, stab);
323 }
324
325 return(a);
326 }
327
328 struct ast *
329 parse_literal(struct scan_st *sc, struct symbol_table *stab)
330 {
331 struct ast *a;
332 struct value *v;
333
334 if (tokeq(sc, "[")) {
335 scan(sc);
336 v = value_new_list();
337 if (tokne(sc, "]")) {
338 a = parse_literal(sc, stab);
339 value_list_append(&v, a->u.value.value);
340 value_release(a->u.value.value);
341 while (tokeq(sc, ",")) {
342 scan(sc);
343 a = parse_literal(sc, stab);
344 value_list_append(&v, a->u.value.value);
345 value_release(a->u.value.value);
346 }
347 }
348 scan_expect(sc, "]");
349 a = ast_new_value(v);
350 value_release(v);
351 } else if (sc->type == TOKEN_BAREWORD && islower(sc->token[0])) {
352 v = value_new_atom(atom_resolve(sc->token));
353 a = ast_new_value(v);
354 value_release(v);
355 scan(sc);
356 } else if (sc->type == TOKEN_NUMBER) {
357 v = value_new_integer(atoi(sc->token));
358 a = ast_new_value(v);
359 value_release(v);
360 scan(sc);
361 } else if (sc->type == TOKEN_QSTRING) {
362 v = value_new_string(sc->token);
363 a = ast_new_value(v);
364 value_release(v);
365 scan(sc);
366 } else {
367 scan_error(sc, "Illegal literal");
368 scan(sc);
369 a = NULL;
370 }
371
372 return(a);
373 }
374
375 struct ast *
376 parse_var(struct scan_st *sc, struct symbol_table *stab,
377 struct symbol **sym,
378 int globality, int existence)
379 {
380 struct ast *a;
381
382 *sym = symbol_lookup(stab, sc->token, globality);
383 if (*sym == NULL) {
384 if (existence == VAR_MUST_EXIST) {
385 scan_error(sc, "Undefined symbol");
386 }
387 *sym = symbol_define(stab, sc->token, SYM_KIND_VARIABLE);
388 } else {
389 if (existence == VAR_MUST_NOT_EXIST) {
390 scan_error(sc, "Symbol already defined");
391 }
392 }
393 scan(sc);
394
395 a = ast_new_sym(*sym);
396 return(a);
397 }
0 /*
1 * parse.h
2 * Parser structures and prototypes for Bhuna.
3 * $Id: parse.h 54 2004-04-23 22:51:09Z catseye $
4 */
5
6 #ifndef __PARSE_H_
7 #define __PARSE_H_
8
9 struct symbol_table;
10 struct symbol;
11 struct scan_st;
12 struct ast;
13
14 struct ast *parse_program(struct scan_st *, struct symbol_table *);
15 struct ast *parse_block(struct scan_st *, struct symbol_table *,
16 struct symbol_table **);
17 struct ast *parse_statement(struct scan_st *, struct symbol_table *);
18 struct ast *parse_assignment(struct scan_st *, struct symbol_table *);
19 struct ast *parse_command(struct scan_st *, struct symbol_table *);
20 struct ast *parse_expr(struct scan_st *, struct symbol_table *, int);
21 struct ast *parse_primitive(struct scan_st *, struct symbol_table *);
22 struct ast *parse_literal(struct scan_st *, struct symbol_table *);
23 struct ast *parse_var(struct scan_st *, struct symbol_table *,
24 struct symbol **, int, int);
25
26 #endif /* !__PARSE_H_ */
0 /*
1 * Copyright (c)2004 Cat's Eye Technologies. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions
5 * are met:
6 *
7 * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 *
10 * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * Neither the name of Cat's Eye Technologies nor the names of its
16 * contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
24 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30 * OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32 /*
33 * scan.c
34 * Lexical scanner for Bhuna.
35 * $Id: scan.c 54 2004-04-23 22:51:09Z catseye $
36 */
37
38 #include <ctype.h>
39 #include <stdarg.h>
40 #include <stdlib.h>
41 #include <string.h>
42
43 #include "mem.h"
44 #include "scan.h"
45
46 struct scan_st *
47 scan_open(char *filename)
48 {
49 struct scan_st *sc;
50
51 if ((sc = bhuna_malloc(sizeof(struct scan_st))) == 0) {
52 return(NULL);
53 }
54 if ((sc->token = (char *)bhuna_malloc(256 * sizeof(char))) == NULL) {
55 bhuna_free(sc);
56 return(NULL);
57 }
58 if ((sc->in = fopen(filename, "r")) == NULL) {
59 bhuna_free(sc->token);
60 bhuna_free(sc);
61 return(NULL);
62 }
63
64 sc->lino = 1;
65 sc->columno = 1;
66 sc->errors = 0;
67 scan(sc); /* prime the pump */
68
69 return(sc);
70 }
71
72 void
73 scan_close(struct scan_st *sc)
74 {
75 fclose(sc->in);
76 bhuna_free(sc->token);
77 bhuna_free(sc);
78 }
79
80 void
81 scan_error(struct scan_st *sc, char *fmt, ...)
82 {
83 va_list args;
84 char err[256];
85
86 va_start(args, fmt);
87 vsnprintf(err, 255, fmt, args);
88
89 printf("Error (line %d, column %d, token '%s'): %s.\n",
90 sc->lino, sc->columno, sc->token, err);
91
92 sc->errors++;
93 }
94
95 void
96 scan_char(struct scan_st *sc, char *x)
97 {
98 *x = (char)getc(sc->in);
99 if (*x == '\n') {
100 sc->columno = 1;
101 sc->lino++;
102 } else {
103 sc->columno++;
104 }
105 }
106
107 void
108 scan_putback(struct scan_st *sc, char x)
109 {
110 if (feof(sc->in)) return;
111 ungetc(x, sc->in);
112 if (x == '\n') {
113 sc->columno = 80; /* XXX heh */
114 sc->lino--;
115 } else {
116 sc->columno--;
117 }
118 }
119
120 void
121 scan(struct scan_st *sc)
122 {
123 char x;
124 int i = 0;
125
126 sc->token[0] = '\0';
127 if (feof(sc->in)) {
128 sc->type = TOKEN_EOF;
129 return;
130 }
131
132 scan_char(sc, &x);
133
134 /* Skip whitespace. */
135
136 top:
137 while (isspace(x) && !feof(sc->in)) {
138 scan_char(sc, &x);
139 }
140
141 /* Skip comments. */
142
143 if (x == '/') {
144 scan_char(sc, &x);
145 if (x == '/') {
146 while (x != '\n' && !feof(sc->in)) {
147 scan_char(sc, &x);
148 }
149 goto top;
150 } else {
151 scan_putback(sc, x);
152 x = '/';
153 /* falls through to the bottom of scan() */
154 }
155 }
156
157 if (feof(sc->in)) {
158 sc->token[0] = '\0';
159 sc->type = TOKEN_EOF;
160 return;
161 }
162
163 /*
164 * Scan decimal numbers. Must start with a
165 * digit (not a sign or decimal point.)
166 */
167 if (isdigit(x)) {
168 while ((isdigit(x) || x == '.') && !feof(sc->in)) {
169 sc->token[i++] = x;
170 scan_char(sc, &x);
171 }
172 scan_putback(sc, x);
173 sc->token[i] = 0;
174 sc->type = TOKEN_NUMBER;
175 return;
176 }
177
178 /*
179 * Scan quoted strings.
180 */
181 if (x == '"') {
182 scan_char(sc, &x);
183 while (x != '"' && !feof(sc->in) && i < 255) {
184 sc->token[i++] = x;
185 scan_char(sc, &x);
186 }
187 sc->token[i] = 0;
188 sc->type = TOKEN_QSTRING;
189 return;
190 }
191
192 /*
193 * Scan alphanumeric ("bareword") tokens.
194 */
195 if (isalpha(x) || x == '_') {
196 while ((isalpha(x) || isdigit(x) || x == '_') && !feof(sc->in)) {
197 sc->token[i++] = x;
198 scan_char(sc, &x);
199 }
200 scan_putback(sc, x);
201 sc->token[i] = 0;
202 sc->type = TOKEN_BAREWORD;
203 return;
204 }
205
206 /*
207 * Scan multi-character symbols.
208 */
209 if (x == '>' || x == '<' || x == '=' || x == '!') {
210 while ((x == '>' || x == '<' || x == '=' || x == '!') &&
211 !feof(sc->in) && i < 255) {
212 sc->token[i++] = x;
213 scan_char(sc, &x);
214 }
215 sc->token[i] = '\0';
216 sc->type = TOKEN_SYMBOL;
217 return;
218 }
219
220 /*
221 * Degenerate case: scan single symbols.
222 */
223 sc->token[0] = x;
224 sc->token[1] = 0;
225 sc->type = TOKEN_SYMBOL;
226 }
227
228 void
229 scan_expect(struct scan_st *sc, char *x)
230 {
231 if (!strcmp(sc->token, x)) {
232 scan(sc);
233 } else {
234 scan_error(sc, "Expected '%s'", x);
235 }
236 }
0 /*
1 * scan.h
2 * Lexical scanner structures and prototypes for Bhuna.
3 * $Id: scan.h 54 2004-04-23 22:51:09Z catseye $
4 */
5
6 #ifndef __SCAN_H_
7 #define __SCAN_H_
8
9 #include <stdio.h>
10 /*
11 #include <string.h>
12 #include <ctype.h>
13 */
14
15 #define TOKEN_EOF 0
16 #define TOKEN_NUMBER 1
17 #define TOKEN_BAREWORD 2
18 #define TOKEN_SYMBOL 3
19 #define TOKEN_QSTRING 4
20
21 struct scan_st {
22 FILE *in; /* file from which we are scanning */
23 char *token; /* text content of token we just scanned */
24 int type; /* type of token that was scanned */
25 int lino; /* current line number, 1-based */
26 int columno; /* current column number, 1-based */
27 int errors; /* # of errors encountered so far */
28 };
29
30 #define tokeq(sc, x) (strcmp(sc->token, x) == 0)
31 #define tokne(sc, x) (strcmp(sc->token, x) != 0)
32
33 extern struct scan_st *scan_open(char *);
34 extern void scan_close(struct scan_st *);
35 extern void scan_error(struct scan_st *, char *, ...);
36 extern void scan(struct scan_st *);
37 extern void scan_expect(struct scan_st *, char *);
38
39 #endif /* !__SCAN_H_ */
0 /*
1 * Copyright (c)2004 Cat's Eye Technologies. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions
5 * are met:
6 *
7 * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 *
10 * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * Neither the name of Cat's Eye Technologies nor the names of its
16 * contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
24 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30 * OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32 /*
33 * symbol.c
34 * Symbol and symbol table housekeeping and manipulation for Bhuna.
35 * $Id: symbol.c 54 2004-04-23 22:51:09Z catseye $
36 */
37
38 #include <ctype.h>
39 #include <err.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43
44 #include "mem.h"
45 #include "symbol.h"
46
47 /*** GLOBALS ***/
48
49 static int anon_counter = 0;
50
51 /*** STATICS ***/
52
53 static struct symbol *
54 symbol_new(char *token, int kind)
55 {
56 struct symbol *sym;
57
58 sym = bhuna_malloc(sizeof(struct symbol));
59
60 if (token == NULL) {
61 asprintf(&sym->token, "%%%d", ++anon_counter);
62 } else {
63 sym->token = bhuna_strdup(token);
64 }
65
66 sym->kind = kind;
67 sym->in = NULL;
68
69 return(sym);
70 }
71
72 static void
73 symbol_free(struct symbol *sym)
74 {
75 bhuna_free(sym->token);
76 bhuna_free(sym);
77 }
78
79 /*** CONSTRUCTOR/DESTRUCTOR ***/
80
81 struct symbol_table *
82 symbol_table_new(struct symbol_table *parent)
83 {
84 struct symbol_table *stab;
85
86 stab = bhuna_malloc(sizeof(struct symbol_table));
87 stab->parent = parent;
88 stab->head = NULL;
89
90 return(stab);
91 }
92
93 void
94 symbol_table_free(struct symbol_table *stab)
95 {
96 struct symbol *s, *t;
97
98 s = stab->head;
99 while (s != NULL) {
100 t = s->next;
101 symbol_free(s);
102 s = t;
103 }
104
105 bhuna_free(stab);
106 }
107
108 struct symbol_table *
109 symbol_table_root(struct symbol_table *stab)
110 {
111 if (stab->parent == NULL)
112 return(stab);
113 else
114 return(symbol_table_root(stab->parent));
115 }
116
117 int
118 symbol_table_is_empty(struct symbol_table *stab)
119 {
120 return(stab->head == NULL);
121 }
122
123 /*** OPERATIONS ***/
124
125 /*
126 * Define a new symbol.
127 * Assumption: a preceding call to symbol_lookup failed.
128 * If token == NULL, a new anonymous symbol is created.
129 */
130 struct symbol *
131 symbol_define(struct symbol_table *stab, char *token, int kind)
132 {
133 struct symbol *new_sym;
134
135 new_sym = symbol_new(token, kind);
136
137 new_sym->in = stab;
138 new_sym->next = stab->head;
139 stab->head = new_sym;
140
141 return(new_sym);
142 }
143
144 struct symbol *
145 symbol_lookup(struct symbol_table *stab, char *s, int global)
146 {
147 struct symbol *sym;
148
149 for (sym = stab->head; sym != NULL; sym = sym->next)
150 if (strcmp(s, sym->token) == 0)
151 return(sym);
152 if (global && stab->parent != NULL)
153 return(symbol_lookup(stab->parent, s, global));
154 return(NULL);
155 }
156
157 int
158 symbol_is_global(struct symbol *sym)
159 {
160 return(sym->in->parent == NULL);
161 }
162
163 #ifdef DEBUG
164 static int stab_indent = 0;
165 #endif
166
167 void
168 symbol_table_dump(struct symbol_table *stab, int show_ast)
169 {
170 #ifdef DEBUG
171 struct symbol *s;
172 int i;
173
174 printf("STAB<\n");
175 stab_indent += 4;
176 for (s = stab->head; s != NULL; s = s->next) {
177 symbol_dump(s, show_ast);
178 /* if (s->next != NULL) */
179 printf("\n");
180 }
181 stab_indent -= 4;
182 for (i = 0; i < stab_indent; i++)
183 printf(" ");
184 printf(">");
185 #endif
186 }
187
188 void
189 symbol_dump(struct symbol *sym, int show_ast)
190 {
191 #ifdef DEBUG
192 int i;
193
194 for (i = 0; i < stab_indent; i++)
195 printf(" ");
196 printf("`%s'(%08lx)", sym->token, (unsigned long)sym);
197 #endif
198 }
0 /*
1 * symbol.h
2 * Symbol structures and prototypes for Bhuna.
3 * $Id: symbol.h 54 2004-04-23 22:51:09Z catseye $
4 */
5
6 #ifndef __SYMBOL_H_
7 #define __SYMBOL_H_
8
9 struct symbol_table {
10 struct symbol_table *parent; /* link to scopes above us */
11 struct symbol *head; /* first symbol in table */
12 };
13
14 struct symbol {
15 struct symbol_table *in; /* link to table we're in */
16 struct symbol *next; /* next symbol in symbol table */
17 char *token; /* lexeme making up the symbol */
18 int kind; /* kind of symbol */
19 };
20
21 #define SYM_KIND_ANONYMOUS 0
22 #define SYM_KIND_COMMAND 1
23 #define SYM_KIND_FUNCTION 2
24 #define SYM_KIND_VARIABLE 3
25
26 struct symbol_table *symbol_table_new(struct symbol_table *);
27 struct symbol_table *symbol_table_dup(struct symbol_table *);
28 void symbol_table_free(struct symbol_table *);
29
30 struct symbol_table *symbol_table_root(struct symbol_table *);
31
32 int symbol_table_is_empty(struct symbol_table *);
33
34 struct symbol *symbol_define(struct symbol_table *, char *, int);
35 struct symbol *symbol_lookup(struct symbol_table *, char *, int);
36
37 int symbol_is_global(struct symbol *);
38
39 void symbol_table_dump(struct symbol_table *, int);
40 void symbol_dump(struct symbol *, int);
41
42 #endif /* !__SYMBOL_H_ */
0 /*
1 * Copyright (c)2004 Cat's Eye Technologies. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions
5 * are met:
6 *
7 * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 *
10 * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * Neither the name of Cat's Eye Technologies nor the names of its
16 * contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
24 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30 * OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32 /*
33 * value.c
34 * Values for Bhuna.
35 * $Id: symbol.c 54 2004-04-23 22:51:09Z catseye $
36 */
37
38 #include <assert.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42
43 #include "mem.h"
44 #include "value.h"
45 #include "symbol.h"
46 #include "ast.h"
47 #include "list.h"
48 #include "closure.h"
49
50 #ifdef DEBUG
51 extern int trace_refcounting;
52 extern int num_vars_created;
53 extern int num_vars_grabbed;
54 extern int num_vars_released;
55 extern int num_vars_freed;
56 extern int num_vars_cowed;
57
58 struct list *global_table = NULL;
59 #endif
60
61 #ifdef DEBUG
62 static void
63 add_value_to_global_table(struct value *v)
64 {
65 struct list *l;
66
67 l = bhuna_malloc(sizeof(struct list));
68 l->next = global_table;
69 l->value = v;
70 global_table = l;
71 }
72
73 static void
74 remove_value_from_global_table(struct value *v)
75 {
76 struct list *l, *prev = NULL;
77
78 for (l = global_table; l != NULL; l = l->next) {
79 if (l->value == v) {
80 if (prev != NULL) {
81 prev->next = l->next;
82 } else {
83 global_table = l->next;
84 }
85 bhuna_free(l);
86 return;
87 }
88 prev = l;
89 }
90
91 fprintf(stderr, "********* VALUE %08lx WAS NEVER ENTERED INTO GLOBAL TABLE!\n",
92 (unsigned long)v);
93 }
94 #endif
95
96 void
97 value_dump_global_table(void)
98 {
99 #ifdef DEBUG
100 struct list *l;
101
102 printf("----- BEGIN Global Table of Values -----\n");
103 for (l = global_table; l != NULL; l = l->next) {
104 value_print(l->value);
105 printf("\n");
106 }
107 printf("----- END Global Table of Values -----\n");
108 #endif
109 }
110
111 /*** CONSTRUCTORS ***/
112
113 struct value *
114 value_new(int type)
115 {
116 struct value *v;
117
118 v = malloc(sizeof(struct value));
119 bzero(v, sizeof(struct value));
120 v->type = type;
121 v->refcount = 1;
122
123 #ifdef DEBUG
124 if (trace_refcounting > 0) {
125 add_value_to_global_table(v);
126 num_vars_created++;
127 }
128 #endif
129
130 return(v);
131 }
132
133 struct value *
134 value_new_integer(int i)
135 {
136 struct value *v;
137
138 v = value_new(VALUE_INTEGER);
139 v->v.i = i;
140
141 #ifdef DEBUG
142 if (trace_refcounting > 1) {
143 printf("[RC] created ");
144 value_print(v);
145 printf("\n");
146 }
147 #endif
148
149 return(v);
150 }
151
152 struct value *
153 value_new_boolean(int b)
154 {
155 struct value *v;
156
157 v = value_new(VALUE_BOOLEAN);
158 v->v.b = b;
159
160 #ifdef DEBUG
161 if (trace_refcounting > 1) {
162 printf("[RC] created ");
163 value_print(v);
164 printf("\n");
165 }
166 #endif
167
168 return(v);
169 }
170
171 struct value *
172 value_new_atom(int atom)
173 {
174 struct value *v;
175
176 v = value_new(VALUE_ATOM);
177 v->v.atom = atom;
178
179 #ifdef DEBUG
180 if (trace_refcounting > 1) {
181 printf("[RC] created ");
182 value_print(v);
183 printf("\n");
184 }
185 #endif
186
187 return(v);
188 }
189
190 struct value *
191 value_new_string(char *s)
192 {
193 struct value *v;
194
195 v = value_new(VALUE_STRING);
196 v->v.s = strdup(s);
197
198 #ifdef DEBUG
199 if (trace_refcounting > 1) {
200 printf("[RC] created ");
201 value_print(v);
202 printf("\n");
203 }
204 #endif
205
206 return(v);
207 }
208
209 struct value *
210 value_new_list(void)
211 {
212 struct value *v;
213
214 v = value_new(VALUE_LIST);
215 v->v.l = NULL;
216
217 #ifdef DEBUG
218 if (trace_refcounting > 1) {
219 printf("[RC] created ");
220 value_print(v);
221 printf("\n");
222 }
223 #endif
224
225 return(v);
226 }
227
228 struct value *
229 value_new_symbol_table(struct symbol_table *stab)
230 {
231 struct value *v;
232
233 v = value_new(VALUE_STAB);
234 v->v.stab = stab;
235
236 #ifdef DEBUG
237 if (trace_refcounting > 1) {
238 printf("[RC] created ");
239 value_print(v);
240 printf("\n");
241 }
242 #endif
243
244 return(v);
245 }
246
247 struct value *
248 value_new_error(char *error)
249 {
250 struct value *v;
251
252 v = value_new(VALUE_ERROR);
253 v->v.e = strdup(error);
254
255 #ifdef DEBUG
256 if (trace_refcounting > 1) {
257 printf("[RC] created ");
258 value_print(v);
259 printf("\n");
260 }
261 #endif
262
263 return(v);
264 }
265
266 struct value *
267 value_new_builtin(void (*f)(struct value **))
268 {
269 struct value *v;
270
271 v = value_new(VALUE_BUILTIN);
272 v->v.f = f;
273
274 #ifdef DEBUG
275 if (trace_refcounting > 1) {
276 printf("[RC] created ");
277 value_print(v);
278 printf("\n");
279 }
280 #endif
281
282 return(v);
283 }
284
285 struct value *
286 value_new_closure(struct ast *a, struct activation *ar)
287 {
288 struct value *v;
289
290 v = value_new(VALUE_CLOSURE);
291 v->v.k = closure_new(a, ar);
292
293 #ifdef DEBUG
294 if (trace_refcounting > 1) {
295 printf("[RC] created ");
296 value_print(v);
297 printf("\n");
298 }
299 #endif
300
301 return(v);
302 }
303
304 struct value *
305 value_new_symbol(struct symbol *sym)
306 {
307 struct value *v;
308
309 v = value_new(VALUE_SYMBOL);
310 v->v.sym = sym;
311
312 #ifdef DEBUG
313 if (trace_refcounting > 1) {
314 printf("[RC] created ");
315 value_print(v);
316 printf("\n");
317 }
318 #endif
319
320 return(v);
321 }
322
323 /*** DUPLICATOR ***/
324
325 /*
326 * Returns a copy of the given value.
327 * The copy is not so 'deep' as it could be, but should be OK w/refcounting.
328 * New strings (char arrays) are created when copying a string;
329 * New list spines (struct list *) are created, but values are only grabbed, not dup'ed.
330 * Symbol tables and AST's are not copied, only the pointers to them.
331 *
332 * Note that the dup'ed value is 'new', i.e. it has a refcount of 1.
333 */
334 static struct value *
335 value_dup(struct value *v)
336 {
337 struct value *n; /* *z; */
338 struct list *l;
339 /* size_t i; */
340
341 switch (v->type) {
342 case VALUE_INTEGER:
343 return(value_new_integer(v->v.i));
344 case VALUE_BOOLEAN:
345 return(value_new_boolean(v->v.b));
346 case VALUE_STRING:
347 return(value_new_string(v->v.s));
348 case VALUE_LIST:
349 n = value_new_list();
350 for (l = v->v.l; l != NULL; l = l->next) {
351 value_list_append(&n, l->value);
352 }
353 return(n);
354 case VALUE_STAB:
355 return(value_new_symbol_table(v->v.stab));
356 case VALUE_ERROR:
357 return(value_new_error(v->v.e));
358 case VALUE_BUILTIN:
359 return(value_new_builtin(v->v.f));
360 case VALUE_CLOSURE:
361 /* XXX depth?? */
362 return(value_new_closure(v->v.k->ast, v->v.k->ar));
363 case VALUE_SYMBOL:
364 return(value_new_symbol(v->v.sym));
365 default:
366 return(value_new_error("unknown type"));
367 }
368 }
369
370 /*** SETTING FUNCTIONS ***/
371
372 /*
373 * If the given value has more than one reference to it,
374 * make and return a new copy of it so that it can be
375 * safely changed without affecting other users of it.
376 */
377 static void
378 copy_on_write(struct value **v)
379 {
380 struct value *old;
381
382 if ((*v)->refcount > 1) {
383 #ifdef DEBUG
384 if (trace_refcounting > 1) {
385 printf("[RC] CoW of ");
386 value_print(*v);
387 printf(" w/refcount of %d", (*v)->refcount);
388 if ((*v)->refcount > 1)
389 printf(", dup'ing");
390 printf("\n");
391 num_vars_cowed++;
392 }
393 #endif
394 old = *v;
395 *v = value_dup(*v);
396 value_release(old);
397 }
398 }
399
400 /*
401 * If the given value is a value which can contain other values,
402 * such as a list, 'empty' it so that it can take on a new value.
403 */
404 static void
405 value_empty(struct value **v)
406 {
407 switch ((*v)->type) {
408 case VALUE_LIST:
409 list_free(&(*v)->v.l);
410 break;
411 case VALUE_STRING:
412 if ((*v)->v.s != NULL)
413 bhuna_free((*v)->v.s);
414 break;
415 case VALUE_ERROR:
416 if ((*v)->v.e != NULL)
417 bhuna_free((*v)->v.e);
418 break;
419 /* VALUE_STAB? */
420 case VALUE_CLOSURE:
421 closure_free((*v)->v.k);
422 break;
423 }
424 }
425
426 /*
427 * These `set' functions implement copy-on-write and emptying.
428 */
429 void
430 value_set_integer(struct value **v, int i)
431 {
432 if (*v == NULL) {
433 *v = value_new_integer(i);
434 return;
435 }
436 copy_on_write(v);
437 value_empty(v);
438 (*v)->type = VALUE_INTEGER;
439 (*v)->v.i = i;
440 }
441
442 void
443 value_set_boolean(struct value **v, int b)
444 {
445 if (*v == NULL) {
446 *v = value_new_boolean(b);
447 return;
448 }
449 copy_on_write(v);
450 value_empty(v);
451 (*v)->type = VALUE_BOOLEAN;
452 (*v)->v.b = b;
453 }
454
455 void
456 value_set_atom(struct value **v, int atom)
457 {
458 if (*v == NULL) {
459 *v = value_new_atom(atom);
460 return;
461 }
462 copy_on_write(v);
463 value_empty(v);
464 (*v)->type = VALUE_ATOM;
465 (*v)->v.atom = atom;
466 }
467
468 void
469 value_set_string(struct value **v, char *s)
470 {
471 if (*v == NULL) {
472 *v = value_new_string(s);
473 return;
474 }
475 copy_on_write(v);
476 value_empty(v);
477 (*v)->type = VALUE_STRING;
478 (*v)->v.s = strdup(s);
479 }
480
481 void
482 value_set_list(struct value **v)
483 {
484 if (*v == NULL) {
485 *v = value_new_list();
486 return;
487 }
488 copy_on_write(v);
489 value_empty(v);
490 (*v)->type = VALUE_LIST;
491 (*v)->v.l = NULL;
492 }
493
494 void
495 value_list_append(struct value **v, struct value *q)
496 {
497 #ifdef DEBUG
498 if (trace_refcounting > 1) {
499 printf("[list] hello ");
500 value_print(*v);
501 printf(" <- ");
502 value_print(q);
503 printf("...\n");
504 }
505 #endif
506
507 if (*v == NULL)
508 *v = value_new_list();
509
510 copy_on_write(v);
511
512 #ifdef DEBUG
513 if (trace_refcounting > 1) {
514 printf("[list] append ");
515 value_print(q);
516 printf(" to ");
517 value_print(*v);
518 printf("\n");
519 }
520 #endif
521
522 list_cons(&((*v)->v.l), q);
523 }
524
525 void
526 value_set_symbol_table(struct value **v, struct symbol_table *stab)
527 {
528 if (*v == NULL) {
529 *v = value_new_symbol_table(stab);
530 return;
531 }
532 copy_on_write(v);
533 value_empty(v);
534 (*v)->type = VALUE_STAB;
535 (*v)->v.stab = stab;
536 }
537
538 void
539 value_set_error(struct value **v, char *e)
540 {
541 if (*v == NULL) {
542 *v = value_new_error(e);
543 return;
544 }
545 copy_on_write(v);
546 value_empty(v);
547 (*v)->type = VALUE_ERROR;
548 (*v)->v.e = strdup(e);
549 }
550
551 void
552 value_set_builtin(struct value **v, void (*f)(struct value **))
553 {
554 if (*v == NULL) {
555 *v = value_new_builtin(f);
556 return;
557 }
558 copy_on_write(v);
559 value_empty(v);
560 (*v)->type = VALUE_BUILTIN;
561 (*v)->v.f = f;
562 }
563
564 void
565 value_set_closure(struct value **v, struct ast *a, struct activation *ar)
566 {
567 if (*v == NULL) {
568 *v = value_new_closure(a, ar);
569 return;
570 }
571
572 copy_on_write(v);
573 value_empty(v);
574
575 (*v)->type = VALUE_CLOSURE;
576 (*v)->v.k = closure_new(a, ar);
577 }
578
579 void
580 value_set_symbol(struct value **v, struct symbol *sym)
581 {
582 if (*v == NULL) {
583 *v = value_new_symbol(sym);
584 return;
585 }
586 copy_on_write(v);
587 value_empty(v);
588 (*v)->type = VALUE_SYMBOL;
589 (*v)->v.sym = sym;
590 }
591
592 /*-----*/
593
594 void
595 value_set_from_value(struct value **v, struct value *q)
596 {
597 /*
598 * We are making another reference to q, so we must grab it
599 */
600 value_release(*v);
601 value_grab(q);
602 *v = q;
603 }
604
605 /*** DESTRUCTOR ***/
606
607 static void
608 value_free(struct value *v)
609 {
610 if (v == NULL)
611 return;
612
613 assert(v->refcount == 0);
614
615 #ifdef DEBUG
616 if (trace_refcounting > 1) {
617 printf("[RC] freeing ");
618 value_print(v);
619 printf("\n");
620 }
621 #endif
622
623 switch (v->type) {
624 case VALUE_STRING:
625 bhuna_free(v->v.s);
626 break;
627 case VALUE_LIST:
628 list_free(&v->v.l);
629 break;
630 case VALUE_STAB:
631 symbol_table_free(v->v.stab);
632 break;
633 case VALUE_ERROR:
634 bhuna_free(v->v.e);
635 break;
636 case VALUE_CLOSURE:
637 closure_free(v->v.k);
638 break;
639 }
640
641 #ifdef DEBUG
642 if (trace_refcounting > 0) {
643 remove_value_from_global_table(v);
644 num_vars_freed++;
645 }
646 #endif
647
648 bhuna_free(v);
649 }
650
651 /*** REFCOUNTERS ***/
652
653 void
654 value_grab(struct value *v)
655 {
656 if (v == NULL)
657 return;
658 v->refcount++;
659 #ifdef DEBUG
660 if (trace_refcounting > 1) {
661 printf("[RC] grabbed ");
662 value_print(v);
663 printf(", refcount now %d\n", v->refcount);
664 num_vars_grabbed++;
665 }
666 #endif
667 }
668
669 void
670 value_release(struct value *v)
671 {
672 if (v == NULL)
673 return;
674 v->refcount--;
675 #ifdef DEBUG
676 if (trace_refcounting > 1) {
677 printf("[RC] released ");
678 value_print(v);
679 printf(", refcount now %d\n", v->refcount);
680 num_vars_released++;
681 }
682 #endif
683 if (v->refcount == 0)
684 value_free(v);
685 }
686
687 void
688 value_print(struct value *v)
689 {
690 if (v == NULL) {
691 printf("(null)");
692 return;
693 }
694 printf("[0x%08lx]", (unsigned long)v);
695 switch (v->type) {
696 case VALUE_INTEGER:
697 printf("%d", v->v.i);
698 break;
699 case VALUE_BOOLEAN:
700 printf("%s", v->v.b ? "true" : "false");
701 break;
702 case VALUE_ATOM:
703 printf("atom<%d>", v->v.atom);
704 break;
705 case VALUE_STRING:
706 printf("\"%s\"", v->v.s);
707 break;
708 case VALUE_LIST:
709 list_dump(v->v.l);
710 break;
711 case VALUE_STAB:
712 symbol_table_dump(v->v.stab, 1);
713 break;
714 case VALUE_ERROR:
715 printf("#ERR<%s>", v->v.e);
716 break;
717 case VALUE_BUILTIN:
718 printf("#FN<%08lx>", (unsigned long)v->v.f);
719 break;
720 case VALUE_CLOSURE:
721 closure_dump(v->v.k);
722 break;
723 case VALUE_SYMBOL:
724 symbol_dump(v->v.sym, 0);
725 break;
726 }
727 }
728
729 int
730 value_equal(struct value *a, struct value *b)
731 {
732 int c;
733 struct list *la, *lb;
734
735 if (a == NULL && b == NULL)
736 return(1);
737 if (a == NULL || b == NULL)
738 return(0);
739 if (a->type != b->type)
740 return(0);
741
742 switch (a->type) {
743 case VALUE_INTEGER:
744 return(a->v.i == b->v.i);
745 case VALUE_BOOLEAN:
746 return(a->v.b == b->v.b);
747 case VALUE_ATOM:
748 return(a->v.atom == b->v.atom);
749 case VALUE_STRING:
750 return(strcmp(a->v.s, b->v.s) == 0);
751 case VALUE_LIST:
752 c = 1;
753 for (la = a->v.l, lb = b->v.l;
754 la != NULL && lb != NULL;
755 la = la->next, lb = lb->next) {
756 if (!value_equal(la->value, lb->value)) {
757 c = 0;
758 break;
759 }
760 }
761 return(c);
762 break;
763 case VALUE_STAB:
764 return(a->v.stab == b->v.stab);
765 case VALUE_ERROR:
766 return(strcmp(a->v.e, b->v.e) == 0);
767 case VALUE_BUILTIN:
768 return(a->v.f == b->v.f);
769 case VALUE_CLOSURE:
770 return(a->v.k->ast == b->v.k->ast); /* XXX */
771 case VALUE_SYMBOL:
772 return(a->v.sym == b->v.sym);
773 }
774 return(0);
775 }
0 /*
1 * value.h
2 * Values for Bhuna.
3 * $Id$
4 */
5
6 #ifndef __VALUE_H_
7 #define __VALUE_H_
8
9 struct symbol;
10 struct symbol_table;
11 struct list;
12 struct value;
13 struct closure;
14 struct ast;
15 struct activation;
16
17 #define VALUE_VOID 0
18 #define VALUE_INTEGER 1
19 #define VALUE_BOOLEAN 2
20 #define VALUE_ATOM 3
21 #define VALUE_STRING 4
22 #define VALUE_LIST 5
23 #define VALUE_STAB 6
24 #define VALUE_ERROR 7
25 #define VALUE_BUILTIN 8
26 #define VALUE_CLOSURE 9
27 #define VALUE_DICT 10
28 #define VALUE_SYMBOL 11 /* ??? */
29 #define VALUE_OPAQUE 15
30
31 union value_union {
32 int i;
33 int b;
34 int atom;
35 char *s;
36 struct list *l;
37 struct symbol_table *stab;
38 char *e;
39 void (*f)(struct value **);
40 struct closure *k;
41 /* struct dict *d; */
42 struct symbol *sym;
43 };
44
45 struct value {
46 int type;
47 int refcount;
48 union value_union v;
49 };
50
51 struct value *value_new(int);
52
53 struct value *value_new_integer(int);
54 struct value *value_new_boolean(int);
55 struct value *value_new_atom(int);
56 struct value *value_new_string(char *);
57 struct value *value_new_list(void);
58 struct value *value_new_symbol_table(struct symbol_table *);
59 struct value *value_new_error(char *);
60 struct value *value_new_builtin(void (*)(struct value **));
61 struct value *value_new_closure(struct ast *, struct activation *);
62 struct value *value_new_symbol(struct symbol *);
63
64 void value_set_integer(struct value **, int);
65 void value_set_boolean(struct value **, int);
66 void value_set_atom(struct value **, int);
67 void value_set_string(struct value **, char *);
68 void value_set_list(struct value **);
69 void value_set_symbol_table(struct value **, struct symbol_table *);
70 void value_set_error(struct value **, char *);
71 void value_set_builtin(struct value **, void (*)(struct value **));
72 void value_set_closure(struct value **, struct ast *, struct activation *);
73 void value_set_symbol(struct value **, struct symbol *);
74
75 void value_set_from_value(struct value **, struct value *);
76
77 void value_grab(struct value *);
78 void value_release(struct value *);
79
80 void value_list_append(struct value **, struct value *);
81
82 void value_print(struct value *);
83 int value_equal(struct value *, struct value *);
84
85 void value_dump_global_table(void);
86
87 #endif /* !__VALUE_H_ */