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