Initial import of Bhuna 0.1 sources.
catseye
13 years ago
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 | { |
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 | 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 | 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 | Q = 23; | |
7 | G; | |
8 | Return G | |
9 | } | |
10 | ||
11 | G = F() | |
12 | G; | |
13 | ||
14 |
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 | 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 | ||
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 | #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_ */ |