ack/lang/m2/comp/walk.c

419 lines
7.8 KiB
C
Raw Normal View History

1986-04-21 17:27:06 +00:00
/* P A R S E T R E E W A L K E R */
1986-05-01 19:06:53 +00:00
#ifndef NORCSID
1986-04-21 17:27:06 +00:00
static char *RcsId = "$Header$";
1986-05-01 19:06:53 +00:00
#endif
1986-04-21 17:27:06 +00:00
/* Routines to walk through parts of the parse tree, and generate
code for these parts.
*/
1986-05-01 19:06:53 +00:00
#include "debug.h"
1986-04-21 17:27:06 +00:00
#include <em_arith.h>
#include <em_label.h>
#include <assert.h>
#include "def.h"
#include "type.h"
#include "scope.h"
#include "main.h"
#include "LLlex.h"
#include "node.h"
1986-04-22 22:36:16 +00:00
#include "Lpars.h"
1986-04-21 17:27:06 +00:00
extern arith align();
static int prclev = 0;
1986-05-01 19:06:53 +00:00
static label instructionlabel;
static label datalabel = 1;
1986-04-23 22:12:22 +00:00
static label return_label;
static char return_expr_occurred;
static struct type *func_type;
1986-04-21 17:27:06 +00:00
1986-05-01 19:06:53 +00:00
label
text_label()
{
return instructionlabel++;
}
label
data_label()
{
return datalabel++;
}
1986-04-21 17:27:06 +00:00
WalkModule(module)
register struct def *module;
{
/* Walk through a module, and all its local definitions.
Also generate code for its body.
*/
1986-04-28 18:06:58 +00:00
register struct def *df = module->mod_vis->sc_scope->sc_def;
struct scopelist *vis;
1986-04-21 17:27:06 +00:00
1986-04-28 18:06:58 +00:00
vis = CurrVis;
CurrVis = module->mod_vis;
1986-04-22 22:36:16 +00:00
1986-04-21 17:27:06 +00:00
if (!prclev && module->mod_number) {
/* This module is a local module, but not within a
procedure. Generate code to allocate storage for its
1986-04-22 22:36:16 +00:00
variables. This is done by generating a "bss",
with label "_<modulenumber><modulename>".
1986-04-21 17:27:06 +00:00
*/
1986-04-28 18:06:58 +00:00
arith size = align(CurrentScope->sc_off, word_align);
1986-04-21 17:27:06 +00:00
if (size == 0) size = word_size;
C_df_dnam(&(CurrentScope->sc_name[1]));
C_bss_cst(size, (arith) 0, 0);
}
1986-04-28 18:06:58 +00:00
else if (CurrVis == Defined->mod_vis) {
1986-04-21 17:27:06 +00:00
/* This module is the module currently being compiled.
Again, generate code to allocate storage for its
variables, which all have an explicit name.
*/
while (df) {
if (df->df_kind == D_VARIABLE) {
C_df_dnam(df->var_name);
C_bss_cst(df->df_type->tp_size, (arith) 0, 0);
}
df = df->df_nextinscope;
}
}
/* Now, walk through it's local definitions
*/
WalkDef(CurrentScope->sc_def);
/* Now, generate initialization code for this module.
First call initialization routines for modules defined within
this module.
*/
CurrentScope->sc_off = 0;
1986-04-23 22:12:22 +00:00
instructionlabel = 1;
return_label = instructionlabel++;
func_type = 0;
1986-04-21 17:27:06 +00:00
C_pro_narg(CurrentScope->sc_name);
MkCalls(CurrentScope->sc_def);
1986-04-22 22:36:16 +00:00
WalkNode(module->mod_body, (label) 0);
1986-04-23 22:12:22 +00:00
C_df_ilb(return_label);
C_ret((label) 0);
1986-04-28 18:06:58 +00:00
C_end(align(-CurrentScope->sc_off, word_align));
1986-04-21 17:27:06 +00:00
1986-04-28 18:06:58 +00:00
CurrVis = vis;
1986-04-21 17:27:06 +00:00
}
WalkProcedure(procedure)
struct def *procedure;
{
/* Walk through the definition of a procedure and all its
local definitions
*/
1986-04-28 18:06:58 +00:00
struct scopelist *vis = CurrVis;
1986-04-21 17:27:06 +00:00
prclev++;
1986-04-28 18:06:58 +00:00
CurrVis = procedure->prc_vis;
1986-04-21 17:27:06 +00:00
WalkDef(CurrentScope->sc_def);
/* Generate code for this procedure
*/
1986-04-22 22:36:16 +00:00
C_pro_narg(CurrentScope->sc_name);
1986-04-21 17:27:06 +00:00
/* generate calls to initialization routines of modules defined within
this procedure
*/
1986-04-23 22:12:22 +00:00
return_label = 1;
instructionlabel = 2;
func_type = procedure->df_type->next;
1986-04-21 17:27:06 +00:00
MkCalls(CurrentScope->sc_def);
1986-04-22 22:36:16 +00:00
WalkNode(procedure->prc_body, (label) 0);
1986-04-23 22:12:22 +00:00
C_df_ilb(return_label);
if (func_type) C_ret((arith) align(func_type->tp_size, word_align));
else C_ret((arith) 0);
1986-04-21 17:27:06 +00:00
C_end(align(-CurrentScope->sc_off, word_size));
1986-04-28 18:06:58 +00:00
CurrVis = vis;
1986-04-21 17:27:06 +00:00
prclev--;
}
WalkDef(df)
register struct def *df;
{
/* Walk through a list of definitions
*/
1986-04-28 18:06:58 +00:00
1986-04-21 17:27:06 +00:00
while (df) {
if (df->df_kind == D_MODULE) {
WalkModule(df);
}
else if (df->df_kind == D_PROCEDURE) {
WalkProcedure(df);
}
df = df->df_nextinscope;
}
}
MkCalls(df)
register struct def *df;
{
/* Generate calls to initialization routines of modules
*/
1986-04-28 18:06:58 +00:00
1986-04-21 17:27:06 +00:00
while (df) {
if (df->df_kind == D_MODULE) {
C_lxl((arith) 0);
1986-04-28 18:06:58 +00:00
C_cal(df->mod_vis->sc_scope->sc_name);
1986-04-21 17:27:06 +00:00
}
df = df->df_nextinscope;
}
}
1986-04-22 22:36:16 +00:00
WalkNode(nd, lab)
register struct node *nd;
label lab;
1986-04-21 17:27:06 +00:00
{
/* Node "nd" represents either a statement or a statement list.
1986-04-22 22:36:16 +00:00
Walk through it.
"lab" represents the label that must be jumped to on
encountering an EXIT statement.
*/
1986-04-28 18:06:58 +00:00
1986-04-22 22:36:16 +00:00
while (nd->nd_class == Link) { /* statement list */
WalkStat(nd->nd_left, lab);
nd = nd->nd_right;
}
WalkStat(nd, lab);
}
WalkStat(nd, lab)
register struct node *nd;
label lab;
{
/* Walk through a statement, generating code for it.
"lab" represents the label that must be jumped to on
encountering an EXIT statement.
*/
register struct node *left = nd->nd_left;
register struct node *right = nd->nd_right;
if (nd->nd_class == Call) {
1986-05-01 19:06:53 +00:00
if (chk_call(nd)) CodeCall(nd);
1986-04-22 22:36:16 +00:00
return;
}
assert(nd->nd_class == Stat);
switch(nd->nd_symb) {
case BECOMES:
1986-04-28 18:06:58 +00:00
WalkDesignator(left);
WalkExpr(right);
if (! TstAssCompat(left->nd_type, right->nd_type)) {
node_error(nd, "type incompatibility in assignment");
break;
}
1986-05-01 19:06:53 +00:00
CodeAssign(nd);
1986-04-22 22:36:16 +00:00
break;
case IF:
{ label l1, l2;
l1 = instructionlabel++;
l2 = instructionlabel++;
ExpectBool(left);
assert(right->nd_symb == THEN);
C_zeq(l1);
WalkNode(right->nd_left, lab);
if (right->nd_right) { /* ELSE part */
C_bra(l2);
C_df_ilb(l1);
WalkNode(right->nd_right, lab);
C_df_ilb(l2);
}
else C_df_ilb(l1);
break;
}
case CASE:
1986-05-01 19:06:53 +00:00
CaseCode(nd, lab);
break;
1986-04-22 22:36:16 +00:00
case WHILE:
{ label l1, l2;
l1 = instructionlabel++;
l2 = instructionlabel++;
C_df_ilb(l1);
ExpectBool(left);
C_zeq(l2);
WalkNode(right, lab);
C_bra(l1);
C_df_ilb(l2);
break;
}
case REPEAT:
{ label l1;
l1 = instructionlabel++;
C_df_ilb(l1);
WalkNode(left, lab);
ExpectBool(right);
C_zeq(l1);
break;
}
case LOOP:
{ label l1, l2;
l1 = instructionlabel++;
l2 = instructionlabel++;
C_df_ilb(l1);
WalkNode(left, l2);
C_bra(l1);
C_df_ilb(l2);
break;
}
case FOR:
/* ??? */
1986-04-28 18:06:58 +00:00
WalkNode(right, lab);
1986-04-22 22:36:16 +00:00
break;
case WITH:
1986-04-28 18:06:58 +00:00
{
struct scopelist link;
WalkDesignator(left);
if (left->nd_type->tp_fund != T_RECORD) {
node_error(left, "record variable expected");
break;
}
link.sc_scope = left->nd_type->rec_scope;
link.next = CurrVis;
CurrVis = &link;
WalkNode(right, lab);
CurrVis = link.next;
/* ??? */
break;
}
1986-04-22 22:36:16 +00:00
case EXIT:
assert(lab != 0);
C_bra(lab);
break;
case RETURN:
1986-04-23 22:12:22 +00:00
if (right) {
WalkExpr(right);
1986-04-28 18:06:58 +00:00
/* What kind of compatibility do we need here ???
assignment compatibility?
*/
if (!TstAssCompat(func_type, right->nd_type)) {
1986-04-23 22:12:22 +00:00
node_error(right, "type incompatibility in RETURN statement");
}
1986-05-01 19:06:53 +00:00
return_expr_occurred = 1;
1986-04-23 22:12:22 +00:00
}
C_bra(return_label);
1986-04-22 22:36:16 +00:00
break;
default:
assert(0);
}
}
ExpectBool(nd)
struct node *nd;
{
/* "nd" must indicate a boolean expression. Check this and
generate code to evaluate the expression.
*/
1986-04-23 22:12:22 +00:00
WalkExpr(nd);
1986-04-22 22:36:16 +00:00
1986-04-22 23:22:19 +00:00
if (nd->nd_type != bool_type && nd->nd_type != error_type) {
1986-04-22 22:36:16 +00:00
node_error(nd, "boolean expression expected");
}
1986-04-23 22:12:22 +00:00
}
1986-04-22 22:36:16 +00:00
1986-04-23 22:12:22 +00:00
WalkExpr(nd)
struct node *nd;
{
/* Check an expression and generate code for it
1986-04-21 17:27:06 +00:00
*/
1986-04-23 22:12:22 +00:00
DO_DEBUG(1, (DumpTree(nd), print("\n")));
1986-05-01 19:06:53 +00:00
if (! chk_expr(nd)) return;
/* ??? */
1986-04-23 22:12:22 +00:00
}
1986-04-25 10:14:08 +00:00
WalkDesignator(nd)
struct node *nd;
{
/* Check designator and generate code for it
*/
DO_DEBUG(1, (DumpTree(nd), print("\n")));
1986-05-01 19:06:53 +00:00
if (! chk_designator(nd, DESIGNATOR|VARIABLE)) return;
/* ??? */
}
CodeCall(nd)
struct node *nd;
{
/* Generate code for a procedure call. Checking of parameters
and result is already done.
*/
/* ??? */
}
CodeAssign(nd)
struct node *nd;
{
/* Generate code for an assignment. Testing of type
compatibility and the like is already done.
*/
/* ??? */
1986-04-25 10:14:08 +00:00
}
1986-04-23 22:12:22 +00:00
#ifdef DEBUG
DumpTree(nd)
struct node *nd;
{
char *s;
extern char *symbol2str();
if (!nd) {
print("()");
return;
}
print("(");
DumpTree(nd->nd_left);
switch(nd->nd_class) {
case Def: s = "Def"; break;
case Oper: s = "Oper"; break;
case Uoper: s = "Uoper"; break;
case Name: s = "Name"; break;
case Set: s = "Set"; break;
case Value: s = "Value"; break;
case Call: s = "Call"; break;
case Xset: s = "Xset"; break;
case Stat: s = "Stat"; break;
case Link: s = "Link"; break;
default: s = "ERROR"; break;
}
print("%s %s", s, symbol2str(nd->nd_symb));
DumpTree(nd->nd_right);
print(")");
1986-04-21 17:27:06 +00:00
}
1986-04-23 22:12:22 +00:00
#endif