592 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			592 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* $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 . C
 | 
						|
 */
 | 
						|
 | 
						|
#include <stdlib.h>
 | 
						|
#include <stdio.h>
 | 
						|
#include <em_spec.h>
 | 
						|
#include <em_pseu.h>
 | 
						|
#include <em_flag.h>
 | 
						|
#include <em_mes.h>
 | 
						|
#include "../share/types.h"
 | 
						|
#include "../share/debug.h"
 | 
						|
#include "../share/def.h"
 | 
						|
#include "../share/map.h"
 | 
						|
#include "ic.h"
 | 
						|
#include "ic_lookup.h"
 | 
						|
#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/utils.h"
 | 
						|
 | 
						|
/* Global variables */
 | 
						|
 | 
						|
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[];
 | 
						|
{
 | 
						|
	/* 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;
 | 
						|
 | 
						|
	hol0_db = block_of_lab((char*)0);
 | 
						|
	while (next_file(argc-8, argv+8) != NULL)
 | 
						|
	{
 | 
						|
		/* Read all EM input files, process the code
 | 
						|
		 * and concatenate all output.
 | 
						|
		 */
 | 
						|
		curhol = (char*)0;
 | 
						|
		process_lines(lfile);
 | 
						|
		dump_procnames(prochash, NPROCHASH, pdump);
 | 
						|
		dump_dblocknames(symhash, NSYMHASH, ddump);
 | 
						|
		/* Save the names of all procedures that were
 | 
						|
		 * first come accross in this file.
 | 
						|
		 */
 | 
						|
		cleanprocs(prochash, NPROCHASH, PF_EXTERNAL);
 | 
						|
		cleandblocks(symhash, NSYMHASH, DF_EXTERNAL);
 | 
						|
		/* 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 */
 | 
						|
	cleanprocs(prochash, NPROCHASH, 0);
 | 
						|
	cleandblocks(symhash, NSYMHASH, 0);
 | 
						|
	/* Now write the datablock table and the proctable */
 | 
						|
	dfile = openfile(dname_out, "w");
 | 
						|
	putdtable(fdblock, dfile);
 | 
						|
	pfile = openfile(pname_out, "w");
 | 
						|
	putptable(fproc, pfile, FALSE);
 | 
						|
	exit(0);
 | 
						|
}
 | 
						|
 | 
						|
/* Value returned by readline */
 | 
						|
 | 
						|
#define NORMAL 0
 | 
						|
#define WITH_OPERAND 1
 | 
						|
#define EOFILE 2
 | 
						|
#define PRO_INSTR 3
 | 
						|
#define END_INSTR 4
 | 
						|
