]> git.sur5r.net Git - cc65/blob - src/cc65/typecmp.c
Bugfix
[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-2000 Ullrich von Bassewitz                                       */
10 /*               Wacholderweg 14                                             */
11 /*               D-70597 Stuttgart                                           */
12 /* EMail:        uz@musoftware.de                                            */
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 "funcdesc.h"
37 #include "symtab.h"
38 #include "typecmp.h"
39
40
41
42 /*****************************************************************************/
43 /*                                   Code                                    */
44 /*****************************************************************************/
45
46
47
48 static void SetResult (typecmp_t* Result, typecmp_t Val)
49 /* Set a new result value if it is less than the existing one */
50 {
51     if (Val < *Result) {
52         *Result = Val;
53     }
54 }
55
56
57
58 static int EqualSymTables (SymTable* Tab1, SymTable* Tab2)
59 /* Compare two symbol tables. Return 1 if they are equal and 0 otherwise */
60 {
61     /* Compare the parameter lists */
62     SymEntry* Sym1 = Tab1->SymHead;
63     SymEntry* Sym2 = Tab2->SymHead;
64
65     /* Compare the fields */
66     while (Sym1 && Sym2) {
67
68         /* Compare this field */
69         if (TypeCmp (Sym1->Type, Sym2->Type) < TC_EQUAL) {
70             /* Field types not equal */
71             return 0;
72         }
73
74         /* Get the pointers to the next fields */
75         Sym1 = Sym1->NextSym;
76         Sym2 = Sym2->NextSym;
77     }
78
79     /* Check both pointers against NULL to compare the field count */
80     return (Sym1 == 0 && Sym2 == 0);
81 }
82
83
84
85 static void DoCompare (const type* lhs, const type* rhs, typecmp_t* Result)
86 /* Recursively compare two types. */
87 {
88     unsigned    Indirections;
89     unsigned    ElementCount;
90     SymEntry*   Sym1;
91     SymEntry*   Sym2;
92     SymTable*   Tab1;
93     SymTable*   Tab2;
94     FuncDesc*   F1;
95     FuncDesc*   F2;
96     int         Ok;
97
98
99     /* Initialize stuff */
100     Indirections = 0;
101     ElementCount = 0;
102
103     /* Compare two types. Determine, where they differ */
104     while (*lhs != T_END) {
105
106         type LeftType, RightType;
107         type LeftSign, RightSign;
108         type LeftQual, RightQual;
109         unsigned LeftCount, RightCount;
110
111         /* Check if the end of the type string is reached */
112         if (*rhs == T_END) {
113             /* End of comparison reached */
114             return;
115         }
116
117         /* Get the raw left and right types, signs and qualifiers */
118         LeftType  = GetType (lhs);
119         RightType = GetType (rhs);
120         LeftSign  = GetSignedness (lhs);
121         RightSign = GetSignedness (rhs);
122         LeftQual  = GetQualifier (lhs);
123         RightQual = GetQualifier (rhs);
124
125         /* If the left type is a pointer and the right is an array, both
126          * are compatible.
127          */
128         if (LeftType == T_TYPE_PTR && RightType == T_TYPE_ARRAY) {
129             RightType = T_TYPE_PTR;
130             rhs += DECODE_SIZE;
131         }
132
133         /* If the raw types are not identical, the types are incompatible */
134         if (LeftType != RightType) {
135             SetResult (Result, TC_INCOMPATIBLE);
136             return;
137         }
138
139         /* On indirection level zero, a qualifier or sign difference is
140          * accepted. The types are no longer equal, but compatible.
141          */
142         if (LeftSign != RightSign) {
143             if (ElementCount == 0) {
144                 SetResult (Result, TC_SIGN_DIFF);
145             } else {
146                 SetResult (Result, TC_INCOMPATIBLE);
147                 return;
148             }
149         }
150         if (LeftQual != RightQual) {
151             /* On the first indirection level, different qualifiers mean
152              * that the types are still compatible. On the second level,
153              * this is a (maybe minor) error, so we create a special
154              * return code, since a qualifier is dropped from a pointer.
155              * Starting from the next level, the types are incompatible
156              * if the qualifiers differ.
157              */
158             switch (Indirections) {
159
160                 case 0:
161                     SetResult (Result, TC_STRICT_COMPATIBLE);
162                     break;
163
164                 case 1:
165                     /* A non const value on the right is compatible to a
166                      * const one to the left, same for volatile.
167                      */
168                     if ((LeftQual & T_QUAL_CONST) < (RightQual & T_QUAL_CONST) ||
169                         (LeftQual & T_QUAL_VOLATILE) < (RightQual & T_QUAL_VOLATILE)) {
170                         SetResult (Result, TC_QUAL_DIFF);
171                     } else {
172                         SetResult (Result, TC_STRICT_COMPATIBLE);
173                     }
174                     break;
175
176                 default:
177                     SetResult (Result, TC_INCOMPATIBLE);
178                     return;
179             }
180         }
181
182         /* Check for special type elements */
183         switch (LeftType) {
184
185             case T_TYPE_PTR:
186                 ++Indirections;
187                 break;
188
189             case T_TYPE_FUNC:
190                 /* Compare the function descriptors */
191                 F1 = DecodePtr (lhs+1);
192                 F2 = DecodePtr (rhs+1);
193
194                 /* If one of the functions is implicitly declared, both
195                  * functions are considered equal. If one of the functions is
196                  * old style, and the other is empty, the functions are
197                  * considered equal.
198                  */
199                 if ((F1->Flags & FD_IMPLICIT) != 0 || (F2->Flags & FD_IMPLICIT) != 0) {
200                     Ok = 1;
201                 } else if ((F1->Flags & FD_OLDSTYLE) != 0 && (F2->Flags & FD_EMPTY) != 0) {
202                     Ok = 1;
203                 } else if ((F1->Flags & FD_EMPTY) != 0 && (F2->Flags & FD_OLDSTYLE) != 0) {
204                     Ok = 1;
205                 } else {
206                     Ok = 0;
207                 }
208
209                 if (!Ok) {
210
211                     /* Check the remaining flags */
212                     if ((F1->Flags & ~FD_IGNORE) != (F2->Flags & ~FD_IGNORE)) {
213                         /* Flags differ */
214                         SetResult (Result, TC_INCOMPATIBLE);
215                         return;
216                     }
217
218                     /* Compare the parameter lists */
219                     if (EqualSymTables (F1->SymTab, F2->SymTab) == 0 ||
220                         EqualSymTables (F1->TagTab, F2->TagTab) == 0) {
221                         /* One of the tables is not identical */
222                         SetResult (Result, TC_INCOMPATIBLE);
223                         return;
224                     }
225                 }
226
227                 /* Skip the FuncDesc pointers to compare the return type */
228                 lhs += DECODE_SIZE;
229                 rhs += DECODE_SIZE;
230                 break;
231
232             case T_TYPE_ARRAY:
233                 /* Check member count */
234                 LeftCount  = Decode (lhs+1);
235                 RightCount = Decode (rhs+1);
236                 if (LeftCount != 0 && RightCount != 0 && LeftCount != RightCount) {
237                     /* Member count given but different */
238                     SetResult (Result, TC_INCOMPATIBLE);
239                     return;
240                 }
241                 lhs += DECODE_SIZE;
242                 rhs += DECODE_SIZE;
243                 break;
244
245             case T_TYPE_STRUCT:
246             case T_TYPE_UNION:
247                 /* Compare the fields recursively. To do that, we fetch the
248                  * pointer to the struct definition from the type, and compare
249                  * the fields.
250                  */
251                 Sym1 = DecodePtr (lhs+1);
252                 Sym2 = DecodePtr (rhs+1);
253
254                 /* Get the field tables from the struct entry */
255                 Tab1 = Sym1->V.S.SymTab;
256                 Tab2 = Sym2->V.S.SymTab;
257
258                 /* One or both structs may be forward definitions. In this case,
259                  * the symbol tables are both non existant. Assume that the
260                  * structs are equal in this case.
261                  */
262                 if (Tab1 != 0 && Tab2 != 0) {
263
264                     if (EqualSymTables (Tab1, Tab2) == 0) {
265                         /* Field lists are not equal */
266                         SetResult (Result, TC_INCOMPATIBLE);
267                         return;
268                     }
269
270                 }
271
272                 /* Structs are equal */
273                 lhs += DECODE_SIZE;
274                 rhs += DECODE_SIZE;
275                 break;
276         }
277
278         /* Next type string element */
279         ++lhs;
280         ++rhs;
281         ++ElementCount;
282     }
283
284     /* Check if end of rhs reached */
285     if (*rhs == T_END) {
286         SetResult (Result, TC_EQUAL);
287     } else {
288         SetResult (Result, TC_INCOMPATIBLE);
289     }
290 }
291
292
293
294 typecmp_t TypeCmp (const type* lhs, const type* rhs)
295 /* Compare two types and return the result */
296 {
297     /* Assume the types are identical */
298     typecmp_t   Result = TC_IDENTICAL;
299
300 #if 0
301     printf ("Left : "); PrintRawType (stdout, lhs);
302     printf ("Right: "); PrintRawType (stdout, rhs);
303 #endif
304
305     /* Recursively compare the types if they aren't identical */
306     if (rhs != lhs) {
307         DoCompare (lhs, rhs, &Result);
308     }
309
310     /* Return the result */
311     return Result;
312 }
313
314
315