3 extern bool special_debug
;
4 //******************************************************************************
5 // Database of the locations of function definitions
6 // && parsing of all of them later
7 // && re-parsing of auto-functions with checks
8 //******************************************************************************
13 typedef struct funcd_t
{
35 static void _store_definition
36 (Token name
, Token
*dclstr
, Token
*argv
, typeID
*argt
, NormPtr body
,
37 recID r
, typeID rett
, Token cname
, bool b
, int ff
, bool poly
, bool have_this
,
40 funcd
*f
= (funcd
*) malloc (sizeof * f
);
44 f
->dclstr
= intdup (dclstr
);
45 f
->argv
= intdup (argv
);
46 f
->argt
= argtdup (argt
);
53 f
->have_this
= have_this
;
54 f
->in_abstract
= bt_macro
;
57 if (definition
[ff
].last
) definition
[ff
].last
->next
= f
;
58 else definition
[ff
].first
= f
;
59 definition
[ff
].last
= f
;
63 (Token name
, Token
*dclstr
, Token
*argv
, typeID
*argt
, NormPtr body
,
64 recID r
, typeID rett
, Token cname
, bool b
, deftype dt
, bool ht
)
66 _store_definition (name
, dclstr
, argv
, argt
, body
, r
, rett
,
67 cname
, b
, dt
, true, ht
, -1);
70 void store_definition_alias
71 (Token name
, Token
*dclstr
, Token
*argv
, typeID
*argt
, NormPtr alias
,
72 recID r
, typeID rett
, Token cname
, bool b
, deftype dt
, bool ht
)
74 _store_definition (name
, dclstr
, argv
, argt
, -1, r
, rett
,
75 cname
, b
, dt
, true, ht
, alias
);
80 void store_define_dtor (Token name
, recID r
)
82 Token argv
[] = { -1 };
83 typeID argt
[] = { pthis_of_struct (r
), INTERNAL_ARGEND
};
85 RESERVED_static
, RESERVED_inline
, RESERVED_void
,
86 '*', name
, '(', RESERVED_struct
,
87 name_of_struct (r
), '*', RESERVED_this
, ')', -1
89 _store_definition (name
, dclstr
, argv
, argt
, CODELESS
, r
,
90 typeID_voidP
, name
, true, DT_NORM
, true, true, -1);
93 /**********************************************************************
94 Rename things on overload
95 **********************************************************************/
96 void rename_fdb (Token on
, Token nn
)
101 for (i
= DT_NORM
; i
<= DT_AUTO
; i
++)
102 for (f
= definition
[i
].first
; f
; f
= f
->next
)
104 intsubst (f
->dclstr
, on
, nn
);
110 void remove_struct_from_def (Token n
)
115 for (i
= DT_NORM
; i
<= DT_AUTO
; i
++)
116 for (f
= definition
[i
].first
; f
; f
= f
->next
)
118 remove_struct_from_this (f
->dclstr
, f
->object
);
122 /**********************************************************************
123 --- Usage && comparison
124 record usage of important things to be able to
125 compare whether two functions are the same
126 **********************************************************************/
127 typedef enum { AF_NOTYET
, AF_TRUE
, AF_FALSE
, AF_DEPENDS
} AutoBool
;
128 enum { USE_END
, USE_TCONST
, USE_FCALL
, USE_VVAR
, USE_MEMB
, USE_UPCAST
, USE_LTDEF
, USE_TYPEID
};
143 static bool textok
= true;
144 static bool calls_pure
= false;
145 static usaged
*udata
;
146 static int nudata
, nudata_alloc
;
148 static int add_udata ()
151 if (nudata
+ 1 >= nudata_alloc
)
152 udata
= (usaged
*) realloc (udata
, sizeof (usaged
) * (nudata_alloc
+= CHUNK
));
156 void usage_tconst (Token v
)
159 int n
= add_udata ();
160 udata
[n
].status
= USE_TCONST
;
165 void usage_typeID (typeID t
)
168 int n
= add_udata ();
169 udata
[n
].status
= USE_TYPEID
;
172 if (base_of (t
) == B_PURE
) {
174 raise_skip_function ();
178 void usage_fcall (Token v
)
181 int n
= add_udata ();
182 udata
[n
].status
= USE_FCALL
;
192 void usage_call_pure ()
194 usage_fcall (RESERVED_0
);
198 void usage_vvar (Token
*t
)
200 if (!t
) usage_notok ();
202 int n
= add_udata ();
203 udata
[n
].status
= USE_VVAR
;
208 void usage_memb (Token v
)
211 int n
= add_udata ();
212 udata
[n
].status
= USE_MEMB
;
217 void usage_set_pure ()
222 void usage_upcast (recID r
)
225 int n
= add_udata ();
226 udata
[n
].status
= USE_UPCAST
;
231 static usaged
*reset_udata ()
235 if (!udata
) return 0;
237 int n
= add_udata ();
238 udata
[n
].status
= USE_END
;
239 usaged
*r
= realloc (udata
, sizeof (usaged
) * nudata
);
240 nudata
= nudata_alloc
= 0;
245 static AutoBool
is_another_autof (Token
);
252 static int compare_usages (usaged
*u1
, recID rd
, usaged
*u2
, recID rb
, Token deps
[])
256 if (!u1
) return AF_FALSE
;
258 for (i
= 0; u1
[i
].status
!= USE_END
; i
++)
259 switch (u1
[i
].status
) {
262 if (u1
[i
].u
.t
!= u2
[i
].u
.t
) return AF_TRUE
;
264 if (u1
[i
].u
.T
!= u2
[i
].u
.T
) return AF_TRUE
;
266 if (u1
[i
].u
.t
== u2
[i
].u
.t
) continue;
267 switch (is_another_autof (u1
[i
].u
.t
)) {
268 case AF_TRUE
: return AF_TRUE
;
269 case AF_FALSE
: continue;
270 default: for (j
= 0; j
< nd
; j
++)
271 if (deps
[j
] == u1
[i
].u
.t
)
274 deps
[nd
++] = u1
[i
].u
.t
;
277 if (intcmp (u1
[i
].u
.s
, u2
[i
].u
.s
))
281 Token p1
[64], p2
[64], *p
;
282 lookup_variable_member (rd
, u1
[i
].u
.t
, p1
, true, 0);
283 lookup_variable_member (rb
, u1
[i
].u
.t
, p2
+ 2, true, 0);
284 p2
[1] = is_ancestor (rd
, rb
, &p
, true) == 2 ? POINTSAT
: '.';
290 /* if different, will catch fcalls */
291 if (u1
[i
].u
.r
!= u2
[i
].u
.r
)
294 Token
*p1
, p2
[64], *p
;
295 is_ancestor (rd
, u1
[i
].u
.r
, &p1
, true);
296 if (rb
!= u1
[i
].u
.r
) {
297 is_ancestor (rb
, u1
[i
].u
.r
, &p
, true);
299 p2
[1] = is_ancestor (rd
, rb
, &p
, true) == 2 ? POINTSAT
: '.';
301 if (p2
[2] == -1) p2
[1] = -1;
302 if (p
[0] == -1) intcpy (p2
, p2
+ 2);
304 is_ancestor (rd
, rb
, &p
, true);
314 return nd
? AF_DEPENDS
: AF_FALSE
;
316 /**********************************************************************
318 **********************************************************************/
319 static OUTSTREAM
do_function_catch (funcd
*);
320 /**********************************************************************
321 --- Auto functions, store & instantiate
322 **********************************************************************/
325 Token dname
, fname
, pname
;
327 Token
*proto
, *argv
, *dcltext
;
328 struct adf
**callers
;
341 static intnode
* autoftree
;
343 void commit_auto_define (Token dname
, recID r
, Token fname
, Token pname
, bool virt
, Token
*proto
, Token
*argv
, typeID ft
)
345 struct adf
*a
= (struct adf
*) malloc (sizeof * a
);
351 a
->status
= AF_NOTYET
;
355 a
->proto
= intdup (proto
);
356 a
->argv
= intdup (argv
);
365 if (last
) last
->next
= a
;
368 union ival u
= { .p
= a
};
369 intadd (&autoftree
, a
->fname
, u
);
372 static void add_caller (struct adf
*a
, struct adf
*c
)
375 a
->callers
= (struct adf
**) malloc (32 * sizeof *a
->callers
);
376 else if (a
->ncallers
% 32 == 0)
377 a
->callers
= (struct adf
**) realloc (a
->callers
, a
->ncallers
+= 32);
378 a
->callers
[a
->ncallers
++] = c
;
381 static AutoBool
is_another_autof (Token t
)
383 intnode
*n
= intfind (autoftree
, t
);
384 if (!n
) return AF_TRUE
;
385 struct adf
*a
= (struct adf
*) n
->v
.p
;
386 return a
->status
== AF_NOTYET
? AF_DEPENDS
: a
->status
;
389 static AutoBool
check_dependancies (Token dep
[])
393 for (i
= 0; dep
[i
] != -1; i
++)
394 switch (((struct adf
*) intfind (autoftree
, dep
[i
])->v
.p
)->status
) {
395 case AF_TRUE
: return AF_TRUE
;
396 case AF_DEPENDS
: r
= AF_DEPENDS
;
402 /* the case where the definition of an auto-function is
404 * make f->body point to parent functions definition body
405 * if available or return false. */
406 static bool autofork (funcd
*f
)
411 if (p
== -1 || !(issymbol (CODE
[p
]) && CODE
[p
+ 1] == '}'))
415 recID r
= lookup_object (o
);
417 if (!r
) parse_error (p
, "Not an class in auto-start");
418 if (!isancestor (f
->object
, r
)) parse_error (p
, "Not derrived");
420 for (s
= definition
[DT_NORM
].first
; s
; s
= s
->next
)
421 if (s
->cname
== f
->cname
&& s
->object
== r
422 && arglist_compare (s
->argt
, f
->argt
)) {
424 for (p
= 0; f
->argv
[p
] != -1; p
++)
425 intsubst1 (f
->dclstr
, f
->argv
[p
], s
->argv
[p
]);
433 /* instantiate the definition of an auto function for a specific class
434 * and then parse it */
435 static Token
*instantiate_auto (struct adf
*a
)
441 for (f
= definition
[DT_AUTO
].first
; f
; f
= f
->next
)
442 if (f
->name
== a
->dname
)
446 if (!autofork (f
)) return 0;
448 a
->have_this
= f
->have_this
;
449 a
->aliasing
= f
->alias
!= -1;
451 dproto
= intdup (a
->proto
);
452 for (i
= 0; a
->argv
[i
] != -1; i
++)
453 intsubst1 (dproto
, a
->argv
[i
], f
->argv
[i
]);
456 .name
= a
->fname
, .cname
= f
->cname
, .object
= a
->r
,
457 .dclstr
= dproto
, .argv
= f
->argv
,
458 .argt
= argtdup (open_typeID (a
->ft
) + 3),
459 .body
= f
->body
, .alias
= f
->alias
, .ret_type
= funcreturn (a
->ft
),
460 .is_destructor
= f
->is_destructor
, .polymorph
= false,
461 .have_this
= f
->have_this
, .virt
= a
->virt
464 return combine_output (do_function_catch (&F
));
467 static AutoBool
same_code (struct adf
*f
)
469 struct adf
*a
= (struct adf
*) intfind (autoftree
, f
->pname
)->v
.p
;
475 AutoBool r
= compare_usages (f
->udata
, f
->r
, a
->udata
, a
->r
, depends
);
477 f
->deps
= intdup (depends
);
481 static void dispatch_to_parent (struct adf
*a
)
484 struct adf
*p
= (struct adf
*) intfind (autoftree
, a
->pname
)->v
.p
;
486 OUTSTREAM O
= new_stream ();
488 //PRINTF ("DISPATCH TO PARENT: %s %s\n", expand (a->fname), expand (a->pname));
489 if (HaveAliases
&& zero_offset (a
->r
, r
)) {
490 outprintf (printproto_si (O
, a
->proto
, a
->fname
, 1), alias_func (r
, a
->pname
), ';', -1);
493 outprintf (printproto (O
,a
->proto
,a
->fname
, 0), '{', RESERVED_return
,a
->pname
,'(',-1);
496 outprintf (O
, ISTR (upcast1_this (a
->r
, r
)), -1);
497 else if (a
->argv
[0] != -1)
498 outprintf (O
, a
->argv
[i
++], -1);
500 for (; a
->argv
[i
] != -1; i
++)
501 outprintf (O
, ',', a
->argv
[i
], -1);
502 outprintf (O
, ')', ';', '}', -1);
506 a
->dcltext
= combine_output (O
);
509 static void rpure_r (struct adf
*a
)
515 if (a
->virt
) purify_vfunc (a
->fname
);
517 for (i
= 0; i
< a
->ncallers
; i
++)
518 rpure_r (a
->callers
[i
]);
521 static void remove_pure ()
529 for (a
= first
; a
; a
= a
->next
)
530 if (a
->dcltext
&& !a
->cpure
&& a
->udata
)
531 for (u
= a
->udata
, i
= 0; u
[i
].status
!= USE_END
; i
++)
532 if (u
[i
].status
== USE_FCALL
) {
534 n
= intfind (autoftree
, t
);
536 c
= (struct adf
*) n
->v
.p
;
542 for (a
= first
; a
; a
= a
->next
)
543 if (a
->cpure
) rpure_r (a
);
546 void define_auto_functions ()
551 // first, parse all of them, hypothetically
553 objective
.recording
= true;
554 for (a
= first
; a
; a
= a
->next
)
555 if (a
->dcltext
= instantiate_auto (a
))
556 a
->textok
= textok
, a
->cpure
= calls_pure
, a
->udata
= reset_udata ();
557 objective
.recording
= false;
565 // now define or dispatch depending whether
566 // the two versions do different things
568 for (a
= first
; a
; a
= a
->next
)
570 if ((a
->status
= (a
->pname
== -1 ? AF_TRUE
: same_code (a
))) == AF_FALSE
)
571 dispatch_to_parent (a
);
574 // autofunctions calling autofunctions
575 // try to resolve known
577 for (fd
= 0, a
= first
; a
; a
= a
->next
)
578 if (a
->status
== AF_DEPENDS
) {
579 switch (a
->status
= check_dependancies (a
->deps
)) {
581 dispatch_to_parent (a
);
594 // circular dependancies left. suppose false
596 for (a
= first
; a
; a
= a
->next
)
597 if (a
->status
== AF_DEPENDS
)
598 dispatch_to_parent (a
);
602 // print the code (and the prototype + linkonce)
604 for (a
= first
; a
; a
= a
->next
)
606 printproto (FPROTOS
, a
->proto
, a
->fname
, 1);
607 bool staticinline
= intchr (a
->proto
, RESERVED_static
) || intchr (a
->proto
, RESERVED_inline
);
609 if (!OneBigFile
&& !staticinline
)
610 output_itoken (FPROTOS
, linkonce_text (a
->fname
));
611 else if (staticinline
&&0)
612 /* Disabled: was for gcc alias bug */
613 outprintf (FPROTOS
, RESERVED___attribute__
, '(', '(', RESERVED_used
, ')', ')', -1);
615 output_itoken (FPROTOS
, ';');
616 outprintf (AUTOFUNCTIONS
, ISTR (a
->dcltext
), -1);
619 // (Do you remember malloc?)
620 for (a
= first
; a
; a
= a
->next
) {
621 if (a
->dcltext
) free (a
->dcltext
);
622 if (a
->udata
) free (a
->udata
);
623 if (a
->deps
) free (a
->deps
);
624 if (a
->proto
) free (a
->proto
);
625 if (a
->argv
) free (a
->argv
);
626 if (a
->ncallers
) free (a
->callers
);
629 /**********************************************************************
630 --- Abstract Class functions, store & instantiate
631 **********************************************************************/
632 /**********************************************************************
634 **********************************************************************/
637 static typeID
elliptic_arg (typeID t
)
639 return typeID_elliptic (t
) ? ptrup (elliptic_type (t
)) : t
;
642 static OUTSTREAM
do_alias_function (funcd
*f
)
644 recID cls
= f
->object
;
646 NormPtr p
= f
->alias
;
647 OUTSTREAM o
= new_stream ();
649 if (ISSYMBOL (CODE
[p
+ 1]) && CODE
[p
+ 2] == ')')
651 else parse_error (p
, "alias (func)");
653 fnm
= lookup_function_member_uname (&cls
, fnm
);
654 if (objective
.recording
)
656 #ifndef BROKEN_ALIASES
658 outprintf (printproto (o
, f
->dclstr
, f
->name
, 1), alias_func (cls
, fnm
), ';', -1);
662 outprintf (printproto_si (o
, f
->dclstr
, f
->name
, 1), '{',
663 RESERVED_return
, fnm
, '(', -1);
665 outprintf (o
, RESERVED_this
, -1);
666 /*XXX: this will break if there are arguments. Add them! */
667 outprintf (o
, ')', ';', '}', -1);
672 static OUTSTREAM
do_function (funcd
*f
)
675 if (debugflag
.FUNCPROGRESS
)
676 PRINTF ("FUNCTION ["COLS
"%s"COLE
"]\n", expand(f
->name
));
680 /* Feature: alias functions */
682 return do_alias_function (f
);
683 /* ~~~~~~~~~~~~~~~~~~~~~~~~ */
686 bool MAIN
; // and gcc warnings get sillier all the time....
687 OUTSTREAM o
= new_stream ();
689 return_typeID
= f
->ret_type
;
690 if (objective
.recording
)
691 usage_typeID (return_typeID
);
692 if (MAIN
= f
->name
== RESERVED_main
)
694 objective
.isdtor
= f
->is_destructor
;
696 /* abstract template class type */
697 SAVE_VAR (bt_macro
, f
->in_abstract
);
698 SAVE_VAR (bt_replace
, name_of_struct (f
->object
));
699 SAVE_VAR (in_function
, f
->name
);
700 SAVE_VAR (may_throw
, false);
701 current_scope
[++top_scope
] = f
->object
;
703 /* set expression semantics in member functions */
704 if ((objective
.yes
= f
->object
!= 0)) {
705 objective
.func
= f
->name
;
706 objective
.class = f
->object
;
707 objective
.efunc
= f
->cname
;
708 objective
.classP
= pthis_of_struct (f
->object
);
709 objective
.have_this
= f
->have_this
;
710 objective
.polymorph
= f
->polymorph
;
713 for (i
= 0; f
->argt
[i
] != -1; i
++)
714 if (f
->argv
[i
] != -1) {
715 typeID t
= elliptic_arg (f
->argt
[i
]);
716 enter_local_obj (f
->argv
[i
], t
);
717 if (objective
.recording
)
723 printproto (o
, f
->dclstr
, f
->name
, 0);
724 else outprintf (o
, ISTR (f
->dclstr
), - 1);
725 if (f
->body
!= CODELESS
)
726 compound_statement (o
, f
->body
);
727 else outprintf (o
, '{', '}', -1);
730 /* Feature: dtors call dtors of dtorable members */
731 if (f
->is_destructor
) {
734 if ((dtn
= idtor (f
->object
))) {
735 make_intern_dtor (f
->object
);
736 outprintf (o
, dtn
, '(', R(this), ')', ';', -1);
738 outprintf (o
, RESERVED_return
, RESERVED_this
, ';', '}', -1);
739 if (objective
.recording
)
742 /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
744 /* Everybody's favorite addition */
746 outprintf (o
, BACKSPACE
, RESERVED_return
, RESERVED_0
, ';', '}', -1);
749 xmark_nothrow (objective
.yes
? FSP (f
->object
) : Global
, f
->cname
, f
->name
);
750 if (f
->is_destructor
) set_dtor_nothrow (f
->object
);
752 //PRINTF (COLS"%i"COLE"may_throw=%s\n", may_throw, expand (f->name));
753 close_local_scope ();
755 RESTOR_VAR (bt_macro
);
756 RESTOR_VAR (bt_replace
);
757 RESTOR_VAR (in_function
);
758 RESTOR_VAR (may_throw
);
761 if (f
->is_destructor
&& vdtor (f
->object
))
762 o
= dispatch_vdtor (f
->object
, o
);
767 static OUTSTREAM
do_function_catch (funcd
*f
)
769 SAVE_VAR (bt_macro
, bt_macro
);
770 SAVE_VAR (bt_replace
, bt_replace
);
771 SAVE_VAR (in_function
, in_function
);
772 SAVE_VAR (top_scope
, top_scope
);
773 SAVE_VAR (may_throw
, may_throw
);
778 set_catch (&ENV
, 0, 0, 1);
781 /* function has been skipped because it references pure typedef */
783 if (f
->is_destructor
&& idtor (f
->object
)) {
784 make_intern_dtor (f
->object
);
785 outprintf (INTERNAL_CODE
, ISTR (f
->dclstr
), '{', idtor (f
->object
), '(',
786 RESERVED_this
, ')', ';', RESERVED_return
, RESERVED_this
,
789 RESTOR_VAR (bt_macro
);
790 RESTOR_VAR (bt_replace
);
791 RESTOR_VAR (in_function
);
792 RESTOR_VAR (top_scope
);
793 RESTOR_VAR (may_throw
);
803 for (f
= definition
[DT_NORM
].first
; f
; f
= f
->next
)
805 concate_streams (FUNCDEFCODE
, do_function (f
));