-
Notifications
You must be signed in to change notification settings - Fork 0
/
ccdecl.c
3683 lines (3319 loc) · 138 KB
/
ccdecl.c
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
/* CCDECL.C - Declaration Parser
**
** (c) Copyright Ken Harrenstien 1989
** All changes after v.371, 28-May-1988
** (c) Copyright Ken Harrenstien, SRI International 1985, 1986
** All changes after v.154, 8-Aug-1985
**
** Original version (C) 1981 K. Chen
*/
#define _DEF_CHAR8 0 /* define this to default char to char8 */
#include <limits.h> /* for INT_MAX */
#include "cc.h"
int strcmp (const char *, const char *);
extern SYMBOL *lsymhead; /* CCSYM - var indicating loc sym blk */
/* Imported functions */
extern SYMBOL *symfidstr(char *), *creatsym(char *), *uniqsym(SYMBOL *); /* CCSYM */
extern SYMBOL *findgsym(SYMBOL *); /* CCSYM */
extern SYMBOL *newlabel(void); /* CCSYM */
extern SYMBOL *symfxext(SYMBOL *); /* CCSYM */
extern SYMBOL *symftag(SYMBOL *); /* CCSYM */
extern SYMBOL *symfmember(SYMBOL *, SYMBOL *); /* CCSYM */
extern SYMBOL *symqcreat(SYMBOL *); /* CCSYM */
extern SYMBOL *isdupsym(SYMBOL *); /* CCSYM */
extern SYMBOL *beglsym(void); /* CCSYM */
extern TYPE *findctype(int, INT, unsigned INT, TYPE *),
*findtype(int, TYPE *), /* CCSYM */
*findftype(TYPE *, TYPE *), /* CCSYM */
*findptype(int, TYPE *, TYPE *); /* CCSYM */
extern TYPE *tcomposite(TYPE *, TYPE *); /* CCSYM */
extern int cmptype(TYPE *, TYPE *), cmputype(TYPE *, TYPE *); /* CCSYM */
extern INT sizetype(TYPE *); /* CCSYM */
extern void copysym(SYMBOL *, SYMBOL *), ridlsym(SYMBOL *); /* CCSYM */
extern void mapintsym(SYMBOL *); /* CCSYM */
extern int mapextsym(SYMBOL *); /* CCSYM */
extern void freesym(SYMBOL *); /* CCSYM */
extern NODE *evalexpr(NODE *); /* CCEVAL */
extern NODE *funstmt(void), *asgnexpr(void); /* CCSTMT */
extern NODE *exprconst(void); /* CCSTMT */
extern long pconst(void); /* CCSTMT */
extern NODE *convasgn(TYPE *, NODE *); /* CCTYPE */
extern TYPE *convfparam(TYPE *); /* CCTYPE */
extern int nextoken(void); /* CCLEX */
extern int expect (int); /* CCERR */
/* Exported functions */
void initpar(void); /* Called by CC mainline */
NODE *extdef(void); /* Called by CC mainline */
NODE *tntdef(void); /* Called by CC mainline */
NODE *ldecllist(void); /* CCSTMT for inner block declarations */
TYPE *typename(void); /* CCSTMT for cast and sizeof exprs */
SYMBOL *defauto(char *, TYPE *); /* CCSTMT for invisible struct return obj */
SYMBOL *funchk(int, int, SYMBOL *, SYMBOL *); /* CCSTMT for calls to undeclared functions */
struct protostate /* State block for prototype parse */
{
int nparams;
SYMBOL *shead, *stail; /* Parameter symbol list */
SYMBOL decl;
};
/* Internal functions */
static NODE *funcdef(SYMBOL *, SYMBOL *, SYMBOL *),
*datadef(SYMBOL *, SYMBOL *, SYMBOL *);
static void pdecllist(void), sdeclenum(SYMBOL *),
decllist(SYMBOL *,SYMBOL *,SYMBOL *,SYMBOL *,NODE **,NODE **);
static INT sdeclstruct(SYMBOL *, int), fldsize(int, INT *, int *),
pbase(SYMBOL *);
static TYPE *qualarray (TYPE *type, int flags, int *oldflags);
static int isdecl(void);
static TYPE *fundecl(SYMBOL *, int),
*paramlist(struct protostate
*),
*mkproto(SYMBOL *);
static void pidentlist(struct protostate
*);
static void plcmpare(TYPE *, TYPE *, int),
plcmpold(SYMBOL *, TYPE *, TYPE *), plcheck(TYPE *);
static NODE *dodecl(int, SYMBOL *, SYMBOL *);
static SYMBOL *declarator(SYMBOL *);
static TYPE *addpp(TYPE *, TYPE *), *pushsztype(int, INT, INT, TYPE *),
*tagspec(int);
static SYMBOL *sdeclaration(SYMBOL *, SYMBOL *, INT *, int *, int *);
static NODE *pizer(SYMBOL *);
static void errtwotyp(SYMBOL *, SYMBOL *), errdupsym(SYMBOL *);
static TYPE *mkprox(SYMBOL *);
static int nsetjmps(void);
static NODE *piztype(TYPE *, int), *chkarith(TYPE *, NODE *, int, int),
*pizstruct(TYPE *, int, int), *pizarray(TYPE *, int),
*pexizer(int), *pizlist(void);
static void pizflush(int);
static int isauto(SYMBOL *), nisconst(NODE *);
static void Set_Register(SYMBOL *, int, int);
/* Internal data */
static int paramok; /* True if OK to parse parameter list for a function
** definition. Only true when at top
** level and parsing the first declarator.
*/
static int inproto; /* True when parsing a function prototype list.
** This is bumped to indicate level.
*/
static NODE *statdecls, /* Pointer to list of static decls within current fn */
*stattail; /* Pointer to tail of statdecls list */
static int nsdefs; /* # of enum/struct/union side effect definitions seen.
** The exact number doesn't matter; this is only used
** to tell when a type-specifier has had the side
** effect of defining a tag or enum constant.
*/
static int itags; /* # of internal tags defined. This is used only
** to create unique names for internal tags.
*/
static int tntcnt; /* # of tentative defs output. Only used to initialize
** tntdef(), by setting to -1.
*/
#if 0
/* Flags returned from pbase(). */
/* These aren't really used yet, maybe should be flushed. */
#define BASEF_SC 01 /* Storage class parsed */
#define BASEF_TS 02 /* Type-specifier parsed */
#define BASEF_TAG 04 /* enum/struct/union tag was defined as side effect */
/* Also not really used yet */
typedef struct
{
int Dflags;
SYMBOL *Dpnext, *Dpsblk;
SYMBOL s;
}
declsym;
#define DSname s.Sname
#define DSvalue s.Svalue
#define DSclass s.Sclass
#define DStype s.Stype
#endif
/* INITPAR - Initialize parser
** Called once for each file compiled.
*/
void
initpar(void)
{
nodeinit(); /* No parse-tree nodes used */
curfn = NULL; /* Not in any function yet */
itags = 0; /* Reset internal tag count for gensyms */
nsdefs = 0; /* Reset side-effect def count for neatness */
tntcnt = -1; /* Reset tntdef() */
}
/* EXTDEF() - Parse top-level declaration or definition
** [dpANS 3.7, 3.5]
**
** <external-decl> ::= <function-definition> | <decl>
**
** <function-definition> ::=
** {decl-specs} <declor> {decl-list} <compound-stmt>
**
** <decl> ::= <decl-specs> {init-decl-list} ';'
**
** <init-decl-list> ::= <init-declor> {',' init-decl-list}
** <init-declor> ::= <declor> {'=' izer}
**
** This is the main entry to input parser. Current token is the
** first one of the <external-decl>. Since both possibilities (function
** def or a decl) can start with <decl-specs>, we parse for that first.
** If there was nothing but <decl-specs>, we can just return. Otherwise
** the initially parsed "base" needs to be passed on for further parsing.
*/
NODE*
extdef (void)
{
SYMBOL* s;
SYMBOL tempsym;
SYMBOL base;
/* Do top level initializations */
paramok = 1; /* OK to parse a function parameter list */
inproto = 0; /* Not in prototype scope */
curfnnew = fline; /* Remember line in file where funct started*/
_reg_count = 0; /* Count of "preserved" registers used */
/* for register variables */
pbase(&base); /* Parse base (storage class & type) */
if (token == T_SCOLON) /* Only got a type (struct)? */
{
if ((base.Sflags&SF_SIDEFF) == 0) /* If no side effs, */
error("Null declaration");
switch (base.Sclass)
{
case SC_UNDEF:
break; /* None given */
case SC_AUTO:
case SC_RAUTO:
error("Illegal storage class");
break;
default:
note("Useless storage class");
break;
}
nextoken(); /* Skip over the semicolon */
return NULL; /* and stop doing this def */
}
/* Parsed <decl-specs>, now look for <declor> to determine whether
** we're doing a function def or not.
*/
copysym(&tempsym, &base); /* Copy base storage class & type */
if (tempsym.Sclass == SC_UNDEF) /* Set up for defaults */
tempsym.Sclass = SC_EXLINK; /* Default stg class: extern */
if (tempsym.Stype == NULL)
tempsym.Stype = deftype; /* Default type: int */
while ((s = declarator(&tempsym)) == NULL)/* Until we find declarator */
/* No declarator found, may want to loop. */
{
error("Null declarator, expecting ident");
if (tempsym.Spmnext) /* Flush param syms if any (in case)*/
ridlsym((SYMBOL *)NULL);
if (token == T_COMMA) /* Only continue if hit comma */
{
nextoken(); /* in which case skip over it */
continue; /* and try again */
}
if (token != T_SCOLON) /* Else give up on it */
error("Bad syntax for top-level declaration");
/* 9/91 infinite loop if test for T_RBRACE also (SPR 9579) */
while (token != T_EOF && token != T_SCOLON)
nextoken(); /* Flush to probable end of stmt */
return NULL;
}
paramok = 0; /* No longer OK to parse function param list */
/* If function type, need to examine more closely to see whether this
** is a definition or just a forward-reference declaration.
** It is a definition only if the current token is one of:
** Left brace (start of function body)
** A type-specifier keyword (a function parameter declaration).
** The "register" keyword (only permissible storage class for
** function parameter declarations).
** We permit any storage class here, for better error diagnostics later.
*/
if (tempsym.Stype->Tspec == TS_FUNCT)
{
if (token == T_LBRACE || isdecl())
return funcdef(&base, &tempsym, s); /* Parse funct def */
}
/* Not a function definition, so is either a function reference, or a
** data definition/reference.
*/
return datadef(&base, &tempsym, s); /* data def/ref or function ref */
}
/* TNTDEF - Return next remaining tentative definition, if any.
** This is only invoked by the CC mainline after all input parsing
** is completed for a file. It scans for all tentative definitions
** with internal or external linkage, and for each one returns a
** node that defines it with a zero initializer.
*/
NODE *
tntdef(void)
{
static SYMBOL *s;
if (++tntcnt == 0) /* If first time, */
s = symbol; /* start scanning global sym list */
while ((s = s->Snext) != NULL)
{
switch (s->Sclass)
{
default:
continue;
case SC_INTREF: /* Should only exist for functions */
if (s->Srefs)
error("Static function %S not defined", s);
else
note("Static function %S not defined or used", s);
continue;
case SC_INTDEF: /* May be function or object */
if (s->Srefs == 0)
note("Static %s %S never used",
(s->Stype->Tspec != TS_FUNCT ? "object" : "function"),
s);
continue;
case SC_INLINK:
s->Sclass = SC_INTDEF;
if (s->Srefs) /* Ensure internal object was used */
break; /* Yup, go define it */
note("Static object %S never used, not emitted", s);
continue;
case SC_EXLINK:
s->Sclass = SC_EXTDEF; /* Always do it if external linkage */
break;
}
/* Set up a Q_IDENT and a null izer definition for it */
return ndefl(N_DATA, ndefl(N_IZ, ndefident(s)));
}
return NULL;
}
/* FUNCDEF() - Parse function definition
** [dpANS 3.7.1]
** <function-definition> ::=
** {decl-specs} <declor> {decl-list} <compound-stmt>
**
** Only called from extdef() when a function declaration turns out
** to be the start of a definition. At this point, the current token
** is the first one past the <declor>.
**
** The first two pointer args always point to temporary symbol
** structures not in the symbol table. However, the parameter list
** symbols ARE in the table, chained as local symbols.
*/
static NODE *
funcdef(SYMBOL *b, SYMBOL *d, SYMBOL *syment)
/* Base, contains parsed <decl-specs>,
* Defaulted <decl-specs> plus <declor> type
* Identifier's symtab entry
*/
{
INT n, siz;
int nsjmps;
NODE *nnode, *header;
SYMBOL *s1;
SYMBOL *args = d->Spmnext; /* List of parameter syms */
int npartypes = (int) d->Svalue; /* # of params if new-style proto */
int nparidents = 0;
NODE *nreg;
/* "syment" points to the function name's symtab entry.
** Lexer will have created the symtab entry with
** class SC_UNDEF if it didn't already exist.
*/
if (strcmp(syment->Sname, "main") == 0)
fn_main = (char) ~0; // FW KCC-NT
else
fn_main = 0;
if (!args) /*If no arglist, need to open local sym blk */
(void) beglsym(); /* (needn't remember start) */
curfnloc = curfnnew;
/* Remember context for error messages */
curfn = syment = funchk(1, b->Sclass, d, syment); /* Do funct decl */
/* which may update symbol and may also */
/* do old-style <decl-list> parse! */
/* Now that types are set, add up sizes and determine offsets for
** each parameter. Also, for new-style function prototype defs, make
** sure that every parameter had an identifier associated with it.
** We do this by comparing the # of identifiers on the paramlist with
** the # of parameters that paramlist() actually parsed while building
** the prototype.
*/
n = 0; /* set up for first arg */
siz = sizetype(syment->Stype->Tsubt); /* get size of return val */
if (siz > 2) /* If returning too-large object, */
n = 1; /* just use struct-return pointer */
while (args != NULL)
{
nparidents++; /* Count # of param idents */
s1 = args; /* get arg symbol */
args = args->Spmnext; /* Move on before zapping it! */
n += sizetype(s1->Stype); /* count off by size */
s1->Svalue = n; /* set offset */
}
if (npartypes && (npartypes-1 != nparidents))
error("Missing identifier for parameter in function def");
maxauto = 0; /* no local variables yet */
stackrefs = 0; /* and therefore no refs to them */
nsjmps = nsetjmps(); /* Remember # of setjmp refs */
statdecls = stattail = NULL; /* No static declarations yet */
/* The big call. Parse function statement, having already set up a
** local symbol block with the parameters in it. On return, this
** block will have been ended, and the current token will be the
** T_RBRACE ('}') terminating the function body. See CCSTMT's
** compound() for further discussion.
*/
nnode = funstmt(); /* Parse function statement */
expect(T_RBRACE); /* Now safe to flush the right brace
** and set up new current token.
** See CCSTMT's compound() for discussion of this.
*/
stkgoto = (nsjmps != nsetjmps()); /* Say whether any setjmps in funct */
header = ndefop(N_NODE); /* Put together the function header */
header->Nright = statdecls; /* Point to any static decls found */
header->Nleft = ndefident(syment); /* Point to Q_IDENT function name */
/* Return completed parse tree */
nreg = ndeflr(N_FUNCTION, header, nnode);
nreg->Nreg = _reg_count;
return nreg;
}
/* NSETJMPS - Auxiliary to find current # of references to the "setjmp"
** function. Any functions which contain calls to setjmp have to
** avoid using tail recursion.
*/
static int
nsetjmps(void)
{
SYMBOL *s;
if ((s = symfidstr("setjmp")) != NULL)
{
--(s->Srefs); /* Not a real reference */
switch (s->Sclass)
{
case SC_EXTREF:
case SC_XEXTREF:
case SC_EXTDEF:
if (s->Stype->Tspec == TS_FUNCT)
return s->Srefs;
}
}
return 0;
}
/* FUNCHK - Check out a function definition or reference for
** proper use of storage class and type specifier.
** Called from funcdef() for a definition and dodecl() for a reference.
** Also called from CCSTMT's primary() to handle the pretend-declaration
** done for a call to an undeclared function.
**
** The parsed declarator symbol struct will have the following special
** members set (by fundecl()) if called from funcdef():
** Svalue - 0 if an old-style function identlist, N+1 if new-style proto,
** where N is the # of real parameters in the prototype.
** Spmnext - if non-NULL, points to a list of parameter identifiers
** and there is still a local symbol block active for the
** prototype scope. This block needs to be closed and the
** symbols flushed if this was only a reference.
** Spmhead - what beglsym() returned for the prototype scope block.
** These syms should be NULL if called from dodecl(), which flushes the
** prototype scope block itself.
**
** May parse the function's <decl-list> if doing an old-style definition.
** Returns with the symbol table entry completely set up, and returns
** pointer to the symbol since it may have changed.
*/
SYMBOL *
funchk(int def, int baseclass, SYMBOL *d, SYMBOL *s)
/* True if a definition
* Parsed base storage class
* Parsed declarator (Sclass and Stype)
* Symtab entry for parsed identifier
*/
{
/* Check out storage class.
** Parsing should have resulted in only one of the following three
** things: SC_UNDEF (none), SC_EXTREF (extern), SC_INTREF (static).
** For existing function def/refs, there are 5
** possible symbol classes:
** SC_EXTREF, SC_EXTDEF, SC_INTREF, SC_INTDEF, plus special case of
** normally invisible SC_XEXTREF.
*/
s = symfxext(s); /* Make SC_XEXTREF visible if any */
switch (baseclass) /* Not all storage classes are allowed */
{
default:
error("Illegal storage class for function, assuming \"extern\"");
return funchk(def, SC_EXTREF, d, s); /* Just call again */
case SC_INTREF: /* Explicit "static" */
/* dpANS: identifier always has internal linkage.
** Note this must not appear within block scope!
*/
if (!lsymhead || def)
{
/* At file-scope level, so "s" will be global */
d->Sclass = (def ? SC_INTDEF : SC_INTREF);
if (s->Sclass == SC_UNDEF /* No old sym */
|| s->Sclass == SC_INTREF /* Or not defined */
|| s->Sclass == SC_INTDEF) /* Or defd, reffing */
break; /* Linkage matches OK */
if (s->Sclass != SC_EXTREF && s->Sclass != SC_EXTDEF
&& s->Sclass != SC_XEXTREF)
{
error("Storage class conflict for \"%s\"", s->Sname);
break; /* Keep internal linkage */
}
warn("Linkage conflict for %S, is external", s);
/* Else fall thru as if SC_EXTREF */
}
else if (!def)
warn("Storage class for function decl in block must be \"extern\"");
/* Drop thru to assume extern and carry on */
case SC_UNDEF: /* dpANS: default same as explicit "extern" */
case SC_EXTREF: /* Explicit "extern" */
/* dpANS: linkage is same as any visible decl of this identifier
** with file scope (ie global). If none, linkage is external.
** If there is already an expired external reference (SC_XEXTREF)
** then we use that in order to emit advisory warnings if the type
** isn't the same.
*/
/* If doing a reference in block scope and function ident already
** belongs to a block-scope symbol, we:
** (1) see if a file-scope symbol exists (if so, use that one)
** (2) see if existing sym is external ref (if so, use that)
** (this includes SC_XEXTREF)
** (3) generate new file-scope symbol with SC_EXTREF.
*/
if (!def && (s->Sflags&SF_LOCAL))
{
SYMBOL *ns;
if ((ns = findgsym(s)) != NULL)/* If file-scope def/ref exists, */
s = ns; /* use that! */
else if (s->Sclass == SC_EXTREF)
; /* OK if a block-scope extern ref */
else
{
if (isdupsym(s)) /* If was defined in this block, */
errdupsym(s); /* barf! */
s = uniqsym(s); /* Create/re-use sym, now SC_UNDEF */
}
}
/* "s" now points to the sym linked to. If it has any linkage, we
** copy that, otherwise we use external linkage.
*/
switch (s->Sclass)
{
case SC_INTDEF:
case SC_INTREF:
d->Sclass = (def ? SC_INTDEF : SC_INTREF);
break;
default:
errdupsym(s);
s->Sclass = SC_UNDEF; /* Sigh! Smash it. */
/* Fall thru to handle as if extern */
case SC_XEXTREF:
case SC_EXTDEF:
case SC_EXTREF:
case SC_UNDEF:
d->Sclass = (def ? SC_EXTDEF : SC_EXTREF);
break;
}
break;
}
/* Check for duplicate function def */
if (def && (s->Sclass == SC_EXTDEF || s->Sclass == SC_INTDEF))
{
error("Duplicate function definition");
s->Sclass = SC_UNDEF; /* Wipe out previous definition! */
}
/* Handle simple case where sym hasn't yet been defined. */
if (s->Sclass == SC_UNDEF) /* Symbol not defined yet? */
{
if (!def)
s = uniqsym(s); /* No, ensure local if needed */
s->Sclass = d->Sclass; /* Copy the parsed class */
s->Stype = d->Stype; /* and the type specification */
s->Srefs = 0; /* and reset usage cnt in case a ref */
if (s->Sclass == SC_INTDEF || s->Sclass == SC_INTREF)
mapintsym(s); /* Set Smaplab (internal unique) */
else if (!mapextsym(s)) /* Else check external map */
error("External link name duplicated: %S", s);
if (def && !s->Stype->Tproto) /* If an old-style definition, */
{
pdecllist(); /* parse parameter declarations! */
s->Shproto = mkproto(d->Spmnext); /* Build invisible prototype */
}
else
s->Shproto = NULL; /* Say no hidden prototype */
return s; /* All done! */
}
/* There is an existing symbol for this identifier, with a matching
** storage class. Must now do lots of hairy type checking.
** First we see if old sym is a function returning a
** compatible type, then maybe check parameter list compatibility.
**
** If both are old-style, no param checking needed.
** If both are new-style, check their param lists.
** If one sym is old-style ref and other is new-style ref/def,
** just do simple check of the proto list.
** If one sym is old-style DEF, then:
** If this is more recent sym, parse decl-list into prototype
** and then compare param lists as if both were new-style.
** Else is previous sym -- compare with "hidden" prototype
** that was generated during the old-style function def.
*/
/* First make sure that basic type is also "function returning ..."
** and that return types are compatible.
*/
if (s->Stype->Tspec != TS_FUNCT
|| !cmptype(d->Stype->Tsubt, s->Stype->Tsubt))
{
/* Earlier ref/def conflicts with current one, smash to current. */
errtwotyp(d, s); /* Complain */
s->Stype = d->Stype; /* Skip prototype testing */
}
/* If doing an old-style definition, OK to parse decl-list now.
** The main reason for not doing this earlier is so error messages
** from the previous checks will show the most helpful context,
** i.e. errors are announced as soon as it is possible to detect them.
*/
if (def && !d->Stype->Tproto) /* If no proto was declared, */
{
pdecllist(); /* parse old-style decl-list */
s->Shproto = mkproto(d->Spmnext); /* Build invisible prototype */
}
/* Now see if the parameter lists need to be checked.
** Test for both old-style, or both with identical prototypes.
*/
if (d->Stype->Tproto != s->Stype->Tproto)
{
TYPE *tc;
if (d->Stype->Tproto && s->Stype->Tproto) /* Compare 2 protos? */
{
tc = tcomposite(d->Stype, s->Stype); /* Get composite */
if (tc)
d->Stype = tc; /* If won, use it! */
else
plcmpare(d->Stype->Tproto, s->Stype->Tproto, 0); /* Give err */
}
else if (d->Stype->Tproto)
{
/* Compare existing non-proto ref/def with new prototype */
if (s->Sclass == SC_EXTDEF || s->Sclass == SC_INTDEF)
{
/* Old-style DEF followed by new-style REF, use hidden proto */
if (!tcomposite(d->Stype, s->Stype)) /* If not compatible */
plcmpare(d->Stype->Tproto, s->Shproto, 1); /* Give err */
/* Don't use composite type, just the new prototype, so
** leave d->Stype alone.
*/
}
else /* Old-style REF followed by new-style proto */
plcheck(d->Stype->Tproto); /* Check new proto */
}
else
{
/* Compare existing proto with new non-proto ref/def */
if (def)
{
/* New-style REF followed by old-style DEF, compare params */
plcmpold(d->Spmnext, s->Shproto, s->Stype->Tproto);
}
else /* New-style ref/def followed by old-style REF */
plcheck(s->Stype->Tproto); /* Check previous proto */
d->Stype = s->Stype; /* Ensure proto retained */
}
}
/* Force the symbol table entry to match current declaration.
** Note that Srefs was incremented by the symbol lookup, hence needs
** to be set back if this was only a ref-type declaration.
** Also, if the existing symbol was a definition, don't change its
** class.
*/
s->Stype = d->Stype; /* Force the type specification */
if (!def) /* If this decl was just a ref, */
--(s->Srefs); /* then usage count to undo lookup bump */
if (s->Sclass != SC_EXTDEF && s->Sclass != SC_INTDEF)
s->Sclass = d->Sclass; /* Force the storage class */
return s;
}
/* PLCMPARE - Compare two prototype parameter lists.
*/
static void
plcmpare(TYPE *t1, TYPE *t2, int flag)
/* flag is 0 if both protos, 1 if t2 is fake proto */
{
int n;
if (t1 == t2)
return;
/* If pointers don't match, prototypes aren't compatible. Examine
** more closely so can give helpful error message (or barf at ourselves
** if necessary)
*/
if (t1 && t1->Tspec != TS_PARVOID && t2 && t2->Tspec != TS_PARVOID)
for (n = 1; t1 && t2; t1 = t1->Tproto, t2 = t2->Tproto, ++n)
if (t1->Tspec != t2->Tspec
|| (t1->Tspec == TS_PARAM && !cmputype(t1->Tsubt, t2->Tsubt)))
{
if (flag)
warn("Type of param #%d conflicts with prior def", n);
else
error("Type of parameter #%d conflicts with prior prototype", n);
return;
}
if (t1 != t2)
{
if (flag)
warn("Number of params conflicts with prior def");
else
error("Number of params conflicts with prior prototype");
}
else
int_warn("plcmpare: proto mismatch not found");
}
/* PLCMPOLD - Compare old-style parameter sym types against a
** prototype parameter list.
*/
static void
plcmpold(SYMBOL *s, TYPE *nt, TYPE *ot)
{
if (nt == ot)
return;
/* Prototypes don't match, try to give clever error msg */
for (; s; s = s->Spmnext, nt = nt->Tproto, ot = ot->Tproto)
if (!nt || !ot || nt->Tspec != ot->Tspec || nt->Tsubt != ot->Tsubt)
{
error("Type of parameter \"%s\" conflicts with prior prototype",
s->Sname);
return;
}
if (nt || ot)
error("Number of params conflicts with prior prototype");
else
int_warn("plcmpold: proto mismatch not found");
}
/* PLCHECK - Check a prototype parameter list to ensure that all types
** are compatible with default argument promotions. Note that use
** of an ellipsis param (TS_PARINF) is illegal in this context.
*/
static void
plcheck(TYPE *t)
{
if (t->Tspec == TS_PARVOID)
{
if (t->Tproto)
int_error("plcheck: void param");
}
else
for (; t; t = t->Tproto)
if (t->Tspec != TS_PARAM || !cmputype(t->Tsubt,convfparam(t->Tsubt)))
{
error("Conflict between prototype and default type reference");
break;
}
}
/* PDECLLIST - Parse the <decl-list> for an old-style function definition.
** [dpANS 3.7.1, 3.6.2]
**
** <decl-list> ::= *[<declaration>]
**
** The only storage-class spec allowed is "register". No initializations
** are permitted.
*/
static void
pdecllist(void)
{
TYPE *t;
SYMBOL *s1, argbase, stemp;
while (token != T_LBRACE && token != T_EOF) /* type-decl-list */
{
pbase(&argbase); /* Parse storage class and type specifier */
copysym(&stemp, &argbase);
switch (stemp.Sclass) /* Check storage class */
{
case SC_AUTO:
#if REGISTER_VARIABLES
if (!use_registers)
{
#endif
stemp.Sclass = SC_ARG;
break;
#if REGISTER_VARIABLES
}
/* else drop thru to error */
#endif
default:
error("Illegal storage class for function parameter");
case SC_UNDEF: /* Default becomes this. */
stemp.Sclass = SC_ARG;
break;
case SC_RAUTO: /* If "register" seen, */
stemp.Sclass = SC_RARG; /* use right symbol class */
break;
}
if ((t = stemp.Stype) == NULL) /* Check type-specifier */
{
if (argbase.Sclass == SC_UNDEF)
error("No type-specifier for parameter decl, assuming int");
t = deftype;
}
/* Have <decl-specs> base, now parse each <declor> */
while (1)
{
stemp.Sname[0] = '\0'; /* no symbol given yet */
stemp.Stype = t; /* Reset base type */
for(;;)
{
if ((s1 = declarator(&stemp)) != NULL) /* Get sym and rest of type */
break;
if (token == T_COMMA)
{
error("Null parameter declarator");
nextoken();
continue;
}
if (token == T_SCOLON)
{
nextoken();
break;
}
error("Bad parameter declaration token");
while (token != T_EOF && token != T_SCOLON && token != T_RBRACE)
nextoken(); /* Flush to probable end of stmt */
break; /* Will get two err msgs, but so what */
}
if (s1 == NULL)
error("Null parameter declaration, expecting ident");
else if (s1->Sclass != SC_ARG && s1->Sclass != SC_RARG)
{
error("Identifier \"%s\" not in function parameter list",
s1->Sname); /* not an arg to this fn */
if (s1->Sclass == SC_UNDEF)
freesym(s1); /* Clean up if boo-boo */
}
else if (s1->Sflags & SF_PARAMDECL)
{
error("Duplicate parameter declaration: \"%s\"",s1->Sname);
}
else /* Is arg, set type to what we parsed */
{
s1->Sclass = stemp.Sclass; /* Maybe indicate register */
s1->Sflags |= SF_PARAMDECL; /* Say decl seen for arg */
s1->Stype = convfparam(stemp.Stype); /* Get right type */
Set_Register(s1, SC_RARG, SC_ARG);
}
if (token != T_COMMA)
break; /* repeat through list */
nextoken(); /* skipping over commas */
}
expect(T_SCOLON); /* decl line ends with a semicolon */
}
}
/* MKPROTO - Make a prototype param type list out of a parameter symbol list.
** Must be recursive for same reason that paramlist() is.
** Note special handling for case of no symbols on list.
*/
static TYPE *
mkproto(SYMBOL *s)
{
return s ? mkprox(s) : findptype(TS_PARVOID, (TYPE *)NULL, (TYPE *)NULL);
}
static TYPE *
mkprox(SYMBOL *s)
{
return s ? findptype(TS_PARAM, mkprox(s->Spmnext), s->Stype) : NULL;
}
/* DATADEF - Parse top-level declaration that isn't a function definition.
** [dpANS 3.5, 3.7.2]
**
** <decl> ::= <decl-specs> {init-decl-list} ';'
**
** <init-decl-list> ::= {init-decl-list ','} <init-declor>
** <init-declor> ::= <declor> {'=' izer}
**
** Invoked by extdef() after determining that a declaration is not
** a function definition, to parse the rest of a top-level data declaration
** or function reference.
** Current token is the first one after the first <declor>.
*/
static NODE *
datadef(SYMBOL *base, SYMBOL *s, SYMBOL *syment)
/* Parsed <decl-specs>
* Default <decl-specs> and 1st <declor>
* Symtab entry of identifier for 1st <declor>
*/
{
SYMBOL defbase;
NODE *root = NULL, *tail = NULL;
/* Check out the storage class and type
** specifications. At top level, some storage class or type specifier
** must have been given.
*/
defbase.Scontents = base->Scontents; /* Copy contents of base */
switch (defbase.Sclass)
{
case SC_UNDEF:
defbase.Sclass = s->Sclass; /* Copy whatever default was */
if (defbase.Stype == NULL)
{
error("Declaration without storage class or type-spec");
}
break;
case SC_EXTREF: /* "extern" */
case SC_INTREF: /* "static" */
case SC_TYPEDEF: /* "typedef" */
break;
default:
error("Illegal top-level storage class");
s->Sclass = defbase.Sclass = SC_EXLINK; /* Use default */
break;
}
if (defbase.Stype == NULL)
defbase.Stype = s->Stype; /* Copy whatever default was */
decllist(base, &defbase, s, syment, &root, &tail);
if (!expect(T_SCOLON) && token == T_RBRACE)
nextoken();
return (root);
}
/* LDECLLIST() - Parse local block declaration list
** [dpANS 3.6.2, 3.5]
**
** <decl-list> ::= <decl> {decl-list}
**
** This is only called by CCSTMT's compound() to parse the
** optional declaration-list at the start of a compound statement.
** Makes entries in the symbol and type tables, and returns a node
** pointer to a list of initializations that must be done.
** Current token is the first of a possible <decl>. If it is not
** a valid first token for a declaration, nothing is done and NULL is returned.
*/
NODE *
ldecllist(void)
{
SYMBOL base, defbase;
NODE *autodecls, *autotail; /* Pointers to list of inits for decls
** within a block */
if (!isdecl())
return NULL; /* Most common case -- no decls */
autodecls = autotail = NULL;
do
{
/* If current token is start of a declaration, handle it. */
pbase(&base); /* Parse base storage-class and type */
/* Note all classes are OK */
copysym(&defbase, &base);
if (defbase.Sclass == SC_UNDEF)
defbase.Sclass = SC_AUTO; /* Default class is AUTO */
if (defbase.Stype == NULL)
defbase.Stype = deftype;
/* Handle the local declaration, adding defs to the right list. */
if (defbase.Sclass == SC_INTREF) /* "static" */
decllist(&base, &defbase, (SYMBOL *)NULL, (SYMBOL *)NULL,
&statdecls, &stattail);
else
decllist(&base, &defbase, (SYMBOL *)NULL, (SYMBOL *)NULL,
&autodecls, &autotail);
expect(T_SCOLON);
}
while (isdecl())
;
return(autodecls);
}
/* DECLLIST - Parse declarator list for a declaration, with possible izers.
** [dpANS 3.5]
**
** <init-decl-list> ::= <init-declor> {',' init-decl-list}
** <init-declor> ::= <declor> {'=' izer}