ack/util/ego/ic/ic.c

593 lines
14 KiB
C
Raw Normal View History

1994-06-24 11:31:16 +00:00
/* $Id$ */
1987-03-09 19:15:41 +00:00
/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
1984-11-26 13:43:22 +00:00
/* I N T E R M E D I A T E C O D E
*
* I C . C
*/
#include <stdlib.h>
1984-11-26 13:43:22 +00:00
#include <stdio.h>
1991-03-05 12:16:17 +00:00
#include <em_spec.h>
#include <em_pseu.h>
#include <em_flag.h>
#include <em_mes.h>
1984-11-26 13:43:22 +00:00
#include "../share/types.h"
#include "../share/debug.h"
#include "../share/def.h"
#include "../share/map.h"
#include "ic.h"
1984-11-30 10:23:34 +00:00
#include "ic_lookup.h"
1984-11-26 13:43:22 +00:00
#include "ic_aux.h"
#include "ic_io.h"
#include "ic_lib.h"
#include "../share/alloc.h"
#include "../share/global.h"
#include "../share/files.h"
#include "../share/put.h"
#include "../share/aux.h"
/* Global variables */
2016-08-21 17:53:14 +00:00
dblock_p db;
dblock_p hol0_db; /* dblock for ABS block */
char* curhol; /* name of hol block in current scope */
dblock_p ldblock; /* last dblock */
proc_p lproc; /* last proc */
short tabval; /* used by table1, table2 and table3 */
offset tabval2;
char string[IDL + 1];
line_p firstline; /* first line of current procedure */
line_p lastline; /* last line read */
int labelcount; /* # labels in current procedure */
short fragm_type = DUNKNOWN; /* fragm. type: DCON, DROM or DUNKNOWN */
short fragm_nr = 0; /* fragment number */
obj_id lastoid = 0;
proc_id lastpid = 0;
dblock_id lastdid = 0;
lab_id lastlid = 0;
offset mespar = UNKNOWN_SIZE;
/* argumument of ps_par message of current procedure */
extern process_lines();
extern int readline();
extern line_p readoperand();
extern line_p inpseudo();
main(argc, argv) int argc;
char* argv[];
1984-11-26 13:43:22 +00:00
{
/* The input files must be legal EM Compact
* Assembly Language files, as produced by the EM Peephole
* Optimizer.
* Their file names are passed as arguments.
* The output consists of the files:
* - lfile: the EM code in Intermediate Code format
* - dfile: the data block table file
* - pfile: the proc table file
* - pdump: the names of all procedures
* - ddump: the names of all data blocks
*/
/* The input file names */
const char* pdump_out = argv[1];
const char* ddump_out = argv[2];
/* The output file names */
const char* pname_out = argv[5];
const char* dname_out = argv[6];
const char* lname_out = argv[7];
FILE* lfile = openfile(lname_out, "w");
FILE* pdump = openfile(pdump_out, "w");
FILE* ddump = openfile(ddump_out, "w");
FILE* dfile;
FILE* pfile;
1984-11-26 13:43:22 +00:00
2016-08-21 17:53:14 +00:00
hol0_db = block_of_lab((char*)0);
while (next_file(argc-8, argv+8) != NULL)
2016-08-21 17:53:14 +00:00
{
1984-11-26 13:43:22 +00:00
/* Read all EM input files, process the code
* and concatenate all output.
*/
2016-08-21 17:53:14 +00:00
curhol = (char*)0;
1984-11-26 13:43:22 +00:00
process_lines(lfile);
2016-08-21 17:53:14 +00:00
dump_procnames(prochash, NPROCHASH, pdump);
dump_dblocknames(symhash, NSYMHASH, ddump);
1984-11-26 13:43:22 +00:00
/* Save the names of all procedures that were
* first come accross in this file.
*/
2016-08-21 17:53:14 +00:00
cleanprocs(prochash, NPROCHASH, PF_EXTERNAL);
cleandblocks(symhash, NSYMHASH, DF_EXTERNAL);
1984-11-26 13:43:22 +00:00
/* Make all procedure names that were internal
* in this input file invisible.
*/
}
fclose(lfile);
fclose(pdump);
fclose(ddump);
/* remove the remainder of the hashing tables */
2016-08-21 17:53:14 +00:00
cleanprocs(prochash, NPROCHASH, 0);
cleandblocks(symhash, NSYMHASH, 0);
1984-11-26 13:43:22 +00:00
/* Now write the datablock table and the proctable */
dfile = openfile(dname_out, "w");
1984-11-26 13:43:22 +00:00
putdtable(fdblock, dfile);
pfile = openfile(pname_out, "w");
2016-08-21 17:53:14 +00:00
putptable(fproc, pfile, FALSE);
1987-03-09 13:14:32 +00:00
exit(0);
1984-11-26 13:43:22 +00:00
}
/* Value returned by readline */
2016-08-21 17:53:14 +00:00
#define NORMAL 0
#define WITH_OPERAND 1
#define EOFILE 2
#define PRO_INSTR 3
#define END_INSTR 4
#define DELETED_INSTR 5
1984-11-26 13:43:22 +00:00
STATIC add_end()
{
/* Add an end-pseudo to the current instruction list */
lastline->l_next = newline(OPNO);
lastline = lastline->l_next;
lastline->l_instr = ps_end;
}
process_lines(fout)
2016-08-21 17:53:14 +00:00
FILE* fout;
1984-11-26 13:43:22 +00:00
{
line_p lnp;
2016-08-21 17:53:14 +00:00
short instr;
bool eof;
1984-11-26 13:43:22 +00:00
/* Read and process the code contained in the current file,
* on a per procedure basis.
* On the fly, fragments are formed. Recall that two
* successive CON pseudos are allocated consecutively
* in a single fragment, unless these CON pseudos are
* separated in the assembly language program by one
* of: ROM, BSS, HOL and END (and of course EndOfFile).
* The same is true for ROM pseudos.
* We keep track of a fragment type (DROM after a ROM
* pseudo, DCON after a CON and DUNKNOWN after a HOL,
* BSS, END or EndOfFile) and a fragment number (which
* is incremented every time we enter a new fragment).
* Every data block is assigned such a number
* when we come accross its defining occurrence.
*/
eof = FALSE;
2016-08-21 17:53:14 +00:00
firstline = (line_p)0;
lastline = (line_p)0;
while (!eof)
{
linecount++; /* for error messages */
switch (readline(&instr, &lnp))
{
1984-11-26 13:43:22 +00:00
/* read one line, see what kind it is */
case WITH_OPERAND:
/* instruction with operand, e.g. LOL 10 */
lnp = readoperand(instr);
lnp->l_instr = instr;
2016-08-21 17:53:14 +00:00
/* Fall through! */
1984-11-26 13:43:22 +00:00
case NORMAL:
VL(lnp);
2016-08-21 17:53:14 +00:00
if (lastline != (line_p)0)
{
1984-11-26 13:43:22 +00:00
lastline->l_next = lnp;
}
lastline = lnp;
break;
case EOFILE:
eof = TRUE;
fragm_type = DUNKNOWN;
2016-08-21 17:53:14 +00:00
if (firstline != (line_p)0)
{
1984-11-26 13:43:22 +00:00
add_end();
2016-08-21 17:53:14 +00:00
putlines(firstline, fout);
firstline = (line_p)0;
1984-11-26 13:43:22 +00:00
}
break;
case PRO_INSTR:
VL(lnp);
labelcount = 0;
2016-08-21 17:53:14 +00:00
if (firstline != lnp)
{
1984-11-26 13:43:22 +00:00
/* If PRO is not the first
* instruction:
*/
add_end();
2016-08-21 17:53:14 +00:00
putlines(firstline, fout);
1984-11-26 13:43:22 +00:00
firstline = lnp;
}
lastline = lnp;
break;
case END_INSTR:
curproc->p_nrformals = mespar;
mespar = UNKNOWN_SIZE;
2016-08-21 17:53:14 +00:00
assert(lastline != (line_p)0);
1984-11-26 13:43:22 +00:00
lastline->l_next = lnp;
2016-08-21 17:53:14 +00:00
putlines(firstline, fout);
1984-11-26 13:43:22 +00:00
/* write and delete code */
2016-08-21 17:53:14 +00:00
firstline = (line_p)0;
lastline = (line_p)0;
1984-11-26 13:43:22 +00:00
cleaninstrlabs();
/* scope of instruction labels ends here,
* so forget about them.
*/
fragm_type = DUNKNOWN;
break;
case DELETED_INSTR:
/* EXP, INA etc. are deleted */
break;
default:
error("illegal readline");
}
}
}
2016-08-21 17:53:14 +00:00
int readline(instr_out, lnp_out) short* instr_out;
line_p* lnp_out;
1984-11-26 13:43:22 +00:00
{
register line_p lnp;
short n;
/* Read one line. If it is a normal EM instruction without
* operand, we can allocate a line struct for it here.
* If so, return a pointer to it via lnp_out, else just
* return the instruction code via instr_out.
*/
2016-08-21 17:53:14 +00:00
VA((short*)instr_out);
VA((short*)lnp_out);
switch (table1())
{
1984-11-26 13:43:22 +00:00
/* table1 sets string, tabval or tabval2 and
* returns an indication of what was read.
*/
case ATEOF:
return EOFILE;
case INST:
*instr_out = tabval; /* instruction code */
return WITH_OPERAND;
case DLBX:
/* data label defining occurrence, precedes
* a data block.
*/
db = block_of_lab(string);
/* global variable, used by inpseudo */
lnp = newline(OPSHORT);
2016-08-21 17:53:14 +00:00
SHORT(lnp) = (short)db->d_id;
1984-11-26 13:43:22 +00:00
lnp->l_instr = ps_sym;
*lnp_out = lnp;
2016-08-21 17:53:14 +00:00
if (firstline == (line_p)0)
{
1984-11-26 13:43:22 +00:00
firstline = lnp;
/* only a pseudo (e.g. PRO) or data label
* can be the first instruction.
*/
}
return NORMAL;
case ILBX:
/* instruction label defining occurrence */
labelcount++;
lnp = newline(OPINSTRLAB);
lnp->l_instr = op_lab;
INSTRLAB(lnp) = instr_lab(tabval);
*lnp_out = lnp;
return NORMAL;
case PSEU:
n = tabval;
lnp = inpseudo(n); /* read a pseudo */
2016-08-21 17:53:14 +00:00
if (n == ps_hol)
n = ps_bss;
if (lnp == (line_p)0)
return DELETED_INSTR;
1984-11-26 13:43:22 +00:00
*lnp_out = lnp;
lnp->l_instr = n;
2016-08-21 17:53:14 +00:00
if (firstline == (line_p)0)
{
1984-11-26 13:43:22 +00:00
firstline = lnp;
/* only a pseudo (e.g. PRO) or data label
* can be the first instruction.
*/
}
2016-08-21 17:53:14 +00:00
if (n == ps_end)
return END_INSTR;
if (n == ps_pro)
return PRO_INSTR;
1984-11-26 13:43:22 +00:00
return NORMAL;
}
/* NOTREACHED */
}
2016-08-21 17:53:14 +00:00
line_p readoperand(instr) short instr;
1984-11-26 13:43:22 +00:00
{
/* Read the operand of the given instruction.
* Create a line struct and return a pointer to it.
*/
register line_p lnp;
short flag;
VI(instr);
2016-08-21 17:53:14 +00:00
flag = em_flag[instr - sp_fmnem] & EM_PAR;
if (flag == PAR_NO)
{
1984-11-26 13:43:22 +00:00
return (newline(OPNO));
}
2016-08-21 17:53:14 +00:00
switch (table2())
{
1984-11-26 13:43:22 +00:00
case sp_cend:
2016-08-21 17:53:14 +00:00
return (newline(OPNO));
1984-11-26 13:43:22 +00:00
case CSTX1:
/* constant */
/* If the instruction has the address
* of an external variable as argument,
* the constant must be regarded as an
* offset in the current hol block,
* so an object must be created.
* Similarly, the instruction may have
* an instruction label as argument.
*/
2016-08-21 17:53:14 +00:00
switch (flag)
{
case PAR_G:
lnp = newline(OPOBJECT);
OBJ(lnp) = object(curhol, (offset)tabval,
opr_size(instr));
break;
case PAR_B:
lnp = newline(OPINSTRLAB);
INSTRLAB(lnp) = instr_lab(tabval);
break;
default:
lnp = newline(OPSHORT);
SHORT(lnp) = tabval;
break;
1984-11-26 13:43:22 +00:00
}
break;
#ifdef LONGOFF
case CSTX2:
/* double constant */
2016-08-21 17:53:14 +00:00
if (flag == PAR_G)
{
lnp = newline(OPOBJECT);
2016-08-21 17:53:14 +00:00
OBJ(lnp) = object(curhol, tabval2,
opr_size(instr));
break;
}
1984-11-26 13:43:22 +00:00
lnp = newline(OPOFFSET);
OFFSET(lnp) = tabval2;
break;
#endif
case ILBX:
/* applied occurrence instruction label */
lnp = newline(OPINSTRLAB);
INSTRLAB(lnp) = instr_lab(tabval);
break;
case DLBX:
/* applied occurrence data label */
lnp = newline(OPOBJECT);
2016-08-21 17:53:14 +00:00
OBJ(lnp) = object(string, (offset)0,
opr_size(instr));
1984-11-26 13:43:22 +00:00
break;
case VALX1:
lnp = newline(OPOBJECT);
2016-08-21 17:53:14 +00:00
OBJ(lnp) = object(string, (offset)tabval,
opr_size(instr));
1984-11-26 13:43:22 +00:00
break;
#ifdef LONGOFF
case VALX2:
lnp = newline(OPOBJECT);
2016-08-21 17:53:14 +00:00
OBJ(lnp) = object(string, tabval2,
opr_size(instr));
1984-11-26 13:43:22 +00:00
break;
#endif
case sp_pnam:
lnp = newline(OPPROC);
2016-08-21 17:53:14 +00:00
PROC(lnp) = proclookup(string, OCCURRING);
1984-11-26 13:43:22 +00:00
VP(PROC(lnp));
break;
default:
assert(FALSE);
}
return lnp;
}
2016-08-21 17:53:14 +00:00
static char* hol_label()
{
static int holno;
line_p lnp;
2016-08-21 17:53:14 +00:00
extern char* lastname;
/* Create a label for a hol pseudo, so that it can be converted
* into a bss. The label is appended to the list of instructions.
*/
sprintf(string, "_HH%d", ++holno);
2016-08-21 17:53:14 +00:00
symlookup(string, OCCURRING); /* to make it exa */
db = block_of_lab(string);
lnp = newline(OPSHORT);
2016-08-21 17:53:14 +00:00
SHORT(lnp) = (short)db->d_id;
lnp->l_instr = ps_sym;
2016-08-21 17:53:14 +00:00
if (firstline == (line_p)0)
{
firstline = lnp;
}
2016-08-21 17:53:14 +00:00
if (lastline != (line_p)0)
{
lastline->l_next = lnp;
}
lastline = lnp;
return lastname;
}
2016-08-21 17:53:14 +00:00
line_p inpseudo(n) short n;
1984-11-26 13:43:22 +00:00
{
int m;
line_p lnp;
byte pseu;
short nlast;
/* Read the (remainder of) a pseudo instruction, the instruction
* code of which is n. The END pseudo may be deleted (return 0).
* The pseudos INA, EXA, INP and EXP (visibility pseudos) must
* also be deleted, although the effects they have on the
* visibility of global names and procedure names must first
* be recorded in the datablock or procedure table.
*/
2016-08-21 17:53:14 +00:00
switch (n)
{
1984-11-26 13:43:22 +00:00
case ps_hol:
/* hol pseudos are carefully converted into bss
* pseudos, so that the IL phase will not be
* bothered by this. Also, references to the ABS
* block will still work when passed through EGO.
*/
2016-08-21 17:53:14 +00:00
if (lastline != (line_p)0 && is_datalabel(lastline))
{
extern char* lastname;
1989-05-30 14:50:16 +00:00
curhol = lastname;
}
2016-08-21 17:53:14 +00:00
else
{
curhol = hol_label();
}
n = ps_bss;
2016-08-21 17:53:14 +00:00
/* fall through */
1984-11-26 13:43:22 +00:00
case ps_bss:
case ps_rom:
case ps_con:
2016-08-21 17:53:14 +00:00
if (lastline == (line_p)0 || !is_datalabel(lastline))
{
assert(lastline != (line_p)0);
nlast = INSTR(lastline);
2016-08-21 17:53:14 +00:00
if (n == nlast && (n == ps_rom || n == ps_con))
{
1984-11-26 13:43:22 +00:00
/* Two successive roms/cons are
* combined into one data block
* if the second is not preceded by
* a data label.
*/
lnp = arglist(0);
2016-08-21 17:53:14 +00:00
pseu = (byte)(n == ps_rom ? DROM : DCON);
combine(db, lastline, lnp, pseu);
1984-11-26 13:43:22 +00:00
oldline(lnp);
2016-08-21 17:53:14 +00:00
return (line_p)0;
}
else
{
error("datablock without label");
1984-11-26 13:43:22 +00:00
}
}
VD(db);
m = (n == ps_bss ? 3 : 0);
1984-11-26 13:43:22 +00:00
lnp = arglist(m);
/* Read the arguments, 3 for hol or bss and a list
* of undetermined length for rom and con.
*/
2016-08-21 17:53:14 +00:00
dblockdef(db, n, lnp);
1984-11-26 13:43:22 +00:00
/* Fill in d_pseudo, d_size and d_values fields of db */
2016-08-21 17:53:14 +00:00
if (fragm_type != db->d_pseudo)
{
1984-11-26 13:43:22 +00:00
/* Keep track of fragment numbers,
* enter a new fragment.
*/
fragm_nr++;
2016-08-21 17:53:14 +00:00
switch (db->d_pseudo)
{
1984-11-26 13:43:22 +00:00
case DCON:
case DROM:
fragm_type = db->d_pseudo;
break;
default:
fragm_type = DUNKNOWN;
break;
}
}
db->d_fragmnr = fragm_nr;
return lnp;
case ps_ina:
getsym(DEFINING);
/* Read and lookup a symbol. As this must be
* the first occurrence of the symbol and we
* say it's a defining occurrence, getsym will
* automatically make it internal (according to
* the EM visibility rules).
* The result (a dblock pointer) is voided.
*/
2016-08-21 17:53:14 +00:00
return (line_p)0;
1984-11-26 13:43:22 +00:00
case ps_inp:
2016-08-21 17:53:14 +00:00
getproc(DEFINING); /* same idea */
return (line_p)0;
1984-11-26 13:43:22 +00:00
case ps_exa:
getsym(OCCURRING);
2016-08-21 17:53:14 +00:00
return (line_p)0;
1984-11-26 13:43:22 +00:00
case ps_exp:
getproc(OCCURRING);
2016-08-21 17:53:14 +00:00
return (line_p)0;
1984-11-26 13:43:22 +00:00
case ps_pro:
curproc = getproc(DEFINING);
/* This is a real defining occurrence of a proc */
curproc->p_localbytes = get_off();
curproc->p_flags1 |= PF_BODYSEEN;
/* Record the fact that we came accross
* the body of this procedure.
*/
lnp = newline(OPPROC);
PROC(lnp) = curproc;
2016-08-21 17:53:14 +00:00
lnp->l_instr = (byte)ps_pro;
1984-11-26 13:43:22 +00:00
return lnp;
case ps_end:
curproc->p_nrlabels = labelcount;
lnp = newline(OPNO);
get_off();
/* Void # localbytes, which we already know
* from the PRO instruction.
*/
return lnp;
case ps_mes:
lnp = arglist(0);
2016-08-21 17:53:14 +00:00
switch ((int)aoff(ARG(lnp), 0))
{
case ms_err:
error("ms_err encountered");
case ms_opt:
error("ms_opt encountered");
case ms_emx:
ws = aoff(ARG(lnp), 1);
ps = aoff(ARG(lnp), 2);
break;
case ms_ext:
1984-11-26 13:43:22 +00:00
/* this message was already processed
* by the lib package
*/
2016-08-21 17:53:14 +00:00
case ms_src:
/* Don't bother about linecounts */
oldline(lnp);
return (line_p)0;
case ms_par:
mespar = aoff(ARG(lnp), 1);
/* #bytes of parameters of current proc */
break;
1984-11-26 13:43:22 +00:00
}
return lnp;
default:
assert(FALSE);
}
/* NOTREACHED */
}