]> git.sur5r.net Git - cc65/blob - src/cc65/typecmp.c
0752d60bac96c3c809a5393f1488c3d671d0fa0f
[cc65] / src / cc65 / typecmp.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 typecmp.c                                 */
4 /*                                                                           */
5 /*               Type compare function for the cc65 C compiler               */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2008 Ullrich von Bassewitz                                       */
10 /*               Roemerstrasse 52                                            */
11 /*               D-70794 Filderstadt                                         */
12 /* EMail:        uz@cc65.org                                                 */
13 /*                                                                           */
14 /*                                                                           */
15 /* This software is provided 'as-is', without any expressed or implied       */
16 /* warranty.  In no event will the authors be held liable for any damages    */
17 /* arising from the use of this software.                                    */
18 /*                                                                           */
19 /* Permission is granted to anyone to use this software for any purpose,     */
20 /* including commercial applications, and to alter it and redistribute it    */
21 /* freely, subject to the following restrictions:                            */
22 /*                                                                           */
23 /* 1. The origin of this software must not be misrepresented; you must not   */
24 /*    claim that you wrote the original software. If you use this software   */
25 /*    in a product, an acknowledgment in the product documentation would be  */
26 /*    appreciated but is not required.                                       */
27 /* 2. Altered source versions must be plainly marked as such, and must not   */
28 /*    be misrepresented as being the original software.                      */
29 /* 3. This notice may not be removed or altered from any source              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <string.h>
37
38 /* cc65 */
39 #include "funcdesc.h"
40 #include "symtab.h"
41 #include "typecmp.h"
42
43
44
45 /*****************************************************************************/
46 /*                                   Code                                    */
47 /*****************************************************************************/
48
49
50
51 static void SetResult (typecmp_t* Result, typecmp_t Val)
52 /* Set a new result value if it is less than the existing one */
53 {
54     if (Val < *Result) {
55         *Result = Val;
56     }
57 }
58
59
60
61 static int ParamsHaveDefaultPromotions (const FuncDesc* F)
62 /* Check if any of the parameters of function F has a default promotion. In
63  * this case, the function is not compatible with an empty parameter name list
64  * declaration.
65  */
66 {
67     /* Get the symbol table */
68     const SymTable* Tab = F->SymTab;
69
70     /* Get the first parameter in the list */
71     const SymEntry* Sym = Tab->SymHead;
72
73     /* Walk over all parameters */
74     while (Sym && (Sym->Flags & SC_PARAM)) {
75
76         /* If this is an integer type, check if the promoted type is equal
77          * to the original type. If not, we have a default promotion.
78          */
79         if (IsClassInt (Sym->Type)) {
80             if (IntPromotion (Sym->Type) != Sym->Type) {
81                 return 1;
82             }
83         }
84
85         /* Get the pointer to the next param */
86         Sym = Sym->NextSym;
87     }
88
89     /* No default promotions in the parameter list */
90     return 0;
91 }
92
93
94
95 static int EqualFuncParams (const FuncDesc* F1, const FuncDesc* F2)
96 /* Compare two function symbol tables regarding function parameters. Return 1
97  * if they are equal and 0 otherwise.
98  */
99 {
100     /* Get the symbol tables */
101     const SymTable* Tab1 = F1->SymTab;
102     const SymTable* Tab2 = F2->SymTab;
103
104     /* Compare the parameter lists */
105     const SymEntry* Sym1 = Tab1->SymHead;
106     const SymEntry* Sym2 = Tab2->SymHead;
107
108     /* Compare the fields */
109     while (Sym1 && (Sym1->Flags & SC_PARAM) && Sym2 && (Sym2->Flags & SC_PARAM)) {
110
111         /* Get the symbol types */
112         Type* Type1 = Sym1->Type;
113         Type* Type2 = Sym2->Type;
114
115         /* If either of both functions is old style, apply the default
116          * promotions to the parameter type.
117          */
118         if (F1->Flags & FD_OLDSTYLE) {
119             if (IsClassInt (Type1)) {
120                 Type1 = IntPromotion (Type1);
121             }
122         }
123         if (F2->Flags & FD_OLDSTYLE) {
124             if (IsClassInt (Type2)) {
125                 Type2 = IntPromotion (Type2);
126             }
127         }
128
129         /* Compare this field */
130         if (TypeCmp (Type1, Type2) < TC_EQUAL) {
131             /* Field types not equal */
132             return 0;
133         }
134
135         /* Get the pointers to the next fields */
136         Sym1 = Sym1->NextSym;
137         Sym2 = Sym2->NextSym;
138     }
139
140     /* Check both pointers against NULL or a non parameter to compare the
141      * field count
142      */
143     return (Sym1 == 0 || (Sym1->Flags & SC_PARAM) == 0) &&
144            (Sym2 == 0 || (Sym2->Flags & SC_PARAM) == 0);
145 }
146
147
148
149 static int EqualSymTables (SymTable* Tab1, SymTable* Tab2)
150 /* Compare two symbol tables. Return 1 if they are equal and 0 otherwise */
151 {
152     /* Compare the parameter lists */
153     SymEntry* Sym1 = Tab1->SymHead;
154     SymEntry* Sym2 = Tab2->SymHead;
155
156     /* Compare the fields */
157     while (Sym1 && Sym2) {
158
159         /* Compare the names of this field */
160         if (!HasAnonName (Sym1) || !HasAnonName (Sym2)) {
161             if (strcmp (Sym1->Name, Sym2->Name) != 0) {
162                 /* Names are not identical */
163                 return 0;
164             }
165         }
166
167         /* Compare the types of this field */
168         if (TypeCmp (Sym1->Type, Sym2->Type) < TC_EQUAL) {
169             /* Field types not equal */
170             return 0;
171         }
172
173         /* Get the pointers to the next fields */
174         Sym1 = Sym1->NextSym;
175         Sym2 = Sym2->NextSym;
176     }
177
178     /* Check both pointers against NULL to compare the field count */
179     return (Sym1 == 0 && Sym2 == 0);
180 }
181
182
183
184 static void DoCompare (const Type* lhs, const Type* rhs, typecmp_t* Result)
185 /* Recursively compare two types. */
186 {
187     unsigned    Indirections;
188     unsigned    ElementCount;
189     SymEntry*   Sym1;
190     SymEntry*   Sym2;
191     SymTable*   Tab1;
192     SymTable*   Tab2;
193     FuncDesc*   F1;
194     FuncDesc*   F2;
195
196
197     /* Initialize stuff */
198     Indirections = 0;
199     ElementCount = 0;
200
201     /* Compare two types. Determine, where they differ */
202     while (lhs->C != T_END) {
203
204         TypeCode LeftType, RightType;
205         TypeCode LeftSign, RightSign;
206         TypeCode LeftQual, RightQual;
207         long LeftCount, RightCount;
208
209         /* Check if the end of the type string is reached */
210         if (rhs->C == T_END) {
211             /* End of comparison reached */
212             return;
213         }
214
215         /* Get the raw left and right types, signs and qualifiers */
216         LeftType  = GetType (lhs);
217         RightType = GetType (rhs);
218         LeftSign  = GetSignedness (lhs);
219         RightSign = GetSignedness (rhs);
220         LeftQual  = GetQualifier (lhs);
221         RightQual = GetQualifier (rhs);
222
223         /* If the left type is a pointer and the right is an array, both
224          * are compatible.
225          */
226         if (LeftType == T_TYPE_PTR && RightType == T_TYPE_ARRAY) {
227             RightType = T_TYPE_PTR;
228         }
229
230         /* If the raw types are not identical, the types are incompatible */
231         if (LeftType != RightType) {
232             SetResult (Result, TC_INCOMPATIBLE);
233             return;
234         }
235
236         /* On indirection level zero, a qualifier or sign difference is
237          * accepted. The types are no longer equal, but compatible.
238          */
239         if (LeftSign != RightSign) {
240             if (ElementCount == 0) {
241                 SetResult (Result, TC_SIGN_DIFF);
242             } else {
243                 SetResult (Result, TC_INCOMPATIBLE);
244                 return;
245             }
246         }
247         if (LeftQual != RightQual) {
248             /* On the first indirection level, different qualifiers mean
249              * that the types are still compatible. On the second level,
250              * this is a (maybe minor) error, so we create a special
251              * return code, since a qualifier is dropped from a pointer.
252              * Starting from the next level, the types are incompatible
253              * if the qualifiers differ.
254              */
255             switch (Indirections) {
256
257                 case 0:
258                     SetResult (Result, TC_STRICT_COMPATIBLE);
259                     break;
260
261                 case 1:
262                     /* A non const value on the right is compatible to a
263                      * const one to the left, same for volatile.
264                      */
265                     if ((LeftQual & T_QUAL_CONST) < (RightQual & T_QUAL_CONST) ||
266                         (LeftQual & T_QUAL_VOLATILE) < (RightQual & T_QUAL_VOLATILE)) {
267                         SetResult (Result, TC_QUAL_DIFF);
268                     } else {
269                         SetResult (Result, TC_STRICT_COMPATIBLE);
270                     }
271                     break;
272
273                 default:
274                     SetResult (Result, TC_INCOMPATIBLE);
275                     return;
276             }
277         }
278
279         /* Check for special type elements */
280         switch (LeftType) {
281
282             case T_TYPE_PTR:
283                 ++Indirections;
284                 break;
285
286             case T_TYPE_FUNC:
287                 /* Compare the function descriptors */
288                 F1 = GetFuncDesc (lhs);
289                 F2 = GetFuncDesc (rhs);
290
291                 /* If one of both functions has an empty parameter list (which
292                  * does also mean, it is not a function definition, because the
293                  * flag is reset in this case), it is considered equal to any
294                  * other definition, provided that the other has no default
295                  * promotions in the parameter list. If none of both parameter
296                  * lists is empty, we have to check the parameter lists and
297                  * other attributes.
298                  */
299                 if (F1->Flags & FD_EMPTY) {
300                     if ((F2->Flags & FD_EMPTY) == 0) {
301                         if (ParamsHaveDefaultPromotions (F2)) {
302                             /* Flags differ */
303                             SetResult (Result, TC_INCOMPATIBLE);
304                             return;
305                         }
306                     }
307                 } else if (F2->Flags & FD_EMPTY) {
308                     if (ParamsHaveDefaultPromotions (F1)) {
309                         /* Flags differ */
310                         SetResult (Result, TC_INCOMPATIBLE);
311                         return;
312                     }
313                 } else {
314
315                     /* Check the remaining flags */
316                     if ((F1->Flags & ~FD_IGNORE) != (F2->Flags & ~FD_IGNORE)) {
317                         /* Flags differ */
318                         SetResult (Result, TC_INCOMPATIBLE);
319                         return;
320                     }
321
322                     /* Compare the parameter lists */
323                     if (EqualFuncParams (F1, F2) == 0) {
324                         /* Parameter list is not identical */
325                         SetResult (Result, TC_INCOMPATIBLE);
326                         return;
327                     }
328                 }
329
330                 /* Keep on and compare the return type */
331                 break;
332
333             case T_TYPE_ARRAY:
334                 /* Check member count */
335                 LeftCount  = GetElementCount (lhs);
336                 RightCount = GetElementCount (rhs);
337                 if (LeftCount  != UNSPECIFIED &&
338                     RightCount != UNSPECIFIED &&
339                     LeftCount  != RightCount) {
340                     /* Member count given but different */
341                     SetResult (Result, TC_INCOMPATIBLE);
342                     return;
343                 }
344                 break;
345
346             case T_TYPE_STRUCT:
347             case T_TYPE_UNION:
348                 /* Compare the fields recursively. To do that, we fetch the
349                  * pointer to the struct definition from the type, and compare
350                  * the fields.
351                  */
352                 Sym1 = GetSymEntry (lhs);
353                 Sym2 = GetSymEntry (rhs);
354
355                 /* If one symbol has a name, the names must be identical */
356                 if (!HasAnonName (Sym1) || !HasAnonName (Sym2)) {
357                     if (strcmp (Sym1->Name, Sym2->Name) != 0) {
358                         /* Names are not identical */
359                         SetResult (Result, TC_INCOMPATIBLE);
360                         return;
361                     }
362                 }
363
364                 /* Get the field tables from the struct entry */
365                 Tab1 = Sym1->V.S.SymTab;
366                 Tab2 = Sym2->V.S.SymTab;
367
368                 /* One or both structs may be forward definitions. In this case,
369                  * the symbol tables are both non existant. Assume that the
370                  * structs are equal in this case.
371                  */
372                 if (Tab1 != 0 && Tab2 != 0) {
373
374                     if (EqualSymTables (Tab1, Tab2) == 0) {
375                         /* Field lists are not equal */
376                         SetResult (Result, TC_INCOMPATIBLE);
377                         return;
378                     }
379
380                 }
381
382                 /* Structs are equal */
383                 break;
384         }
385
386         /* Next type string element */
387         ++lhs;
388         ++rhs;
389         ++ElementCount;
390     }
391
392     /* Check if end of rhs reached */
393     if (rhs->C == T_END) {
394         SetResult (Result, TC_EQUAL);
395     } else {
396         SetResult (Result, TC_INCOMPATIBLE);
397     }
398 }
399
400
401
402 typecmp_t TypeCmp (const Type* lhs, const Type* rhs)
403 /* Compare two types and return the result */
404 {
405     /* Assume the types are identical */
406     typecmp_t   Result = TC_IDENTICAL;
407
408 #if 0
409     printf ("Left : "); PrintRawType (stdout, lhs);
410     printf ("Right: "); PrintRawType (stdout, rhs);
411 #endif
412
413     /* Recursively compare the types if they aren't identical */
414     if (rhs != lhs) {
415         DoCompare (lhs, rhs, &Result);
416     }
417
418     /* Return the result */
419     return Result;
420 }
421
422
423
424