-
Notifications
You must be signed in to change notification settings - Fork 0
/
decl_common.cpp
397 lines (367 loc) · 9.23 KB
/
decl_common.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
#include "decl_common.hpp"
#include <string>
storage_specifiers::storage_specifiers(storage spec) { this->spec = spec; }
storage_specifiers *storage_specifiers::add_spec(storage spec) {
if (this->spec != UNSET) {
print_warning("Only one storage specifier is allowed. Taking the new one!");
}
this->spec = spec;
return this;
}
void storage_specifiers::dump_tree() {
if (spec != UNSET) {
cout << "- (storage_specifiers) " << to_string() << endl;
}
}
std::string storage_specifiers::to_string() {
switch (spec) {
case UNSET:
return "unset";
case TYPEDEF:
return "typedef";
case EXTERN:
return "extern";
case STATIC:
return "static";
case THREAD_LOCAL:
return "_Thread_local";
case AUTO:
return "auto";
case REGISTER:
return "register";
}
return "unkown";
}
type_specifiers::type_specifiers(type spec) {
this->specs = UNSET;
if (spec == UNSET) {
return;
}
add_spec(spec);
}
type_specifiers *type_specifiers::raise_incompat_error(type spec) {
raise_error("Incompatible type specifiers");
return this;
}
type_specifiers *type_specifiers::change_type(type specs) {
this->specs = specs;
return this;
}
type_specifiers *type_specifiers::add_spec(type spec) {
bool was_inserted = types_seen.insert(spec).second;
// FIXME maybe: Weirdish fix for LONG being able to appear twice
if (!was_inserted && spec == LONG) {
was_inserted = types_seen.insert(LONG_LONG).second;
}
if (!was_inserted) { // => Already present
return raise_incompat_error(spec);
}
switch (this->specs) {
case UNSET:
switch (spec) {
case UNSIGNED:
return change_type(UINT);
case SIGNED:
return change_type(INT);
default:
return change_type(spec);
}
case VOID:
case SCHAR:
case UCHAR:
case UINT:
case FLOAT:
case BOOL:
case LONG_DOUBLE:
return raise_incompat_error(spec);
case CHAR:
switch (spec) {
case UNSIGNED:
return change_type(UCHAR);
case SIGNED:
return change_type(SCHAR);
default:
return raise_incompat_error(spec);
}
case SHORT:
switch (spec) {
case SIGNED:
case INT:
return this;
case UNSIGNED:
return change_type(USHORT);
default:
return raise_incompat_error(spec);
}
case USHORT:
switch (spec) {
case INT:
return this;
default:
return raise_incompat_error(spec);
}
case INT:
switch (spec) {
case SHORT:
return change_type(SHORT);
case LONG:
return change_type(LONG);
case SIGNED:
return this;
case UNSIGNED:
return change_type(UINT);
default:
return raise_incompat_error(spec);
}
case LONG:
switch (spec) {
case SIGNED:
case INT:
return this;
case LONG:
return change_type(LONG_LONG);
case UNSIGNED:
return change_type(ULONG);
case DOUBLE:
return change_type(LONG_DOUBLE);
default:
return raise_incompat_error(spec);
}
case ULONG:
switch (spec) {
case INT:
return this;
case LONG:
return change_type(ULONG_LONG);
default:
return raise_incompat_error(spec);
}
case LONG_LONG:
switch (spec) {
case INT:
case SIGNED:
return this;
case UNSIGNED:
return change_type(ULONG_LONG);
default:
return raise_incompat_error(spec);
}
case ULONG_LONG:
switch (spec) {
case INT:
return this;
default:
return raise_incompat_error(spec);
}
case DOUBLE:
switch (spec) {
case LONG:
return change_type(LONG_DOUBLE);
default:
return raise_incompat_error(spec);
}
case SIGNED:
switch (spec) {
case INT:
case SHORT:
case LONG:
case LONG_LONG:
return change_type(spec);
case CHAR:
return change_type(SCHAR);
default:
return raise_incompat_error(spec);
}
case UNSIGNED:
switch (spec) {
case INT:
return change_type(UINT);
case SHORT:
return change_type(USHORT);
case LONG:
return change_type(ULONG);
case LONG_LONG:
return change_type(ULONG_LONG);
case CHAR:
return change_type(UCHAR);
default:
return raise_incompat_error(spec);
}
}
print_warning("Undefined type given to type_specifiers::add_spec");
return this;
}
type_specifiers::type type_specifiers::get_specs() { return specs; }
void type_specifiers::dump_tree() {
cout << "- (type_specifier) " << to_string() << endl;
}
std::string type_specifiers::to_string() {
switch (specs) {
case UNSET:
return "unset";
case VOID:
return "void";
case CHAR:
return "char";
case SCHAR:
return "signed char";
case UCHAR:
return "unsigned char";
case SHORT:
return "short";
case USHORT:
return "unsigned short";
case INT:
return "int";
case UINT:
return "unsigned int";
case LONG:
return "long";
case ULONG:
return "unsigned long";
case LONG_LONG:
return "long long";
case ULONG_LONG:
return "unsigned long long";
case FLOAT:
return "float";
case DOUBLE:
return "double";
case LONG_DOUBLE:
return "long double";
case SIGNED:
return "signed";
case UNSIGNED:
return "unsigned";
case BOOL:
return "bool";
}
return "unknown";
}
bool type_specifiers::is_signed() {
switch (specs) {
case CHAR:
case UCHAR:
case USHORT:
case UINT:
case ULONG:
case ULONG_LONG:
case UNSIGNED:
return false;
}
return true;
}
/*
* Using https://en.cppreference.com/w/c/language/arithmetic_types as reference
*/
llvm::Type *type_specifiers::get_llvm_type() {
switch (specs) {
case VOID:
return llvm::Type::getVoidTy(the_context);
case CHAR:
case SCHAR:
case UCHAR:
return llvm::Type::getInt8Ty(the_context);
case SHORT:
case USHORT:
return llvm::Type::getInt16Ty(the_context);
case INT:
case UINT:
case LONG:
case ULONG:
return llvm::Type::getInt32Ty(the_context);
case LONG_LONG:
case ULONG_LONG:
return llvm::Type::getInt64Ty(the_context);
case FLOAT:
return llvm::Type::getFloatTy(the_context);
case DOUBLE:
return llvm::Type::getDoubleTy(the_context);
case LONG_DOUBLE:
return llvm::Type::getFP128Ty(the_context); // Not sure what to use here
case BOOL:
// A _Bool could be i1 but the spec wants alignment requirement to be
// atleast as strict as that of char and I can't find any reference for
// the alignment of i1
return llvm::Type::getInt8Ty(the_context);
}
print_warning(
"Cannot be converted to llvm Type. Either not set or incomplete");
cout << "Current type is " << type_specifiers(specs).to_string() << endl;
return nullptr;
}
type_i type_specifiers::get_type() {
return type_i(get_llvm_type(), is_signed());
}
type_qualifiers *type_qualifiers::add_qual(type_qualifiers::qualifier qual) {
// Section 6.7.3, point 5: "If the same qualifier appears more than once
// in the samespecifier-qualifier-list, either directly or via one or
// more typedefs, the behavior is the same as if it appeared only once."
// So we simply insert into the set and don't check for repetitions;
qualifiers.insert(qual);
return this;
}
void type_qualifiers::dump_tree() {
cout << "- (type_qualifiers) ";
if (qualifiers.empty()) {
cout << "NONE" << endl;
return;
}
for (auto qual : qualifiers) {
cout << to_string(qual) << ' ';
}
cout << endl;
}
std::string type_qualifiers::to_string(type_qualifiers::qualifier qual) {
switch (qual) {
case CONST:
return "const";
case RESTRICT:
return "restrict";
case VOLATILE:
return "volatile";
case ATOMIC:
return "_Atomic";
}
return "unknown";
}
pointer_node *pointer_node::add(type_qualifiers *qual) {
quals.push_back(qual);
return this;
}
void pointer_node::dump_tree() {
cout << "- (pointer)" << endl;
cout.indent();
for (auto &qual : quals) {
qual->dump_tree();
}
cout.unindent();
}
type_i pointer_node::get_type(type_i type) {
llvm::Type *&ret = type.llvm_type;
for (auto &qual : quals) {
ret = ret->getPointerTo();
}
return type;
}
declaration_specs *declaration_specs::add(storage_specifiers::storage spec) {
this->storage_spec.add_spec(spec);
return this;
}
declaration_specs *declaration_specs::add(type_specifiers::type spec) {
this->type_spec.add_spec(spec);
return this;
}
declaration_specs *declaration_specs::add(type_qualifiers::qualifier qual) {
this->type_qual.add_qual(qual);
return this;
}
void declaration_specs::dump_tree() {
cout << "- (declaration_specifiers)" << endl;
cout.indent();
storage_spec.dump_tree();
type_spec.dump_tree();
type_qual.dump_tree();
cout.unindent();
}
type_i declaration_specs::get_type() { return type_spec.get_type(); }