2 * 'sparse' library helper routines.
4 * Copyright (C) 2003 Transmeta Corp.
7 * Licensed under the Open Software License version 1.1
18 #include <sys/types.h>
25 #include "expression.h"
28 struct token
*skip_to(struct token
*token
, int op
)
30 while (!match_op(token
, op
) && !eof_token(token
))
35 struct token
*expect(struct token
*token
, int op
, const char *where
)
37 if (!match_op(token
, op
)) {
38 static struct token bad_token
;
39 if (token
!= &bad_token
) {
40 bad_token
.next
= token
;
41 warn(token
->pos
, "Expected %s %s", show_special(op
), where
);
42 warn(token
->pos
, "got %s", show_token(token
));
45 return skip_to(token
, op
);
51 unsigned int hexval(unsigned int c
)
59 retval
= c
- 'a' + 10;
62 retval
= c
- 'A' + 10;
69 * Simple allocator for data that doesn't get partially free'd.
70 * The tokenizer and parser allocate a _lot_ of small data structures
71 * (often just two-three bytes for things like small integers),
72 * and since they all depend on each other you can't free them
73 * individually _anyway_. So do something that is very space-
74 * efficient: allocate larger "blobs", and give out individual
75 * small bits and pieces of it with no maintenance overhead.
77 struct allocation_blob
{
78 struct allocation_blob
*next
;
79 unsigned int left
, offset
;
84 #define blob_alloc(size) mmap(NULL, ((size)+4095) & ~4095, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)
85 #define blob_free(addr,size) munmap((addr), ((size)+4095) & ~4095)
87 struct allocator_struct
{
89 struct allocation_blob
*blobs
;
90 unsigned int alignment
;
91 unsigned int chunking
;
93 unsigned int allocations
, total_bytes
, useful_bytes
;
96 void drop_all_allocations(struct allocator_struct
*desc
)
98 struct allocation_blob
*blob
= desc
->blobs
;
101 desc
->allocations
= 0;
102 desc
->total_bytes
= 0;
103 desc
->useful_bytes
= 0;
105 struct allocation_blob
*next
= blob
->next
;
106 blob_free(blob
, desc
->chunking
);
111 void *allocate(struct allocator_struct
*desc
, unsigned int size
)
113 unsigned long alignment
= desc
->alignment
;
114 struct allocation_blob
*blob
= desc
->blobs
;
118 desc
->useful_bytes
+= size
;
119 size
= (size
+ alignment
- 1) & ~(alignment
-1);
120 if (!blob
|| blob
->left
< size
) {
121 unsigned int offset
, chunking
= desc
->chunking
;
122 struct allocation_blob
*newblob
= blob_alloc(chunking
);
124 die("out of memory");
125 desc
->total_bytes
+= chunking
;
126 newblob
->next
= blob
;
128 desc
->blobs
= newblob
;
129 offset
= offsetof(struct allocation_blob
, data
);
130 if (alignment
> offset
)
132 blob
->left
= chunking
- offset
;
133 blob
->offset
= offset
- offsetof(struct allocation_blob
, data
);
135 retval
= blob
->data
+ blob
->offset
;
136 blob
->offset
+= size
;
141 static void show_allocations(struct allocator_struct
*x
)
143 fprintf(stderr
, "%s: %d allocations, %d bytes (%d total bytes, "
144 "%6.2f%% usage, %6.2f average size)\n",
145 x
->name
, x
->allocations
, x
->useful_bytes
, x
->total_bytes
,
146 100 * (double) x
->useful_bytes
/ x
->total_bytes
,
147 (double) x
->useful_bytes
/ x
->allocations
);
150 struct allocator_struct ident_allocator
= { "identifiers", NULL
, __alignof__(struct ident
), CHUNK
};
151 struct allocator_struct token_allocator
= { "tokens", NULL
, __alignof__(struct token
), CHUNK
};
152 struct allocator_struct symbol_allocator
= { "symbols", NULL
, __alignof__(struct symbol
), CHUNK
};
153 struct allocator_struct expression_allocator
= { "expressions", NULL
, __alignof__(struct expression
), CHUNK
};
154 struct allocator_struct statement_allocator
= { "statements", NULL
, __alignof__(struct statement
), CHUNK
};
155 struct allocator_struct string_allocator
= { "strings", NULL
, __alignof__(struct statement
), CHUNK
};
156 struct allocator_struct scope_allocator
= { "scopes", NULL
, __alignof__(struct scope
), CHUNK
};
157 struct allocator_struct bytes_allocator
= { "bytes", NULL
, 1, CHUNK
};
159 #define __ALLOCATOR(type, size, x) \
160 type *__alloc_##x(int extra) \
162 return allocate(&x##_allocator, size+extra); \
164 void show_##x##_alloc(void) \
166 show_allocations(&x##_allocator); \
168 void clear_##x##_alloc(void) \
170 drop_all_allocations(&x##_allocator); \
172 #define ALLOCATOR(x) __ALLOCATOR(struct x, sizeof(struct x), x)
174 ALLOCATOR(ident
); ALLOCATOR(token
); ALLOCATOR(symbol
);
175 ALLOCATOR(expression
); ALLOCATOR(statement
); ALLOCATOR(string
);
176 ALLOCATOR(scope
); __ALLOCATOR(void, 0, bytes
);
178 int ptr_list_size(struct ptr_list
*head
)
183 struct ptr_list
*list
= head
;
186 } while ((list
= list
->next
) != head
);
191 void iterate(struct ptr_list
*head
, void (*callback
)(void *, void *, int), void *data
)
193 struct ptr_list
*list
= head
;
194 int flag
= ITERATE_FIRST
;
200 for (i
= 0; i
< list
->nr
; i
++) {
201 if (i
== list
->nr
-1 && list
->next
== head
)
202 flag
|= ITERATE_LAST
;
203 callback(list
->list
[i
], data
, flag
);
207 } while (list
!= head
);
210 void add_ptr_list(struct ptr_list
**listp
, void *ptr
)
212 struct ptr_list
*list
= *listp
;
215 if (!list
|| (nr
= list
->nr
) >= LIST_NODE_NR
) {
216 struct ptr_list
*newlist
= malloc(sizeof(*newlist
));
218 die("out of memory for symbol/statement lists");
219 memset(newlist
, 0, sizeof(*newlist
));
221 newlist
->next
= newlist
;
222 newlist
->prev
= newlist
;
225 newlist
->next
= list
;
226 newlist
->prev
= list
->prev
;
227 list
->prev
->next
= newlist
;
228 list
->prev
= newlist
;
233 list
->list
[nr
] = ptr
;
238 void free_ptr_list(struct ptr_list
**listp
)
240 struct ptr_list
*tmp
, *list
= *listp
;
245 list
->prev
->next
= NULL
;
255 static void do_warn(const char *type
, struct position pos
, const char * fmt
, va_list args
)
257 static char buffer
[512];
260 vsprintf(buffer
, fmt
, args
);
261 name
= input_streams
[pos
.stream
].name
;
263 fprintf(stderr
, "%s: %s:%d:%d: %s\n",
264 type
, name
, pos
.line
, pos
.pos
, buffer
);
267 void warn(struct position pos
, const char * fmt
, ...)
269 static int warnings
= 0;
272 if (warnings
> 100) {
276 fmt
= "too many warnings";
281 do_warn("warning", pos
, fmt
, args
);
286 void error(struct position pos
, const char * fmt
, ...)
290 do_warn("error", pos
, fmt
, args
);
295 void die(const char *fmt
, ...)
298 static char buffer
[512];
301 vsnprintf(buffer
, sizeof(buffer
), fmt
, args
);
304 fprintf(stderr
, "%s\n", buffer
);
308 unsigned int pre_buffer_size
;
309 unsigned char pre_buffer
[8192];
315 void add_pre_buffer(const char *fmt
, ...)
321 size
= pre_buffer_size
;
322 size
+= vsnprintf(pre_buffer
+ size
,
323 sizeof(pre_buffer
) - size
,
325 pre_buffer_size
= size
;
329 char **handle_switch(char *arg
, char **next
)
333 const char *name
= arg
+1;
334 const char *value
= "";
340 if (isspace(c
) || c
== '=') {
346 add_pre_buffer("#define %s %s\n", name
, value
);
357 add_pre_buffer("#add_include \"%s/\"\n", arg
+1);
360 if (*next
&& !strcmp(arg
, "include")) {
361 char *name
= *++next
;
362 int fd
= open(name
, O_RDONLY
);
371 /* Ignore unknown command line options - they're probably gcc switches */
377 void create_builtin_stream(void)
379 add_pre_buffer("#define __i386__ 1\n");
380 add_pre_buffer("#define __linux__ 1\n");
381 add_pre_buffer("#define __STDC__ 1\n");
382 add_pre_buffer("#define linux linux\n");
383 add_pre_buffer("#define __CHECKER__ 1\n");
384 add_pre_buffer("#define cond_syscall(x)\n");
385 add_pre_buffer("#define __GNUC__ 2\n");
386 add_pre_buffer("#define __GNUC_MINOR__ 95\n");
387 add_pre_buffer("#define __func__ \"function\"\n");
388 add_pre_buffer("#define __extension__\n");
389 add_pre_buffer("#define __pragma__\n");
390 add_pre_buffer("extern void *__builtin_memcpy(void *, const void *, unsigned long);\n");
391 add_pre_buffer("extern void * __builtin_return_address(int);\n");
392 add_pre_buffer("#define __builtin_stdarg_start(a,b) ((a) = (__builtin_va_list)(&(b)))\n");
393 add_pre_buffer("#define __builtin_va_arg(arg,type) ((type)0)\n");
394 add_pre_buffer("#define __builtin_va_end(arg)\n");