#define DELETED_INSTR 5
 | 
						|
 | 
						|
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)
 | 
						|
    FILE* fout;
 | 
						|
{
 | 
						|
	line_p lnp;
 | 
						|
	short instr;
 | 
						|
	bool eof;
 | 
						|
 | 
						|
	/* 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;
 | 
						|
	firstline = (line_p)0;
 | 
						|
	lastline = (line_p)0;
 | 
						|
	while (!eof)
 | 
						|
	{
 | 
						|
		linecount++; /* for error messages */
 | 
						|
		switch (readline(&instr, &lnp))
 | 
						|
		{
 | 
						|
			/* 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;
 | 
						|
			/* Fall through! */
 | 
						|
			case NORMAL:
 | 
						|
				VL(lnp);
 | 
						|
				if (lastline != (line_p)0)
 | 
						|
				{
 | 
						|
					lastline->l_next = lnp;
 | 
						|
				}
 | 
						|
				lastline = lnp;
 | 
						|
				break;
 | 
						|
			case EOFILE:
 | 
						|
				eof = TRUE;
 | 
						|
				fragm_type = DUNKNOWN;
 | 
						|
				if (firstline != (line_p)0)
 | 
						|
				{
 | 
						|
					add_end();
 | 
						|
					putlines(firstline, fout);
 | 
						|
					firstline = (line_p)0;
 | 
						|
				}
 | 
						|
				break;
 | 
						|
			case PRO_INSTR:
 | 
						|
				VL(lnp);
 | 
						|
				labelcount = 0;
 | 
						|
				if (firstline != lnp)
 | 
						|
				{
 | 
						|
					/* If PRO is not the first
 | 
						|
					 * instruction:
 | 
						|
					 */
 | 
						|
					add_end();
 | 
						|
					putlines(firstline, fout);
 | 
						|
					firstline = lnp;
 | 
						|
				}
 | 
						|
				lastline = lnp;
 | 
						|
				break;
 | 
						|
			case END_INSTR:
 | 
						|
				curproc->p_nrformals = mespar;
 | 
						|
				mespar = UNKNOWN_SIZE;
 | 
						|
				assert(lastline != (line_p)0);
 | 
						|
				lastline->l_next = lnp;
 | 
						|
				putlines(firstline, fout);
 | 
						|
				/* write and delete code */
 | 
						|
				firstline = (line_p)0;
 | 
						|
				lastline = (line_p)0;
 | 
						|
				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");
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
int readline(instr_out, lnp_out) short* instr_out;
 | 
						|
line_p* lnp_out;
 | 
						|
{
 | 
						|
	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.
 | 
						|
	 */
 | 
						|
 | 
						|
	VA((short*)instr_out);
 | 
						|
	VA((short*)lnp_out);
 | 
						|
	switch (table1())
 | 
						|
	{
 | 
						|
		/* 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);
 | 
						|
			SHORT(lnp) = (short)db->d_id;
 | 
						|
			lnp->l_instr = ps_sym;
 | 
						|
			*lnp_out = lnp;
 | 
						|
			if (firstline == (line_p)0)
 | 
						|
			{
 | 
						|
				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 */
 | 
						|
			if (n == ps_hol)
 | 
						|
				n = ps_bss;
 | 
						|
			if (lnp == (line_p)0)
 | 
						|
				return DELETED_INSTR;
 | 
						|
			*lnp_out = lnp;
 | 
						|
			lnp->l_instr = n;
 | 
						|
			if (firstline == (line_p)0)
 | 
						|
			{
 | 
						|
				firstline = lnp;
 | 
						|
				/* only a pseudo (e.g. PRO) or data label
 | 
						|
				 * can be the first instruction.
 | 
						|
				 */
 | 
						|
			}
 | 
						|
			if (n == ps_end)
 | 
						|
				return END_INSTR;
 | 
						|
			if (n == ps_pro)
 | 
						|
				return PRO_INSTR;
 | 
						|
			return NORMAL;
 | 
						|
	}
 | 
						|
	/* NOTREACHED */
 | 
						|
}
 | 
						|
 | 
						|
line_p readoperand(instr) short instr;
 | 
						|
{
 | 
						|
	/* 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);
 | 
						|
	flag = em_flag[instr - sp_fmnem] & EM_PAR;
 | 
						|
	if (flag == PAR_NO)
 | 
						|
	{
 | 
						|
		return (newline(OPNO));
 | 
						|
	}
 | 
						|
	switch (table2())
 | 
						|
	{
 | 
						|
		case sp_cend:
 | 
						|
			return (newline(OPNO));
 | 
						|
		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.
 | 
						|
			 */
 | 
						|
			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;
 | 
						|
			}
 | 
						|
			break;
 | 
						|
#ifdef LONGOFF
 | 
						|
		case CSTX2:
 | 
						|
			/* double constant */
 | 
						|
			if (flag == PAR_G)
 | 
						|
			{
 | 
						|
				lnp = newline(OPOBJECT);
 | 
						|
				OBJ(lnp) = object(curhol, tabval2,
 | 
						|
				    opr_size(instr));
 | 
						|
				break;
 | 
						|
			}
 | 
						|
			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);
 | 
						|
			OBJ(lnp) = object(string, (offset)0,
 | 
						|
			    opr_size(instr));
 | 
						|
			break;
 | 
						|
		case VALX1:
 | 
						|
			lnp = newline(OPOBJECT);
 | 
						|
			OBJ(lnp) = object(string, (offset)tabval,
 | 
						|
			    opr_size(instr));
 | 
						|
			break;
 | 
						|
#ifdef LONGOFF
 | 
						|
		case VALX2:
 | 
						|
			lnp = newline(OPOBJECT);
 | 
						|
			OBJ(lnp) = object(string, tabval2,
 | 
						|
			    opr_size(instr));
 | 
						|
			break;
 | 
						|
#endif
 | 
						|
		case sp_pnam:
 | 
						|
			lnp = newline(OPPROC);
 | 
						|
			PROC(lnp) = proclookup(string, OCCURRING);
 | 
						|
			VP(PROC(lnp));
 | 
						|
			break;
 | 
						|
		default:
 | 
						|
			assert(FALSE);
 | 
						|
	}
 | 
						|
	return lnp;
 | 
						|
}
 | 
						|
 | 
						|
