/* $Id$ */ /* * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. * See the copyright notice in the ACK home directory, in the file "Copyright". */ /* I N T E R M E D I A T E C O D E * * I C _ A U X . C */ #include #include #include #include #include #include "../share/types.h" #include "../share/global.h" #include "../share/debug.h" #include "../share/def.h" #include "../share/aux.h" #include "ic.h" #include "ic_io.h" #include "ic_lookup.h" #include "../share/alloc.h" #include "ic_aux.h" /* opr_size */ offset opr_size(short instr) { switch(instr) { case op_loe: case op_ste: case op_ine: case op_dee: case op_zre: return (offset) ws; case op_lde: case op_sde: return (offset) 2*ws; case op_lae: case op_fil: case op_gto: return (offset) UNKNOWN_SIZE; default: error("illegal operand of opr_size: %d", instr); } /* NOTREACHED */ return 0; } /* dblockdef */ static offset argsize(arg_p arg) { /* Compute the size (in bytes) that the given initializer * will occupy. */ offset s; argb_p argb; switch(arg->a_type) { case ARGOFF: /* See if value fits in a short */ if ((short) arg->a_a.a_offset == arg->a_a.a_offset) { return ws; } else { return 2*ws; } case ARGINSTRLAB: case ARGOBJECT: case ARGPROC: return ps; /* pointer size */ case ARGSTRING: /* strings are partitioned into pieces */ s = 0; for (argb = &arg->a_a.a_string; argb != (argb_p) 0; argb = argb->ab_next) { s += argb->ab_index; } return s; case ARGICN: case ARGUCN: case ARGFCN: return arg->a_a.a_con.ac_length; default: assert(FALSE); } /* NOTREACHED */ return 0; } static offset blocksize(byte pseudo, arg_p args) { /* Determine the number of bytes of a datablock */ arg_p arg; offset sum; switch(pseudo) { case DHOL: case DBSS: if (args->a_type != ARGOFF) { error("offset expected"); } return args->a_a.a_offset; case DCON: case DROM: sum = 0; for (arg = args; arg != (arg_p) 0; arg = arg->a_next) { /* Add the sizes of all initializers */ sum += argsize(arg); } return sum; default: assert(FALSE); } /* NOTREACHED */ return 0; } static arg_p copy_arg(arg_p arg) { /* Copy one argument */ arg_p new; assert(arg->a_type == ARGOFF); new = newarg(ARGOFF); new->a_a.a_offset = arg->a_a.a_offset; return new; } static arg_p copy_rom(arg_p args) { /* Make a copy of the values of a rom, * provided that the rom contains only integer values, */ arg_p arg, arg2, argh; for (arg = args; arg != (arg_p) 0; arg = arg->a_next) { if (arg->a_type != ARGOFF) { return (arg_p) 0; } } /* Now make the copy */ arg2 = argh = copy_arg(args); for (arg = args->a_next; arg != (arg_p) 0; arg = arg->a_next) { arg2->a_next = copy_arg(arg); arg2 = arg2->a_next; } return argh; } void dblockdef(dblock_p db, int n, line_p lnp) { /* Process a data block defining occurrence */ byte m = 0; switch(n) { case ps_hol: m = DHOL; break; case ps_bss: m = DBSS; break; case ps_con: m = DCON; break; case ps_rom: m = DROM; break; default: assert(FALSE); } db->d_pseudo = m; db->d_size = blocksize(m, ARG(lnp)); if (m == DROM) { /* We keep the values of a rom block in the data block * table if the values consist of integers only. */ db->d_values = copy_rom(ARG(lnp)); } } /* combine */ void combine(dblock_p db, line_p l1, line_p l2, byte pseu) { /* Combine two successive ROMs/CONs (without a data label * in between into a single ROM. E.g.: * xyz * rom 3,6,9,12 * rom 7,0,2 * is changed into: * xyz * rom 3,6,9,12,7,0,2 */ arg_p v; db->d_size += blocksize(pseu,ARG(l2)); /* db is the data block that was already assigned to the * first rom/con. The second one is not assigned a new * data block of course, as the two are combined into * one instruction. */ if (pseu == DROM && db->d_values != (arg_p) 0) { /* The values contained in a ROM are only copied * to the data block if they may be useful to us * (e.g. they certainly may not be strings). In our * case it means that both ROMs must have useful * arguments. */ for (v = db->d_values; v->a_next != (arg_p) 0; v = v->a_next); /* The first rom contained useful arguments. v now points to * its last argument. Append the arguments of the second * rom to this list. If the second rom has arguments that are * not useful, throw away the entire list (we want to copy * everything or nothing). */ if ((v->a_next = copy_rom(ARG(l2))) == (arg_p) 0) { oldargs(db->d_values); db->d_values = (arg_p) 0; } } for (v = ARG(l1); v->a_next != (arg_p) 0; v = v->a_next); /* combine the arguments of both instructions. */ v->a_next = ARG(l2); ARG(l2) = (arg_p) 0; } /* arglist */ static void arg_string(offset length, argb_p abp) { while (length--) { if (abp->ab_index == NARGBYTES) abp = abp->ab_next = newargb(); abp->ab_contents[abp->ab_index++] = readchar(); } } line_p arglist(int n) { line_p lnp; register arg_p ap,*app; bool moretocome; offset length; /* * creates an arglist with n elements * if n == 0 the arglist is variable and terminated by sp_cend */ lnp = newline(OPLIST); app = &ARG(lnp); moretocome = TRUE; do { switch(table2()) { default: error("unknown byte in arglist"); case CSTX1: tabval2 = (offset) tabval; case CSTX2: *app = ap = newarg(ARGOFF); ap->a_a.a_offset = tabval2; app = &ap->a_next; break; case ILBX: *app = ap = newarg(ARGINSTRLAB); ap->a_a.a_instrlab = instr_lab((short) tabval); app = &ap->a_next; break; case DLBX: *app = ap = newarg(ARGOBJECT); ap->a_a.a_obj = object(string,(offset) 0, (offset) 0); /* The size of the object is unknown */ app = &ap->a_next; break; case sp_pnam: *app = ap = newarg(ARGPROC); ap->a_a.a_proc = proclookup(string,OCCURRING); app = &ap->a_next; break; case VALX1: tabval2 = (offset) tabval; case VALX2: *app = ap = newarg(ARGOBJECT); ap->a_a.a_obj = object(string, tabval2, (offset) 0); app = &ap->a_next; break; case sp_scon: *app = ap = newarg(ARGSTRING); length = get_off(); arg_string(length,&ap->a_a.a_string); app = &ap->a_next; break; case sp_icon: *app = ap = newarg(ARGICN); goto casecon; case sp_ucon: *app = ap = newarg(ARGUCN); goto casecon; case sp_fcon: *app = ap = newarg(ARGFCN); casecon: length = get_int(); ap->a_a.a_con.ac_length = (short) length; arg_string(get_off(),&ap->a_a.a_con.ac_con); app = &ap->a_next; break; case sp_cend: moretocome = FALSE; } if (n && (--n) == 0) moretocome = FALSE; } while (moretocome); return(lnp); } /* is_datalabel */ bool is_datalabel(line_p l) { VL(l); return (l->l_instr == (byte) ps_sym); } /* block_of_lab */ dblock_p block_of_lab(char *ident) { dblock_p dbl; /* Find the datablock with the given name. * Used for defining occurrences. */ dbl = symlookup(ident,DEFINING); VD(dbl); if (dbl->d_pseudo != DUNKNOWN) { error("identifier %s redeclared", ident); } return dbl; } /* object */ static obj_p make_object(dblock_p dbl, offset off, offset size) { /* Allocate an obj struct with the given attributes * (if it did not exist already). * Return a pointer to the found or newly created object struct. */ obj_p obj, prev, new; /* See if the object was already present in the object list * of the given datablock. If it is not yet present, find * the right place to insert the new object. Note that * the objects are sorted by offset. */ prev = (obj_p) 0; for (obj = dbl->d_objlist; obj != (obj_p) 0; obj = obj->o_next) { if (obj->o_off >= off) { break; } prev = obj; } /* Note that the data block may contain several objects * with the required offset; we also want the size to * be the right one. */ while (obj != (obj_p) 0 && obj->o_off == off) { if (obj->o_size == UNKNOWN_SIZE) { obj->o_size = size; return obj; } else { if (size == UNKNOWN_SIZE || obj->o_size == size) { return obj; /* This is the right one */ } else { prev = obj; obj = obj->o_next; } } } /* Allocate a new object */ new = newobject(); new->o_id = ++lastoid; /* create a unique object id */ new->o_off = off; new->o_size = size; new->o_dblock = dbl; /* Insert the new object */ if (prev == (obj_p) 0) { dbl->d_objlist = new; } else { prev->o_next = new; } new->o_next = obj; return new; } obj_p object(char *ident, offset off, offset size) { dblock_p dbl; /* Create an object struct (if it did not yet exist) * for the object with the given size and offset * within the datablock of the given name. */ dbl = (ident == (char *) 0 ? hol0_db : symlookup(ident, OCCURRING)); VD(dbl); return(make_object(dbl,off,size)); }