274 lines
		
	
	
	
		
			5.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			274 lines
		
	
	
	
		
			5.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*  I N T E R M E D I A T E   C O D E
 | |
|  *
 | |
|  *  I C _ L I B . C
 | |
|  */
 | |
| 
 | |
| 
 | |
| #include <stdio.h>
 | |
| #include "../share/types.h"
 | |
| #include "../share/debug.h"
 | |
| #include "../../../h/em_spec.h"
 | |
| #include "../../../h/em_pseu.h"
 | |
| #include "../../../h/em_mes.h"
 | |
| #include "../../../h/arch.h"
 | |
| #include "ic.h"
 | |
| #include "ic_lookup.h"
 | |
| #include "ic_io.h"
 | |
| #include "../share/global.h"
 | |
| #include "../share/files.h"
 | |
| #include "ic_lib.h"
 | |
| 
 | |
| 
 | |
| STATIC skip_string(n)
 | |
| 	offset n;
 | |
| {
 | |
| 	/* Read a string of length n and void it */
 | |
| 
 | |
| 	while (n--) {
 | |
| 		readchar();
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| STATIC skip_arguments()
 | |
| {
 | |
| 	/* Skip the arguments of a MES pseudo. The argument
 | |
| 	 * list is terminated by a sp_cend byte.
 | |
| 	 */
 | |
| 
 | |
| 	for (;;) {
 | |
| 		switch(table2()) {
 | |
| 			case sp_scon:
 | |
| 				get_off(); /* void */
 | |
| 				/* fall through !!! */
 | |
| 			case sp_icon:
 | |
| 			case sp_ucon:
 | |
| 			case sp_fcon:
 | |
| 				get_int(); /* void */
 | |
| 				skip_string(get_off());
 | |
| 				break;
 | |
| 			case sp_cend:
 | |
| 				return;
 | |
| 			default:
 | |
| 				break;
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| STATIC bool proc_wanted(name)
 | |
| 	char *name;
 | |
| {
 | |
| 	/* See if 'name' is the name of an external procedure
 | |
| 	 * that has been used before, but for which no body
 | |
| 	 * has been given so far.
 | |
| 	 */
 | |
| 
 | |
| 	proc_p p;
 | |
| 
 | |
| 	if (( p = proclookup(name,IMPORTING)) != (proc_p) 0 &&
 | |
| 	   !(p->p_flags1 & PF_BODYSEEN)) {
 | |
| 		return TRUE;
 | |
| 	} else {
 | |
| 		return FALSE;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| STATIC bool data_wanted(name)
 | |
| 	char *name;
 | |
| {
 | |
| 	/* See if 'name' is the name of an externally visible
 | |
| 	 * data block that has been used before, but for which
 | |
| 	 * no defining occurrence has been given yet.
 | |
| 	 */
 | |
| 
 | |
| 	dblock_p db;
 | |
| 
 | |
| 	if ((db = symlookup(name,IMPORTING)) != (dblock_p) 0 &&
 | |
| 	   db->d_pseudo == DUNKNOWN) {
 | |
| 		return TRUE;
 | |
| 	} else {
 | |
| 		return FALSE;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| STATIC bool wanted_names()
 | |
| {
 | |
| 	/* Read the names of procedures and data labels,
 | |
| 	 * appearing in a 'MES ms_ext' pseudo. Those are
 | |
| 	 * the names of entities that are imported by
 | |
| 	 * a library module.
 | |
| 	 * If any of them is wanted, return TRUE.
 | |
| 	 * A name is wanted if it is the name of a procedure
 | |
| 	 * or data block for which applied occurrences but
 | |
| 	 * no defining occurrence has been met.
 | |
| 	 */
 | |
| 
 | |
| 	for (;;) {
 | |
| 		switch(table2()) {
 | |
| 			case DLBX:
 | |
| 				if (data_wanted(string)) {
 | |
| 					return TRUE;
 | |
| 				}
 | |
| 				/* A data entity with the name
 | |
| 				 * string is available.
 | |
| 				 */
 | |
| 				break;
 | |
| 			case sp_pnam:
 | |
| 				if (proc_wanted(string)) {
 | |
| 					return TRUE;
 | |
| 				}
 | |
| 				break;
 | |
| 			case sp_cend:
 | |
| 				return FALSE;
 | |
| 			default:
 | |
| 				error("wrong argument of MES %d", ms_ext);
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| STATIC FILE *curfile = NULL;
 | |
| STATIC bool useful()
 | |
| {
 | |
| 	/* Determine if any entity imported by the current
 | |
| 	 * compact EM assembly file  (which will usually be
 | |
| 	 * part of an archive file) is useful to us.
 | |
| 	 * The file must contain (before any other non-MES line)
 | |
| 	 * a 'MES ms_ext' pseudo that has as arguments the names
 | |
| 	 * of the entities imported.
 | |
| 	 */
 | |
| 
 | |
| 	for (;;) {
 | |
| 		if (table1() != PSEU || tabval != ps_mes) {
 | |
| 			error("cannot find MES %d in library file",ms_ext);
 | |
| 		}
 | |
| 		if (table2() != CSTX1) {
 | |
| 			error("message number expected");
 | |
| 		}
 | |
| 		if (tabval == ms_ext) {
 | |
| 			/* This is the one we searched */
 | |
| 			return wanted_names();
 | |
| 			/* Read the names of the imported entities
 | |
| 			 * and check if any of them is wanted.
 | |
| 			 */
 | |
| 		} else {
 | |
| 			skip_arguments(); /* skip remainder of this MES */
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| STATIC bool is_archive(name)
 | |
| 	char *name;
 | |
| {
 | |
| 	/* See if 'name' is the name of an archive file, i.e. it
 | |
| 	 * should end on ".a" and should at least be three characters
 | |
| 	 * long (i.e. the name ".a" is not accepted as an archive name!).
 | |
| 	 */
 | |
| 
 | |
| 	register char *p;
 | |
| 
 | |
| 	for (p = name; *p; p++);
 | |
| 	return (p > name+2) && (*--p == 'a') && (*--p == '.');
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| STATIC struct ar_hdr hdr;
 | |
| 
 | |
| STATIC bool read_hdr()
 | |
| {
 | |
| 	/* Read the header of an archive module */
 | |
| 
 | |
| 
 | |
| 	fread(&hdr, sizeof(hdr), 1, curfile);
 | |
| 	return !feof(curfile);
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| STATIC int argcnt = ARGSTART - 1;
 | |
| STATIC short arstate = NO_ARCHIVE;
 | |
| 
 | |
| 
 | |
| FILE *next_file(argc,argv)
 | |
| 	int argc;
 | |
| 	char *argv[];
 | |
| {
 | |
| 	/* See if there are more EM input files. The file names
 | |
| 	 * are given via argv. If a file is an archive file
 | |
| 	 * it is supposed to be a library of EM compact assembly
 | |
| 	 * files. A module (file) contained in this archive file
 | |
| 	 * is only used if it imports at least one procedure or
 | |
| 	 * datalabel for which we have not yet seen a defining
 | |
| 	 * occurrence, although we have seen a used occurrence.
 | |
| 	 */
 | |
| 
 | |
| 	 long ptr;
 | |
| 
 | |
| 	 for (;;) {
 | |
| 		/* This loop is only exited via a return */
 | |
| 		if (arstate == ARCHIVE) {
 | |
| 			/* We were reading an archive file */
 | |
| 			if (ftell(curfile) & 1) {
 | |
| 				/* modules in an archive file always
 | |
| 				 * begin on a word boundary, i.e. at
 | |
| 				 * an even address.
 | |
| 				 */
 | |
| 				fseek(curfile,1L,1);
 | |
| 			}
 | |
| 			if (read_hdr()) { /* read header of next module */
 | |
| 				ptr = ftell(curfile); /* file position */
 | |
| 				file_init(curfile,ARCHIVE,hdr.ar_size);
 | |
| 				/* tell i/o package that we're reading
 | |
| 				 * an archive module of given length.
 | |
| 				 */
 | |
| 				if (useful()) {
 | |
| 					/* re-initialize file, because 'useful'
 | |
| 					 * has read some bytes too.
 | |
| 					 */
 | |
| 					fseek(curfile,ptr,0); /* start module */
 | |
| 					file_init(curfile,ARCHIVE,hdr.ar_size);
 | |
| 					return curfile;
 | |
| 				} else {
 | |
| 					/* skip this module */
 | |
| 					fseek(curfile,
 | |
| 					  ptr+hdr.ar_size,0);
 | |
| 				}
 | |
| 			} else {
 | |
| 				/* done with this archive */
 | |
| 				arstate = NO_ARCHIVE;
 | |
| 			}
 | |
| 		} else {
 | |
| 			/* open next file, close old */
 | |
| 			if (curfile != NULL) {
 | |
| 				fclose(curfile);
 | |
| 			}
 | |
| 			argcnt++;
 | |
| 			if (argcnt >= argc) {
 | |
| 				/* done with all arguments */
 | |
| 				return NULL;
 | |
| 			}
 | |
| 			filename = argv[argcnt];
 | |
| 			if ((curfile = fopen(filename,"r")) == NULL) {
 | |
| 				error("cannot open %s",filename);
 | |
| 			}
 | |
| 			if (is_archive(filename)) {
 | |
| 				/* ends on '.a' */
 | |
| 				arstate = ARCHIVE;
 | |
| 				arch_init(curfile); /* read magic ar number */
 | |
| 			} else {
 | |
| 				file_init(curfile,NO_ARCHIVE,0L);
 | |
| 				return curfile;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 |