#include "os.h"
#include "y.tab.h"
#include "lnode.h"
#include "config.h"
#define NUM_CHUNK 50 /* Number of chunks to allocate */
extern int current_line; /* lexical.l */
extern char string_space[], *end_of_string_space; /* string_space.c */
/* comm1.c */
extern void add_message(char *fmt, ...);
/* simulate.c */
extern void fatal(char *fmt, ...);
/* main.c */
extern void *xalloc(int size);
/* string_space.h */
extern char *find_string_space (char *str);
int tot_alloc_lnode;
int tot_alloc_strings;
int tot_lnode_block;
int lnode_size[(L_MAX >> L_SHIFT) + 1];
struct lnode_var_def *prog_status;
static int tot_lnode_single;
static int tot_lnode_number;
static int tot_lnode_name;
static int tot_lnode_variable;
static int tot_lnode_1;
static struct lnode_2 *lnode_2_list;
static int tot_lnode_2;
static int tot_lnode_3;
static int tot_lnode_def;
static int tot_var_def;
static int tot_funcall;
struct lnode_single *alloc_lnode_single (int type)
{
struct lnode_single *p;
p = (struct lnode_single *) xalloc (sizeof (struct lnode_single));
p->type = type;
p->line = current_line + L_SINGLE;
tot_lnode_single++;
return p;
}
struct lnode_number *alloc_lnode_number (int type, int number)
{
struct lnode_number *p;
p = (struct lnode_number *) xalloc (sizeof (struct lnode_number));
p->type = type;
p->number = number;
p->line = current_line + L_NUMBER;
tot_lnode_number++;
return p;
}
/*
* Try tro use string_space if possible.
* Be carfule not to free() such an area.
*/
struct lnode_name *alloc_lnode_name (int type, char *name)
{
struct lnode_name *p;
char *spn;
p = (struct lnode_name *) xalloc (sizeof (struct lnode_name));
p->type = type;
spn = find_string_space (name);
if (spn) {
free (name);
p->name = spn;
} else {
p->name = name;
tot_alloc_strings += strlen (name) + 1;
}
p->line = current_line + L_NAME;
tot_lnode_name++;
return p;
}
struct lnode_variable *alloc_lnode_variable (int type, int number)
{
struct lnode_variable *p;
p = (struct lnode_variable *) xalloc (sizeof (struct lnode_variable));
p->type = type;
p->number = number;
p->line = current_line + L_VARIABLE;
tot_lnode_variable++;
return p;
}
struct lnode_1 *alloc_lnode_1 (int type, struct lnode *expr)
{
struct lnode_1 *p;
p = (struct lnode_1 *) xalloc (sizeof (struct lnode_1));
p->type = type;
p->expr = expr;
p->line = current_line + L_1;
tot_lnode_1++;
return p;
}
struct lnode_2 *alloc_lnode_2 (int type, struct lnode *expr1,
struct lnode *expr2)
{
struct lnode_2 *p;
if (!lnode_2_list) {
int i;
lnode_2_list = (struct lnode_2 *) xalloc (NUM_CHUNK *
sizeof (struct lnode_2));
for (p = lnode_2_list, i = 0; i < NUM_CHUNK - 1; p++, i++)
p->expr1 = (struct lnode *) (p + 1);
p->expr1 = 0;
tot_lnode_2 += NUM_CHUNK;
}
p = lnode_2_list;
lnode_2_list = (struct lnode_2 *) lnode_2_list->expr1;
p->type = type;
p->line = current_line + L_2;
p->expr1 = expr1;
p->expr2 = expr2;
return p;
}
struct lnode_3 *alloc_lnode_3 (int type, struct lnode *expr1,
struct lnode *expr2, struct lnode *expr3)
{
struct lnode_3 *p;
p = (struct lnode_3 *) xalloc (sizeof (struct lnode_3));
p->type = type;
p->line = current_line + L_3;
p->expr1 = expr1;
p->expr2 = expr2;
p->expr3 = expr3;
tot_lnode_3++;
return p;
}
struct lnode_def *alloc_lnode_def (int type, char *name, struct lnode *block,
int num_var)
{
struct lnode_def *p;
char *spn;
p = (struct lnode_def *) xalloc (sizeof (struct lnode_def));
p->type = type;
p->line = current_line + L_DEF;
spn = find_string_space (name);
if (spn) {
free (name);
p->name = spn;
} else {
p->name = name;
tot_alloc_strings += strlen (name) + 1;
}
p->num_var = num_var;
p->block = block;
p->next = 0;
p->num_ref = 0;
tot_lnode_def++;
return p;
}
void alloc_lnode_var_def (int type, char *name, int num_var)
{
struct lnode_var_def *p;
p = (struct lnode_var_def *) xalloc (sizeof (struct lnode_var_def));
p->type = type;
p->line = current_line + L_VAR_DEF;
p->name = name;
p->num_var = num_var;
p->next = prog_status;
prog_status = p;
tot_var_def++;
}
struct lnode_funcall *alloc_lnode_funcall (int type, char *name,
struct lnode *arg)
{
struct lnode_funcall *p;
char *spn;
p = (struct lnode_funcall *) xalloc (sizeof (struct lnode_funcall));
p->type = type;
p->line = current_line + L_FUNCALL;
spn = find_string_space (name);
if (spn) {
free (name);
p->name = spn;
} else {
p->name = name;
tot_alloc_strings += strlen (name) + 1;
}
p->expr = arg;
tot_funcall++;
return p;
}
struct lnode_block *alloc_lnode_block (struct lnode *p)
{
int size, num;
char *block, *block2;
struct lnode *l, *next;
struct lnode_block *ret;
for (num = 0, size = 0, l = p; l; l = l->a2) {
size += lnode_size[l->a1->line >> L_SHIFT];
num++;
}
if (num == 1) {
/* Only one statement. No need to make a block ! */
struct lnode *stat;
stat = p->a1;
free_lnode (p, 1);
return (struct lnode_block *) stat;
}
block = xalloc (sizeof (int) + size);
block2 = block;
for (l = p; l; l = next) {
int s;
s = lnode_size[l->a1->line >> L_SHIFT];
memcpy (block2, (char *) l->a1, s);
free_lnode (l->a1, 0); /* Node has been copied. */
l->a1 = 0;
block2 += s;
next = l->a2;
free_lnode (l, 1);
}
ret = (struct lnode_block *) xalloc (sizeof (struct lnode_block));
ret->type = F_BLOCK;
ret->line = current_line + L_BLOCK;
ret->block = block;
ret->num_nodes = num;
tot_lnode_block++;
return ret;
}
void print_lnode_status (int tot_before_this)
{
int tot =
tot_lnode_number * sizeof (struct lnode_number) +
tot_lnode_name * sizeof (struct lnode_name) +
tot_lnode_variable * sizeof (struct lnode_variable) +
tot_lnode_1 * sizeof (struct lnode_1) +
tot_lnode_2 * sizeof (struct lnode_2) +
tot_lnode_3 * sizeof (struct lnode_3) +
tot_var_def * sizeof (struct lnode_var_def) +
tot_funcall * sizeof (struct lnode_funcall) +
tot_lnode_def * sizeof (struct lnode_def) +
tot_lnode_block * sizeof (struct lnode_block) + tot_before_this;
add_message ("lnode:\n");
add_message (" single: %5d %6d\n", tot_lnode_single,
tot_lnode_single * sizeof (struct lnode_single));
add_message (" numbers: %5d %6d\n", tot_lnode_number,
tot_lnode_number * sizeof (struct lnode_number));
add_message (" names: %5d %6d\n", tot_lnode_name,
tot_lnode_name * sizeof (struct lnode_name));
add_message (" variables: %5d %6d\n", tot_lnode_variable,
tot_lnode_variable * sizeof (struct lnode_variable));
add_message (" 1 size expr:%5d %6d\n", tot_lnode_1,
tot_lnode_1 * sizeof (struct lnode_1));
add_message (" 2 size expr:%5d %6d\n", tot_lnode_2,
tot_lnode_2 * sizeof (struct lnode_2));
add_message (" 3 size expr:%5d %6d\n", tot_lnode_3,
tot_lnode_3 * sizeof (struct lnode_3));
add_message (" functions: %5d %6d\n", tot_lnode_def,
tot_lnode_def * sizeof (struct lnode_def));
add_message (" glob vars: %5d %6d\n", tot_var_def,
tot_var_def * sizeof (struct lnode_var_def));
add_message (" fun calls: %5d %6d\n", tot_funcall,
tot_funcall * sizeof (struct lnode_funcall));
add_message (" blocks: %5d %6d\n", tot_lnode_block,
tot_lnode_block * sizeof (struct lnode_block));
add_message (" Total bytes %6d\n", tot);
}
/*
* Setup fast access to the size of an lnode.
*/
void compute_lnode_size (void)
{
lnode_size[L_SINGLE >> L_SHIFT] = sizeof (struct lnode_single);
lnode_size[L_NUMBER >> L_SHIFT] = sizeof (struct lnode_number);
lnode_size[L_NAME >> L_SHIFT] = sizeof (struct lnode_name);
lnode_size[L_VARIABLE >> L_SHIFT] = sizeof (struct lnode_variable);
lnode_size[L_1 >> L_SHIFT] = sizeof (struct lnode_1);
lnode_size[L_2 >> L_SHIFT] = sizeof (struct lnode_2);
lnode_size[L_3 >> L_SHIFT] = sizeof (struct lnode_3);
lnode_size[L_DEF >> L_SHIFT] = sizeof (struct lnode_def);
lnode_size[L_VARIABLE >> L_SHIFT] = sizeof (struct lnode_var_def);
lnode_size[L_FUNCALL >> L_SHIFT] = sizeof (struct lnode_funcall);
lnode_size[L_BLOCK >> L_SHIFT] = sizeof (struct lnode_block);
}
void free_lnode (struct lnode *p, int update_count)
{
switch (p->line & L_MASK) {
case L_SINGLE:
if (update_count)
tot_lnode_single--;
break;
case L_NUMBER:
if (update_count)
tot_lnode_number--;
break;
case L_NAME:
if (update_count)
tot_lnode_name--;
break;
case L_VARIABLE:
if (update_count)
tot_lnode_variable--;
break;
case L_1:
if (update_count)
tot_lnode_1--;
break;
case L_2:
((struct lnode_2 *) p)->expr1 = (struct lnode *) lnode_2_list;
lnode_2_list = (struct lnode_2 *) p;
return;
case L_3:
if (update_count)
tot_lnode_3--;
break;
case L_DEF:
if (update_count)
tot_lnode_def--;
break;
case L_VAR_DEF:
if (update_count)
tot_var_def--;
break;
case L_FUNCALL:
if (update_count)
tot_funcall--;
break;
case L_BLOCK:
if (update_count)
tot_lnode_block--;
break;
default:
fatal ("Bad type in lnode_size(): 0x%x\n", p->line & L_MASK);
}
free (p);
}
void add_prog_ref (struct lnode_def *p)
{
p->num_ref++;
}
int free_prog (struct lnode_def *p)
{
p->num_ref--;
if (p->num_ref > 0)
return 0;
free_sub_part ((struct lnode *)p, 1);
return 1;
}
/*
* Free the space of one node, and all linkes from it.
* When a L_BLOCK is freed, don't call free_lnode() with the nodes
* in the top of the block, because these are allocated in one big
* chunk.
*/
void free_sub_part (struct lnode *p, int do_free)
{
extern int tot_alloc_strings;
if (p == 0)
return;
switch (p->line & L_MASK) {
case L_SINGLE:
break;
case L_NUMBER:
break;
case L_NAME:
if (((struct lnode_name *) p)->name < string_space ||
((struct lnode_name *) p)->name >= end_of_string_space) {
tot_alloc_strings -= strlen (((struct lnode_name *) p)->name) + 1;
free (((struct lnode_name *) p)->name);
}
((struct lnode_name *) p)->name = 0;
break;
case L_VARIABLE:
break;
case L_1:
free_sub_part (((struct lnode_1 *) p)->expr, 1);
((struct lnode_1 *) p)->expr = 0;
break;
case L_2:
free_sub_part (((struct lnode_2 *) p)->expr1, 1);
((struct lnode_2 *) p)->expr1 = 0;
free_sub_part (((struct lnode_2 *) p)->expr2, 1);
((struct lnode_2 *) p)->expr2 = 0;
break;
case L_3:
free_sub_part (((struct lnode_3 *) p)->expr1, 1);
((struct lnode_3 *) p)->expr1 = 0;
free_sub_part (((struct lnode_3 *) p)->expr2, 1);
((struct lnode_3 *) p)->expr2 = 0;
free_sub_part (((struct lnode_3 *) p)->expr3, 1);
((struct lnode_3 *) p)->expr3 = 0;
break;
case L_DEF:
{
struct lnode_def *dp = (struct lnode_def *) p;
if (dp->name < string_space || dp->name >= end_of_string_space) {
tot_alloc_strings -= strlen (dp->name) + 1;
free (dp->name);
}
dp->name = 0;
free_sub_part (dp->block, 1);
dp->block = 0;
if (dp->next) {
free_sub_part ((struct lnode *) dp->next, 1);
dp->next = 0;
}
break;
}
case L_VAR_DEF:
free (((struct lnode_var_def *) p)->name);
((struct lnode_var_def *) p)->name = 0;
break;
case L_FUNCALL:
if (((struct lnode_funcall *) p)->name < string_space ||
((struct lnode_funcall *) p)->name >= end_of_string_space) {
tot_alloc_strings -= strlen (((struct lnode_funcall *) p)->name) + 1;
free (((struct lnode_funcall *) p)->name);
}
((struct lnode_funcall *) p)->name = 0;
free_sub_part (((struct lnode_funcall *) p)->expr, 1);
((struct lnode_funcall *) p)->expr = 0;
break;
case L_BLOCK:
{
struct lnode_block *lb = (struct lnode_block *) p;
char *block = lb->block;
int i;
for (i = 0; i < lb->num_nodes; i++) {
free_sub_part ((struct lnode *) block, 0);
block += lnode_size[((struct lnode *) block)->line >> L_SHIFT];
}
free (lb->block);
break;
}
default:
fatal ("Bad type in free_sub_part(): 0x%x\n", p->line & L_MASK);
}
if (do_free)
free_lnode (p, 1);
}