]> pd.if.org Git - lice/blob - init.c
autocommit for files dated 2014-11-17 20:15:26
[lice] / init.c
1 /*
2  * This file implements a small state machine for handling all the forms
3  * of initialization C offers. It's called from the parser just like
4  * declaration specification. It's a sub portion of the core parser,
5  * seperated from all that logic due to the nature of initializer
6  * complexity.
7  */
8 #include "parse.h"
9 #include "init.h"
10 #include "lice.h"
11 #include "lexer.h"
12 #include "conv.h"
13
14 #include <string.h>
15 #include <stdlib.h>
16
17 static void init_element   (list_t *, data_type_t *, int, bool);
18 static void init_structure (list_t *, data_type_t *, int, bool);
19 static void init_array     (list_t *, data_type_t *, int, bool);
20 static void init_list      (list_t *, data_type_t *, int, bool);
21
22 /*
23  * Initializer elements need to be sorted by semantic order, instead
24  * of lexical order since designated initializers are allowed to
25  * overwrite existingly assigned fields lexically, but the order needs
26  * to stay dependent on semantics. It's also generally more efficent for
27  * initialization to stay sorted.
28  */
29 static int init_sort_predicate(const void *p, const void *q) {
30     const ast_t *const *restrict a = p;
31     const ast_t *const *restrict b = q;
32
33     return (*a)->init.offset <  (*b)->init.offset ? -1 :
34            (*a)->init.offset == (*b)->init.offset ?  0 : 1;
35 }
36
37 static void init_sort(list_t *inits) {
38     size_t           length = list_length(inits);
39     size_t           index  = 0;
40     ast_t          **temp   = memory_allocate(sizeof(ast_t *) * length);
41     list_iterator_t *it     = list_iterator(inits);
42
43     while (!list_iterator_end(it))
44         temp[index++] = list_iterator_next(it);
45
46     qsort(temp, length, sizeof(ast_t *), &init_sort_predicate);
47
48     list_empty(inits);
49     for (index = 0; index < length; index++)
50         list_push(inits, temp[index]);
51 }
52
53 static bool init_earlyout(lexer_token_t *token, bool brace, bool designated) {
54     if ((lexer_ispunct(token, '.') || lexer_ispunct(token, '[')) && !brace && !designated) {
55         lexer_unget(token);
56         return true;
57     }
58     return false;
59 }
60
61 /*
62  * Utility routines to determine and skip to braces for initialization
63  * involving aggregates.
64  */
65 static bool init_skip_brace_maybe(void) {
66     lexer_token_t *token = lexer_next();
67     if (lexer_ispunct(token, '{'))
68         return true;
69     lexer_unget(token);
70     return false;
71 }
72
73 static void init_skip_comma_maybe(void) {
74     lexer_token_t *token = lexer_next();
75
76     if (!lexer_ispunct(token, ','))
77         lexer_unget(token);
78 }
79
80 static void init_skip_brace(void) {
81     for (;;) {
82         /*
83          * Potentially infinite look a head, got to love C's grammar for
84          * this sort of crap.
85          */
86         lexer_token_t *token = lexer_next();
87         if (lexer_ispunct(token, '}'))
88             return;
89
90         if (lexer_ispunct(token, '.')) {
91             lexer_next();
92             parse_expect('=');
93         } else {
94             lexer_unget(token);
95         }
96
97         ast_t *ignore = parse_expression_assignment();
98         if (!ignore)
99             return;
100
101         compile_warn("excess elements in initializer");
102         init_skip_comma_maybe();
103     }
104 }
105
106 /*
107  * Structure and array initialization routines:
108  *  deals with standard initialization via aggregate initializer, as well
109  *  as designated initialization, and nested aggreate + designation. In
110  *  the case of array designated initialization array subscripting is
111  *  handled, where as in the case of structure designated initialization
112  *  field members are indexed by .fieldname. The GCC style of designated
113  *  initializers isn't supported yet, neither is range initialization.
114  */
115 static void init_structure_intermediate(list_t *init, data_type_t *type, int offset, bool designated) {
116     bool             brace = init_skip_brace_maybe();
117     list_iterator_t *it    = list_iterator(table_keys(type->fields));
118
119     for (;;) {
120         lexer_token_t *token = lexer_next();
121         if (lexer_ispunct(token, '}')) {
122             if (!brace)
123                 lexer_unget(token);
124             return;
125         }
126
127         char        *fieldname;
128         data_type_t *fieldtype;
129
130         if (init_earlyout(token, brace, designated))
131             return;
132
133         if (lexer_ispunct(token, '.')) {
134             if (!(token = lexer_next()) || token->type != LEXER_TOKEN_IDENTIFIER)
135                 compile_error("invalid designated initializer");
136             fieldname = token->string;
137             if (!(fieldtype = table_find(type->fields, fieldname)))
138                 compile_error("field `%s' doesn't exist in designated initializer", fieldname);
139
140             it = list_iterator(table_keys(type->fields));
141             while (!list_iterator_end(it))
142                 if (!strcmp(fieldname, list_iterator_next(it)))
143                     break;
144             designated = true;
145         } else {
146             lexer_unget(token);
147             if (list_iterator_end(it))
148                 break;
149
150             fieldname = list_iterator_next(it);
151             fieldtype = table_find(type->fields, fieldname);
152         }
153         init_element(init, fieldtype, offset + fieldtype->offset, designated);
154         init_skip_comma_maybe();
155         designated = false;
156
157         if (!type->isstruct)
158             break;
159     }
160     if (brace)
161         init_skip_brace();
162 }
163
164 static void init_array_intermediate(list_t *init, data_type_t *type, int offset, bool designated) {
165     bool brace    = init_skip_brace_maybe();
166     bool flexible = (type->length <= 0);
167     int  size     = type->pointer->size;
168     int  i;
169
170     for (i = 0; flexible || i < type->length; i++) {
171         lexer_token_t *token = lexer_next();
172         if (lexer_ispunct(token, '}')) {
173             if (!brace)
174                 lexer_unget(token);
175             goto complete;
176         }
177
178         if (init_earlyout(token, brace, designated))
179             return;
180
181         if (lexer_ispunct(token, '[')) {
182             /* designated array initializer */
183             int index = parse_expression_evaluate();
184             if (index < 0 || (!flexible && type->length <= index))
185                 compile_error("out of bounds");
186             i = index;
187             parse_expect(']');
188             designated = true;
189         } else {
190             lexer_unget(token);
191         }
192         init_element(init, type->pointer, offset + size * i, designated);
193         init_skip_comma_maybe();
194         designated = false;
195     }
196     if (brace)
197         init_skip_brace();
198
199 complete:
200     if (type->length < 0) {
201         type->length = i;
202         type->size   = size * i;
203     }
204 }
205
206 /*
207  * Intermediate stages deal with all the logic, these functions are
208  * just tail calls (hopefully optimized) to the intermediate stages followed
209  * by a sorting of the elements to honor semantic ordering of initialization.
210  */
211 static void init_structure(list_t *init, data_type_t *type, int offset, bool designated) {
212     init_structure_intermediate(init, type, offset, designated);
213     init_sort(init);
214 }
215
216 static void init_array(list_t *init, data_type_t *type, int offset, bool designated) {
217     init_array_intermediate(init, type, offset, designated);
218     init_sort(init);
219 }
220
221 /*
222  * The entry points to the initializers, single element initialization
223  * and initializer list initialization will dispatch into the appropriate
224  * initialization parsing routines as defined above.
225  */
226 static void init_element(list_t *init, data_type_t *type, int offset, bool designated) {
227     parse_next('=');
228     if (type->type == TYPE_ARRAY || type->type == TYPE_STRUCTURE)
229         init_list(init, type, offset, designated);
230     else if (parse_next('{')) {
231         init_element(init, type, offset, designated);
232         parse_expect('}');
233     } else {
234         ast_t *expression = parse_expression_assignment();
235         parse_semantic_assignable(type, expression->ctype);
236         list_push(init, ast_initializer(expression, type, offset));
237     }
238 }
239
240 static void init_string(list_t *init, data_type_t *type, char *p, int offset) {
241     if (type->length == -1)
242         type->length = type->size = strlen(p) + 1;
243
244     int i = 0;
245     for (; i < type->length && *p; i++) {
246         list_push(init, ast_initializer(
247             ast_new_integer(ast_data_table[AST_DATA_CHAR], *p++),
248             ast_data_table[AST_DATA_CHAR], offset + i
249         ));
250     }
251     for (; i < type->length; i++) {
252         list_push(init, ast_initializer(
253             ast_new_integer(ast_data_table[AST_DATA_CHAR], 0),
254             ast_data_table[AST_DATA_CHAR], offset + i
255         ));
256     }
257 }
258
259 static void init_list(list_t *init, data_type_t *type, int offset, bool designated) {
260     lexer_token_t *token = lexer_next();
261     if (ast_type_isstring(type)) {
262         if (token->type == LEXER_TOKEN_STRING) {
263             init_string(init, type, token->string, offset);
264             return;
265         }
266
267         if (lexer_ispunct(token, '{') && lexer_peek()->type == LEXER_TOKEN_STRING) {
268             token = lexer_next();
269             init_string(init, type, token->string, offset);
270             parse_expect('}');
271             return;
272         }
273     }
274     lexer_unget(token);
275
276     if (type->type == TYPE_ARRAY)
277         init_array(init, type, offset, designated);
278     else if (type->type == TYPE_STRUCTURE)
279         init_structure(init, type, offset, designated);
280     else
281         init_array(init, ast_array(type, 1), offset, designated);
282 }
283
284 /*
285  * Actual entry point of the parser, parses an initializer list, while
286  * also dispatching into the appropriate parser routines depending on
287  * certain state like, array/structure, designated or not.
288  */
289 list_t *init_entry(data_type_t *type) {
290     list_t *list = list_create();
291     if (lexer_ispunct(lexer_peek(), '{') || ast_type_isstring(type)) {
292         init_list(list, type, 0, false);
293         return list;
294     }
295
296     ast_t *init = parse_expression_assignment();
297     if (conv_capable(init->ctype) && init->ctype->type != type->type)
298         init = ast_type_convert(type, init);
299     list_push(list, ast_initializer(init, type, 0));
300
301     return list;
302 }