ack/lang/m2/comp/walk.c

1193 lines
25 KiB
C
Raw Normal View History

/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*
* Author: Ceriel J.H. Jacobs
*/
1986-04-21 17:27:06 +00:00
/* P A R S E T R E E W A L K E R */
1994-06-24 14:02:31 +00:00
/* $Id$ */
1986-04-21 17:27:06 +00:00
/* Routines to walk through parts of the parse tree, and generate
code for these parts.
*/
2017-01-08 10:23:56 +00:00
#include <stdlib.h>
#include <string.h>
#include "parameters.h"
2017-01-08 10:23:56 +00:00
#include "debug.h"
#include <em_arith.h>
#include <em_label.h>
#include <em_reg.h>
#include <em_code.h>
#include <m2_traps.h>
#include <assert.h>
#include <alloc.h>
#include <stb.h>
#include "LLlex.h"
#include "def.h"
#include "type.h"
#include "scope.h"
#include "main.h"
#include "node.h"
#include "Lpars.h"
#include "desig.h"
#include "typequiv.h"
2017-01-08 10:23:56 +00:00
#include "f_info.h"
#include "idf.h"
#include "chk_expr.h"
#include "walk.h"
#include "misc.h"
#include "error.h"
#include "tmpvar.h"
#include "stab.h"
#include "code.h"
2017-01-08 10:23:56 +00:00
#include "warning.h"
int CaseCode(struct node *, label, int);
2017-01-08 10:23:56 +00:00
extern int proclevel;
extern int gdb_flag;
label text_label;
label data_label = 1;
struct withdesig* WithDesigs;
struct node* Modules;
2017-01-08 10:23:56 +00:00
static struct type* func_type;
static struct node* priority;
2017-01-08 10:23:56 +00:00
static int oldlineno;
2017-01-08 10:23:56 +00:00
#define NO_EXIT_LABEL ((label)0)
#define RETURN_LABEL ((label)1)
1986-09-25 19:39:06 +00:00
2017-01-08 10:23:56 +00:00
#define REACH_FLAG 1
#define EXIT_FLAG 2
/* Forward declarations. */
static void WalkDef(register struct def*);
static void MkCalls(register struct def*);
static void UseWarnings(register struct def*);
static void RegisterMessage(register struct def*);
static void WalkDefList(register struct def*, void (*proc)(struct def*));
#ifdef DBSYMTAB
static void stabdef(struct def*);
#endif
int LblWalkNode(label lbl, struct node *nd, int exit, int reach)
{
/* Generate code for node "nd", after generating instruction
label "lbl". "exit" is the exit label for the closest
enclosing LOOP.
*/
def_ilb(lbl);
return WalkNode(nd, exit, reach);
}
1988-03-23 17:44:25 +00:00
static arith tmpprio;
static void DoPriority(void)
1986-12-01 10:06:53 +00:00
{
/* For the time being (???), handle priorities by calls to
the runtime system
*/
2017-01-08 10:23:56 +00:00
if (priority)
{
1988-03-23 17:44:25 +00:00
tmpprio = NewInt();
C_loc(priority->nd_INT);
2017-01-08 10:23:56 +00:00
CAL("stackprio", (int)word_size);
1988-03-23 17:44:25 +00:00
C_lfr(word_size);
C_stl(tmpprio);
1986-12-01 10:06:53 +00:00
}
}
static void EndPriority(void)
1986-12-01 10:06:53 +00:00
{
2017-01-08 10:23:56 +00:00
if (priority)
{
1988-03-23 17:44:25 +00:00
C_lol(tmpprio);
2017-01-08 10:23:56 +00:00
CAL("unstackprio", (int)word_size);
1988-03-23 17:44:25 +00:00
FreeInt(tmpprio);
1986-12-01 10:06:53 +00:00
}
}
void def_ilb(label l)
{
/* Instruction label definition. Forget about line number.
*/
C_df_ilb(l);
oldlineno = 0;
}
void DoLineno(register struct node* nd)
{
2017-01-08 10:23:56 +00:00
if ((!options['L']
1991-03-13 13:49:56 +00:00
#ifdef DBSYMTAB
2017-01-08 10:23:56 +00:00
|| options['g']
1991-03-13 13:49:56 +00:00
#endif /* DBSYMTAB */
2017-01-08 10:23:56 +00:00
)
&& nd->nd_lineno && nd->nd_lineno != oldlineno)
{
oldlineno = nd->nd_lineno;
2017-01-08 10:23:56 +00:00
if (!options['L'])
C_lin((arith)nd->nd_lineno);
#ifdef DBSYMTAB
2017-01-08 10:23:56 +00:00
if (options['g'])
{
static int ms_lineno;
1990-07-30 15:56:25 +00:00
2017-01-08 10:23:56 +00:00
if (ms_lineno != nd->nd_lineno)
{
1990-07-30 15:56:25 +00:00
ms_lineno = nd->nd_lineno;
2017-01-08 10:23:56 +00:00
C_ms_std((char*)0, N_SLINE, ms_lineno);
1990-07-30 15:56:25 +00:00
}
}
#endif /* DBSYMTAB */
}
}
void DoFilename(int needed)
1986-05-23 09:46:31 +00:00
{
2017-01-08 10:23:56 +00:00
static label filename_label = 0;
1986-05-23 09:46:31 +00:00
2017-01-08 10:23:56 +00:00
oldlineno = 0; /* always invalidate remembered line number */
if (needed && !options['L'])
{
1986-11-26 16:40:45 +00:00
2017-01-08 10:23:56 +00:00
if (!filename_label)
{
filename_label = 1;
2017-01-08 10:23:56 +00:00
C_df_dlb((label)1);
C_rom_scon(FileName, (arith)(strlen(FileName) + 1));
1986-05-23 09:46:31 +00:00
}
2017-01-08 10:23:56 +00:00
C_fil_dlb((label)1, (arith)0);
1986-05-23 09:46:31 +00:00
}
}
void WalkModule(register struct def* module)
1986-04-21 17:27:06 +00:00
{
register struct scope* sc;
struct scopelist* savevis = CurrVis;
1986-04-21 17:27:06 +00:00
1986-04-28 18:06:58 +00:00
CurrVis = module->mod_vis;
priority = module->mod_priority;
1986-05-23 19:25:21 +00:00
sc = CurrentScope;
1986-04-22 22:36:16 +00:00
1986-06-26 09:39:36 +00:00
/* Walk through it's local definitions
1986-04-21 17:27:06 +00:00
*/
WalkDefList(sc->sc_def, WalkDef);
1986-04-21 17:27:06 +00:00
/* Now, generate initialization code for this module.
First call initialization routines for modules defined within
this module.
*/
2017-01-08 10:23:56 +00:00
sc->sc_off = 0; /* no locals (yet) */
text_label = 1; /* label at end of initialization routine */
TmpOpen(sc); /* Initialize for temporaries */
1986-06-26 09:39:36 +00:00
C_pro_narg(sc->sc_name);
#ifdef DBSYMTAB
2017-01-08 10:23:56 +00:00
if (options['g'])
{
stb_string(module, D_MODULE);
WalkDefList(sc->sc_def, stabdef);
2017-01-08 10:23:56 +00:00
if (state == PROGRAM && module == Defined)
{
C_ms_stb_cst(module->df_idf->id_text,
2017-01-08 10:23:56 +00:00
N_MAIN,
0,
(arith)0);
}
stb_string(module, D_END);
}
#endif
1986-12-01 10:06:53 +00:00
DoPriority();
2017-01-08 10:23:56 +00:00
if (module == Defined)
{
1986-05-28 18:36:51 +00:00
/* Body of implementation or program module.
Call initialization routines of imported modules.
Also prevent recursive calls of this one.
*/
register struct node* nd = Modules;
1986-05-28 18:36:51 +00:00
2017-01-08 10:23:56 +00:00
if (state == IMPLEMENTATION)
{
/* We don't actually prevent recursive calls,
1986-06-04 09:01:48 +00:00
but do nothing if called recursively
*/
1987-05-18 15:57:33 +00:00
C_df_dlb(++data_label);
2017-01-08 10:23:56 +00:00
C_con_cst((arith)0);
1986-09-25 19:39:06 +00:00
/* if this one is set to non-zero, the initialization
was already done.
*/
2017-01-08 10:23:56 +00:00
C_loe_dlb(data_label, (arith)0);
1986-09-25 19:39:06 +00:00
C_zne(RETURN_LABEL);
2017-01-08 10:23:56 +00:00
C_ine_dlb(data_label, (arith)0);
1986-06-04 09:01:48 +00:00
}
2017-01-08 10:23:56 +00:00
else if (!options['R'])
{
/* put funny value in BSS, in an attempt to detect
uninitialized variables
*/
C_cal("killbss");
}
1986-05-28 18:36:51 +00:00
2017-01-08 10:23:56 +00:00
for (; nd; nd = nd->nd_NEXT)
{
1988-03-23 17:44:25 +00:00
C_cal(nd->nd_def->mod_vis->sc_scope->sc_name);
1986-05-28 18:36:51 +00:00
}
1988-10-25 17:43:19 +00:00
DoFilename(1);
1986-05-28 18:36:51 +00:00
}
WalkDefList(sc->sc_def, MkCalls);
1986-05-28 18:36:51 +00:00
proclevel++;
#ifdef DBSYMTAB
2017-01-08 10:23:56 +00:00
if (options['g'])
{
C_ms_std((char*)0, N_LBRAC, gdb_flag ? 0 : proclevel);
1990-07-30 15:56:25 +00:00
}
#endif /* DBSYMTAB */
WalkNode(module->mod_body, NO_EXIT_LABEL, REACH_FLAG);
DO_DEBUG(options['X'], PrNode(module->mod_body, 0));
def_ilb(RETURN_LABEL);
1986-12-01 10:06:53 +00:00
EndPriority();
2017-01-08 10:23:56 +00:00
C_ret((arith)0);
#ifdef DBSYMTAB
2017-01-08 10:23:56 +00:00
if (options['g'])
{
C_ms_std((char*)0, N_RBRAC, gdb_flag ? 0 : proclevel);
1990-07-30 15:56:25 +00:00
}
#endif /* DBSYMTAB */
1986-05-23 19:25:21 +00:00
C_end(-sc->sc_off);
1986-05-28 18:36:51 +00:00
proclevel--;
1986-05-23 09:46:31 +00:00
TmpClose();
1986-04-21 17:27:06 +00:00
1986-06-26 09:39:36 +00:00
CurrVis = savevis;
WalkDefList(sc->sc_def, UseWarnings);
1986-04-21 17:27:06 +00:00
}
void WalkProcedure(register struct def* procedure)
1986-04-21 17:27:06 +00:00
{
struct scopelist* savevis = CurrVis;
register struct type* tp;
register struct paramlist* param;
register struct scope* procscope = procedure->prc_vis->sc_scope;
2017-01-08 10:23:56 +00:00
label too_big = 0; /* returnsize larger than returnarea */
arith StackAdjustment = 0; /* space for conformant arrays */
arith retsav = 0; /* temporary space for return value */
1986-09-25 19:39:06 +00:00
arith func_res_size = 0;
#ifdef USE_INSERT
int partno = C_getid();
int partno2 = C_getid();
#else
label cd_init;
label cd_body;
#endif
1986-04-21 17:27:06 +00:00
1986-05-16 17:15:36 +00:00
proclevel++;
1986-04-28 18:06:58 +00:00
CurrVis = procedure->prc_vis;
1986-06-26 09:39:36 +00:00
1986-06-20 14:36:49 +00:00
/* Generate code for all local modules and procedures
*/
WalkDefList(procscope->sc_def, WalkDef);
1986-04-21 17:27:06 +00:00
func_type = tp = RemoveEqual(ResultType(procedure->df_type));
2017-01-08 10:23:56 +00:00
if (tp)
{
func_res_size = WA(tp->tp_size);
2017-01-08 10:23:56 +00:00
if (TooBigForReturnArea(tp))
{
#ifdef BIG_RESULT_ON_STACK
/* The result type of this procedure is too big.
The caller will have reserved space on its stack,
above the parameters, to store the result.
*/
too_big = 1;
#else
/* The result type of this procedure is too big.
The actual procedure will return a pointer to a
global data area in which the function result is
stored.
Notice that this makes the code non-reentrant.
Here, we create the data area for the function
result.
*/
too_big = ++data_label;
C_df_dlb(too_big);
C_bss_cst(func_res_size, (arith)0, 0);
#endif /* BIG_RESULT_ON_STACK */
}
}
1986-04-21 17:27:06 +00:00
/* Generate code for this procedure
*/
TmpOpen(procscope);
#ifdef USE_INSERT
2017-01-08 10:23:56 +00:00
C_insertpart(partno2); /* procedure header */
#else
1991-03-13 13:49:56 +00:00
C_pro_narg(procedure->prc_name);
#ifdef DBSYMTAB
2017-01-08 10:23:56 +00:00
if (options['g'])
{
stb_string(procedure, D_PROCEDURE);
WalkDefList(procscope->sc_def, stabdef);
stb_string(procedure, D_PEND);
2017-01-08 10:23:56 +00:00
C_ms_std((char*)0, N_LBRAC, gdb_flag ? 0 : proclevel);
}
#endif /* DBSYMTAB */
C_ms_par(procedure->df_type->prc_nbpar
#ifdef BIG_RESULT_ON_STACK
2017-01-08 10:23:56 +00:00
+ (too_big ? func_res_size : 0)
#endif
2017-01-08 10:23:56 +00:00
);
#endif
/* generate code for filename only when the procedure can be
exported, either directly or by taking the address.
This cannot be done if the level is bigger than one (because in
this case it is a nested procedure).
*/
DoFilename(procscope->sc_level == 1);
DoPriority();
2017-01-08 10:23:56 +00:00
text_label = 1; /* label at end of procedure */
/* Check if we must save the stack pointer */
for (param = ParamList(procedure->df_type);
param;
2017-01-08 10:23:56 +00:00
param = param->par_next)
{
if (!IsVarParam(param))
{
tp = TypeOfParam(param);
2017-01-08 10:23:56 +00:00
if (IsConformantArray(tp))
{
/* First time we get here
*/
2017-01-08 10:23:56 +00:00
if (func_type && !too_big)
{
/* Some local space, only
needed if the value itself
is returned
*/
2017-01-08 10:23:56 +00:00
retsav = TmpSpace(func_res_size, 1);
}
StackAdjustment = NewPtr();
2017-01-08 10:23:56 +00:00
C_lor((arith)1);
STL(StackAdjustment, pointer_size);
}
}
}
#ifdef USE_INSERT
C_insertpart(partno);
#else
cd_init = ++text_label;
cd_body = ++text_label;
1993-11-19 09:53:47 +00:00
c_bra(cd_init);
def_ilb(cd_body);
#endif
2017-01-08 10:23:56 +00:00
if ((WalkNode(procedure->prc_body, NO_EXIT_LABEL, REACH_FLAG) & REACH_FLAG))
{
if (func_res_size)
{
node_warning(procscope->sc_end,
2017-01-08 10:23:56 +00:00
W_ORDINARY,
"function procedure \"%s\" does not always return a value",
procedure->df_idf->id_text);
c_loc(M2_NORESULT);
C_trp();
C_asp(-func_res_size);
}
#ifndef USE_INSERT
1993-11-19 09:53:47 +00:00
c_bra(RETURN_LABEL);
#endif
}
#ifdef USE_INSERT
C_beginpart(partno);
#else
def_ilb(cd_init);
#endif
1986-06-20 14:36:49 +00:00
/* Generate calls to initialization routines of modules defined within
1986-04-21 17:27:06 +00:00
this procedure
*/
WalkDefList(procscope->sc_def, MkCalls);
1986-06-20 14:36:49 +00:00
/* Make sure that arguments of size < word_size are on a
fixed place.
Also make copies of parameters when neccessary.
1986-06-20 14:36:49 +00:00
*/
for (param = ParamList(procedure->df_type);
param;
2017-01-08 10:23:56 +00:00
param = param->par_next)
{
if (!IsVarParam(param))
{
tp = TypeOfParam(param);
1986-06-20 14:36:49 +00:00
2017-01-08 10:23:56 +00:00
if (!IsConformantArray(tp))
{
if (tp->tp_size < word_size && (int)word_size % (int)tp->tp_size == 0)
{
1986-08-26 14:33:24 +00:00
C_lol(param->par_def->var_off);
STL(param->par_def->var_off,
tp->tp_size);
1986-08-26 14:33:24 +00:00
}
continue;
1986-08-26 14:33:24 +00:00
}
1991-03-13 13:49:56 +00:00
/* Here, we have to make a copy of the
array. We must also remember how much
room is reserved for copies, because
we have to adjust the stack pointer before
a RET is done. This is even more complicated
when the procedure returns a value.
Then, the value must be saved,
the stack adjusted, the return value pushed
again, and then RET
*/
/* First compute new stackpointer */
C_lal(param->par_def->var_off);
CAL("new_stackptr", (int)pointer_size);
C_lfr(pointer_size);
C_ass(pointer_size);
2017-01-08 10:23:56 +00:00
/* adjusted stack pointer */
1991-03-13 13:49:56 +00:00
LOL(param->par_def->var_off, pointer_size);
2017-01-08 10:23:56 +00:00
/* push source address */
1991-03-13 13:49:56 +00:00
CAL("copy_array", (int)pointer_size);
2017-01-08 10:23:56 +00:00
/* copy */
1986-06-20 14:36:49 +00:00
}
1986-05-28 18:36:51 +00:00
}
#ifdef USE_INSERT
C_endpart(partno);
#else
1993-11-19 09:53:47 +00:00
c_bra(cd_body);
#endif
DO_DEBUG(options['X'], PrNode(procedure->prc_body, 0));
2017-01-08 10:23:56 +00:00
def_ilb(RETURN_LABEL); /* label at end */
if (too_big)
{
/* Fill the data area reserved for the function result
1986-09-25 19:39:06 +00:00
with the result
*/
#ifdef BIG_RESULT_ON_STACK
C_lal(procedure->df_type->prc_nbpar);
#else
c_lae_dlb(too_big);
#endif /* BIG_RESULT_ON_STACK */
1987-07-13 10:30:37 +00:00
C_sti(func_res_size);
2017-01-08 10:23:56 +00:00
if (StackAdjustment)
{
1986-09-25 19:39:06 +00:00
/* Remove copies of conformant arrays
*/
1988-03-22 17:54:01 +00:00
LOL(StackAdjustment, pointer_size);
2017-01-08 10:23:56 +00:00
C_str((arith)1);
1986-05-14 09:03:51 +00:00
}
#ifdef BIG_RESULT_ON_STACK
func_res_size = 0;
#else
c_lae_dlb(too_big);
func_res_size = pointer_size;
#endif /* BIG_RESULT_ON_STACK */
1986-05-14 09:03:51 +00:00
}
2017-01-08 10:23:56 +00:00
else if (StackAdjustment)
{
1987-06-23 17:12:25 +00:00
/* First save the function result in a safe place.
Then remove copies of conformant arrays,
and put function result back on the stack
*/
2017-01-08 10:23:56 +00:00
if (func_type)
{
1988-03-22 17:54:01 +00:00
STL(retsav, func_res_size);
1987-06-23 17:12:25 +00:00
}
1988-03-22 17:54:01 +00:00
LOL(StackAdjustment, pointer_size);
2017-01-08 10:23:56 +00:00
C_str((arith)1);
if (func_type)
{
1988-03-22 17:54:01 +00:00
LOL(retsav, func_res_size);
1986-08-26 14:33:24 +00:00
}
}
1987-06-23 17:12:25 +00:00
EndPriority();
C_ret(func_res_size);
#ifdef USE_INSERT
C_beginpart(partno2);
1991-03-13 13:49:56 +00:00
C_pro(procedure->prc_name, -procscope->sc_off);
#ifdef DBSYMTAB
2017-01-08 10:23:56 +00:00
if (options['g'])
{
stb_string(procedure, D_PROCEDURE);
WalkDefList(procscope->sc_def, stabdef);
stb_string(procedure, D_PEND);
2017-01-08 10:23:56 +00:00
C_ms_std((char*)0, N_LBRAC, gdb_flag ? 0 : proclevel);
1990-07-30 15:56:25 +00:00
}
#endif /* DBSYMTAB */
C_ms_par(procedure->df_type->prc_nbpar
#ifdef BIG_RESULT_ON_STACK
2017-01-08 10:23:56 +00:00
+ (too_big ? func_res_size : 0)
#endif
2017-01-08 10:23:56 +00:00
);
#endif
2017-01-08 10:23:56 +00:00
if (!options['n'])
WalkDefList(procscope->sc_def, RegisterMessage);
#ifdef USE_INSERT
C_endpart(partno2);
#endif
#ifdef DBSYMTAB
2017-01-08 10:23:56 +00:00
if (options['g'])
{
C_ms_std((char*)0, N_RBRAC, gdb_flag ? 0 : proclevel);
1990-07-30 15:56:25 +00:00
}
#endif /* DBSYMTAB */
C_end(-procscope->sc_off);
2017-01-08 10:23:56 +00:00
if (!fit(procscope->sc_off, (int)word_size))
{
node_error(procedure->prc_body,
2017-01-08 10:23:56 +00:00
"maximum local byte count exceeded");
1987-11-24 14:21:35 +00:00
}
1986-05-23 09:46:31 +00:00
TmpClose();
1986-06-20 14:36:49 +00:00
CurrVis = savevis;
1986-05-16 17:15:36 +00:00
proclevel--;
WalkDefList(procscope->sc_def, UseWarnings);
1986-04-21 17:27:06 +00:00
}
/* Walk through a list of definitions */
static void WalkDef(register struct def* df)
1986-04-21 17:27:06 +00:00
{
1986-04-28 18:06:58 +00:00
2017-01-08 10:23:56 +00:00
switch (df->df_kind)
{
case D_MODULE:
WalkModule(df);
break;
case D_PROCEDURE:
WalkProcedure(df);
break;
case D_VARIABLE:
if (!proclevel && !(df->df_flags & D_ADDRGIVEN))
{
C_df_dnam(df->var_name);
C_bss_cst(
WA(df->df_type->tp_size),
(arith)0, 0);
}
break;
default:
/* nothing */
;
1986-04-21 17:27:06 +00:00
}
}
/* Generate calls to initialization routines of modules */
static void MkCalls(register struct def* df)
1986-04-21 17:27:06 +00:00
{
1986-04-28 18:06:58 +00:00
2017-01-08 10:23:56 +00:00
if (df->df_kind == D_MODULE)
{
C_lxl((arith)0);
CAL(df->mod_vis->sc_scope->sc_name, (int)pointer_size);
1986-04-21 17:27:06 +00:00
}
}
int WalkLink(register struct node* nd, label exit_label, int end_reached)
1986-04-21 17:27:06 +00:00
{
1986-04-28 18:06:58 +00:00
2017-01-08 10:23:56 +00:00
while (nd && nd->nd_class == Link)
{ /* statement list */
end_reached = WalkNode(nd->nd_LEFT, exit_label, end_reached);
nd = nd->nd_RIGHT;
1986-04-22 22:36:16 +00:00
}
return WalkNode(nd, exit_label, end_reached);
1986-06-20 14:36:49 +00:00
}
static void ForLoopVarExpr(register struct node* nd)
{
register struct type* tp = nd->nd_type;
CodePExpr(nd);
CodeCoercion(tp, BaseType(tp));
}
int WalkStat(register struct node* nd, label exit_label, int end_reached)
1986-04-22 22:36:16 +00:00
{
register struct node* left = nd->nd_LEFT;
register struct node* right = nd->nd_RIGHT;
1986-05-23 09:46:31 +00:00
1986-04-22 22:36:16 +00:00
assert(nd->nd_class == Stat);
2017-01-08 10:23:56 +00:00
if (nd->nd_symb == ';')
return 1;
2017-01-08 10:23:56 +00:00
if (!end_reached & REACH_FLAG)
{
node_warning(nd, W_ORDINARY, "statement not reached");
}
2017-01-08 10:23:56 +00:00
if (nd->nd_symb != WHILE || nd->nd_lineno != left->nd_lineno)
{
/* Avoid double linenumber generation in while statements */
DoLineno(nd);
}
1988-03-23 17:44:25 +00:00
options['R'] = (nd->nd_flags & ROPTION);
options['A'] = (nd->nd_flags & AOPTION);
2017-01-08 10:23:56 +00:00
switch (nd->nd_symb)
{
case '(':
{
struct node* nd1 = nd;
2017-01-08 10:23:56 +00:00
if (ChkCall(&nd1))
{
assert(nd == nd1);
if (nd->nd_type != 0)
{
node_error(nd, "only proper procedures can be called from top-level "
"statement; this is a function procedure");
2017-01-08 10:23:56 +00:00
break;
}
CodeCall(nd);
}
}
break;
2017-01-08 10:23:56 +00:00
case BECOMES:
DoAssign(nd);
break;
1986-04-22 22:36:16 +00:00
2017-01-08 10:23:56 +00:00
case IF:
{
label l1 = ++text_label, l3 = ++text_label;
int end_r;
1986-04-22 22:36:16 +00:00
ExpectBool(&(nd->nd_LEFT), l3, l1);
1986-04-22 22:36:16 +00:00
assert(right->nd_symb == THEN);
end_r = LblWalkNode(l3, right->nd_LEFT, exit_label, end_reached);
1986-04-22 22:36:16 +00:00
2017-01-08 10:23:56 +00:00
if (right->nd_RIGHT)
{ /* ELSE part */
1986-10-06 20:36:30 +00:00
label l2 = ++text_label;
1993-11-19 09:53:47 +00:00
c_bra(l2);
end_reached = end_r | LblWalkNode(l1, right->nd_RIGHT, exit_label, end_reached);
l1 = l2;
1986-04-22 22:36:16 +00:00
}
2017-01-08 10:23:56 +00:00
else
end_reached |= end_r;
def_ilb(l1);
1986-04-22 22:36:16 +00:00
break;
}
2017-01-08 10:23:56 +00:00
case CASE:
end_reached = CaseCode(nd, exit_label, end_reached);
break;
1986-04-22 22:36:16 +00:00
2017-01-08 10:23:56 +00:00
case WHILE:
{
label loop = ++text_label,
exit = ++text_label,
dummy = ++text_label;
1986-04-22 22:36:16 +00:00
1993-11-19 09:53:47 +00:00
c_bra(dummy);
end_reached |= LblWalkNode(loop, right, exit_label, end_reached);
def_ilb(dummy);
ExpectBool(&(nd->nd_LEFT), loop, exit);
def_ilb(exit);
1986-04-22 22:36:16 +00:00
break;
}
2017-01-08 10:23:56 +00:00
case REPEAT:
{
label loop = ++text_label, exit = ++text_label;
1986-04-22 22:36:16 +00:00
end_reached = LblWalkNode(loop, left, exit_label, end_reached);
ExpectBool(&(nd->nd_RIGHT), exit, loop);
def_ilb(exit);
1986-04-22 22:36:16 +00:00
break;
}
2017-01-08 10:23:56 +00:00
case LOOP:
{
label loop = ++text_label, exit = ++text_label;
1986-04-22 22:36:16 +00:00
2017-01-08 10:23:56 +00:00
if (LblWalkNode(loop, right, exit, end_reached) & EXIT_FLAG)
{
end_reached &= REACH_FLAG;
}
2017-01-08 10:23:56 +00:00
else
end_reached = 0;
1993-11-19 09:53:47 +00:00
c_bra(loop);
def_ilb(exit);
1986-04-22 22:36:16 +00:00
break;
}
2017-01-08 10:23:56 +00:00
case FOR:
1986-05-28 18:36:51 +00:00
{
1987-09-14 11:24:12 +00:00
arith tmp = NewInt();
arith tmp2 = NewInt();
1986-11-26 16:40:45 +00:00
int good_forvar;
1986-06-20 14:36:49 +00:00
label l1 = ++text_label;
label l2 = ++text_label;
int uns = 0;
1987-08-10 13:01:54 +00:00
arith stepsize;
struct type* bstp;
struct node* loopid;
1986-05-28 18:36:51 +00:00
good_forvar = DoForInit(left);
loopid = left->nd_LEFT;
2017-01-08 10:23:56 +00:00
if ((stepsize = right->nd_LEFT->nd_INT) == 0)
{
node_warning(right->nd_LEFT,
2017-01-08 10:23:56 +00:00
W_ORDINARY,
"zero stepsize in FOR loop");
1987-08-10 13:01:54 +00:00
}
2017-01-08 10:23:56 +00:00
if (good_forvar)
{
bstp = BaseType(loopid->nd_type);
uns = bstp->tp_fund != T_INTEGER;
CodePExpr(left->nd_RIGHT->nd_RIGHT);
1987-08-10 13:01:54 +00:00
C_stl(tmp);
CodePExpr(left->nd_RIGHT->nd_LEFT);
1988-11-04 10:24:34 +00:00
C_dup(int_size);
C_stl(tmp2);
1987-08-10 13:01:54 +00:00
C_lol(tmp);
2017-01-08 10:23:56 +00:00
if (uns)
C_cmu(int_size);
else
C_cmi(int_size);
if (stepsize >= 0)
C_zgt(l2);
else
C_zlt(l2);
C_lol(tmp2);
RangeCheck(loopid->nd_type,
2017-01-08 10:23:56 +00:00
left->nd_RIGHT->nd_LEFT->nd_type);
CodeDStore(loopid);
2017-01-08 10:23:56 +00:00
if (stepsize >= 0)
{
C_lol(tmp);
ForLoopVarExpr(loopid);
}
2017-01-08 10:23:56 +00:00
else
{
stepsize = -stepsize;
ForLoopVarExpr(loopid);
C_lol(tmp);
1987-08-10 13:01:54 +00:00
}
C_sbu(int_size);
2017-01-08 10:23:56 +00:00
if (stepsize)
{
1987-08-10 13:01:54 +00:00
C_loc(stepsize);
C_dvu(int_size);
}
C_stl(tmp);
loopid->nd_def->df_flags |= D_FORLOOP;
def_ilb(l1);
2017-01-08 10:23:56 +00:00
if (!options['R'])
{
ForLoopVarExpr(loopid);
1987-09-14 12:41:08 +00:00
C_stl(tmp2);
1991-03-13 13:49:56 +00:00
}
end_reached |= WalkNode(right->nd_RIGHT, exit_label, end_reached);
2017-01-08 10:23:56 +00:00
if (!options['R'])
{
1991-03-13 13:49:56 +00:00
label x = ++text_label;
1987-09-14 12:41:08 +00:00
C_lol(tmp2);
ForLoopVarExpr(loopid);
1987-11-09 10:17:20 +00:00
C_beq(x);
c_loc(M2_FORCH);
C_trp();
def_ilb(x);
1987-09-14 12:41:08 +00:00
}
loopid->nd_def->df_flags &= ~D_FORLOOP;
FreeInt(tmp2);
2017-01-08 10:23:56 +00:00
if (stepsize)
{
1987-09-14 12:41:08 +00:00
C_lol(tmp);
C_zeq(l2);
C_lol(tmp);
c_loc(1);
1987-09-14 12:41:08 +00:00
C_sbu(int_size);
C_stl(tmp);
C_loc(right->nd_LEFT->nd_INT);
ForLoopVarExpr(loopid);
1987-09-14 12:41:08 +00:00
C_adu(int_size);
RangeCheck(loopid->nd_type, bstp);
CodeDStore(loopid);
1987-09-14 12:41:08 +00:00
}
1986-11-26 16:40:45 +00:00
}
2017-01-08 10:23:56 +00:00
else
{
end_reached |= WalkNode(right->nd_RIGHT, exit_label, end_reached);
loopid->nd_def->df_flags &= ~D_FORLOOP;
1988-10-13 15:43:23 +00:00
}
1993-11-19 09:53:47 +00:00
c_bra(l1);
def_ilb(l2);
1987-08-10 13:01:54 +00:00
FreeInt(tmp);
1986-05-28 18:36:51 +00:00
}
1986-04-22 22:36:16 +00:00
break;
2017-01-08 10:23:56 +00:00
case WITH:
1986-04-28 18:06:58 +00:00
{
struct scopelist link;
1986-05-16 17:15:36 +00:00
struct withdesig wds;
struct desig ds;
1986-04-28 18:06:58 +00:00
2017-01-08 10:23:56 +00:00
if (!WalkDesignator(&(nd->nd_LEFT), &ds, D_USED))
break;
left = nd->nd_LEFT;
2017-01-08 10:23:56 +00:00
if (left->nd_type->tp_fund != T_RECORD)
{
1986-04-28 18:06:58 +00:00
node_error(left, "record variable expected");
break;
}
1986-05-16 17:15:36 +00:00
wds.w_next = WithDesigs;
wds.w_flags = D_USED;
1986-05-16 17:15:36 +00:00
WithDesigs = &wds;
wds.w_scope = left->nd_type->rec_scope;
1986-07-08 14:59:02 +00:00
CodeAddress(&ds);
ds.dsg_kind = DSG_FIXED;
1986-09-25 19:39:06 +00:00
/* Create a designator structure for the temporary.
1986-07-08 14:59:02 +00:00
*/
1986-10-06 20:36:30 +00:00
ds.dsg_offset = NewPtr();
1986-07-08 14:59:02 +00:00
ds.dsg_name = 0;
1987-06-23 17:12:25 +00:00
CodeStore(&ds, address_type);
1986-07-08 14:59:02 +00:00
ds.dsg_kind = DSG_PFIXED;
/* the record is indirectly available */
1986-06-17 12:04:05 +00:00
wds.w_desig = ds;
1986-05-16 17:15:36 +00:00
link.sc_scope = wds.w_scope;
1987-07-16 19:51:40 +00:00
link.sc_next = CurrVis;
1986-04-28 18:06:58 +00:00
CurrVis = &link;
end_reached = WalkNode(right, exit_label, end_reached);
1987-07-16 19:51:40 +00:00
CurrVis = link.sc_next;
1986-05-16 17:15:36 +00:00
WithDesigs = wds.w_next;
1986-10-06 20:36:30 +00:00
FreePtr(ds.dsg_offset);
2017-01-08 10:23:56 +00:00
ChkDesig(&(nd->nd_LEFT), wds.w_flags & (D_USED | D_DEFINED));
1986-04-28 18:06:58 +00:00
break;
}
1986-04-22 22:36:16 +00:00
2017-01-08 10:23:56 +00:00
case EXIT:
assert(exit_label != 0);
1986-04-22 22:36:16 +00:00
2017-01-08 10:23:56 +00:00
if (end_reached & REACH_FLAG)
end_reached = EXIT_FLAG;
c_bra(exit_label);
break;
1986-04-22 22:36:16 +00:00
2017-01-08 10:23:56 +00:00
case RETURN:
end_reached &= ~REACH_FLAG;
if (right)
{
if (!ChkExpression(&(nd->nd_RIGHT)))
break;
/* The type of the return-expression must be
1986-06-20 14:36:49 +00:00
assignment compatible with the result type of the
function procedure (See Rep. 9.11).
1986-04-28 18:06:58 +00:00
*/
2017-01-08 10:23:56 +00:00
if (!ChkAssCompat(&(nd->nd_RIGHT), func_type, "RETURN"))
{
break;
}
right = nd->nd_RIGHT;
if (right->nd_type->tp_fund == T_STRING)
{
CodePString(right, func_type);
}
else
CodePExpr(right);
1986-11-26 16:40:45 +00:00
}
2017-01-08 10:23:56 +00:00
c_bra(RETURN_LABEL);
break;
1986-04-22 22:36:16 +00:00
2017-01-08 10:23:56 +00:00
default:
crash("(WalkStat)");
1986-04-22 22:36:16 +00:00
}
return end_reached;
1986-04-22 22:36:16 +00:00
}
1986-06-20 14:36:49 +00:00
int (*WalkTable[])(struct node*, label, int) = {
1986-06-20 14:36:49 +00:00
NodeCrash,
NodeCrash,
NodeCrash,
NodeCrash,
NodeCrash,
NodeCrash,
1986-06-20 14:36:49 +00:00
NodeCrash,
NodeCrash,
NodeCrash,
NodeCrash,
WalkStat,
NodeCrash,
1986-06-20 14:36:49 +00:00
WalkLink,
};
extern struct desig null_desig;
void ExpectBool(register struct node** pnd, label true_label, label false_label)
1986-04-22 22:36:16 +00:00
{
struct desig ds;
1986-04-22 22:36:16 +00:00
ds = null_desig;
2017-01-08 10:23:56 +00:00
if (ChkExpression(pnd))
{
if ((*pnd)->nd_type != bool_type && (*pnd)->nd_type != error_type)
{
node_error(*pnd, "boolean expression expected");
}
1986-04-22 22:36:16 +00:00
2017-01-08 10:23:56 +00:00
CodeExpr(*pnd, &ds, true_label, false_label);
1986-04-22 22:36:16 +00:00
}
1986-04-23 22:12:22 +00:00
}
int WalkDesignator(struct node** pnd, struct desig* ds, int flags)
1986-04-25 10:14:08 +00:00
{
2017-01-08 10:23:56 +00:00
if (!ChkVariable(pnd, flags))
return 0;
1986-05-01 19:06:53 +00:00
*ds = null_desig;
CodeDesig(*pnd, ds);
1986-08-26 14:33:24 +00:00
return 1;
1986-05-30 18:48:00 +00:00
}
int DoForInit(struct node* nd)
1986-05-30 18:48:00 +00:00
{
register struct node* right = nd->nd_RIGHT;
register struct def* df;
struct type* base_tp;
struct type *tpl, *tpr;
1991-04-25 16:47:47 +00:00
int r;
1986-05-28 18:36:51 +00:00
2017-01-08 10:23:56 +00:00
r = ChkVariable(&(nd->nd_LEFT), D_USED | D_DEFINED);
1991-04-25 16:47:47 +00:00
r &= ChkExpression(&(right->nd_LEFT));
r &= ChkExpression(&(right->nd_RIGHT));
2017-01-08 10:23:56 +00:00
if (!r)
return 0;
1986-05-30 18:48:00 +00:00
df = nd->nd_LEFT->nd_def;
2017-01-08 10:23:56 +00:00
if (df->df_kind == D_FIELD)
{
1986-10-06 20:36:30 +00:00
node_error(nd,
2017-01-08 10:23:56 +00:00
"FOR-loop variable may not be a field of a record");
1986-11-26 16:40:45 +00:00
return 1;
1986-06-20 14:36:49 +00:00
}
2017-01-08 10:23:56 +00:00
if (!df->var_name && df->var_off >= 0)
{
1986-06-20 14:36:49 +00:00
node_error(nd, "FOR-loop variable may not be a parameter");
1986-11-26 16:40:45 +00:00
return 1;
1986-06-20 14:36:49 +00:00
}
2017-01-08 10:23:56 +00:00
if (df->df_scope != CurrentScope)
{
register struct scopelist* sc = CurrVis;
1986-06-20 14:36:49 +00:00
2017-01-08 10:23:56 +00:00
for (;;)
{
if (!sc)
{
1986-10-06 20:36:30 +00:00
node_error(nd,
2017-01-08 10:23:56 +00:00
"FOR-loop variable may not be imported");
1986-11-26 16:40:45 +00:00
return 1;
1986-10-06 20:36:30 +00:00
}
2017-01-08 10:23:56 +00:00
if (sc->sc_scope == df->df_scope)
break;
1986-06-20 14:36:49 +00:00
sc = nextvisible(sc);
}
}
2017-01-08 10:23:56 +00:00
if (df->df_type->tp_size > word_size || !(df->df_type->tp_fund & T_DISCRETE))
{
1986-05-30 18:48:00 +00:00
node_error(nd, "illegal type of FOR loop variable");
1986-11-26 16:40:45 +00:00
return 1;
1986-05-30 18:48:00 +00:00
}
base_tp = BaseType(df->df_type);
tpl = right->nd_LEFT->nd_type;
tpr = right->nd_RIGHT->nd_type;
#ifndef STRICT_3RD_ED
2017-01-08 10:23:56 +00:00
if (!options['3'])
{
if (!ChkAssCompat(&(right->nd_LEFT), base_tp, "FOR statement") || !ChkAssCompat(&(right->nd_RIGHT), base_tp, "FOR statement"))
{
return 1;
}
if (!TstCompat(df->df_type, tpl) || !TstCompat(df->df_type, tpr))
{
node_warning(nd, W_OLDFASHIONED, "compatibility required in FOR statement");
}
}
else
#endif
2017-01-08 10:23:56 +00:00
if (!ChkCompat(&(right->nd_LEFT), base_tp, "FOR statement") || !ChkCompat(&(right->nd_RIGHT), base_tp, "FOR statement"))
{
return 1;
1986-05-30 18:48:00 +00:00
}
1986-06-06 02:22:09 +00:00
return 1;
1986-05-28 18:36:51 +00:00
}
void DoAssign(register struct node* nd)
1986-05-28 18:36:51 +00:00
{
1986-09-25 19:39:06 +00:00
/* May we do it in this order (expression first) ???
The reference manual sais nothing about it, but the book does:
it sais that the left hand side is evaluated first.
1986-10-06 20:36:30 +00:00
DAMN THE BOOK!
1986-09-25 19:39:06 +00:00
*/
struct desig dsr;
register struct type* tp;
1986-05-28 18:36:51 +00:00
2017-01-08 10:23:56 +00:00
if (!(ChkExpression(&(nd->nd_RIGHT)) & ChkVariable(&(nd->nd_LEFT), D_DEFINED)))
return;
tp = nd->nd_LEFT->nd_type;
1986-10-06 20:36:30 +00:00
2017-01-08 10:23:56 +00:00
if (!ChkAssCompat(&(nd->nd_RIGHT), tp, "assignment"))
{
1986-05-28 18:36:51 +00:00
return;
}
dsr = null_desig;
1986-05-28 18:36:51 +00:00
2017-01-08 10:23:56 +00:00
#define StackNeededFor(ds) ((ds).dsg_kind == DSG_PLOADED \
|| (ds).dsg_kind == DSG_INDEXED)
CodeExpr(nd->nd_RIGHT, &dsr, NO_LABEL, NO_LABEL);
tp = nd->nd_RIGHT->nd_type;
2017-01-08 10:23:56 +00:00
if (complex(tp))
{
if (StackNeededFor(dsr))
CodeAddress(&dsr);
}
2017-01-08 10:23:56 +00:00
else
{
CodeValue(&dsr, tp);
1986-05-28 18:36:51 +00:00
}
CodeMove(&dsr, nd->nd_LEFT, tp);
1986-06-17 12:04:05 +00:00
}
static void RegisterMessage(register struct def* df)
1986-06-17 12:04:05 +00:00
{
register struct type* tp;
1986-05-28 18:36:51 +00:00
2017-01-08 10:23:56 +00:00
if (df->df_kind == D_VARIABLE)
{
if (!(df->df_flags & D_NOREG))
{
1986-06-17 12:04:05 +00:00
/* Examine type and size
*/
1986-06-26 09:39:36 +00:00
tp = BaseType(df->df_type);
2017-01-08 10:23:56 +00:00
if ((df->df_flags & D_VARPAR) || (tp->tp_fund & (T_POINTER | T_HIDDEN | T_EQUAL)))
{
1988-10-13 15:43:23 +00:00
C_ms_reg(df->var_off,
2017-01-08 10:23:56 +00:00
pointer_size,
reg_pointer,
0);
1986-06-26 09:39:36 +00:00
}
2017-01-08 10:23:56 +00:00
else if (tp->tp_fund & T_NUMERIC)
{
1988-10-13 15:43:23 +00:00
C_ms_reg(df->var_off,
2017-01-08 10:23:56 +00:00
tp->tp_size,
tp->tp_fund == T_REAL ? reg_float : reg_any,
0);
1986-06-17 12:04:05 +00:00
}
}
}
1986-04-25 10:14:08 +00:00
}
static void df_warning(struct node* nd, struct def* df, char* warning)
1989-04-11 14:34:21 +00:00
{
2017-01-08 10:23:56 +00:00
if (!(df->df_kind & (D_VARIABLE | D_PROCEDURE | D_TYPE | D_CONST | D_PROCHEAD)))
{
1989-04-11 14:34:21 +00:00
return;
}
2017-01-08 10:23:56 +00:00
if (warning)
{
1989-04-11 14:34:21 +00:00
node_warning(nd,
2017-01-08 10:23:56 +00:00
W_ORDINARY,
"%s \"%s\" %s",
(df->df_flags & D_VALPAR) ? "value parameter" : (df->df_flags & D_VARPAR) ? "variable parameter" : (df->df_kind == D_VARIABLE) ? "variable" : (df->df_kind == D_TYPE) ? "type" : (df->df_kind == D_CONST) ? "constant" : "procedure",
df->df_idf->id_text, warning);
1989-04-11 14:34:21 +00:00
}
}
static void UseWarnings(register struct def* df)
{
struct node* nd = df->df_scope->sc_end;
1988-03-22 17:54:01 +00:00
2017-01-08 10:23:56 +00:00
if (is_anon_idf(df->df_idf) || !(df->df_kind & (D_IMPORTED | D_VARIABLE | D_PROCEDURE | D_CONST | D_TYPE)) || (df->df_flags & (D_EXPORTED | D_QEXPORTED)))
{
1988-03-22 17:54:01 +00:00
return;
}
2017-01-08 10:23:56 +00:00
if (df->df_kind & D_IMPORTED)
{
register struct def* df1 = df->imp_def;
1988-03-22 17:54:01 +00:00
2017-01-08 10:23:56 +00:00
df1->df_flags |= df->df_flags & (D_USED | D_DEFINED);
if (df->df_kind == D_INUSE)
return;
if (!(df->df_flags & D_IMP_BY_EXP))
{
if (df->df_flags & (D_USED | D_DEFINED))
{
1989-04-11 14:34:21 +00:00
return;
}
1989-04-11 14:34:21 +00:00
df_warning(nd,
2017-01-08 10:23:56 +00:00
df1,
df1->df_kind == D_VARIABLE ? "imported but not used/assigned" : "imported but not used");
1988-03-22 17:54:01 +00:00
return;
}
1988-03-22 17:54:01 +00:00
df = df1;
1989-04-11 14:34:21 +00:00
nd = df->df_scope->sc_end;
1988-03-22 17:54:01 +00:00
}
2017-01-08 10:23:56 +00:00
switch (df->df_flags & (D_USED | D_DEFINED | D_VALPAR | D_VARPAR))
{
case 0:
case D_VARPAR:
df_warning(nd, df, "never used/assigned");
break;
case D_USED:
df_warning(nd, df, "never assigned");
break;
case D_VALPAR:
case D_DEFINED:
case D_DEFINED | D_VALPAR:
df_warning(nd, df, "never used");
break;
}
}
static void WalkDefList(register struct def* df, void (*proc)(struct def*))
{
2017-01-08 10:23:56 +00:00
for (; df; df = df->df_nextinscope)
{
(*proc)(df);
}
}
#ifdef DBSYMTAB
static void stabdef(struct def* df)
{
2017-01-08 10:23:56 +00:00
switch (df->df_kind)
{
case D_CONST:
case D_VARIABLE:
stb_string(df, df->df_kind);
break;
}
}
#endif