static char* hol_label()
 | 
						|
{
 | 
						|
	static int holno;
 | 
						|
	line_p lnp;
 | 
						|
	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);
 | 
						|
	symlookup(string, OCCURRING); /* to make it exa */
 | 
						|
	db = block_of_lab(string);
 | 
						|
	lnp = newline(OPSHORT);
 | 
						|
	SHORT(lnp) = (short)db->d_id;
 | 
						|
	lnp->l_instr = ps_sym;
 | 
						|
	if (firstline == (line_p)0)
 | 
						|
	{
 | 
						|
		firstline = lnp;
 | 
						|
	}
 | 
						|
	if (lastline != (line_p)0)
 | 
						|
	{
 | 
						|
		lastline->l_next = lnp;
 | 
						|
	}
 | 
						|
	lastline = lnp;
 | 
						|
	return lastname;
 | 
						|
}
 | 
						|
 | 
						|
line_p inpseudo(n) short n;
 | 
						|
{
 | 
						|
	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.
 | 
						|
	 */
 | 
						|
 | 
						|
	switch (n)
 | 
						|
	{
 | 
						|
		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.
 | 
						|
			 */
 | 
						|
 | 
						|
			if (lastline != (line_p)0 && is_datalabel(lastline))
 | 
						|
			{
 | 
						|
				extern char* lastname;
 | 
						|
 | 
						|
				curhol = lastname;
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				curhol = hol_label();
 | 
						|
			}
 | 
						|
			n = ps_bss;
 | 
						|
		/* fall through */
 | 
						|
		case ps_bss:
 | 
						|
		case ps_rom:
 | 
						|
		case ps_con:
 | 
						|
			if (lastline == (line_p)0 || !is_datalabel(lastline))
 | 
						|
			{
 | 
						|
				assert(lastline != (line_p)0);
 | 
						|
				nlast = INSTR(lastline);
 | 
						|
				if (n == nlast && (n == ps_rom || n == ps_con))
 | 
						|
				{
 | 
						|
					/* Two successive roms/cons are
 | 
						|
					 * combined into one data block
 | 
						|
					 * if the second is not preceded by
 | 
						|
					 * a data label.
 | 
						|
					 */
 | 
						|
					lnp = arglist(0);
 | 
						|
					pseu = (byte)(n == ps_rom ? DROM : DCON);
 | 
						|
					combine(db, lastline, lnp, pseu);
 | 
						|
					oldline(lnp);
 | 
						|
					return (line_p)0;
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
					error("datablock without label");
 | 
						|
				}
 | 
						|
			}
 | 
						|
			VD(db);
 | 
						|
			m = (n == ps_bss ? 3 : 0);
 | 
						|
			lnp = arglist(m);
 | 
						|
			/* Read the arguments, 3 for hol or bss and a list
 | 
						|
			 * of undetermined length for rom and con.
 | 
						|
			 */
 | 
						|
			dblockdef(db, n, lnp);
 | 
						|
			/* Fill in d_pseudo, d_size and d_values fields of db */
 | 
						|
			if (fragm_type != db->d_pseudo)
 | 
						|
			{
 | 
						|
				/* Keep track of fragment numbers,
 | 
						|
				 * enter a new fragment.
 | 
						|
				 */
 | 
						|
				fragm_nr++;
 | 
						|
				switch (db->d_pseudo)
 | 
						|
				{
 | 
						|
					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.
 | 
						|
			 */
 | 
						|
			return (line_p)0;
 | 
						|
		case ps_inp:
 | 
						|
			getproc(DEFINING); /* same idea */
 | 
						|
			return (line_p)0;
 | 
						|
		case ps_exa:
 | 
						|
			getsym(OCCURRING);
 | 
						|
			return (line_p)0;
 | 
						|
		case ps_exp:
 | 
						|
			getproc(OCCURRING);
 | 
						|
			return (line_p)0;
 | 
						|
		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;
 | 
						|
			lnp->l_instr = (byte)ps_pro;
 | 
						|
			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);
 | 
						|
			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:
 | 
						|
				/* this message was already processed
 | 
						|
				 * by the lib package
 | 
						|
				 */
 | 
						|
				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;
 | 
						|
			}
 | 
						|
			return lnp;
 | 
						|
		default:
 | 
						|
			assert(FALSE);
 | 
						|
	}
 | 
						|
	/* NOTREACHED */
 | 
						|
}
 |