2 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
3 * See the copyright notice in the ACK home directory, in the file "Copyright".
5 * Author: Ceriel J.H. Jacobs
8 /* P A R S E T R E E W A L K E R */
10 /* $Id: walk.c,v 1.104 1996/06/06 07:47:00 ceriel Exp $ */
12 /* Routines to walk through parts of the parse tree, and generate
27 #include "strict3rd.h"
43 #include "bigresult.h"
44 #include "use_insert.h"
46 extern arith NewPtr();
47 extern arith NewInt();
48 extern arith TmpSpace();
55 struct withdesig *WithDesigs;
58 static t_type *func_type;
59 static t_node *priority;
62 static int RegisterMessage();
68 static int UseWarnings();
70 #define NO_EXIT_LABEL ((label) 0)
71 #define RETURN_LABEL ((label) 1)
77 LblWalkNode(lbl, nd, exit, reach)
81 /* Generate code for node "nd", after generating instruction
82 label "lbl". "exit" is the exit label for the closest
87 return WalkNode(nd, exit, reach);
95 /* For the time being (???), handle priorities by calls to
100 C_loc(priority->nd_INT);
101 CAL("stackprio", (int) word_size);
112 CAL("unstackprio", (int) word_size);
120 /* Instruction label definition. Forget about line number.
129 /* Generate line number information, if necessary.
134 #endif /* DBSYMTAB */
137 nd->nd_lineno != oldlineno) {
138 oldlineno = nd->nd_lineno;
139 if (! options['L']) C_lin((arith) nd->nd_lineno);
142 static int ms_lineno;
144 if (ms_lineno != nd->nd_lineno) {
145 ms_lineno = nd->nd_lineno;
146 C_ms_std((char *) 0, N_SLINE, ms_lineno);
149 #endif /* DBSYMTAB */
155 /* Generate filename information, when needed.
156 This routine is called at the generation of a
157 procedure entry, and after generating a call to
160 static label filename_label = 0;
162 oldlineno = 0; /* always invalidate remembered line number */
163 if (needed && ! options['L']) {
165 if (! filename_label) {
168 C_rom_scon(FileName, (arith) (strlen(FileName) + 1));
171 C_fil_dlb((label) 1, (arith) 0);
176 register t_def *module;
178 /* Walk through a module, and all its local definitions.
179 Also generate code for its body.
180 This code is collected in an initialization routine.
182 register t_scope *sc;
183 t_scopelist *savevis = CurrVis;
185 CurrVis = module->mod_vis;
186 priority = module->mod_priority;
189 /* Walk through it's local definitions
191 WalkDefList(sc->sc_def, WalkDef);
193 /* Now, generate initialization code for this module.
194 First call initialization routines for modules defined within
197 sc->sc_off = 0; /* no locals (yet) */
198 text_label = 1; /* label at end of initialization routine */
199 TmpOpen(sc); /* Initialize for temporaries */
200 C_pro_narg(sc->sc_name);
203 stb_string(module, D_MODULE);
204 WalkDefList(sc->sc_def, stabdef);
205 if (state == PROGRAM && module == Defined) {
206 C_ms_stb_cst(module->df_idf->id_text,
211 stb_string(module, D_END);
215 if (module == Defined) {
216 /* Body of implementation or program module.
217 Call initialization routines of imported modules.
218 Also prevent recursive calls of this one.
220 register t_node *nd = Modules;
222 if (state == IMPLEMENTATION) {
223 /* We don't actually prevent recursive calls,
224 but do nothing if called recursively
226 C_df_dlb(++data_label);
227 C_con_cst((arith) 0);
228 /* if this one is set to non-zero, the initialization
231 C_loe_dlb(data_label, (arith) 0);
233 C_ine_dlb(data_label, (arith) 0);
235 else if (! options['R']) {
236 /* put funny value in BSS, in an attempt to detect
237 uninitialized variables
242 for (; nd; nd = nd->nd_NEXT) {
243 C_cal(nd->nd_def->mod_vis->sc_scope->sc_name);
247 WalkDefList(sc->sc_def, MkCalls);
251 C_ms_std((char *) 0, N_LBRAC, gdb_flag ? 0 : proclevel);
253 #endif /* DBSYMTAB */
254 WalkNode(module->mod_body, NO_EXIT_LABEL, REACH_FLAG);
255 DO_DEBUG(options['X'], PrNode(module->mod_body, 0));
256 def_ilb(RETURN_LABEL);
261 C_ms_std((char *) 0, N_RBRAC, gdb_flag ? 0 : proclevel);
263 #endif /* DBSYMTAB */
269 WalkDefList(sc->sc_def, UseWarnings);
272 WalkProcedure(procedure)
273 register t_def *procedure;
275 /* Walk through the definition of a procedure and all its
276 local definitions, checking and generating code.
278 t_scopelist *savevis = CurrVis;
280 register t_param *param;
281 register t_scope *procscope = procedure->prc_vis->sc_scope;
282 label too_big = 0; /* returnsize larger than returnarea */
283 arith StackAdjustment = 0; /* space for conformant arrays */
284 arith retsav = 0; /* temporary space for return value */
285 arith func_res_size = 0;
287 int partno = C_getid();
288 int partno2 = C_getid();
295 CurrVis = procedure->prc_vis;
297 /* Generate code for all local modules and procedures
299 WalkDefList(procscope->sc_def, WalkDef);
301 func_type = tp = RemoveEqual(ResultType(procedure->df_type));
304 func_res_size = WA(tp->tp_size);
305 if (TooBigForReturnArea(tp)) {
306 #ifdef BIG_RESULT_ON_STACK
307 /* The result type of this procedure is too big.
308 The caller will have reserved space on its stack,
309 above the parameters, to store the result.
313 /* The result type of this procedure is too big.
314 The actual procedure will return a pointer to a
315 global data area in which the function result is
317 Notice that this makes the code non-reentrant.
318 Here, we create the data area for the function
321 too_big = ++data_label;
323 C_bss_cst(func_res_size, (arith)0, 0);
324 #endif /* BIG_RESULT_ON_STACK */
328 /* Generate code for this procedure
332 C_insertpart(partno2); /* procedure header */
334 C_pro_narg(procedure->prc_name);
337 stb_string(procedure, D_PROCEDURE);
338 WalkDefList(procscope->sc_def, stabdef);
339 stb_string(procedure, D_PEND);
340 C_ms_std((char *) 0, N_LBRAC, gdb_flag ? 0 : proclevel);
342 #endif /* DBSYMTAB */
343 C_ms_par(procedure->df_type->prc_nbpar
344 #ifdef BIG_RESULT_ON_STACK
345 + (too_big ? func_res_size : 0)
349 /* generate code for filename only when the procedure can be
350 exported, either directly or by taking the address.
351 This cannot be done if the level is bigger than one (because in
352 this case it is a nested procedure).
354 DoFilename(procscope->sc_level == 1);
357 text_label = 1; /* label at end of procedure */
359 /* Check if we must save the stack pointer */
360 for (param = ParamList(procedure->df_type);
362 param = param->par_next) {
363 if (! IsVarParam(param)) {
364 tp = TypeOfParam(param);
366 if ( IsConformantArray(tp)) {
367 /* First time we get here
369 if (func_type && !too_big) {
370 /* Some local space, only
371 needed if the value itself
374 retsav= TmpSpace(func_res_size, 1);
376 StackAdjustment = NewPtr();
378 STL(StackAdjustment, pointer_size);
384 C_insertpart(partno);
386 cd_init = ++text_label;
387 cd_body = ++text_label;
392 if ((WalkNode(procedure->prc_body, NO_EXIT_LABEL, REACH_FLAG) & REACH_FLAG)) {
394 node_warning(procscope->sc_end,
396 "function procedure \"%s\" does not always return a value",
397 procedure->df_idf->id_text);
400 C_asp(-func_res_size);
413 /* Generate calls to initialization routines of modules defined within
416 WalkDefList(procscope->sc_def, MkCalls);
418 /* Make sure that arguments of size < word_size are on a
420 Also make copies of parameters when neccessary.
422 for (param = ParamList(procedure->df_type);
424 param = param->par_next) {
425 if (! IsVarParam(param)) {
426 tp = TypeOfParam(param);
428 if (! IsConformantArray(tp)) {
429 if (tp->tp_size < word_size &&
430 (int) word_size % (int) tp->tp_size == 0) {
431 C_lol(param->par_def->var_off);
432 STL(param->par_def->var_off,
437 /* Here, we have to make a copy of the
438 array. We must also remember how much
439 room is reserved for copies, because
440 we have to adjust the stack pointer before
441 a RET is done. This is even more complicated
442 when the procedure returns a value.
443 Then, the value must be saved,
444 the stack adjusted, the return value pushed
447 /* First compute new stackpointer */
448 C_lal(param->par_def->var_off);
449 CAL("new_stackptr", (int)pointer_size);
452 /* adjusted stack pointer */
453 LOL(param->par_def->var_off, pointer_size);
454 /* push source address */
455 CAL("copy_array", (int)pointer_size);
464 DO_DEBUG(options['X'], PrNode(procedure->prc_body, 0));
465 def_ilb(RETURN_LABEL); /* label at end */
467 /* Fill the data area reserved for the function result
470 #ifdef BIG_RESULT_ON_STACK
471 C_lal(procedure->df_type->prc_nbpar);
474 #endif /* BIG_RESULT_ON_STACK */
475 C_sti(func_res_size);
476 if (StackAdjustment) {
477 /* Remove copies of conformant arrays
479 LOL(StackAdjustment, pointer_size);
482 #ifdef BIG_RESULT_ON_STACK
486 func_res_size = pointer_size;
487 #endif /* BIG_RESULT_ON_STACK */
489 else if (StackAdjustment) {
490 /* First save the function result in a safe place.
491 Then remove copies of conformant arrays,
492 and put function result back on the stack
495 STL(retsav, func_res_size);
497 LOL(StackAdjustment, pointer_size);
500 LOL(retsav, func_res_size);
504 C_ret(func_res_size);
506 C_beginpart(partno2);
507 C_pro(procedure->prc_name, -procscope->sc_off);
510 stb_string(procedure, D_PROCEDURE);
511 WalkDefList(procscope->sc_def, stabdef);
512 stb_string(procedure, D_PEND);
513 C_ms_std((char *) 0, N_LBRAC, gdb_flag ? 0 : proclevel);
515 #endif /* DBSYMTAB */
516 C_ms_par(procedure->df_type->prc_nbpar
517 #ifdef BIG_RESULT_ON_STACK
518 + (too_big ? func_res_size : 0)
522 if (! options['n']) WalkDefList(procscope->sc_def, RegisterMessage);
528 C_ms_std((char *) 0, N_RBRAC, gdb_flag ? 0 : proclevel);
530 #endif /* DBSYMTAB */
531 C_end(-procscope->sc_off);
532 if (! fit(procscope->sc_off, (int) word_size)) {
533 node_error(procedure->prc_body,
534 "maximum local byte count exceeded");
539 WalkDefList(procscope->sc_def, UseWarnings);
546 /* Walk through a list of definitions
549 switch(df->df_kind) {
557 if (!proclevel && !(df->df_flags & D_ADDRGIVEN)) {
558 C_df_dnam(df->var_name);
560 WA(df->df_type->tp_size),
574 /* Generate calls to initialization routines of modules
577 if (df->df_kind == D_MODULE) {
579 CAL(df->mod_vis->sc_scope->sc_name, (int)pointer_size);
583 WalkLink(nd, exit_label, end_reached)
587 /* Walk node "nd", which is a link.
588 "exit_label" is set to a label number when inside a LOOP.
589 "end_reached" maintains info about reachability (REACH_FLAG),
590 and whether an EXIT statement was seen (EXIT_FLAG).
593 while (nd && nd->nd_class == Link) { /* statement list */
594 end_reached = WalkNode(nd->nd_LEFT, exit_label, end_reached);
598 return WalkNode(nd, exit_label, end_reached);
605 register t_type *tp = nd->nd_type;
608 CodeCoercion(tp, BaseType(tp));
612 WalkStat(nd, exit_label, end_reached)
616 /* Walk through a statement, generating code for it.
618 register t_node *left = nd->nd_LEFT;
619 register t_node *right = nd->nd_RIGHT;
621 assert(nd->nd_class == Stat);
623 if (nd->nd_symb == ';') return 1;
625 if (! end_reached & REACH_FLAG) {
626 node_warning(nd, W_ORDINARY, "statement not reached");
628 if (nd->nd_symb != WHILE ||
629 nd->nd_lineno != left->nd_lineno) {
630 /* Avoid double linenumber generation in while statements */
633 options['R'] = (nd->nd_flags & ROPTION);
634 options['A'] = (nd->nd_flags & AOPTION);
635 switch(nd->nd_symb) {
640 if (nd->nd_type != 0) {
641 node_error(nd, "procedure call expected instead of function call");
654 { label l1 = ++text_label, l3 = ++text_label;
657 ExpectBool(&(nd->nd_LEFT), l3, l1);
658 assert(right->nd_symb == THEN);
659 end_r = LblWalkNode(l3, right->nd_LEFT, exit_label, end_reached);
661 if (right->nd_RIGHT) { /* ELSE part */
662 label l2 = ++text_label;
665 end_reached = end_r | LblWalkNode(l1, right->nd_RIGHT, exit_label, end_reached);
668 else end_reached |= end_r;
674 end_reached = CaseCode(nd, exit_label, end_reached);
678 { label loop = ++text_label,
680 dummy = ++text_label;
683 end_reached |= LblWalkNode(loop, right, exit_label, end_reached);
685 ExpectBool(&(nd->nd_LEFT), loop, exit);
691 { label loop = ++text_label, exit = ++text_label;
693 end_reached = LblWalkNode(loop, left, exit_label, end_reached);
694 ExpectBool(&(nd->nd_RIGHT), exit, loop);
700 { label loop = ++text_label, exit = ++text_label;
702 if (LblWalkNode(loop, right, exit, end_reached) & EXIT_FLAG) {
703 end_reached &= REACH_FLAG;
705 else end_reached = 0;
713 arith tmp = NewInt();
714 arith tmp2 = NewInt();
716 label l1 = ++text_label;
717 label l2 = ++text_label;
723 good_forvar = DoForInit(left);
724 loopid = left->nd_LEFT;
725 if ((stepsize = right->nd_LEFT->nd_INT) == 0) {
726 node_warning(right->nd_LEFT,
728 "zero stepsize in FOR loop");
731 bstp = BaseType(loopid->nd_type);
732 uns = bstp->tp_fund != T_INTEGER;
733 CodePExpr(left->nd_RIGHT->nd_RIGHT);
735 CodePExpr(left->nd_RIGHT->nd_LEFT);
739 if (uns) C_cmu(int_size);
740 else C_cmi(int_size);
741 if (stepsize >= 0) C_zgt(l2);
744 RangeCheck(loopid->nd_type,
745 left->nd_RIGHT->nd_LEFT->nd_type);
749 ForLoopVarExpr(loopid);
752 stepsize = -stepsize;
753 ForLoopVarExpr(loopid);
762 loopid->nd_def->df_flags |= D_FORLOOP;
764 if (! options['R']) {
765 ForLoopVarExpr(loopid);
768 end_reached |= WalkNode(right->nd_RIGHT, exit_label, end_reached);
769 if (! options['R']) {
770 label x = ++text_label;
772 ForLoopVarExpr(loopid);
778 loopid->nd_def->df_flags &= ~D_FORLOOP;
787 C_loc(right->nd_LEFT->nd_INT);
788 ForLoopVarExpr(loopid);
790 RangeCheck(loopid->nd_type, bstp);
795 end_reached |= WalkNode(right->nd_RIGHT, exit_label, end_reached);
796 loopid->nd_def->df_flags &= ~D_FORLOOP;
807 struct withdesig wds;
810 if (! WalkDesignator(&(nd->nd_LEFT), &ds, D_USED)) break;
812 if (left->nd_type->tp_fund != T_RECORD) {
813 node_error(left, "record variable expected");
817 wds.w_next = WithDesigs;
818 wds.w_flags = D_USED;
820 wds.w_scope = left->nd_type->rec_scope;
822 ds.dsg_kind = DSG_FIXED;
823 /* Create a designator structure for the temporary.
825 ds.dsg_offset = NewPtr();
827 CodeStore(&ds, address_type);
828 ds.dsg_kind = DSG_PFIXED;
829 /* the record is indirectly available */
831 link.sc_scope = wds.w_scope;
832 link.sc_next = CurrVis;
834 end_reached = WalkNode(right, exit_label, end_reached);
835 CurrVis = link.sc_next;
836 WithDesigs = wds.w_next;
837 FreePtr(ds.dsg_offset);
838 ChkDesig(&(nd->nd_LEFT), wds.w_flags & (D_USED|D_DEFINED));
843 assert(exit_label != 0);
845 if (end_reached & REACH_FLAG) end_reached = EXIT_FLAG;
850 end_reached &= ~REACH_FLAG;
852 if (! ChkExpression(&(nd->nd_RIGHT))) break;
853 /* The type of the return-expression must be
854 assignment compatible with the result type of the
855 function procedure (See Rep. 9.11).
857 if (!ChkAssCompat(&(nd->nd_RIGHT), func_type, "RETURN")) {
860 right = nd->nd_RIGHT;
861 if (right->nd_type->tp_fund == T_STRING) {
862 CodePString(right, func_type);
864 else CodePExpr(right);
875 extern int NodeCrash();
877 int (*WalkTable[])() = {
893 extern t_desig null_desig;
895 ExpectBool(pnd, true_label, false_label)
896 register t_node **pnd;
897 label true_label, false_label;
899 /* "pnd" must indicate a boolean expression. Check this and
900 generate code to evaluate the expression.
905 if (ChkExpression(pnd)) {
906 if ((*pnd)->nd_type != bool_type &&
907 (*pnd)->nd_type != error_type) {
908 node_error(*pnd, "boolean expression expected");
911 CodeExpr(*pnd, &ds, true_label, false_label);
916 WalkDesignator(pnd, ds, flags)
920 /* Check designator and generate code for it
923 if (! ChkVariable(pnd, flags)) return 0;
933 register t_node *right = nd->nd_RIGHT;
939 r = ChkVariable(&(nd->nd_LEFT), D_USED|D_DEFINED);
940 r &= ChkExpression(&(right->nd_LEFT));
941 r &= ChkExpression(&(right->nd_RIGHT));
944 df = nd->nd_LEFT->nd_def;
945 if (df->df_kind == D_FIELD) {
947 "FOR-loop variable may not be a field of a record");
951 if (!df->var_name && df->var_off >= 0) {
952 node_error(nd, "FOR-loop variable may not be a parameter");
956 if (df->df_scope != CurrentScope) {
957 register t_scopelist *sc = CurrVis;
962 "FOR-loop variable may not be imported");
965 if (sc->sc_scope == df->df_scope) break;
966 sc = nextvisible(sc);
970 if (df->df_type->tp_size > word_size ||
971 !(df->df_type->tp_fund & T_DISCRETE)) {
972 node_error(nd, "illegal type of FOR loop variable");
976 base_tp = BaseType(df->df_type);
977 tpl = right->nd_LEFT->nd_type;
978 tpr = right->nd_RIGHT->nd_type;
979 #ifndef STRICT_3RD_ED
980 if (! options['3']) {
981 if (!ChkAssCompat(&(right->nd_LEFT), base_tp, "FOR statement") ||
982 !ChkAssCompat(&(right->nd_RIGHT), base_tp, "FOR statement")) {
985 if (!TstCompat(df->df_type, tpl) ||
986 !TstCompat(df->df_type, tpr)) {
987 node_warning(nd, W_OLDFASHIONED, "compatibility required in FOR statement");
991 if (!ChkCompat(&(right->nd_LEFT), base_tp, "FOR statement") ||
992 !ChkCompat(&(right->nd_RIGHT), base_tp, "FOR statement")) {
1000 register t_node *nd;
1002 /* May we do it in this order (expression first) ???
1003 The reference manual sais nothing about it, but the book does:
1004 it sais that the left hand side is evaluated first.
1008 register t_type *tp;
1010 if (! (ChkExpression(&(nd->nd_RIGHT)) &
1011 ChkVariable(&(nd->nd_LEFT), D_DEFINED))) return;
1012 tp = nd->nd_LEFT->nd_type;
1014 if (! ChkAssCompat(&(nd->nd_RIGHT), tp, "assignment")) {
1019 #define StackNeededFor(ds) ((ds).dsg_kind == DSG_PLOADED \
1020 || (ds).dsg_kind == DSG_INDEXED)
1021 CodeExpr(nd->nd_RIGHT, &dsr, NO_LABEL, NO_LABEL);
1022 tp = nd->nd_RIGHT->nd_type;
1024 if (StackNeededFor(dsr)) CodeAddress(&dsr);
1027 CodeValue(&dsr, tp);
1029 CodeMove(&dsr, nd->nd_LEFT, tp);
1036 register t_type *tp;
1038 if (df->df_kind == D_VARIABLE) {
1039 if ( !(df->df_flags & D_NOREG)) {
1040 /* Examine type and size
1042 tp = BaseType(df->df_type);
1043 if ((df->df_flags & D_VARPAR) ||
1044 (tp->tp_fund&(T_POINTER|T_HIDDEN|T_EQUAL))) {
1045 C_ms_reg(df->var_off,
1050 else if (tp->tp_fund & T_NUMERIC) {
1051 C_ms_reg(df->var_off,
1053 tp->tp_fund == T_REAL ?
1054 reg_float : reg_any,
1062 df_warning(nd, df, warning)
1067 if (! (df->df_kind & (D_VARIABLE|D_PROCEDURE|D_TYPE|D_CONST|D_PROCHEAD))) {
1074 (df->df_flags & D_VALPAR) ? "value parameter" :
1075 (df->df_flags & D_VARPAR) ? "variable parameter" :
1076 (df->df_kind == D_VARIABLE) ? "variable" :
1077 (df->df_kind == D_TYPE) ? "type" :
1078 (df->df_kind == D_CONST) ? "constant" :
1080 df->df_idf->id_text, warning);
1088 t_node *nd = df->df_scope->sc_end;
1090 if (is_anon_idf(df->df_idf) ||
1091 !(df->df_kind&(D_IMPORTED|D_VARIABLE|D_PROCEDURE|D_CONST|D_TYPE)) ||
1092 (df->df_flags&(D_EXPORTED|D_QEXPORTED))) {
1096 if (df->df_kind & D_IMPORTED) {
1097 register t_def *df1 = df->imp_def;
1099 df1->df_flags |= df->df_flags & (D_USED|D_DEFINED);
1100 if (df->df_kind == D_INUSE) return;
1101 if ( !(df->df_flags & D_IMP_BY_EXP)) {
1102 if (df->df_flags & (D_USED | D_DEFINED)) {
1107 df1->df_kind == D_VARIABLE ?
1108 "imported but not used/assigned" :
1109 "imported but not used");
1113 nd = df->df_scope->sc_end;
1115 switch(df->df_flags & (D_USED|D_DEFINED|D_VALPAR|D_VARPAR)) {
1118 df_warning(nd, df,"never used/assigned");
1121 df_warning(nd, df,"never assigned");
1125 case D_DEFINED|D_VALPAR:
1126 df_warning(nd, df,"never used");
1131 WalkDefList(df, proc)
1135 for (; df; df = df->df_nextinscope) {
1145 switch(df->df_kind) {
1148 stb_string(df, df->df_kind);