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