]> git.sur5r.net Git - cc65/blob - src/cc65/typecmp.c
ValidSegName now defined in segnames.h
[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-2003 Ullrich von Bassewitz                                       */
10 /*               Römerstrasse 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 EqualFuncParams (SymTable* Tab1, SymTable* Tab2)
62 /* Compare two function symbol tables regarding function parameters. Return 1
63  * if they are equal and 0 otherwise.
64  */
65 {
66     /* Compare the parameter lists */
67     SymEntry* Sym1 = Tab1->SymHead;
68     SymEntry* Sym2 = Tab2->SymHead;
69
70     /* Compare the fields */
71     while (Sym1 && (Sym1->Flags & SC_PARAM) && Sym2 && (Sym2->Flags & SC_PARAM)) {
72
73         /* Compare this field */
74         if (TypeCmp (Sym1->Type, Sym2->Type) < TC_EQUAL) {
75             /* Field types not equal */
76             return 0;
77         }
78
79         /* Get the pointers to the next fields */
80         Sym1 = Sym1->NextSym;
81         Sym2 = Sym2->NextSym;
82     }
83
84     /* Check both pointers against NULL or a non parameter to compare the
85      * field count
86      */
87     return (Sym1 == 0 || (Sym1->Flags & SC_PARAM) == 0) &&
88            (Sym2 == 0 || (Sym2->Flags & SC_PARAM) == 0);
89 }
90
91
92
93 static int EqualSymTables (SymTable* Tab1, SymTable* Tab2)
94 /* Compare two symbol tables. Return 1 if they are equal and 0 otherwise */
95 {
96     /* Compare the parameter lists */
97     SymEntry* Sym1 = Tab1->SymHead;
98     SymEntry* Sym2 = Tab2->SymHead;
99
100     /* Compare the fields */
101     while (Sym1 && Sym2) {
102
103         /* Compare the names of this field */
104         if (!HasAnonName (Sym1) || !HasAnonName (Sym2)) {
105             if (strcmp (Sym1->Name, Sym2->Name) != 0) {
106                 /* Names are not identical */
107                 return 0;
108             }
109         }
110
111         /* Compare the types of this field */
112         if (TypeCmp (Sym1->Type, Sym2->Type) < TC_EQUAL) {
113             /* Field types not equal */
114             return 0;
115         }
116
117         /* Get the pointers to the next fields */
118         Sym1 = Sym1->NextSym;
119         Sym2 = Sym2->NextSym;
120     }
121
122     /* Check both pointers against NULL to compare the field count */
123     return (Sym1 == 0 && Sym2 == 0);
124 }
125
126
127
128 static void DoCompare (const type* lhs, const type* rhs, typecmp_t* Result)
129 /* Recursively compare two types. */
130 {
131     unsigned    Indirections;
132     unsigned    ElementCount;
133     SymEntry*   Sym1;
134     SymEntry*   Sym2;
135     SymTable*   Tab1;
136     SymTable*   Tab2;
137     FuncDesc*   F1;
138     FuncDesc*   F2;
139     int         Ok;
140
141
142     /* Initialize stuff */
143     Indirections = 0;
144     ElementCount = 0;
145
146     /* Compare two types. Determine, where they differ */
147     while (*lhs != T_END) {
148
149         type LeftType, RightType;
150         type LeftSign, RightSign;
151         type LeftQual, RightQual;
152         long LeftCount, RightCount;
153
154         /* Check if the end of the type string is reached */
155         if (*rhs == T_END) {
156             /* End of comparison reached */
157             return;
158         }
159
160         /* Get the raw left and right types, signs and qualifiers */
161         LeftType  = GetType (lhs);
162         RightType = GetType (rhs);
163         LeftSign  = GetSignedness (lhs);
164         RightSign = GetSignedness (rhs);
165         LeftQual  = GetQualifier (lhs);
166         RightQual = GetQualifier (rhs);
167
168         /* If the left type is a pointer and the right is an array, both
169          * are compatible.
170          */
171         if (LeftType == T_TYPE_PTR && RightType == T_TYPE_ARRAY) {
172             RightType = T_TYPE_PTR;
173             rhs += DECODE_SIZE;
174         }
175
176         /* If the raw types are not identical, the types are incompatible */
177         if (LeftType != RightType) {
178             SetResult (Result, TC_INCOMPATIBLE);
179             return;
180         }
181
182         /* On indirection level zero, a qualifier or sign difference is
183          * accepted. The types are no longer equal, but compatible.
184          */
185         if (LeftSign != RightSign) {
186             if (ElementCount == 0) {
187                 SetResult (Result, TC_SIGN_DIFF);
188             } else {
189                 SetResult (Result, TC_INCOMPATIBLE);
190                 return;
191             }
192         }
193         if (LeftQual != RightQual) {
194             /* On the first indirection level, different qualifiers mean
195              * that the types are still compatible. On the second level,
196              * this is a (maybe minor) error, so we create a special
197              * return code, since a qualifier is dropped from a pointer.
198              * Starting from the next level, the types are incompatible
199              * if the qualifiers differ.
200              */
201             switch (Indirections) {
202
203                 case 0:
204                     SetResult (Result, TC_STRICT_COMPATIBLE);
205                     break;
206
207                 case 1:
208                     /* A non const value on the right is compatible to a
209                      * const one to the left, same for volatile.
210                      */
211                     if ((LeftQual & T_QUAL_CONST) < (RightQual & T_QUAL_CONST) ||
212                         (LeftQual & T_QUAL_VOLATILE) < (RightQual & T_QUAL_VOLATILE)) {
213                         SetResult (Result, TC_QUAL_DIFF);
214                     } else {
215                         SetResult (Result, TC_STRICT_COMPATIBLE);
216                     }
217                     break;
218
219                 default:
220                     SetResult (Result, TC_INCOMPATIBLE);
221                     return;
222             }
223         }
224
225         /* Check for special type elements */
226         switch (LeftType) {
227
228             case T_TYPE_PTR:
229                 ++Indirections;
230                 break;
231
232             case T_TYPE_FUNC:
233                 /* Compare the function descriptors */
234                 F1 = DecodePtr (lhs+1);
235                 F2 = DecodePtr (rhs+1);
236
237                 /* If one of the functions is implicitly declared, both
238                  * functions are considered equal. If one of the functions is
239                  * old style, and the other is empty, the functions are
240                  * considered equal.
241                  */
242                 if ((F1->Flags & FD_IMPLICIT) != 0 || (F2->Flags & FD_IMPLICIT) != 0) {
243                     Ok = 1;
244                 } else if ((F1->Flags & FD_OLDSTYLE) != 0 && (F2->Flags & FD_EMPTY) != 0) {
245                     Ok = 1;
246                 } else if ((F1->Flags & FD_EMPTY) != 0 && (F2->Flags & FD_OLDSTYLE) != 0) {
247                     Ok = 1;
248                 } else {
249                     Ok = 0;
250                 }
251
252                 if (!Ok) {
253
254                     /* Check the remaining flags */
255                     if ((F1->Flags & ~FD_IGNORE) != (F2->Flags & ~FD_IGNORE)) {
256                         /* Flags differ */
257                         SetResult (Result, TC_INCOMPATIBLE);
258                         return;
259                     }
260
261                     /* Compare the parameter lists */
262                     if (EqualFuncParams (F1->SymTab, F2->SymTab) == 0 ||
263                         EqualSymTables (F1->TagTab, F2->TagTab) == 0) {
264                         /* One of the tables is not identical */
265                         SetResult (Result, TC_INCOMPATIBLE);
266                         return;
267                     }
268                 }
269
270                 /* Skip the FuncDesc pointers to compare the return type */
271                 lhs += DECODE_SIZE;
272                 rhs += DECODE_SIZE;
273                 break;
274
275             case T_TYPE_ARRAY:
276                 /* Check member count */
277                 LeftCount  = GetElementCount (lhs);
278                 RightCount = GetElementCount (rhs);
279                 if (LeftCount  != UNSPECIFIED &&
280                     RightCount != UNSPECIFIED &&
281                     LeftCount  != RightCount) {
282                     /* Member count given but different */
283                     SetResult (Result, TC_INCOMPATIBLE);
284                     return;
285                 }
286                 lhs += DECODE_SIZE;
287                 rhs += DECODE_SIZE;
288                 break;
289
290             case T_TYPE_STRUCT:
291             case T_TYPE_UNION:
292                 /* Compare the fields recursively. To do that, we fetch the
293                  * pointer to the struct definition from the type, and compare
294                  * the fields.
295                  */
296                 Sym1 = DecodePtr (lhs+1);
297                 Sym2 = DecodePtr (rhs+1);
298
299                 /* If one symbol has a name, the names must be identical */
300                 if (!HasAnonName (Sym1) || !HasAnonName (Sym2)) {
301                     if (strcmp (Sym1->Name, Sym2->Name) != 0) {
302                         /* Names are not identical */
303                         SetResult (Result, TC_INCOMPATIBLE);
304                         return;
305                     }
306                 }
307
308                 /* Get the field tables from the struct entry */
309                 Tab1 = Sym1->V.S.SymTab;
310                 Tab2 = Sym2->V.S.SymTab;
311
312                 /* One or both structs may be forward definitions. In this case,
313                  * the symbol tables are both non existant. Assume that the
314                  * structs are equal in this case.
315                  */
316                 if (Tab1 != 0 && Tab2 != 0) {
317
318                     if (EqualSymTables (Tab1, Tab2) == 0) {
319                         /* Field lists are not equal */
320                         SetResult (Result, TC_INCOMPATIBLE);
321                         return;
322                     }
323
324                 }
325
326                 /* Structs are equal */
327                 lhs += DECODE_SIZE;
328                 rhs += DECODE_SIZE;
329                 break;
330         }
331
332         /* Next type string element */
333         ++lhs;
334         ++rhs;
335         ++ElementCount;
336     }
337
338     /* Check if end of rhs reached */
339     if (*rhs == T_END) {
340         SetResult (Result, TC_EQUAL);
341     } else {
342         SetResult (Result, TC_INCOMPATIBLE);
343     }
344 }
345
346
347
348 typecmp_t TypeCmp (const type* lhs, const type* rhs)
349 /* Compare two types and return the result */
350 {
351     /* Assume the types are identical */
352     typecmp_t   Result = TC_IDENTICAL;
353
354 #if 0
355     printf ("Left : "); PrintRawType (stdout, lhs);
356     printf ("Right: "); PrintRawType (stdout, rhs);
357 #endif
358
359     /* Recursively compare the types if they aren't identical */
360     if (rhs != lhs) {
361         DoCompare (lhs, rhs, &Result);
362     }
363
364     /* Return the result */
365     return Result;
366 }
367
368
369