forked from freewilll/wcc
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathparser.c
More file actions
3683 lines (2947 loc) · 131 KB
/
parser.c
File metadata and controls
3683 lines (2947 loc) · 131 KB
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
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include "wcc.h"
#define INITIAL_INITALIZERS_COUNT 32
typedef struct base_type {
Type *type;
int storage_class;
} BaseType;
typedef struct goto_backpatch {
char *identifier;
Tac *ir;
} GotoBackPatch;
int function_call_count; // Uniquely identify a function call within a function
int vreg_count; // Virtual register count for currently parsed function
int local_static_symbol_count; // Amount of static objects with block scope
Value *controlling_case_value; // Controlling value for the current switch statement
LongMap *case_values; // Already seen case value in current switch statement
Tac *case_ir_start; // Start of IR for current switch case conditional & jump statements
Tac *case_ir; // IR for current switch case conditional & jump statements
Value *case_default_label; // Label for curren't switch's statement default case, if present
int seen_switch_default; // Set to 1 if a default label has been seen within the current switch statement
Value **vs_bottom; // Allocated value stack
Value **vs_start; // Value stack start
Value **vs; // Value stack current position
static List *allocated_strings;
static StrMap *origin_filenames; // Map lexer filename to a unique filename in memory
static List *allocated_origins; // Allocated Origin instances
static List *allocated_sets; // Allocated Set instances
static Type *parse_struct_or_union_type_specifier(void);
static Type *parse_enum_type_specifier(void);
static TypeIterator *parse_initializer(TypeIterator *it, Value *value, Value *expression);
void check_and_or_operation_type(Value *src1, Value *src2);
Value *parse_expression_and_pop(int level);
static void parse_statement(void);
static void parse_expression(int level);
static void parse_compound_statement(void);
static BaseType *base_type;
// Duplicate a string an track it in allocate_strings
static char *parser_wstrdup(char *str) {
if (!str) return NULL;
char *result = wstrdup(str);
append_to_list(allocated_strings, result);
return result;
}
static int value_stack_is_empty(void) {
return vs == vs_start;
}
static Value *vtop(void) {
if (vs == vs_start) error("Missing expression");
return *vs;
}
// Allocate a new virtual register
static int new_vreg(void) {
vreg_count++;
if (vreg_count >= MAX_VREG_COUNT) panic_with_line_number("Exceeded max vreg count %d", MAX_VREG_COUNT);
return vreg_count;
}
// Add an instruction and set the line number and filename
Tac *add_parser_instruction(int operation, Value *dst, Value *src1, Value *src2) {
Origin *origin = wmalloc(sizeof(Origin));
append_to_list(allocated_origins, origin);
char *filename = NULL;
if (cur_filename) {
filename = strmap_get(origin_filenames, cur_filename);
if (!filename) {
filename = parser_wstrdup(cur_filename);
strmap_put(origin_filenames, filename, filename);
}
}
origin->filename = filename;
origin->line_number = cur_line;
Tac *tac = add_instruction(operation, dst, src1, src2);
tac->origin = origin;
return tac;
}
static Value *decay_array_value(Value *v) {
Value *result = dup_value(v);
result->type = decay_array_to_pointer(v->type);
return result;
}
// Push a value to the stack
static Value *push(Value *v) {
*--vs = v;
return v;
}
static void check_stack_has_value(void) {
if (vs == vs_start) panic_with_line_number("Empty parser stack");
if (vtop()->type->type == TYPE_VOID) error("Illegal attempt to use a void value");
}
// Pop a value from the stack
static Value *pop(void) {
check_stack_has_value();
Value *result = *vs++;
return result;
}
// Make a void value
static Value *make_void_value(void) {
Value *v = new_value();
v->type = new_type(TYPE_VOID);
v->vreg = new_vreg();
return v;
}
// Push a void value to the stack
static void push_void(void) {
push(make_void_value());
}
// Pop a void value from the stack,unless the stack is empty
static void *pop_void(void) {
if (vs == vs_start) return NULL;
vs++;
}
static Value *load_bit_field(Value *src1) {
Value *dst = new_value();
dst->type = new_type(TYPE_INT);
dst->type->is_unsigned = src1->type->is_unsigned;
dst->vreg = new_vreg();
add_parser_instruction(IR_LOAD_BIT_FIELD, dst, src1, 0);
return dst;
}
// load a value into a register if not already done. lvalues are converted into
// rvalues.
static Value *load(Value *src1) {
if (src1->is_constant) return src1;
if (src1->vreg && !src1->is_lvalue) return src1;
if (src1->type->type == TYPE_STRUCT_OR_UNION) return src1;
if (src1->type->type == TYPE_FUNCTION) return src1;
if (src1->bit_field_size) return load_bit_field(src1);
Value *dst = dup_value(src1);
dst->vreg = new_vreg();
dst->is_lvalue = 0;
dst->type->is_const = 0;
// Ensure an offset read from a struct/union isn't persisted into a register which might
// get moved back onto a stack, e.g. for long doubles
dst->offset = 0;
if (src1->type->type == TYPE_ARRAY) {
if (src1->is_string_literal) {
// Load the address of a string literal into a register
dst->type = decay_array_to_pointer(dst->type);
dst->is_string_literal = 0;
dst->string_literal_index = 0;
add_parser_instruction(IR_MOVE, dst, src1, 0);
}
else {
// Take the address of an array
dst->local_index = 0;
dst->global_symbol = 0;
dst->type = decay_array_to_pointer(dst->type);
add_parser_instruction(IR_ADDRESS_OF, dst, src1, 0);
// If it's a pointer in a register with an offset, the offset needs to be
// added to it.
if (src1->vreg && src1->offset) {
Value *tmp = dup_value(dst);
tmp->vreg = new_vreg();
add_parser_instruction(IR_ADD, tmp, dst, new_integral_constant(TYPE_INT, src1->offset));
dst = tmp;
src1->offset = 0; // Ensure downstream code doesn't deal with the offset again.
}
}
}
else if (src1->vreg && src1->is_lvalue) {
// An lvalue in a register needs a dereference
if (src1->type->type == TYPE_VOID) error("Cannot dereference a *void");
if (src1->type->type == TYPE_STRUCT_OR_UNION) error("Cannot dereference a pointer to a struct/union");
if (src1->type->type == TYPE_ARRAY) error("Cannot dereference a pointer to an array");
src1 = dup_value(src1);
src1->type = make_pointer(src1->type);
src1->is_lvalue = 0;
src1->type->is_const = 0;
add_parser_instruction(IR_INDIRECT, dst, src1, 0);
}
else {
// Load a value into a register. This could be a global or a local.
dst->local_index = 0;
dst->global_symbol = 0;
add_parser_instruction(IR_MOVE, dst, src1, 0);
}
return dst;
}
// Pop and load.
static Value *pl(void) {
return load(pop());
}
static int new_local_index(void) {
return -1 - cur_function_symbol->function->local_symbol_count++;
}
// Create a new typed constant value and push it to the stack.
// type doesn't have to be dupped
static void push_integral_constant(int type_type, long value) {
push(new_integral_constant(type_type, value));
}
// Push cur_long, using the lexer determined type cur_lexer_type
static void push_cur_long(void) {
Value *v = new_integral_constant(cur_lexer_type->type, cur_long);
v->type->is_unsigned = cur_lexer_type->is_unsigned;
push(v);
}
// Create a new typed floating point constant value and push it to the stack.
// type doesn't have to be dupped
static void push_floating_point_constant(int type_type, long double value) {
push(new_floating_point_constant(type_type, value));
}
// Push the currently lexed long double floating point number, cur_long_double
static void push_cur_long_double(void) {
Value *v = new_floating_point_constant(cur_lexer_type->type, cur_long_double);
push(v);
}
Value *make_string_literal_value_from_cur_string_literal(void) {
Value *value = new_value();
value->type = make_array(new_type(cur_string_literal.is_wide_char ? TYPE_INT : TYPE_CHAR), cur_string_literal.size);
value->string_literal_index = string_literal_count;
value->is_string_literal = 1;
if (string_literal_count > MAX_STRING_LITERALS) panic_with_line_number("Exceeded max string literals %d", MAX_STRING_LITERALS);
string_literals[string_literal_count] = cur_string_literal;
// Copy string literal data
int count = cur_string_literal.size * (cur_string_literal.is_wide_char ? 4 : 1);
char *copy = wmalloc(count);
for (int i = 0; i < count; i++) copy[i] = cur_string_literal.data[i];
append_to_list(allocated_strings, copy);
string_literals[string_literal_count].data = copy;
string_literal_count++;
return value;
}
// Add an operation to the IR
static Tac *add_ir_op(int operation, Type *type, int vreg, Value *src1, Value *src2) {
Value *v = new_value();
v->vreg = vreg;
v->type = dup_type(type);
Tac *result = add_parser_instruction(operation, v, src1, src2);
push(v);
return result;
}
// Returns destination type of an operation with two operands
// https://en.cppreference.com/w/c/language/conversion
Type *operation_type(Value *src1, Value *src2, int for_ternary) {
Type *src1_type = src1->type;
Type *src2_type = src2->type;
// Decay arrays to pointers
if (src1_type->type == TYPE_ARRAY) src1_type = decay_array_to_pointer(src1_type);
if (src2_type->type == TYPE_ARRAY) src2_type = decay_array_to_pointer(src2_type);
if (src1_type->type == TYPE_FUNCTION && src2_type->type == TYPE_FUNCTION)
return dup_type(src1_type);
Type *result;
if (src1_type->type == TYPE_STRUCT_OR_UNION || src2_type->type == TYPE_STRUCT_OR_UNION)
// Compatibility should already have been checked for at this point
return src1_type;
// If it's a ternary and one is a pointer and the other a pointer to void, then the result is a pointer to void.
else if (src1_type->type == TYPE_PTR && is_pointer_to_void(src2->type)) return for_ternary ? src2->type : src1->type;
else if (src2_type->type == TYPE_PTR && is_pointer_to_void(src1->type)) return for_ternary ? src1->type : src2->type;
else if (for_ternary && (src1_type->type == TYPE_PTR || src1_type->type == TYPE_FUNCTION) && is_null_pointer(src2)) return src1->type;
else if (for_ternary && (src2_type->type == TYPE_PTR || src2_type->type == TYPE_FUNCTION) && is_null_pointer(src1)) return src2->type;
else if (for_ternary && src1_type->type == TYPE_PTR && src2_type->type == TYPE_PTR) return ternary_pointer_composite_type(src1->type, src2->type);
else if (src1_type->type == TYPE_PTR) return src1_type;
else if (src2_type->type == TYPE_PTR) return src2_type;
// If either is a long double, promote both to long double
if (src1_type->type == TYPE_LONG_DOUBLE || src2_type->type == TYPE_LONG_DOUBLE)
return new_type(TYPE_LONG_DOUBLE);
// If either is a double, promote both to double
if (src1_type->type == TYPE_DOUBLE || src2_type->type == TYPE_DOUBLE)
return new_type(TYPE_DOUBLE);
// If either is a float, promote both to float
if (src1_type->type == TYPE_FLOAT || src2_type->type == TYPE_FLOAT)
return new_type(TYPE_FLOAT);
if (src1_type->type == TYPE_VOID || src2_type->type == TYPE_VOID)
return new_type(TYPE_VOID);
// Otherwise, apply integral promotions
src1_type = integer_promote_type(src1_type);
src2_type = integer_promote_type(src2_type);
// They are two integer types
if (src1_type->type == TYPE_LONG || src2_type->type == TYPE_LONG)
result = new_type(TYPE_LONG);
else
result = new_type(TYPE_INT);
result->is_unsigned = is_integer_operation_result_unsigned(src1_type, src2_type);
return result;
}
// Returns destination type of an operation using the top two values in the stack
static Type *vs_operation_type(void) {
return operation_type(vtop(), vs[1], 0);
}
int cur_token_is_type(void) {
return (
cur_token == TOK_SIGNED ||
cur_token == TOK_UNSIGNED ||
cur_token == TOK_INLINE ||
cur_token == TOK_CONST ||
cur_token == TOK_VOLATILE ||
cur_token == TOK_RESTRICT ||
cur_token == TOK_VOID ||
cur_token == TOK_CHAR ||
cur_token == TOK_SHORT ||
cur_token == TOK_INT ||
cur_token == TOK_FLOAT ||
cur_token == TOK_DOUBLE ||
cur_token == TOK_LONG ||
cur_token == TOK_STRUCT ||
cur_token == TOK_UNION ||
cur_token == TOK_ENUM ||
cur_token == TOK_AUTO ||
cur_token == TOK_REGISTER ||
cur_token == TOK_EXTERN ||
cur_token == TOK_STATIC ||
cur_token == TOK_TYPEDEF_TYPE ||
cur_token == TOK_ATTRIBUTE
);
}
// How much will the ++, --, +=, -= operators increment a type?
static int get_type_inc_dec_size(Type *type) {
return type->type == TYPE_PTR ? get_type_size(type->target) : 1;
}
// Parse optional repeated __attribute__ ((...)), ignoring everything inside the ((...))
void parse_attributes(void) {
while (1) {
if (cur_token != TOK_ATTRIBUTE) return;
next();
consume(TOK_LPAREN, "(");
consume(TOK_LPAREN, "(");
int parentheses_nesting_level = 2;
// Keep parsing until we break out of the ((
while (cur_token != TOK_EOF) {
if (cur_token == TOK_LPAREN) parentheses_nesting_level++;
else if (cur_token == TOK_RPAREN) parentheses_nesting_level--;
next();
if (!parentheses_nesting_level) break;
}
}
}
// Parse
// - storage-class-specifiers: auto, register, static, extern
// - type-specifiers: void, int, signed, unsigned, ... long, double, struct, union
// - type-qualifiers: const, volatile
// - typedef type names
static BaseType *parse_declaration_specifiers() {
Type *type = 0;
// Type specifiers
int seen_void = 0;
int seen_char = 0;
int seen_short = 0;
int seen_int = 0;
int seen_long = 0;
int seen_long_double = 0;
int seen_float = 0;
int seen_double = 0;
int seen_signed = 0;
int seen_unsigned = 0;
int seen_inline = 0;
// Qualifiers
int seen_const = 0;
int seen_volatile = 0;
int seen_restrict = 0;
// Storage class specifiers
int seen_auto = 0;
int seen_register = 0;
int seen_static = 0;
int seen_extern = 0;
int seen_typedef = 0;
int seen_struct = 0;
int seen_union = 0;
int seen_enum = 0;
int changed = 1;
while (changed) {
changed = 1;
switch (cur_token) {
case TOK_VOID: next(); seen_void++; type = new_type(TYPE_VOID); break;
case TOK_CHAR: next(); seen_char++; type = new_type(TYPE_CHAR); break;
case TOK_INT: next(); seen_int++; type = new_type(TYPE_INT); break;
case TOK_FLOAT: next(); seen_float++; type = new_type(TYPE_FLOAT); break;
case TOK_DOUBLE: next(); seen_double++; type = new_type(TYPE_DOUBLE); break;
case TOK_SHORT:
next();
if (cur_token == TOK_INT) next();
seen_short++;
type = new_type(TYPE_SHORT);
break;
case TOK_LONG:
next();
if (cur_token == TOK_DOUBLE) {
next();
seen_long_double++;
type = new_type(TYPE_LONG_DOUBLE);
}
else {
type = new_type(TYPE_LONG);
seen_long++;
}
break;
case TOK_STRUCT:
seen_struct++;
type = dup_type(parse_struct_or_union_type_specifier());
break;
case TOK_UNION:
seen_union++;
type = dup_type(parse_struct_or_union_type_specifier());
break;
case TOK_ENUM:
seen_enum++;
type = dup_type(parse_enum_type_specifier());
break;
case TOK_TYPEDEF_TYPE:
// If a typedef type has been encountered by the lexer and a type already
// exists, then it's not a typedef type, but a redefinition of a typedef
// type.
if (!type) {
seen_typedef++;
type = dup_type(cur_lexer_type);
next();
}
else
changed = 0;
break;
case TOK_SIGNED: next(); seen_signed++; break;
case TOK_UNSIGNED: next(); seen_unsigned++; break;
case TOK_INLINE: next(); seen_inline++; break;
case TOK_CONST: next(); seen_const++; break;
case TOK_VOLATILE: next(); seen_volatile++; break;
case TOK_RESTRICT: next(); seen_restrict++; break;
case TOK_AUTO: next(); seen_auto++; break;
case TOK_REGISTER: next(); seen_register++; break;
case TOK_STATIC: next(); seen_static++; break;
case TOK_EXTERN: next(); seen_extern++; break;
case TOK_ATTRIBUTE: parse_attributes(); break;
default: changed = 0;
}
}
if (seen_long == 2) seen_long = 1;
else if (seen_long > 2) error("Too many longs in type specifier");
if (seen_int && seen_long) {
seen_int = 0;
type = new_type(TYPE_LONG);
}
int data_type_sum =
seen_void + seen_char + seen_short + seen_int + seen_long +
seen_float + seen_double + seen_long_double +
seen_struct + seen_union + seen_enum;
if ((data_type_sum == 0) && !seen_typedef)
// Implicit int
type = new_type(TYPE_INT);
if (!type) panic_with_line_number("Type is null");
if ((data_type_sum > 1))
error("Two or more data types in declaration specifiers");
if (seen_signed && seen_unsigned)
error("Both ‘signed’ and ‘unsigned’ in declaration specifiers");
int is_integer_type = type && (type->type == TYPE_CHAR || type->type == TYPE_SHORT || type->type == TYPE_INT || type->type == TYPE_LONG);
if (!is_integer_type && (seen_signed || seen_unsigned))
error("Signed/unsigned can only apply to integer types");
if ((seen_auto + seen_register + seen_static + seen_extern > 1))
error("Duplicate storage class specifiers");
BaseType *base_type = wmalloc(sizeof(BaseType));
base_type->type = type;
base_type->storage_class = SC_NONE;
if (seen_extern) base_type->storage_class = SC_EXTERN;
if (seen_static) base_type->storage_class = SC_STATIC;
if (seen_auto) base_type->storage_class = SC_AUTO;
if (seen_register) base_type->storage_class = SC_REGISTER;
if (seen_restrict) type->is_restrict = 1;
if (seen_const) type->is_const = 1;
if (seen_volatile) type->is_volatile = 1;
if (seen_unsigned) type->is_unsigned = 1;
return base_type;
}
// If an array type is declared with the const type qualifier (through the use of
// typedef), the array type is not const-qualified, but its element type is.
static Type *move_array_const(Type *type) {
Type *result = type;
while (type && type->type == TYPE_ARRAY && type->is_const) {
type->is_const = 0;
type->target->is_const = 1;
type = type->target;
}
return result;
}
static Type *concat_types(Type *type1, Type *type2) {
if (type1 == 0) return move_array_const(type2);
else if (type2 == 0) return move_array_const(type1);
else if (type1 == 0 && type2 == 0) panic_with_line_number("concat type got two null types");
Type *type1_tail = type1;
while (type1_tail->target) type1_tail = type1_tail->target;
type1_tail->target = type2;
if (type1_tail->type == TYPE_FUNCTION && type2->type == TYPE_ARRAY)
error("Functions cannot return arrays");
// Check arrays have complete elements
if (type1_tail->type == TYPE_ARRAY) {
if (type2->type == TYPE_STRUCT_OR_UNION && !get_type_size(type2))
error("Array has incomplete element type");
}
return move_array_const(type1);
}
static Type *concat_base_type(Type *type, BaseType *base_type) {
Type *result = concat_types(type, dup_type(base_type->type));
result->storage_class = base_type->storage_class;
return result;
}
Type *parse_direct_declarator(void);
Type *parse_declarator(void) {
Type *type = 0;
while (1) {
if (cur_token != TOK_MULTIPLY) {
// Go up a level and return
return concat_types(parse_direct_declarator(), type);
}
else if (cur_token == TOK_MULTIPLY) {
// Pointer
next();
type = make_pointer(type);
// Parse type qualifiers. They are allowed to be duplicated, e.g. const const
while (cur_token == TOK_CONST || cur_token == TOK_VOLATILE || cur_token == TOK_RESTRICT) {
if (cur_token == TOK_CONST) type->is_const = 1;
else type->is_volatile = 1;
next();
}
}
else
return type;
}
}
static Type *parse_function_type(void) {
Type *function_type = new_type(TYPE_FUNCTION);
enter_scope();
function_type->function->scope = cur_scope;
function_type->function->is_paramless = 1;
int param_count = 0;
while (1) {
if (cur_token == TOK_RPAREN) break;
int is_type_token = cur_token_is_type();
if (cur_token == TOK_IDENTIFIER || is_type_token) {
char *old_cur_type_identifier = cur_type_identifier;
Type *type;
if (is_type_token) {
cur_type_identifier = 0;
type = parse_type_name();
function_type->function->is_paramless = 0;
if (type->storage_class == SC_AUTO || type->storage_class == SC_STATIC || type->storage_class == SC_EXTERN)
error("Invalid storage for function parameter");
}
else {
type = new_type(TYPE_INT);
cur_type_identifier = parser_wstrdup(cur_identifier);
next();
}
if (type->type == TYPE_VOID) {
cur_type_identifier = old_cur_type_identifier;
break;
}
Symbol *param_symbol = 0;
char *cur_type_identifier_dup = cur_type_identifier;
if (cur_type_identifier_dup) param_symbol = new_symbol(cur_type_identifier_dup);
Type *symbol_type;
// Convert parameter types
if (type->type == TYPE_ARRAY)
symbol_type = decay_array_to_pointer(type);
else if (type->type == TYPE_FUNCTION) {
symbol_type = make_pointer(type);
type = symbol_type;
}
else if (type->type == TYPE_ENUM)
symbol_type = new_type(TYPE_INT);
else
symbol_type = type;
if (param_symbol) param_symbol->type = dup_type(symbol_type);
append_to_list(function_type->function->param_types, dup_type(type));
append_to_list(function_type->function->param_identifiers, cur_type_identifier_dup);
if (param_symbol) param_symbol->local_index = param_count;
param_count++;
cur_type_identifier = old_cur_type_identifier;
}
else if (cur_token == TOK_ELLIPSES) {
function_type->function->is_variadic = 1;
next();
}
else
error("Expected type or )");
if (cur_token == TOK_RPAREN) break;
consume(TOK_COMMA, ",");
if (cur_token == TOK_RPAREN) error("Expected expression");
}
function_type->function->param_count = param_count;
exit_scope();
consume(TOK_RPAREN, ")");
return function_type;
}
// Parse old style K&R function declaration list,
static void parse_function_paramless_declaration_list(Function *function) {
while (cur_token != TOK_LCURLY) {
BaseType *base_type = parse_declaration_specifiers();
while (cur_token != TOK_SEMI) {
cur_type_identifier = 0;
Type *type = concat_base_type(parse_declarator(), base_type);
// Array parameters decay to a pointer
if (type->type == TYPE_ARRAY) type = decay_array_to_pointer(type);
if (type->type == TYPE_ENUM) type = new_type(TYPE_INT);
// Associate type with param symbol
if (!cur_type_identifier) error("Expected identifier");
Symbol *symbol = lookup_symbol(cur_type_identifier, cur_scope, 0);
if (!symbol) error("Declaration for unknown parameter %s", cur_type_identifier);
symbol->type = type;
int found_identifier = 0;
for (int i = 0; i < function->type->function->param_count; i++) {
if (!strcmp(function->type->function->param_identifiers->elements[i], cur_type_identifier)) {
function->type->function->param_types->elements[i] = type;
found_identifier = 1;
break;
}
}
if (!found_identifier) panic_with_line_number("unable to match function param identifier");
if (cur_token != TOK_COMMA && cur_token != TOK_SEMI) error("Expected a ; or ,");
if (cur_token == TOK_COMMA) next();
}
wfree(base_type);
while (cur_token == TOK_SEMI) consume(TOK_SEMI, ";");
}
}
Type *parse_direct_declarator(void) {
Type *type = 0;
if (cur_token == TOK_TYPEDEF_TYPE) {
// Special case of redefining a typedef. The lexer identifies it as a typedef,
// but in this context, it's an identifier;
cur_token = TOK_IDENTIFIER;
}
if (cur_token == TOK_IDENTIFIER) {
// Set cur_type_identifier only once. The caller is expected to set
// cur_type_identifier to zero. This way, the first parsed identifier
// is kept.
if (!cur_type_identifier) cur_type_identifier = parser_wstrdup(cur_identifier);
next();
}
else if (cur_token == TOK_LPAREN) {
// (subtype)
next();
type = concat_types(type, parse_declarator());
consume(TOK_RPAREN, ")");
}
while (1) {
if (cur_token == TOK_LPAREN) {
// Function
next();
type = concat_types(type, parse_function_type());
}
else if (cur_token == TOK_LBRACKET) {
// Array [] or [<num>]
next();
int size = 0;
if (cur_token != TOK_RBRACKET) {
Value *v = parse_constant_integer_expression(0);
size = v->int_value;
}
Type *array_type = new_type(TYPE_ARRAY);
array_type->array_size = size;
type = concat_types(type, array_type);
consume(TOK_RBRACKET, "]");
}
else
return type;
}
}
Type *parse_type_name(void) {
BaseType *base_type = parse_declaration_specifiers();
base_type->type->storage_class = base_type->storage_class;
Type *result = concat_types(parse_declarator(), base_type->type);
wfree(base_type);
return result;
}
// Search for a struct tag. Returns 0 if not found.
Type *find_struct_or_union(char *identifier, int is_union, int recurse) {
Tag *tag = lookup_tag(identifier, cur_scope, recurse);
if (!tag) return 0;
if (tag->type->type == TYPE_STRUCT_OR_UNION) {
if (tag->type->struct_or_union_desc->is_union != is_union)
error("Tag %s is the wrong kind of tag", identifier);
return tag->type;
}
else
error("Tag %s is the wrong kind of tag", identifier);
}
static Type *find_enum(char *identifier) {
Tag *tag = lookup_tag(identifier, cur_scope, 1);
if (!tag) return 0;
if (tag->type->type != TYPE_ENUM) error("Tag %s is the wrong kind of tag", identifier);
return tag->type;
}
// Recursively add a struct member. In the simplest case, it just gets added. For anonymous
// structs/unions, the function is called recursively with the sub members.
static StructOrUnionMember *add_struct_member(char *identifier, Type *type, StructOrUnion *s, int *member_count) {
StructOrUnionMember *member = new_struct_member();
member->identifier = identifier;
member->type = dup_type(type);
if (*member_count == MAX_STRUCT_MEMBERS)
panic_with_line_number("Exceeded max struct/union members %d", MAX_STRUCT_MEMBERS);
s->members[(*member_count)++] = member;
return member;
}
// Parse an optional __attribute(packed|aligned). Returns is_packed True/False
static int parse_struct_or_union_attribute(void) {
// Check for optional packed & aligned attributes
int is_packed = 0;
if (cur_token == TOK_ATTRIBUTE) {
consume(TOK_ATTRIBUTE, "attribute");
consume(TOK_LPAREN, "(");
consume(TOK_LPAREN, "(");
if (cur_token == TOK_PACKED) {
is_packed = 1;
next();
}
else if (cur_token == TOK_ALIGNED) {
// Ignore aligned and __aligned__
next();
}
consume(TOK_RPAREN, ")");
consume(TOK_RPAREN, ")");
is_packed = 1;
}
return is_packed;
}
// Parse struct definitions and uses.
static Type *parse_struct_or_union_type_specifier(void) {
// Parse a struct or union
int is_union = cur_token == TOK_UNION;
next();
// Parse __attribute__ that might precede the definition
int is_packed1 = parse_struct_or_union_attribute();
char *identifier = 0;
// A typedef identifier be the same as a struct tag, in this context, the lexer
// sees a typedef tag, but really it's a struct tag.
if (cur_token == TOK_IDENTIFIER || cur_token == TOK_TYPEDEF_TYPE) {
identifier = parser_wstrdup(cur_identifier);
next();
}
if (cur_token == TOK_LCURLY) {
// Struct/union definition
consume(TOK_LCURLY, "{");
Type *type = 0;
if (identifier) type = find_struct_or_union(identifier, is_union, 0);
if (!type) type = new_struct_or_union(identifier);
StructOrUnion *s = type->struct_or_union_desc;
s->is_union = is_union;
// Loop over members
int member_count = 0;
while (cur_token != TOK_RCURLY) {
BaseType *member_base_type = parse_declaration_specifiers();
int done_parsing_members = 0;
while (!done_parsing_members) {
Type *type;
int unnamed_bit_field = 0;
if (cur_token != TOK_COLON) {
cur_type_identifier = 0;
type = concat_base_type(parse_declarator(), member_base_type);
}
else {
// Unnamed bit field
next();
cur_type_identifier = 0;
type = new_type(TYPE_INT);
unnamed_bit_field = 1;
}
// GCC Arrays of Length Zero extension
// https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
int is_zero_length_array = type->type == TYPE_ARRAY && type->array_size == 0;
if (!is_zero_length_array && is_incomplete_type(type)) error("Struct/union members cannot have an incomplete type");
if (type->type == TYPE_FUNCTION) error("Struct/union members cannot have a function type");
StructOrUnionMember *member = add_struct_member(cur_type_identifier, type, s, &member_count);
if (member && unnamed_bit_field || cur_token == TOK_COLON) {
// Bit field
if (!unnamed_bit_field) next(); // consume TOK_COLON
if (type->type != TYPE_INT) error("Bit fields must be integers");
Value *v = parse_constant_integer_expression(0);
int bit_field_size = v->int_value;
if (cur_type_identifier && bit_field_size == 0) error("Invalid bit field size 0 for named member");
if (bit_field_size < 0 || bit_field_size > 32) error("Invalid bit field size %d", cur_long);
member->is_bit_field = 1;
member->bit_field_size = bit_field_size;
}
if (cur_token == TOK_COMMA) next();
else if (cur_token == TOK_SEMI) {
next();
done_parsing_members = 1;
}
else error("Expected a ;, or ,");
} // Parsing members with member_base_type
wfree(member_base_type);
if (cur_token == TOK_RCURLY) break;
} // Parsing struct
consume(TOK_RCURLY, "}");
// Parse __attribute__ that might come after the definition
int is_packed2 = parse_struct_or_union_attribute();
s->is_packed = is_packed1 || is_packed2;
complete_struct_or_union(s);
return type;
}
else {
// Struct/union use
Type *type = find_struct_or_union(identifier, is_union, 1);
if (type) return type; // Found a complete or incomplete struct
// Didn't find a struct, but that's ok, create a incomplete one
// to be populated later when it's defined.
type = new_struct_or_union(parser_wstrdup(identifier));
StructOrUnion *s = type->struct_or_union_desc;
s->is_incomplete = 1;
s->is_packed = is_packed1;
s->is_union = is_union;
return type;
}
}
static Type *parse_enum_type_specifier(void) {