2 /********************************************
4 copyright 1991, Michael D. Brennan
6 This is a source file for mawk, an implementation of
7 the AWK programming language.
9 Mawk is distributed without warranty under the terms of
10 the GNU General Public License, version 2, 1991.
11 ********************************************/
15 * Revision 1.7 1995/08/27 15:46:47 mike
16 * change some errmsgs to compile_errors
18 * Revision 1.6 1995/06/09 22:58:24 mike
19 * cast to shutup solaris cc on comparison of short to ushort
21 * Revision 1.5 1995/06/06 00:18:26 mike
22 * change mawk_exit(1) to mawk_exit(2)
24 * Revision 1.4 1995/04/21 14:20:14 mike
25 * move_level variable to fix bug in arglist patching of moved code.
27 * Revision 1.3 1995/02/19 22:15:37 mike
28 * Always set the call_offset field in a CA_REC (for obscure
29 * reasons in fcall.c (see comments) there.)
31 * Revision 1.2 1993/07/17 13:22:52 mike
32 * indent and general code cleanup
34 * Revision 1.1.1.1 1993/07/03 18:58:11 mike
37 * Revision 5.4 1993/01/09 19:03:44 mike
38 * code_pop checks if the resolve_list needs relocation
40 * Revision 5.3 1993/01/07 02:50:33 mike
41 * relative vs absolute code
43 * Revision 5.2 1993/01/01 21:30:48 mike
44 * split new_STRING() into new_STRING and new_STRING0
46 * Revision 5.1 1991/12/05 07:55:54 brennan
55 /* This file has functions involved with type checking of
59 static FCALL_REC *PROTO(first_pass, (FCALL_REC *)) ;
60 static CA_REC *PROTO(call_arg_check, (FBLOCK *, CA_REC *,
62 static int PROTO(arg_cnt_ok, (FBLOCK *, CA_REC *, unsigned)) ;
63 static void PROTO(relocate_arglist, (CA_REC *, int, unsigned, int)) ;
66 static int check_progress ;
67 /* flag that indicates call_arg_check() was able to type
68 check some call arguments */
70 /* type checks a list of call arguments,
71 returns a list of arguments whose type is still unknown
74 call_arg_check(callee, entry_list, start, line_no)
77 INST *start ; /* to locate patch */
78 unsigned line_no ; /* for error messages */
81 CA_REC *exit_list = (CA_REC *) 0 ;
88 if OK zfree(q) else put on exit_list */
89 while ((q = entry_list))
91 entry_list = q->link ;
93 if (q->type == ST_NONE)
95 /* try to infer the type */
96 /* it might now be in symbol table */
97 if (q->sym_p->type == ST_VAR)
99 /* set type and patch */
101 start[q->call_offset + 1].ptr = (PTR) q->sym_p->stval.cp ;
103 else if (q->sym_p->type == ST_ARRAY)
106 start[q->call_offset].op = A_PUSHA ;
107 start[q->call_offset + 1].ptr = (PTR) q->sym_p->stval.array ;
109 else /* try to infer from callee */
111 switch (callee->typev[q->arg_num])
115 q->sym_p->type = ST_VAR ;
116 q->sym_p->stval.cp = ZMALLOC(CELL) ;
117 q->sym_p->stval.cp->type = C_NOINIT ;
118 start[q->call_offset + 1].ptr =
119 (PTR) q->sym_p->stval.cp ;
124 q->sym_p->type = ST_ARRAY ;
125 q->sym_p->stval.array = new_ARRAY() ;
126 start[q->call_offset].op = A_PUSHA ;
127 start[q->call_offset + 1].ptr =
128 (PTR) q->sym_p->stval.array ;
133 else if (q->type == ST_LOCAL_NONE)
135 /* try to infer the type */
136 if (*q->type_p == ST_LOCAL_VAR)
138 /* set type , don't need to patch */
141 else if (*q->type_p == ST_LOCAL_ARRAY)
144 start[q->call_offset].op = LA_PUSHA ;
145 /* offset+1 op is OK */
147 else /* try to infer from callee */
149 switch (callee->typev[q->arg_num])
153 *q->type_p = ST_LOCAL_VAR ;
154 /* do not need to patch */
159 *q->type_p = ST_LOCAL_ARRAY ;
160 start[q->call_offset].op = LA_PUSHA ;
166 /* if we still do not know the type put on the new list
168 if (q->type == ST_NONE || q->type == ST_LOCAL_NONE)
170 q->link = exit_list ;
173 else /* type known */
175 if (callee->typev[q->arg_num] == ST_LOCAL_NONE)
176 callee->typev[q->arg_num] = q->type ;
177 else if (q->type != callee->typev[q->arg_num])
178 compile_error("type error in arg(%d) in call to %s",
179 q->arg_num + 1, callee->name) ;
191 arg_cnt_ok(fbp, q, line_no)
196 if ((int)q->arg_num >= (int)fbp->nargs)
197 /* casts shutup stupid warning from solaris sun cc */
199 compile_error("too many arguments in call to %s", fbp->name) ;
206 FCALL_REC *resolve_list ;
207 /* function calls whose arg types need checking
208 are stored on this list */
211 /* on first pass thru the resolve list
213 if forward referenced functions were really defined
214 if right number of arguments
215 and compute call_start which is now known
220 register FCALL_REC *p ;
223 register FCALL_REC *q = &dummy ; /* trails p */
228 if (!p->callee->code)
230 /* callee never defined */
231 compile_error("function %s never defined", p->callee->name) ;
232 /* delete p from list */
234 /* don't worry about freeing memory, we'll exit soon */
236 /* note p->arg_list starts with last argument */
237 else if (!p->arg_list /* nothing to do */ ||
238 (!p->arg_cnt_checked &&
239 !arg_cnt_ok(p->callee, p->arg_list, p->line_no)))
241 q->link = p->link ; /* delete p */
242 /* the ! arg_list case is not an error so free memory */
247 /* keep p and set call_start */
249 switch (p->call_scope)
252 p->call_start = main_start ;
256 p->call_start = begin_start ;
260 p->call_start = end_start ;
264 p->call_start = p->call->code ;
273 /* continuously walk the resolve_list making type deductions
274 until this list goes empty or no more progress can be made
275 (An example where no more progress can be made is at end of file
281 register FCALL_REC *p, *old_list, *new_list ;
282 int progress ; /* a flag */
284 old_list = first_pass(resolve_list) ;
285 new_list = (FCALL_REC *) 0 ;
293 old_list = new_list ;
294 if (!old_list /* nothing left */
295 || !progress /* can't do any more */ )
298 new_list = (FCALL_REC *) 0 ; progress = 0 ;
304 if ((p->arg_list = call_arg_check(p->callee, p->arg_list,
305 p->call_start, p->line_no)))
307 /* still have work to do , put on new_list */
308 progress |= check_progress ;
309 p->link = new_list ; new_list = p ;
320 /* the parser has just reduced a function call ;
321 the info needed to type check is passed in. If type checking
322 can not be done yet (most common reason -- function referenced
323 but not defined), a node is added to the resolve list.
326 check_fcall(callee, call_scope, move_level, call, arg_list, line_no)
338 /* forward reference to a function to be defined later */
339 p = ZMALLOC(FCALL_REC) ;
341 p->call_scope = call_scope ;
342 p->move_level = move_level ;
344 p->arg_list = arg_list ;
345 p->arg_cnt_checked = 0 ;
346 p->line_no = line_no ;
347 /* add to resolve list */
348 p->link = resolve_list ; resolve_list = p ;
350 else if (arg_list && arg_cnt_ok(callee, arg_list, line_no))
352 /* usually arg_list disappears here and all is well
353 otherwise add to resolve list */
355 if ((arg_list = call_arg_check(callee, arg_list,
356 code_base, line_no)))
358 p = ZMALLOC(FCALL_REC) ;
360 p->call_scope = call_scope ;
361 p->move_level = move_level ;
363 p->arg_list = arg_list ;
364 p->arg_cnt_checked = 1 ;
365 p->line_no = line_no ;
366 /* add to resolve list */
367 p->link = resolve_list ; resolve_list = p ;
373 /* code_pop() has just moved some code. If this code contains
374 a function call, it might need to be relocated on the
375 resolve list too. This function does it.
379 relocate_resolve_list(scope, move_level, fbp, orig_offset, len, delta)
385 int delta ; /* relocation distance */
387 FCALL_REC *p = resolve_list ;
391 if (scope == p->call_scope && move_level == p->move_level &&
392 (scope == SCOPE_FUNCT ? fbp == p->call : 1))
394 relocate_arglist(p->arg_list, orig_offset,
402 relocate_arglist(arg_list, offset, len, delta)
410 if (!arg_list) return ;
413 /* all nodes must be relocated or none, so test the
416 /* Note: call_offset is always set even for args that don't need to
417 be patched so that this check works. */
418 if ( p->call_offset < offset || p->call_offset >= offset + len )
421 /* relocate the whole list */
424 p->call_offset += delta ;
434 /* example where typing cannot progress
438 function f(x) { print NR }
440 # this is legal, does something useful, but absurdly written
441 # We have to design so this works