2 * compiler/core/dependency.c - sorts types/values in order of dependency.
3 * typeDefs list is re-ordered
4 * going from independent->dependent types
6 * this is done after all import linking is done
10 * Copyright (C) 1991, 1992 Michael Sample
11 * and the University of British Columbia
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * $Header: /cvs/Darwin/Security/SecuritySNACCRuntime/compiler/core/dependency.c,v 1.1 2001/06/20 21:27:56 dmitch Exp $
19 * $Log: dependency.c,v $
20 * Revision 1.1 2001/06/20 21:27:56 dmitch
21 * Adding missing snacc compiler files.
23 * Revision 1.1.1.1 1999/03/16 18:06:46 aram
24 * Originals from SMIME Free Library.
26 * Revision 1.4 1995/07/25 19:41:22 rj
27 * changed `_' to `-' in file names.
29 * Revision 1.3 1994/10/08 03:48:37 rj
30 * since i was still irritated by cpp standing for c++ and not the C preprocessor, i renamed them to cxx (which is one known suffix for C++ source files). since the standard #define is __cplusplus, cplusplus would have been the more obvious choice, but it is a little too long.
32 * Revision 1.2 1994/09/01 00:31:56 rj
33 * snacc_config.h removed; dependency.h includet.
35 * Revision 1.1 1994/08/28 09:49:00 rj
36 * first check-in. for a list of changes to the snacc-1.1 distribution please refer to the ChangeLog.
44 #include "asn1module.h"
45 #include "snacc-util.h"
46 #include "dependency.h"
51 void SortTypeDependencies
PROTO ((Module
*m
));
53 void SortInterModuleDependencies
PROTO ((ModuleList
*m
));
55 TypeDefList
*RemoveAndSortIndependents
PROTO ((TypeDefList
*tdl
));
57 void SortTypeDefs
PROTO ((TypeDefList
*tdl
));
59 void BuildLocalRefList
PROTO ((Type
*t
, TypeDefList
*refList
));
61 void BuildWeightedLocalRefList
PROTO ((Type
*t
, TypeDefList
*refList
));
64 long int GetElmtIndex
PROTO ((TypeDef
*td
, TypeDefList
*tdl
));
67 void MoveAfter PROTO ((unsigned long int currIndex, unsigned long int afterIndex, AsnList *l));
71 * Sorts type dependencies by reodering TypeDefs linear list
72 * with least dependent types followed by dependent types
75 SortAllDependencies
PARAMS ((modList
),
80 FOR_EACH_LIST_ELMT (m
, modList
)
82 SortTypeDependencies (m
);
85 /* SortInterModuleDependencies (modList); */
87 } /* SortAllDependencies */
91 * This attempts to sort the types in order of dependency
92 * (least dependent --> dependent)
94 * This should only be called after the CTypeInfo or CxxTypeInfo
95 * has been added to the types.
96 * (the isPtr field is used to help determine ordering)
100 * First separte the ASN.1 type defs into 4 separate groups
102 * 1. Type defs that are defined directly from primitive/library types
103 * eg Foo ::= INTEGER {one (1), two (2) }
105 * 2. Type defs reference no local types in a way that needs a
106 * forward decl. of the ref'd type (ie ptr refs)
108 * 3. Type defs that reference local types in a way that needs
109 * a previous decl of the ref'd type (ie non ptr refs for SET/SEQ
112 * 4. Type defs that are not referenced by any local types
113 * (hence no local types depend on them so they can go last)
116 * The type defs in group 3 are further sorted by the SortTypeDefs routine
118 * Then all of the groups are merged in the order 1-2-3-4.
120 * Some wierd recursive types might cause problems...
126 SortTypeDependencies
PARAMS ((m
),
133 TypeDefList
*notRefd
;
134 TypeDef
**newElmtHndl
;
136 prims
= AsnListNew (sizeof (void*));
137 noRefs
= AsnListNew (sizeof (void*));
138 refs
= AsnListNew (sizeof (void*));
139 notRefd
= AsnListNew (sizeof (void*));
141 /* put each TypeDef in the appropriate list (1-4)*/
142 FOR_EACH_LIST_ELMT (curr
, m
->typeDefs
)
144 if (IsDefinedByLibraryType (curr
->type
))
145 newElmtHndl
= (TypeDef
**) AsnListAppend (prims
);
147 else if (curr
->localRefCount
== 0)
148 newElmtHndl
= (TypeDef
**) AsnListAppend (notRefd
);
152 /* get list of local types that this type def refs */
153 curr
->refList
= AsnListNew (sizeof (void*));
154 BuildLocalRefList (curr
->type
, curr
->refList
);
156 if (LIST_EMPTY (curr
->refList
))
158 newElmtHndl
= (TypeDef
**) AsnListAppend (noRefs
);
159 Free (curr
->refList
);
160 curr
->refList
= NULL
;
163 newElmtHndl
= (TypeDef
**) AsnListAppend (refs
);
169 /* sort problem types */
172 /* free refList space */
173 FOR_EACH_LIST_ELMT (curr
, refs
)
175 if (curr
->refList
!= NULL
)
177 AsnListFree (curr
->refList
);
178 curr
->refList
= NULL
;
183 * combine the typdef lists with the prims followed by the
184 * types that don't reference other types
185 * then prims, followed by composite types
187 prims
= AsnListConcat (prims
, noRefs
);
188 prims
= AsnListConcat (prims
, refs
);
189 prims
= AsnListConcat (prims
, notRefd
);
191 AsnListFree (m
->typeDefs
);
198 } /* SortTypeDependencies */
204 * Attempt to sort modules in order of "depends on none" to
205 * "depends on all" where a dependency is caused by importing
206 * from another module.
207 * cyclic dependencies are a pain
210 * Not implemented yet... perhaps best left in user's hands
211 * ie set it by the cmd line order
215 SortInterModuleDependencies PARAMS ((m),
219 } SortInterModuleDependencies */
224 * Given a non-empty TypeDef list, the refLists of TypeDefs
225 * are used to divide the list into two lists, one list
226 * that is sorted the order of dependency (independed-->dependent)
227 * and the other list contains types that are mutually dependent
228 * (recursive or depend on recursive types)
229 * The sorted list is returned and the passed in list has those
230 * TypeDefs that are now in the sorted list removed.
233 RemoveAndSortIndependents
PARAMS ((tdl
),
240 AsnListNode
*nextListNode
;
242 long int lastSLCount
;
243 TypeDefList
*subList
;
247 * iterate through the list making sub lists that don't depend
248 * on the others in the active list. Join sub lists in order
249 * and then deal with the active list if any
251 lastSLCount
= -1; /* just to start */
252 subList
= AsnListNew (sizeof (void*));
254 if (LIST_EMPTY (tdl
))
257 /* iterate through each type def in the tdl */
258 while ((LIST_COUNT (subList
) > lastSLCount
) && !LIST_EMPTY (tdl
))
260 lastSLCount
= LIST_COUNT (subList
);
261 last
= (TypeDef
*)LAST_LIST_ELMT (tdl
);
262 SET_CURR_LIST_NODE (tdl
, FIRST_LIST_NODE (tdl
));
263 currTd
= (TypeDef
*)CURR_LIST_ELMT (tdl
);
266 nextListNode
= NEXT_LIST_NODE (tdl
);
270 * iterate through this type def's local type refs.
272 * if any type def in the current type's local type ref list
273 * is in the tdl, then teh current type must remain in the tdl
274 * because it depends on that type.
276 FOR_EACH_LIST_ELMT (tdRef
, currTd
->refList
)
278 /* don't worry about recursive refs to self */
282 * if the tdRef is not in tdl
283 * GetElmtIndex will return < 0
284 * if the tdRef is in the tdl, then the
285 * currTd must remain in the tdl.
287 tdIndex
= GetElmtIndex (tdRef
, tdl
);
294 /* append to sublist and remove for tdl */
295 tdHndl
= (TypeDef
**) AsnListAppend (subList
);
300 break; /* exit while */
302 SET_CURR_LIST_NODE (tdl
, nextListNode
);
303 currTd
= (TypeDef
*)CURR_LIST_ELMT (tdl
);
308 } /* RemoveAndSortIndependents */
312 * Given a list of types that depend on each other, this attempts
313 * to sort the list from independent--> most dependent.
315 * Kind of wierd algorithm
316 * 1. first separate and sort out linearly dependent types and place in
317 * a properly ordered list (RemoveAndSortIndependents) (call it "A")
319 * 2. if types with non-linear (recursive) dependencies remain,
320 * divide them into two groups, recursive (call it "B")(see recursive.c)
321 * and non-recursive (call it "C". The non-recursive ones will depend
322 * on the recursive ones (otherwise step 1 would have grabbed 'em).
324 * 3. Sort the types in list C as done in step one - there should be
325 * no problems (ie unsorted leftovers) since none of them are recursive.
327 * 4. For the recursive types in list B, re-do their refLists such that
328 * any types ref'd by a Ptr are not included in the refList
329 * (may have to update this wrt how the ref is used -
330 * eg in an inline of the ref'ing type). Then sort as in Step 1.
331 * Any types that could not be sorted have a definite problem and
332 * compiliation problems will occur. (.. And the code generation
333 * technique must be changed)
334 * (for C only the SET OF and SEQ OF Types are stripped from this
335 * since they are 'generic' - ie don't depend on the list elmt type)
337 * 5. re-combine all of the lists in order of dependency ie
338 * A-B-(B's leftovers)-C
340 * (the stripped C lists go after 'A')
343 SortTypeDefs
PARAMS ((tdl
),
351 AsnListNode
*tdNodeToMove
;
352 AsnListNode
*nextListNode
;
353 long int maxRefCount
;
354 TypeDefList
*subList
; /* "A" */
356 TypeDefList
*sortedRec
; /* "B" */
357 TypeDefList
*sortedNonRec
; /* "C" */
360 if ((tdl
== NULL
) || (LIST_EMPTY (tdl
)))
363 subList
= RemoveAndSortIndependents (tdl
);
365 /* return if simple sort worked (no recursive types) */
366 if (LIST_EMPTY (tdl
))
374 * divide the remaining interdepedent types into
375 * two groups recursive and non-recursive.
376 * leave the recursive in the tdl and put the others in a new list.
377 * The non-recursive ones obviously depend on the recursive
378 * on since all of the simple type dependencies have been
379 * dealt with by RemoveAndSortIndependents
381 last
= (TypeDef
*)LAST_LIST_ELMT (tdl
);
382 SET_CURR_LIST_NODE (tdl
, FIRST_LIST_NODE (tdl
));
383 currTd
= (TypeDef
*)CURR_LIST_ELMT (tdl
);
384 nonRec
= AsnListNew (sizeof (void*));
388 nextListNode
= NEXT_LIST_NODE (tdl
);
390 if (!currTd
->recursive
)
392 tdHndl
= (TypeDef
**)AsnListAppend (nonRec
);
398 break; /* exit while */
400 SET_CURR_LIST_NODE (tdl
, nextListNode
);
401 currTd
= (TypeDef
*)CURR_LIST_ELMT (tdl
);
404 /* sort the non-recusive types */
405 sortedNonRec
= RemoveAndSortIndependents (nonRec
);
407 if (!LIST_EMPTY (nonRec
))
409 fprintf (stderr
,"SortTypeDefs: internal compiler error - non recursive type defs failed sort.\n");
410 sortedNonRec
= AsnListConcat (sortedNonRec
, nonRec
);
415 * Remove list types from the list since they are generic.
416 * put them in "cLists".
417 * then re-do the dependency list for each type definition that
418 * remain in the recursive list with weighting - ie types
419 * that are ref'd as ptrs don't count. Then re-sort.
421 last
= (TypeDef
*)LAST_LIST_ELMT (tdl
);
422 SET_CURR_LIST_NODE (tdl
, FIRST_LIST_NODE (tdl
));
423 currTd
= (TypeDef
*)CURR_LIST_ELMT (tdl
);
425 cLists
= AsnListNew (sizeof (void*));
428 nextListNode
= NEXT_LIST_NODE (tdl
);
430 /* nuke old ref list */
431 AsnListFree (currTd
->refList
);
432 currTd
->refList
= NULL
;
434 /* for C only, remove lists since they are generic */
435 if ((currTd
->cTypeDefInfo
!= NULL
) &&
436 ((currTd
->type
->basicType
->choiceId
== BASICTYPE_SETOF
) ||
437 (currTd
->type
->basicType
->choiceId
== BASICTYPE_SEQUENCEOF
)))
439 tdHndl
= (TypeDef
**)AsnListAppend (cLists
);
445 break; /* exit while */
447 SET_CURR_LIST_NODE (tdl
, nextListNode
);
448 currTd
= (TypeDef
*)CURR_LIST_ELMT (tdl
);
453 FOR_EACH_LIST_ELMT (currTd
, tdl
)
455 currTd
->refList
= AsnListNew (sizeof (void*));
456 BuildWeightedLocalRefList (currTd
->type
, currTd
->refList
);
459 sortedRec
= RemoveAndSortIndependents (tdl
);
462 * now merge subLists and put in tdl:
463 * tdl = cLists + sortedRec + impossible rec in tdl + sorted nonRec
465 subList
= AsnListConcat (subList
, cLists
);
466 subList
= AsnListConcat (subList
, sortedRec
);
467 subList
= AsnListConcat (subList
, tdl
);
468 subList
= AsnListConcat (subList
, sortedNonRec
);
482 * Builds list of TypeDefs in this module that the given type refs.
483 * Does not follow type refs to include their type refs.
486 BuildLocalRefList
PARAMS ((t
, refList
),
488 TypeDefList
*refList
)
493 switch (t
->basicType
->choiceId
)
495 case BASICTYPE_CHOICE
:
497 case BASICTYPE_SEQUENCE
:
498 FOR_EACH_LIST_ELMT (e
, t
->basicType
->a
.choice
)
500 BuildLocalRefList (e
->type
, refList
);
504 case BASICTYPE_SETOF
:
505 case BASICTYPE_SEQUENCEOF
:
506 BuildLocalRefList (t
->basicType
->a
.setOf
, refList
);
509 case BASICTYPE_LOCALTYPEREF
:
510 tdHndl
= (TypeDef
**)AsnListAppend (refList
);
511 *tdHndl
= t
->basicType
->a
.localTypeRef
->link
;
515 * default: other types are not aggregate and
519 } /* BuildLocalRefList */
523 * Builds list of TypeDefs in this module that the given type references.
524 * Does not follow type refs to include their type refs.
525 * Does not include types that are ref'd as ptrs since
526 * If the target lang is C the type SET OF/SEQ OF types reference
527 * are not counted due to the current 'genericness' of the C list type
528 * (it doesn't need type info)
529 * they shouldn't affect type ordering.
532 BuildWeightedLocalRefList
PARAMS ((t
, refList
),
534 TypeDefList
*refList
)
539 switch (t
->basicType
->choiceId
)
541 case BASICTYPE_CHOICE
:
543 case BASICTYPE_SEQUENCE
:
544 FOR_EACH_LIST_ELMT (e
, t
->basicType
->a
.choice
)
546 BuildWeightedLocalRefList (e
->type
, refList
);
552 case BASICTYPE_SETOF
:
553 case BASICTYPE_SEQUENCEOF
:
555 * normalize makes embedded list defs into
556 * separate type defs now so this clause will
557 * not fire. (ie they will be a LOCAL_TYPEREF
558 * to the removed list type instead)
562 * list types for C don't really depend on
563 * the component type (void*). So if the target lang
564 * is C then can achieve better ordering
565 * for ugly recursive defs by using this relaxation
566 * (ie not including the component type in the ref list)
568 if (t
->cTypeRefInfo
== NULL
)
569 BuildWeightedLocalRefList (t
->basicType
->a
.setOf
, refList
);
573 case BASICTYPE_LOCALTYPEREF
:
575 if (((t
->cxxTypeRefInfo
!= NULL
) &&
576 !(t
->cxxTypeRefInfo
->isPtr
)) ||
577 ((t
->cTypeRefInfo
!= NULL
) && !(t
->cTypeRefInfo
->isPtr
)))
579 tdHndl
= (TypeDef
**)AsnListAppend (refList
);
580 *tdHndl
= t
->basicType
->a
.localTypeRef
->link
;
585 * default: other types are not aggregate and
589 } /* BuildWeightedLocalRefList */
594 * Returns the index (starting a 0 for the first elmt)
595 * of the given td in the td list (tdl)
596 * returns -1 if td is not in the list
599 GetElmtIndex
PARAMS ((td
, tdl
),
608 tmp
= (void*) CURR_LIST_NODE (tdl
);
609 FOR_EACH_LIST_ELMT (tmpTd
, tdl
)
613 SET_CURR_LIST_NODE (tdl
, tmp
);
620 SET_CURR_LIST_NODE (tdl
, tmp
);
630 * Attempts to order the types in tdl from independent-->most depenedent
631 * uses insertion after TypeDef that the given type def depends on.
632 * Hoky - doesn't work very well - differing results depending on
636 AttemptDependencySort PARAMS ((tdl),
643 AsnListNode *nextListNode;
648 if (LIST_EMPTY (tdl))
651 last = (TypeDef*)LAST_LIST_ELMT (tdl);
653 FOR_EACH_LIST_ELMT (currTd, tdl)
655 currTd->visited = FALSE;
658 SET_CURR_LIST_NODE (tdl, FIRST_LIST_NODE (tdl));
659 currTd = (TypeDef*)CURR_LIST_ELMT (tdl);
663 nextListNode = NEXT_LIST_NODE (tdl);
665 if (!currTd->visited)
667 currTd->visited = TRUE;
669 FOR_EACH_LIST_ELMT (tdRef, currTd->refList)
671 tdIndex = GetElmtIndex (tdRef, tdl);
672 if (tdIndex > maxTdIndex)
673 maxTdIndex = tdIndex;
677 currIndex = GetElmtIndex (currTd, tdl);
679 if ((maxTdIndex >= 0) && (currIndex < maxTdIndex))
681 MoveAfter (currIndex, maxTdIndex, tdl);
687 SET_CURR_LIST_NODE (tdl, nextListNode);
688 currTd = (TypeDef*)CURR_LIST_ELMT (tdl);
690 } AttemptDependencySort */
695 * Moves list node at currIndex to after Node at afterIndex
696 * in the given list l. Indexes start at 0 for the first elmt.
697 * May confuse the 'curr' pointer of the list
700 MoveAfter PARAMS ((currIndex, afterIndex, l),
701 unsigned long int currIndex _AND_
702 unsigned long int afterIndex _AND_
706 AsnListNode *nodeToMove;
707 AsnListNode *afterNode;
711 (LIST_COUNT (l) <= currIndex) ||
712 (LIST_COUNT (l) <= afterIndex))
714 fprintf (stderr,"Internal compiler error - index confusion in MoveAfter\n");
718 tmp = (void*) CURR_LIST_NODE (l);
720 nodeToMove = l->first;
721 for (i = 0; i < currIndex; i++)
722 nodeToMove = nodeToMove->next;
724 afterNode = l->first;
725 for (i = 0; i < afterIndex; i++)
726 afterNode = afterNode->next;
729 if (nodeToMove->next)
730 nodeToMove->next->prev = nodeToMove->prev;
732 l->last = nodeToMove->prev;
734 if (nodeToMove->prev)
735 nodeToMove->prev->next = nodeToMove->next;
737 l->first = nodeToMove->next;
739 insert node to move after selected node
740 nodeToMove->next = afterNode->next;
741 nodeToMove->prev = afterNode;
744 afterNode->next->prev = nodeToMove;
746 l->last = nodeToMove;
748 afterNode->next = nodeToMove;