1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
|
/*
* 'sparse' library helper routines.
*
* Copyright (C) 2003 Linus Torvalds, all rights reserved.
*/
#include <stddef.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lib.h"
#include "token.h"
#include "parse.h"
#include "symbol.h"
struct token *skip_to(struct token *token, int op)
{
while (!match_op(token, op) && !eof_token(token))
token = token->next;
return token;
}
struct token *expect(struct token *token, int op, const char *where)
{
if (!match_op(token, op)) {
static struct token bad_token;
if (token != &bad_token) {
bad_token.next = token;
warn(token, "Expected %s %s", show_special(op), where);
warn(token, "got %s", show_token(token));
}
if (op == ';')
return skip_to(token, op);
return &bad_token;
}
return token->next;
}
unsigned int hexval(unsigned int c)
{
int retval = 256;
switch (c) {
case '0'...'9':
retval = c - '0';
break;
case 'a'...'f':
retval = c - 'a' + 10;
break;
case 'A'...'F':
retval = c - 'A' + 10;
break;
}
return retval;
}
/*
* Simple allocator for data that doesn't get partially free'd.
* The tokenizer and parser allocate a _lot_ of small data structures
* (often just two-three bytes for things like small integers),
* and since they all depend on each other you can't free them
* individually _anyway_. So do something that is very space-
* efficient: allocate larger "blobs", and give out individual
* small bits and pieces of it with no maintenance overhead.
*/
struct allocation_blob {
struct allocation_blob *next;
unsigned int left, offset;
unsigned char data[];
};
struct allocator_struct {
const char *name;
struct allocation_blob *blobs;
unsigned int alignment;
unsigned int chunking;
/* statistics */
unsigned int allocations, total_bytes, useful_bytes;
};
void drop_all_allocations(struct allocator_struct *desc)
{
struct allocation_blob *blob = desc->blobs;
desc->blobs = NULL;
desc->allocations = 0;
desc->total_bytes = 0;
desc->useful_bytes = 0;
while (blob) {
struct allocation_blob *next = blob->next;
free(blob);
blob = next;
}
}
void *allocate(struct allocator_struct *desc, unsigned int size)
{
unsigned long alignment = desc->alignment;
struct allocation_blob *blob = desc->blobs;
void *retval;
desc->allocations++;
desc->useful_bytes += size;
size = (size + alignment - 1) & ~(alignment-1);
if (!blob || blob->left < size) {
unsigned int offset, chunking = desc->chunking;
struct allocation_blob *newblob = malloc(chunking);
if (!newblob)
die("out of memory");
desc->total_bytes += chunking;
newblob->next = blob;
blob = newblob;
desc->blobs = newblob;
offset = offsetof(struct allocation_blob, data);
if (alignment > offset)
offset = alignment;
blob->left = chunking - offset;
blob->offset = offset - offsetof(struct allocation_blob, data);
}
retval = blob->data + blob->offset;
blob->offset += size;
blob->left -= size;
return retval;
}
static void show_allocations(struct allocator_struct *x)
{
fprintf(stderr, "%s: %d allocations, %d bytes (%d total bytes, "
"%6.2f%% usage, %6.2f average size)\n",
x->name, x->allocations, x->useful_bytes, x->total_bytes,
100 * (double) x->useful_bytes / x->total_bytes,
(double) x->useful_bytes / x->allocations);
}
struct allocator_struct ident_allocator = { "identifiers", NULL, __alignof__(struct ident), 8192 };
struct allocator_struct token_allocator = { "tokens", NULL, __alignof__(struct token), 8192 };
struct allocator_struct symbol_allocator = { "symbols", NULL, __alignof__(struct symbol), 8192 };
struct allocator_struct expression_allocator = { "expressions", NULL, __alignof__(struct expression), 8192 };
struct allocator_struct statement_allocator = { "statements", NULL, __alignof__(struct statement), 8192 };
struct allocator_struct string_allocator = { "strings", NULL, __alignof__(struct statement), 8192 };
struct allocator_struct bytes_allocator = { "bytes", NULL, 1, 8192 };
#define __ALLOCATOR(type, size, prepare, x) \
type *__alloc_##x(int extra) \
{ \
type *ret = allocate(&x##_allocator, \
size+extra); \
prepare; \
return ret; \
} \
void show_##x##_alloc(void) \
{ \
show_allocations(&x##_allocator); \
} \
void clear_##x##_alloc(void) \
{ \
drop_all_allocations(&x##_allocator); \
}
#define ALLOCATOR(x) __ALLOCATOR(struct x, sizeof(struct x), memset(ret, 0, sizeof(struct x)), x)
ALLOCATOR(ident); ALLOCATOR(token); ALLOCATOR(symbol);
ALLOCATOR(expression); ALLOCATOR(statement); ALLOCATOR(string);
__ALLOCATOR(void, 0, , bytes);
void iterate(struct ptr_list *head, void (*callback)(void *, void *, int), void *data)
{
struct ptr_list *list = head;
int flag = ITERATE_FIRST;
if (!head)
return;
do {
int i;
for (i = 0; i < list->nr; i++) {
if (i == list->nr-1 && list->next == head)
flag |= ITERATE_LAST;
callback(list->list[i], data, flag);
}
flag = 0;
list = list->next;
} while (list != head);
}
void add_ptr_list(struct ptr_list **listp, void *ptr)
{
struct ptr_list *list = *listp;
int nr;
if (!list || (nr = list->nr) >= LIST_NODE_NR) {
struct ptr_list *newlist = malloc(sizeof(*newlist));
if (!newlist)
die("out of memory for symbol/statement lists");
memset(newlist, 0, sizeof(*newlist));
if (!list) {
newlist->next = newlist;
newlist->prev = newlist;
*listp = newlist;
} else {
newlist->next = list;
newlist->prev = list->prev;
list->prev->next = newlist;
list->prev = newlist;
}
list = newlist;
nr = 0;
}
list->list[nr] = ptr;
nr++;
list->nr = nr;
}
static void do_warn(const char *type, struct token *token, const char * fmt, va_list args)
{
static char buffer[512];
const char *name;
int pos,line;
vsprintf(buffer, fmt, args);
name = "EOF";
pos = 0;
line = 0;
if (token) {
name = input_streams[token->stream].name;
pos = token->pos;
line = token->line;
}
fprintf(stderr, "%s: %s:%d:%d: %s\n",
type, name, line, pos, buffer);
}
void warn(struct token *token, const char * fmt, ...)
{
static int warnings = 0;
va_list args;
va_start(args, fmt);
do_warn("warning", token, fmt, args);
va_end(args);
warnings++;
if (warnings > 100)
error(token, "too many warnings");
}
void error(struct token *token, const char * fmt, ...)
{
va_list args;
va_start(args, fmt);
do_warn("error", token, fmt, args);
va_end(args);
exit(1);
}
void die(const char *fmt, ...)
{
va_list args;
static char buffer[512];
va_start(args, fmt);
vsnprintf(buffer, sizeof(buffer), fmt, args);
va_end(args);
fprintf(stderr, "%s\n", buffer);
exit(1);
}
|