]> pd.if.org Git - lice/blob - decl.c
autocommit for files dated 2014-11-17 20:15:26
[lice] / decl.c
1 /*
2  * Deals with all the complexity in C's declaration specification with
3  * a rather large state machine model. C has a lot of ways to specify
4  * something, that happens to be equivlant to other meanings, which are
5  * also used. This state machine monitors the occurance of certain
6  * identifiers to build a serise of on/off state which ultimatly
7  * allows us to disambiguate the meaning, while at the same time enforcing
8  * correctness.
9  *
10  * For instance it isn't legal in C to have a typedef of a 'signed' size
11  * specified type, than use that typedef with another size specifier.
12  * More of these rules apply as well, and are documented in the state
13  * machine set logic.
14  *
15  * Once the state machine has completed it's work the get function uses
16  * the state of the machine to determine what type to return from the
17  * ast data table for types, or if there needs to be a new type created
18  * to compensate for the declaration. Similarly at this stage the state
19  * can be invalid (if something wen terribly wrong) and we can handle,
20  * or ice.
21  *
22  * The main entry point is decl_spec and it's called from the parser,
23  * if everything passes the callsite gets a data_type_t of the type
24  * specified.
25  */
26 #include <string.h>
27
28 #include "parse.h"
29 #include "lice.h"
30 #include "lexer.h"
31
32 typedef enum {
33     SPEC_TYPE_NULL,
34     SPEC_TYPE_VOID,
35     SPEC_TYPE_BOOL,
36     SPEC_TYPE_CHAR,
37     SPEC_TYPE_INT,
38     SPEC_TYPE_FLOAT,
39     SPEC_TYPE_DOUBLE,
40 } spec_type_t;
41
42 typedef enum {
43     SPEC_SIZE_NULL,
44     SPEC_SIZE_SHORT,
45     SPEC_SIZE_LONG,
46     SPEC_SIZE_LLONG
47 } spec_size_t;
48
49 typedef enum {
50     SPEC_SIGN_NULL,
51     SPEC_SIGN_SIGNED,
52     SPEC_SIGN_UNSIGNED
53 } spec_sign_t;
54
55 static const char *spec_type_string[] = {
56     "null", "void",  "_Bool", "char",
57     "int",  "float", "double"
58 };
59
60 static const char *spec_size_string[] = {
61     "null", "short", "long", "long long"
62 };
63
64 static const char *spec_sign_string[] = {
65     "null", "signed", "unsigned"
66 };
67
68 static const char *spec_var_string[] = {
69     "null", "type", "size", "sign", "user"
70 };
71
72 typedef struct {
73     storage_t    class;
74     spec_type_t  type;
75     spec_size_t  size;
76     spec_sign_t  sign;
77     data_type_t *user;
78     bool         kconst;
79     bool         kvolatile;
80     bool         kinline;
81 } decl_spec_t;
82
83 typedef enum {
84     SPEC_VAR_NULL,
85     SPEC_VAR_TYPE,
86     SPEC_VAR_SIZE,
87     SPEC_VAR_SIGN,
88     SPEC_VAR_USER
89 } decl_var_t;
90
91 #define decl_spec_error(X, SELECT) \
92     decl_spec_error_impl((X), (SELECT), __LINE__)
93
94 static const char *debug_storage_string(const storage_t class) {
95     switch (class) {
96         case STORAGE_AUTO:      return "auto";
97         case STORAGE_EXTERN:    return "extern";
98         case STORAGE_REGISTER:  return "register";
99         case STORAGE_STATIC:    return "static";
100         case STORAGE_TYPEDEF:   return "typedef";
101     }
102     return "default";
103 }
104
105 static void decl_spec_error_impl(const decl_spec_t *spec, const decl_var_t select, const size_t line) {
106     const char *type = spec_type_string[spec->type];
107     const char *size = spec_size_string[spec->size];
108     const char *sign = spec_sign_string[spec->sign];
109     const char *var  = spec_var_string[select];
110
111     if (!type) type = "unspecified";
112     if (!size) size = "unspecified";
113     if (!sign) sign = "unspecified";
114     if (!var)  var  = "unspecified";
115
116     compile_ice("declaration specifier error %d\n"
117                 "debug info:\n"
118                 "   select:   %s\n"
119                 "   class:    %s\n"
120                 "   type:     %s\n"
121                 "   size:     %s\n"
122                 "   sign:     %s\n"
123                 "   const:    %s\n"
124                 "   volatile: %s\n"
125                 "   inline:   %s\n",
126                 line,
127                 var,
128                 debug_storage_string(spec->class),
129                 type,
130                 size,
131                 sign,
132                 bool_string(spec->kconst),
133                 bool_string(spec->kvolatile),
134                 bool_string(spec->kinline)
135     );
136 }
137
138 static void decl_spec_class(decl_spec_t *spec, const storage_t class) {
139     if (spec->class != 0)
140         decl_spec_error(spec, SPEC_VAR_NULL);
141     spec->class = class;
142 }
143
144 static void decl_spec_set(decl_spec_t *spec, const decl_var_t select, void *value) {
145     switch (select) {
146         case SPEC_VAR_SIGN:
147             if (spec->sign != SPEC_SIGN_NULL)
148                 decl_spec_error(spec, select);
149             spec->sign = *(spec_sign_t*)value;
150             break;
151         case SPEC_VAR_SIZE:
152             if (spec->size != SPEC_SIZE_NULL)
153                 decl_spec_error(spec, select);
154             spec->size = *(spec_size_t*)value;
155             break;
156         case SPEC_VAR_TYPE:
157             if (spec->type != SPEC_TYPE_NULL)
158                 decl_spec_error(spec, select);
159             spec->type = *(spec_type_t*)value;
160             break;
161         case SPEC_VAR_USER:
162             if (spec->user != 0)
163                 decl_spec_error(spec, select);
164             spec->user = value;
165             break;
166         default:
167             compile_ice("decl_spec_get state machine got null variable reference");
168             break;
169     }
170
171     /* bool cannot have a sign, it's only legal as it's own entity. */
172     if (spec->type == SPEC_TYPE_BOOL && (spec->size != SPEC_SIZE_NULL && spec->sign != SPEC_SIGN_NULL))
173         decl_spec_error(spec, select);
174
175     switch (spec->size) {
176         case SPEC_SIZE_SHORT:
177             /*
178              * short and short int are the only legal uses of the short
179              * size specifier.
180              */
181             if (spec->type != SPEC_TYPE_NULL && spec->type != SPEC_TYPE_INT)
182                 decl_spec_error(spec, select);
183             break;
184
185         case SPEC_SIZE_LONG:
186             /*
187              * long, long int and long double are the only legal uses of
188              * long size specifier.
189              */
190             if (spec->type != SPEC_TYPE_NULL && spec->type != SPEC_TYPE_INT && spec->type != SPEC_TYPE_DOUBLE)
191                 decl_spec_error(spec, select);
192             break;
193
194         default:
195             break;
196     }
197
198     /*
199      * sign and unsigned sign specifiers are not legal on void, float and
200      * double types.
201      */
202     if (spec->sign != SPEC_SIGN_NULL) {
203         switch (spec->type) {
204             case SPEC_TYPE_VOID:
205             case SPEC_TYPE_FLOAT:
206             case SPEC_TYPE_DOUBLE:
207                 decl_spec_error(spec, select);
208                 break;
209             default:
210                 break;
211         }
212     }
213
214     /*
215      * user types cannot have additional levels of specification on it,
216      * for instance 'typedef unsigned int foo; 'signed foo'.
217      */
218     if (spec->user && (spec->type != SPEC_TYPE_NULL ||
219                        spec->size != SPEC_SIZE_NULL ||
220                        spec->sign != SPEC_SIGN_NULL))
221         decl_spec_error(spec, select);
222 }
223
224 #define decl_spec_seti(SPEC, SELECT, VAR) \
225     decl_spec_set((SPEC), (SELECT), &(int){ VAR })
226
227 static data_type_t *decl_spec_get(const decl_spec_t *spec) {
228     bool sign = !!(spec->sign != SPEC_SIGN_UNSIGNED);
229
230     switch (spec->type) {
231         case SPEC_TYPE_VOID:
232             return ast_data_table[AST_DATA_VOID];
233         case SPEC_TYPE_BOOL:
234             return ast_type_create(TYPE_BOOL, false);
235         case SPEC_TYPE_CHAR:
236             return ast_type_create(TYPE_CHAR, sign);
237         case SPEC_TYPE_FLOAT:
238             return ast_type_create(TYPE_FLOAT, false);
239         case SPEC_TYPE_DOUBLE:
240             if (spec->size == SPEC_SIZE_LONG)
241                 return ast_type_create(TYPE_LDOUBLE, false);
242             return ast_type_create(TYPE_DOUBLE, false);
243         default:
244             break;
245     }
246
247     switch (spec->size) {
248         case SPEC_SIZE_SHORT:
249             return ast_type_create(TYPE_SHORT, sign);
250         case SPEC_SIZE_LONG:
251             return ast_type_create(TYPE_LONG, sign);
252         case SPEC_SIZE_LLONG:
253             return ast_type_create(TYPE_LLONG, sign);
254         default:
255             /* implicit int */
256             return ast_type_create(TYPE_INT, sign);
257     }
258     compile_ice("declaration specifier");
259 }
260
261 data_type_t *decl_spec(storage_t *const class) {
262     decl_spec_t spec;
263     memset(&spec, 0, sizeof(spec));
264
265     for (;;) {
266         lexer_token_t *token = lexer_next();
267         if (!token)
268             compile_error("type specification with unexpected ending");
269
270         if (token->type != LEXER_TOKEN_IDENTIFIER) {
271             lexer_unget(token);
272             break;
273         }
274
275         if (!strcmp(token->string, "const"))
276             spec.kconst = true;
277         else if (!strcmp(token->string, "volatile"))
278             spec.kvolatile = true;
279         else if (!strcmp(token->string, "inline"))
280             spec.kinline = true;
281         else if (!strcmp(token->string, "typedef"))
282             decl_spec_class(&spec, STORAGE_TYPEDEF);
283         else if (!strcmp(token->string, "extern"))
284             decl_spec_class(&spec, STORAGE_EXTERN);
285         else if (!strcmp(token->string, "static") || !strcmp(token->string, "__static__"))
286             decl_spec_class(&spec, STORAGE_STATIC);
287         else if (!strcmp(token->string, "auto"))
288             decl_spec_class(&spec, STORAGE_AUTO);
289         else if (!strcmp(token->string, "register"))
290             decl_spec_class(&spec, STORAGE_REGISTER);
291         else if (!strcmp(token->string, "void"))
292             decl_spec_seti(&spec, SPEC_VAR_TYPE, SPEC_TYPE_VOID);
293         else if (!strcmp(token->string, "_Bool"))
294             decl_spec_seti(&spec, SPEC_VAR_TYPE, SPEC_TYPE_BOOL);
295         else if (!strcmp(token->string, "char"))
296             decl_spec_seti(&spec, SPEC_VAR_TYPE, SPEC_TYPE_CHAR);
297         else if (!strcmp(token->string, "int"))
298             decl_spec_seti(&spec, SPEC_VAR_TYPE, SPEC_TYPE_INT);
299         else if (!strcmp(token->string, "float"))
300             decl_spec_seti(&spec, SPEC_VAR_TYPE, SPEC_TYPE_FLOAT);
301         else if (!strcmp(token->string, "double"))
302             decl_spec_seti(&spec, SPEC_VAR_TYPE, SPEC_TYPE_DOUBLE);
303         else if (!strcmp(token->string, "signed"))
304             decl_spec_seti(&spec, SPEC_VAR_SIGN, SPEC_SIGN_SIGNED);
305         else if (!strcmp(token->string, "unsigned"))
306             decl_spec_seti(&spec, SPEC_VAR_SIGN, SPEC_SIGN_UNSIGNED);
307         else if (!strcmp(token->string, "struct"))
308             decl_spec_set(&spec, SPEC_VAR_USER, parse_structure());
309         else if (!strcmp(token->string, "union"))
310             decl_spec_set(&spec, SPEC_VAR_USER, parse_union());
311         else if (!strcmp(token->string, "enum"))
312             decl_spec_set(&spec, SPEC_VAR_USER, parse_enumeration());
313         else if (!strcmp(token->string, "short"))
314             decl_spec_seti(&spec, SPEC_VAR_SIZE, SPEC_SIZE_SHORT);
315         else if (!strcmp(token->string, "long")) {
316             if (spec.size == 0)
317                 decl_spec_seti(&spec, SPEC_VAR_SIZE, SPEC_SIZE_LONG);
318             else if (spec.size == SPEC_SIZE_LONG)
319                 spec.size = SPEC_SIZE_LLONG;
320             else
321                 decl_spec_error(&spec, SPEC_VAR_NULL);
322         }
323         else if (!strcmp(token->string, "typeof") || !strcmp(token->string, "__typeof__"))
324             decl_spec_set(&spec, SPEC_VAR_USER, parse_typeof());
325         else if (parse_typedef_find(token->string) && !spec.user)
326             decl_spec_set(&spec, SPEC_VAR_USER, parse_typedef_find(token->string));
327         else {
328             lexer_unget(token);
329             break;
330         }
331     }
332
333     if (class)
334         *class = spec.class;
335     if (spec.user)
336         return spec.user;
337
338     return decl_spec_get(&spec);
339 }