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
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);
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.
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;
33 return (*a)->init.offset < (*b)->init.offset ? -1 :
34 (*a)->init.offset == (*b)->init.offset ? 0 : 1;
37 static void init_sort(list_t *inits) {
38 size_t length = list_length(inits);
40 ast_t **temp = memory_allocate(sizeof(ast_t *) * length);
41 list_iterator_t *it = list_iterator(inits);
43 while (!list_iterator_end(it))
44 temp[index++] = list_iterator_next(it);
46 qsort(temp, length, sizeof(ast_t *), &init_sort_predicate);
49 for (index = 0; index < length; index++)
50 list_push(inits, temp[index]);
53 static bool init_earlyout(lexer_token_t *token, bool brace, bool designated) {
54 if ((lexer_ispunct(token, '.') || lexer_ispunct(token, '[')) && !brace && !designated) {
62 * Utility routines to determine and skip to braces for initialization
63 * involving aggregates.
65 static bool init_skip_brace_maybe(void) {
66 lexer_token_t *token = lexer_next();
67 if (lexer_ispunct(token, '{'))
73 static void init_skip_comma_maybe(void) {
74 lexer_token_t *token = lexer_next();
76 if (!lexer_ispunct(token, ','))
80 static void init_skip_brace(void) {
83 * Potentially infinite look a head, got to love C's grammar for
86 lexer_token_t *token = lexer_next();
87 if (lexer_ispunct(token, '}'))
90 if (lexer_ispunct(token, '.')) {
97 ast_t *ignore = parse_expression_assignment();
101 compile_warn("excess elements in initializer");
102 init_skip_comma_maybe();
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.
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));
120 lexer_token_t *token = lexer_next();
121 if (lexer_ispunct(token, '}')) {
128 data_type_t *fieldtype;
130 if (init_earlyout(token, brace, designated))
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);
140 it = list_iterator(table_keys(type->fields));
141 while (!list_iterator_end(it))
142 if (!strcmp(fieldname, list_iterator_next(it)))
147 if (list_iterator_end(it))
150 fieldname = list_iterator_next(it);
151 fieldtype = table_find(type->fields, fieldname);
153 init_element(init, fieldtype, offset + fieldtype->offset, designated);
154 init_skip_comma_maybe();
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;
170 for (i = 0; flexible || i < type->length; i++) {
171 lexer_token_t *token = lexer_next();
172 if (lexer_ispunct(token, '}')) {
178 if (init_earlyout(token, brace, designated))
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");
192 init_element(init, type->pointer, offset + size * i, designated);
193 init_skip_comma_maybe();
200 if (type->length < 0) {
202 type->size = size * i;
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.
211 static void init_structure(list_t *init, data_type_t *type, int offset, bool designated) {
212 init_structure_intermediate(init, type, offset, designated);
216 static void init_array(list_t *init, data_type_t *type, int offset, bool designated) {
217 init_array_intermediate(init, type, offset, designated);
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.
226 static void init_element(list_t *init, data_type_t *type, int offset, bool designated) {
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);
234 ast_t *expression = parse_expression_assignment();
235 parse_semantic_assignable(type, expression->ctype);
236 list_push(init, ast_initializer(expression, type, offset));
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;
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
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
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);
267 if (lexer_ispunct(token, '{') && lexer_peek()->type == LEXER_TOKEN_STRING) {
268 token = lexer_next();
269 init_string(init, type, token->string, offset);
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);
281 init_array(init, ast_array(type, 1), offset, designated);
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.
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);
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));