1 /* $Id: ic.c,v 1.11 1994/06/24 10:24:00 ceriel Exp $ */
3 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
4 * See the copyright notice in the ACK home directory, in the file "Copyright".
6 /* I N T E R M E D I A T E C O D E
16 #include "../share/types.h"
17 #include "../share/debug.h"
18 #include "../share/def.h"
19 #include "../share/map.h"
21 #include "ic_lookup.h"
25 #include "../share/alloc.h"
26 #include "../share/global.h"
27 #include "../share/files.h"
28 #include "../share/put.h"
29 #include "../share/aux.h"
32 /* Global variables */
36 dblock_p hol0_db; /* dblock for ABS block */
37 char *curhol; /* name of hol block in current scope */
38 dblock_p ldblock; /* last dblock */
39 proc_p lproc; /* last proc */
40 short tabval; /* used by table1, table2 and table3 */
43 line_p firstline; /* first line of current procedure */
44 line_p lastline; /* last line read */
45 int labelcount; /* # labels in current procedure */
46 short fragm_type = DUNKNOWN; /* fragm. type: DCON, DROM or DUNKNOWN */
47 short fragm_nr = 0; /* fragment number */
50 dblock_id lastdid = 0;
53 offset mespar = UNKNOWN_SIZE;
54 /* argumument of ps_par message of current procedure */
57 extern process_lines();
58 extern int readline();
59 extern line_p readoperand();
60 extern line_p inpseudo();
67 /* The input files must be legal EM Compact
68 * Assembly Language files, as produced by the EM Peephole
70 * Their file names are passed as arguments.
71 * The output consists of the files:
72 * - lfile: the EM code in Intermediate Code format
73 * - dfile: the data block table file
74 * - pfile: the proc table file
75 * - pdump: the names of all procedures
76 * - ddump: the names of all data blocks
79 FILE *lfile, *dfile, *pfile, *pdump, *ddump;
81 lfile = openfile(lname2,"w");
82 pdump = openfile(argv[1],"w");
83 ddump = openfile(argv[2],"w");
84 hol0_db = block_of_lab((char *) 0);
85 while (next_file(argc,argv) != NULL) {
86 /* Read all EM input files, process the code
87 * and concatenate all output.
91 dump_procnames(prochash,NPROCHASH,pdump);
92 dump_dblocknames(symhash,NSYMHASH,ddump);
93 /* Save the names of all procedures that were
94 * first come accross in this file.
96 cleanprocs(prochash,NPROCHASH,PF_EXTERNAL);
97 cleandblocks(symhash,NSYMHASH,DF_EXTERNAL);
98 /* Make all procedure names that were internal
99 * in this input file invisible.
107 /* remove the remainder of the hashing tables */
108 cleanprocs(prochash,NPROCHASH,0);
109 cleandblocks(symhash,NSYMHASH,0);
110 /* Now write the datablock table and the proctable */
111 dfile = openfile(dname2,"w");
112 putdtable(fdblock, dfile);
113 pfile = openfile(pname2,"w");
114 putptable(fproc, pfile,FALSE);
120 /* Value returned by readline */
123 #define WITH_OPERAND 1
127 #define DELETED_INSTR 5
132 /* Add an end-pseudo to the current instruction list */
134 lastline->l_next = newline(OPNO);
135 lastline = lastline->l_next;
136 lastline->l_instr = ps_end;
147 /* Read and process the code contained in the current file,
148 * on a per procedure basis.
149 * On the fly, fragments are formed. Recall that two
150 * successive CON pseudos are allocated consecutively
151 * in a single fragment, unless these CON pseudos are
152 * separated in the assembly language program by one
153 * of: ROM, BSS, HOL and END (and of course EndOfFile).
154 * The same is true for ROM pseudos.
155 * We keep track of a fragment type (DROM after a ROM
156 * pseudo, DCON after a CON and DUNKNOWN after a HOL,
157 * BSS, END or EndOfFile) and a fragment number (which
158 * is incremented every time we enter a new fragment).
159 * Every data block is assigned such a number
160 * when we come accross its defining occurrence.
164 firstline = (line_p) 0;
165 lastline = (line_p) 0;
167 linecount++; /* for error messages */
168 switch(readline(&instr, &lnp)) {
169 /* read one line, see what kind it is */
171 /* instruction with operand, e.g. LOL 10 */
172 lnp = readoperand(instr);
173 lnp->l_instr = instr;
177 if (lastline != (line_p) 0) {
178 lastline->l_next = lnp;
184 fragm_type = DUNKNOWN;
185 if (firstline != (line_p) 0) {
187 putlines(firstline,fout);
188 firstline = (line_p) 0;
194 if (firstline != lnp) {
195 /* If PRO is not the first
199 putlines(firstline,fout);
205 curproc->p_nrformals = mespar;
206 mespar = UNKNOWN_SIZE;
207 assert(lastline != (line_p) 0);
208 lastline->l_next = lnp;
209 putlines(firstline,fout);
210 /* write and delete code */
211 firstline = (line_p) 0;
212 lastline = (line_p) 0;
214 /* scope of instruction labels ends here,
215 * so forget about them.
217 fragm_type = DUNKNOWN;
220 /* EXP, INA etc. are deleted */
223 error("illegal readline");
230 int readline(instr_out, lnp_out)
237 /* Read one line. If it is a normal EM instruction without
238 * operand, we can allocate a line struct for it here.
239 * If so, return a pointer to it via lnp_out, else just
240 * return the instruction code via instr_out.
243 VA((short *) instr_out);
244 VA((short *) lnp_out);
246 /* table1 sets string, tabval or tabval2 and
247 * returns an indication of what was read.
252 *instr_out = tabval; /* instruction code */
255 /* data label defining occurrence, precedes
258 db = block_of_lab(string);
259 /* global variable, used by inpseudo */
260 lnp = newline(OPSHORT);
261 SHORT(lnp) = (short) db->d_id;
262 lnp->l_instr = ps_sym;
264 if (firstline == (line_p) 0) {
266 /* only a pseudo (e.g. PRO) or data label
267 * can be the first instruction.
272 /* instruction label defining occurrence */
274 lnp = newline(OPINSTRLAB);
275 lnp->l_instr = op_lab;
276 INSTRLAB(lnp) = instr_lab(tabval);
281 lnp = inpseudo(n); /* read a pseudo */
282 if (n == ps_hol) n = ps_bss;
283 if (lnp == (line_p) 0) return DELETED_INSTR;
286 if (firstline == (line_p) 0) {
288 /* only a pseudo (e.g. PRO) or data label
289 * can be the first instruction.
292 if (n == ps_end) return END_INSTR;
293 if (n == ps_pro) return PRO_INSTR;
300 line_p readoperand(instr)
303 /* Read the operand of the given instruction.
304 * Create a line struct and return a pointer to it.
312 flag = em_flag[ instr - sp_fmnem] & EM_PAR;
313 if (flag == PAR_NO) {
314 return (newline(OPNO));
318 return(newline(OPNO));
321 /* If the instruction has the address
322 * of an external variable as argument,
323 * the constant must be regarded as an
324 * offset in the current hol block,
325 * so an object must be created.
326 * Similarly, the instruction may have
327 * an instruction label as argument.
331 lnp = newline(OPOBJECT);
333 object(curhol,(offset) tabval,
337 lnp = newline(OPINSTRLAB);
338 INSTRLAB(lnp) = instr_lab(tabval);
341 lnp = newline(OPSHORT);
348 /* double constant */
350 lnp = newline(OPOBJECT);
352 object(curhol, tabval2,
356 lnp = newline(OPOFFSET);
357 OFFSET(lnp) = tabval2;
361 /* applied occurrence instruction label */
362 lnp = newline(OPINSTRLAB);
363 INSTRLAB(lnp) = instr_lab(tabval);
366 /* applied occurrence data label */
367 lnp = newline(OPOBJECT);
368 OBJ(lnp) = object(string, (offset) 0,
372 lnp = newline(OPOBJECT);
373 OBJ(lnp) = object(string, (offset) tabval,
378 lnp = newline(OPOBJECT);
379 OBJ(lnp) = object(string,tabval2,
384 lnp = newline(OPPROC);
385 PROC(lnp) = proclookup(string,OCCURRING);
395 static char *hol_label()
399 extern char *lastname;
401 /* Create a label for a hol pseudo, so that it can be converted
402 * into a bss. The label is appended to the list of instructions.
405 sprintf(string, "_HH%d", ++holno);
406 symlookup(string, OCCURRING); /* to make it exa */
407 db = block_of_lab(string);
408 lnp = newline(OPSHORT);
409 SHORT(lnp) = (short) db->d_id;
410 lnp->l_instr = ps_sym;
411 if (firstline == (line_p) 0) {
414 if (lastline != (line_p) 0) {
415 lastline->l_next = lnp;
430 /* Read the (remainder of) a pseudo instruction, the instruction
431 * code of which is n. The END pseudo may be deleted (return 0).
432 * The pseudos INA, EXA, INP and EXP (visibility pseudos) must
433 * also be deleted, although the effects they have on the
434 * visibility of global names and procedure names must first
435 * be recorded in the datablock or procedure table.
441 /* hol pseudos are carefully converted into bss
442 * pseudos, so that the IL phase will not be
443 * bothered by this. Also, references to the ABS
444 * block will still work when passed through EGO.
447 if (lastline != (line_p) 0 && is_datalabel(lastline)) {
448 extern char *lastname;
453 curhol = hol_label();
460 if (lastline == (line_p) 0 || !is_datalabel(lastline)) {
461 assert(lastline != (line_p) 0);
462 nlast = INSTR(lastline);
464 (n == ps_rom || n == ps_con)) {
465 /* Two successive roms/cons are
466 * combined into one data block
467 * if the second is not preceded by
471 pseu = (byte) (n == ps_rom?DROM:DCON);
472 combine(db,lastline,lnp,pseu);
476 error("datablock without label");
480 m = (n == ps_bss ? 3 : 0);
482 /* Read the arguments, 3 for hol or bss and a list
483 * of undetermined length for rom and con.
486 /* Fill in d_pseudo, d_size and d_values fields of db */
487 if (fragm_type != db->d_pseudo) {
488 /* Keep track of fragment numbers,
489 * enter a new fragment.
492 switch(db->d_pseudo) {
495 fragm_type = db->d_pseudo;
498 fragm_type = DUNKNOWN;
502 db->d_fragmnr = fragm_nr;
506 /* Read and lookup a symbol. As this must be
507 * the first occurrence of the symbol and we
508 * say it's a defining occurrence, getsym will
509 * automatically make it internal (according to
510 * the EM visibility rules).
511 * The result (a dblock pointer) is voided.
515 getproc(DEFINING); /* same idea */
524 curproc = getproc(DEFINING);
525 /* This is a real defining occurrence of a proc */
526 curproc->p_localbytes = get_off();
527 curproc->p_flags1 |= PF_BODYSEEN;
528 /* Record the fact that we came accross
529 * the body of this procedure.
531 lnp = newline(OPPROC);
533 lnp->l_instr = (byte) ps_pro;
536 curproc->p_nrlabels = labelcount;
539 /* Void # localbytes, which we already know
540 * from the PRO instruction.
545 switch((int) aoff(ARG(lnp),0)) {
547 error("ms_err encountered");
549 error("ms_opt encountered");
551 ws = aoff(ARG(lnp),1);
552 ps = aoff(ARG(lnp),2);
555 /* this message was already processed
559 /* Don't bother about linecounts */
563 mespar = aoff(ARG(lnp),1);
564 /* #bytes of parameters of current proc */