2108 lines
		
	
	
	
		
			49 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2108 lines
		
	
	
	
		
			49 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/****************************************************************
 | 
						|
Copyright 1990, 1991 by AT&T Bell Laboratories and Bellcore.
 | 
						|
 | 
						|
Permission to use, copy, modify, and distribute this software
 | 
						|
and its documentation for any purpose and without fee is hereby
 | 
						|
granted, provided that the above copyright notice appear in all
 | 
						|
copies and that both that the copyright notice and this
 | 
						|
permission notice and warranty disclaimer appear in supporting
 | 
						|
documentation, and that the names of AT&T Bell Laboratories or
 | 
						|
Bellcore or any of their entities not be used in advertising or
 | 
						|
publicity pertaining to distribution of the software without
 | 
						|
specific, written prior permission.
 | 
						|
 | 
						|
AT&T and Bellcore disclaim all warranties with regard to this
 | 
						|
software, including all implied warranties of merchantability
 | 
						|
and fitness.  In no event shall AT&T or Bellcore be liable for
 | 
						|
any special, indirect or consequential damages or any damages
 | 
						|
whatsoever resulting from loss of use, data or profits, whether
 | 
						|
in an action of contract, negligence or other tortious action,
 | 
						|
arising out of or in connection with the use or performance of
 | 
						|
this software.
 | 
						|
****************************************************************/
 | 
						|
 | 
						|
/* Format.c -- this file takes an intermediate file (generated by pass 1
 | 
						|
   of the translator) and some state information about the contents of that
 | 
						|
   file, and generates C program text. */
 | 
						|
 | 
						|
#include "defs.h"
 | 
						|
#include "p1defs.h"
 | 
						|
#include "format.h"
 | 
						|
#include "output.h"
 | 
						|
#include "names.h"
 | 
						|
#include "iob.h"
 | 
						|
 | 
						|
int c_output_line_length = DEF_C_LINE_LENGTH;
 | 
						|
 | 
						|
int last_was_label;	/* Boolean used to generate semicolons
 | 
						|
				   when a label terminates a block */
 | 
						|
static char this_proc_name[52];	/* Name of the current procedure.  This is
 | 
						|
				   probably too simplistic to handle
 | 
						|
				   multiple entry points */
 | 
						|
 | 
						|
static int p1getd(), p1gets(), p1getf(), get_p1_token();
 | 
						|
static int p1get_const(), p1getn();
 | 
						|
static expptr do_format(), do_p1_name_pointer(), do_p1_const();
 | 
						|
static expptr do_p1_expr(), do_p1_ident(), do_p1_charp(), do_p1_extern();
 | 
						|
static expptr do_p1_head(), do_p1_list(), do_p1_literal();
 | 
						|
static void do_p1_label(), do_p1_asgoto(), do_p1_goto();
 | 
						|
static void do_p1_if(), do_p1_else(), do_p1_elif(), do_p1_endif();
 | 
						|
static void do_p1_endelse(), do_p1_subr_ret(), do_p1_comp_goto();
 | 
						|
static void do_p1_for(), do_p1_end_for(), do_p1_fortran();
 | 
						|
static void do_p1_1while(), do_p1_2while(), do_p1_elseifstart();
 | 
						|
static void do_p1_comment(), do_p1_set_line();
 | 
						|
static expptr do_p1_addr();
 | 
						|
static void proto();
 | 
						|
void list_arg_types();
 | 
						|
chainp length_comp();
 | 
						|
void listargs();
 | 
						|
extern chainp assigned_fmts;
 | 
						|
static long old_lineno;
 | 
						|
static char filename[P1_FILENAME_MAX];
 | 
						|
extern int gflag;
 | 
						|
extern char *parens;
 | 
						|
 | 
						|
start_formatting ()
 | 
						|
{
 | 
						|
    FILE *infile;
 | 
						|
    static int wrote_one = 0;
 | 
						|
    extern int usedefsforcommon;
 | 
						|
    extern char *p1_file, *p1_bakfile;
 | 
						|
 | 
						|
    this_proc_name[0] = '\0';
 | 
						|
    last_was_label = 0;
 | 
						|
    old_lineno = lineno;
 | 
						|
    ei_next = ei_first;
 | 
						|
    wh_next = wh_first;
 | 
						|
 | 
						|
    (void) fclose (pass1_file);
 | 
						|
    if ((infile = fopen (p1_file, binread)) == NULL)
 | 
						|
	Fatal("start_formatting:  couldn't open the intermediate file\n");
 | 
						|
 | 
						|
    if (wrote_one)
 | 
						|
	nice_printf (c_file, "\n");
 | 
						|
 | 
						|
    while (!feof (infile)) {
 | 
						|
	expptr this_expr;
 | 
						|
 | 
						|
	this_expr = do_format (infile, c_file);
 | 
						|
	if (this_expr) {
 | 
						|
	    out_and_free_statement (c_file, this_expr);
 | 
						|
	} /* if this_expr */
 | 
						|
    } /* while !feof infile */
 | 
						|
 | 
						|
    (void) fclose (infile);
 | 
						|
 | 
						|
    if (last_was_label)
 | 
						|
	nice_printf (c_file, ";\n");
 | 
						|
 | 
						|
    prev_tab (c_file);
 | 
						|
    if (this_proc_name[0])
 | 
						|
	nice_printf (c_file, "} /* %s */\n", this_proc_name);
 | 
						|
 | 
						|
 | 
						|
/* Write the #undefs for common variable reference */
 | 
						|
 | 
						|
    if (usedefsforcommon) {
 | 
						|
	Extsym *ext;
 | 
						|
	int did_one = 0;
 | 
						|
 | 
						|
	for (ext = extsymtab; ext < nextext; ext++)
 | 
						|
	    if (ext -> extstg == STGCOMMON && ext -> used_here) {
 | 
						|
		ext -> used_here = 0;
 | 
						|
		if (!did_one)
 | 
						|
		    nice_printf (c_file, "\n");
 | 
						|
		wr_abbrevs(c_file, 0, ext->extp);
 | 
						|
		did_one = 1;
 | 
						|
		ext -> extp = CHNULL;
 | 
						|
	    } /* if */
 | 
						|
 | 
						|
	if (did_one)
 | 
						|
	    nice_printf (c_file, "\n");
 | 
						|
    } /* if usedefsforcommon */
 | 
						|
 | 
						|
    other_undefs(c_file);
 | 
						|
 | 
						|
    wrote_one = 1;
 | 
						|
 | 
						|
/* For debugging only */
 | 
						|
 | 
						|
    if (debugflag && (pass1_file = fopen (p1_bakfile, binwrite)))
 | 
						|
	if (infile = fopen (p1_file, binread)) {
 | 
						|
	    ffilecopy (infile, pass1_file);
 | 
						|
	    fclose (infile);
 | 
						|
	    fclose (pass1_file);
 | 
						|
	} /* if infile */
 | 
						|
 | 
						|
/* End of "debugging only" */
 | 
						|
 | 
						|
    scrub(p1_file);	/* optionally unlink */
 | 
						|
 | 
						|
    if ((pass1_file = fopen (p1_file, binwrite)) == NULL)
 | 
						|
	err ("start_formatting:  couldn't reopen the pass1 file");
 | 
						|
 | 
						|
} /* start_formatting */
 | 
						|
 | 
						|
 | 
						|
 static void
 | 
						|
put_semi(outfile)
 | 
						|
 FILE *outfile;
 | 
						|
{
 | 
						|
	nice_printf (outfile, ";\n");
 | 
						|
	last_was_label = 0;
 | 
						|
	}
 | 
						|
 | 
						|
#define SEM_CHECK(x) if (last_was_label) put_semi(x)
 | 
						|
 | 
						|
/* do_format -- takes an input stream (a file in pass1 format) and writes
 | 
						|
   the appropriate C code to   outfile   when possible.  When reading an
 | 
						|
   expression, the expression tree is returned instead. */
 | 
						|
 | 
						|
static expptr do_format (infile, outfile)
 | 
						|
FILE *infile, *outfile;
 | 
						|
{
 | 
						|
    int gsave, token_type, was_c_token;
 | 
						|
    expptr retval = ENULL;
 | 
						|
 | 
						|
    token_type = get_p1_token (infile);
 | 
						|
    was_c_token = 1;
 | 
						|
    switch (token_type) {
 | 
						|
	case P1_COMMENT:
 | 
						|
	    do_p1_comment (infile, outfile);
 | 
						|
	    was_c_token = 0;
 | 
						|
	    break;
 | 
						|
	case P1_SET_LINE:
 | 
						|
	    do_p1_set_line (infile);
 | 
						|
	    was_c_token = 0;
 | 
						|
	    break;
 | 
						|
	case P1_FILENAME:
 | 
						|
	    p1gets(infile, filename, P1_FILENAME_MAX);
 | 
						|
	    was_c_token = 0;
 | 
						|
	    break;
 | 
						|
	case P1_NAME_POINTER:
 | 
						|
	    retval = do_p1_name_pointer (infile);
 | 
						|
	    break;
 | 
						|
	case P1_CONST:
 | 
						|
	    retval = do_p1_const (infile);
 | 
						|
	    break;
 | 
						|
	case P1_EXPR:
 | 
						|
	    retval = do_p1_expr (infile, outfile);
 | 
						|
	    break;
 | 
						|
	case P1_IDENT:
 | 
						|
	    retval = do_p1_ident(infile);
 | 
						|
	    break;
 | 
						|
	case P1_CHARP:
 | 
						|
		retval = do_p1_charp(infile);
 | 
						|
		break;
 | 
						|
	case P1_EXTERN:
 | 
						|
	    retval = do_p1_extern (infile);
 | 
						|
	    break;
 | 
						|
	case P1_HEAD:
 | 
						|
	    gsave = gflag;
 | 
						|
	    gflag = 0;
 | 
						|
	    retval = do_p1_head (infile, outfile);
 | 
						|
	    gflag = gsave;
 | 
						|
	    break;
 | 
						|
	case P1_LIST:
 | 
						|
	    retval = do_p1_list (infile, outfile);
 | 
						|
	    break;
 | 
						|
	case P1_LITERAL:
 | 
						|
	    retval = do_p1_literal (infile);
 | 
						|
	    break;
 | 
						|
	case P1_LABEL:
 | 
						|
	    do_p1_label (infile, outfile);
 | 
						|
	    /* last_was_label = 1; -- now set in do_p1_label */
 | 
						|
	    was_c_token = 0;
 | 
						|
	    break;
 | 
						|
	case P1_ASGOTO:
 | 
						|
	    do_p1_asgoto (infile, outfile);
 | 
						|
	    break;
 | 
						|
	case P1_GOTO:
 | 
						|
	    do_p1_goto (infile, outfile);
 | 
						|
	    break;
 | 
						|
	case P1_IF:
 | 
						|
	    do_p1_if (infile, outfile);
 | 
						|
	    break;
 | 
						|
	case P1_ELSE:
 | 
						|
	    SEM_CHECK(outfile);
 | 
						|
	    do_p1_else (outfile);
 | 
						|
	    break;
 | 
						|
	case P1_ELIF:
 | 
						|
	    SEM_CHECK(outfile);
 | 
						|
	    do_p1_elif (infile, outfile);
 | 
						|
	    break;
 | 
						|
	case P1_ENDIF:
 | 
						|
	    SEM_CHECK(outfile);
 | 
						|
	    do_p1_endif (outfile);
 | 
						|
	    break;
 | 
						|
	case P1_ENDELSE:
 | 
						|
	    SEM_CHECK(outfile);
 | 
						|
	    do_p1_endelse (outfile);
 | 
						|
	    break;
 | 
						|
	case P1_ADDR:
 | 
						|
	    retval = do_p1_addr (infile, outfile);
 | 
						|
	    break;
 | 
						|
	case P1_SUBR_RET:
 | 
						|
	    do_p1_subr_ret (infile, outfile);
 | 
						|
	    break;
 | 
						|
	case P1_COMP_GOTO:
 | 
						|
	    do_p1_comp_goto (infile, outfile);
 | 
						|
	    break;
 | 
						|
	case P1_FOR:
 | 
						|
	    do_p1_for (infile, outfile);
 | 
						|
	    break;
 | 
						|
	case P1_ENDFOR:
 | 
						|
	    SEM_CHECK(outfile);
 | 
						|
	    do_p1_end_for (outfile);
 | 
						|
	    break;
 | 
						|
	case P1_WHILE1START:
 | 
						|
		do_p1_1while(outfile);
 | 
						|
		break;
 | 
						|
	case P1_WHILE2START:
 | 
						|
		do_p1_2while(infile, outfile);
 | 
						|
		break;
 | 
						|
	case P1_PROCODE:
 | 
						|
		procode(outfile);
 | 
						|
		break;
 | 
						|
	case P1_ELSEIFSTART:
 | 
						|
		SEM_CHECK(outfile);
 | 
						|
		do_p1_elseifstart(outfile);
 | 
						|
		break;
 | 
						|
	case P1_FORTRAN:
 | 
						|
		do_p1_fortran(infile, outfile);
 | 
						|
		/* no break; */
 | 
						|
	case P1_EOF:
 | 
						|
	    was_c_token = 0;
 | 
						|
	    break;
 | 
						|
	case P1_UNKNOWN:
 | 
						|
	    Fatal("do_format:  Unknown token type in intermediate file");
 | 
						|
	    break;
 | 
						|
	default:
 | 
						|
	    Fatal("do_format:  Bad token type in intermediate file");
 | 
						|
	    break;
 | 
						|
   } /* switch */
 | 
						|
 | 
						|
    if (was_c_token)
 | 
						|
	last_was_label = 0;
 | 
						|
    return retval;
 | 
						|
} /* do_format */
 | 
						|
 | 
						|
 | 
						|
 static void
 | 
						|
do_p1_comment (infile, outfile)
 | 
						|
FILE *infile, *outfile;
 | 
						|
{
 | 
						|
    extern int c_output_line_length, in_comment;
 | 
						|
 | 
						|
    char storage[COMMENT_BUFFER_SIZE + 1];
 | 
						|
    int length;
 | 
						|
 | 
						|
    if (!p1gets(infile, storage, COMMENT_BUFFER_SIZE + 1))
 | 
						|
	return;
 | 
						|
 | 
						|
    length = strlen (storage);
 | 
						|
 | 
						|
    in_comment = 1;
 | 
						|
    if (length > c_output_line_length - 6)
 | 
						|
	margin_printf (outfile, "/*%s*/\n", storage);
 | 
						|
    else
 | 
						|
	margin_printf (outfile, length ? "/* %s */\n" : "\n", storage);
 | 
						|
    in_comment = 0;
 | 
						|
} /* do_p1_comment */
 | 
						|
 | 
						|
 static void
 | 
						|
do_p1_set_line (infile)
 | 
						|
FILE *infile;
 | 
						|
{
 | 
						|
    int status;
 | 
						|
    long new_line_number = -1;
 | 
						|
 | 
						|
    status = p1getd (infile, &new_line_number);
 | 
						|
 | 
						|
    if (status == EOF)
 | 
						|
	err ("do_p1_set_line:  Missing line number at end of file\n");
 | 
						|
    else if (status == 0 || new_line_number == -1)
 | 
						|
	errl("do_p1_set_line:  Illegal line number in intermediate file: %ld\n",
 | 
						|
		new_line_number);
 | 
						|
    else {
 | 
						|
	lineno = new_line_number;
 | 
						|
	if (gflag)
 | 
						|
		fprintf(c_file, "/*# %ld \"%s\"*/\n", lineno, filename);
 | 
						|
	}
 | 
						|
} /* do_p1_set_line */
 | 
						|
 | 
						|
 | 
						|
static expptr do_p1_name_pointer (infile)
 | 
						|
FILE *infile;
 | 
						|
{
 | 
						|
    Namep namep = (Namep) NULL;
 | 
						|
    int status;
 | 
						|
 | 
						|
    status = p1getd (infile, (long *) &namep);
 | 
						|
 | 
						|
    if (status == EOF)
 | 
						|
	err ("do_p1_name_pointer:  Missing pointer at end of file\n");
 | 
						|
    else if (status == 0 || namep == (Namep) NULL)
 | 
						|
	erri ("do_p1_name_pointer:  Illegal name pointer in p1 file: '%x'\n",
 | 
						|
		(int) namep);
 | 
						|
 | 
						|
    return (expptr) namep;
 | 
						|
} /* do_p1_name_pointer */
 | 
						|
 | 
						|
 | 
						|
 | 
						|
static expptr do_p1_const (infile)
 | 
						|
FILE *infile;
 | 
						|
{
 | 
						|
    struct Constblock *c = (struct Constblock *) NULL;
 | 
						|
    long type = -1;
 | 
						|
    int status;
 | 
						|
 | 
						|
    status = p1getd (infile, &type);
 | 
						|
 | 
						|
    if (status == EOF)
 | 
						|
	err ("do_p1_const:  Missing constant type at end of file\n");
 | 
						|
    else if (status == 0)
 | 
						|
	errl("do_p1_const:  Illegal constant type in p1 file: %ld\n", type);
 | 
						|
    else {
 | 
						|
	status = p1get_const (infile, (int)type, &c);
 | 
						|
 | 
						|
	if (status == EOF) {
 | 
						|
	    err ("do_p1_const:  Missing constant value at end of file\n");
 | 
						|
	    c = (struct Constblock *) NULL;
 | 
						|
	} else if (status == 0) {
 | 
						|
	    err ("do_p1_const:  Illegal constant value in p1 file\n");
 | 
						|
	    c = (struct Constblock *) NULL;
 | 
						|
	} /* else */
 | 
						|
    } /* else */
 | 
						|
    return (expptr) c;
 | 
						|
} /* do_p1_const */
 | 
						|
 | 
						|
 | 
						|
static expptr do_p1_literal (infile)
 | 
						|
FILE *infile;
 | 
						|
{
 | 
						|
    int status;
 | 
						|
    long memno;
 | 
						|
    Addrp addrp;
 | 
						|
 | 
						|
    status = p1getd (infile, &memno);
 | 
						|
 | 
						|
    if (status == EOF)
 | 
						|
	err ("do_p1_literal:  Missing memno at end of file");
 | 
						|
    else if (status == 0)
 | 
						|
	err ("do_p1_literal:  Missing memno in p1 file");
 | 
						|
    else {
 | 
						|
	struct Literal *litp, *lastlit;
 | 
						|
 | 
						|
	addrp = ALLOC (Addrblock);
 | 
						|
	addrp -> tag = TADDR;
 | 
						|
	addrp -> vtype = TYUNKNOWN;
 | 
						|
	addrp -> Field = NULL;
 | 
						|
 | 
						|
	lastlit = litpool + nliterals;
 | 
						|
	for (litp = litpool; litp < lastlit; litp++)
 | 
						|
	    if (litp -> litnum == memno) {
 | 
						|
		addrp -> vtype = litp -> littype;
 | 
						|
		*((union Constant *) &(addrp -> user)) =
 | 
						|
			*((union Constant *) &(litp -> litval));
 | 
						|
		break;
 | 
						|
	    } /* if litp -> litnum == memno */
 | 
						|
 | 
						|
	addrp -> memno = memno;
 | 
						|
	addrp -> vstg = STGMEMNO;
 | 
						|
	addrp -> uname_tag = UNAM_CONST;
 | 
						|
    } /* else */
 | 
						|
 | 
						|
    return (expptr) addrp;
 | 
						|
} /* do_p1_literal */
 | 
						|
 | 
						|
 | 
						|
static void do_p1_label (infile, outfile)
 | 
						|
FILE *infile, *outfile;
 | 
						|
{
 | 
						|
    int status;
 | 
						|
    ftnint stateno;
 | 
						|
    char *user_label ();
 | 
						|
    struct Labelblock *L;
 | 
						|
    char *fmt;
 | 
						|
 | 
						|
    status = p1getd (infile, &stateno);
 | 
						|
 | 
						|
    if (status == EOF)
 | 
						|
	err ("do_p1_label:  Missing label at end of file");
 | 
						|
    else if (status == 0)
 | 
						|
	err ("do_p1_label:  Missing label in p1 file ");
 | 
						|
    else if (stateno < 0) {	/* entry */
 | 
						|
	margin_printf(outfile, "\n%s:\n", user_label(stateno));
 | 
						|
	last_was_label = 1;
 | 
						|
	}
 | 
						|
    else {
 | 
						|
	L = labeltab + stateno;
 | 
						|
	if (L->labused) {
 | 
						|
		fmt = "%s:\n";
 | 
						|
		last_was_label = 1;
 | 
						|
		}
 | 
						|
	else
 | 
						|
		fmt = "/* %s: */\n";
 | 
						|
	margin_printf(outfile, fmt, user_label(L->stateno));
 | 
						|
    } /* else */
 | 
						|
} /* do_p1_label */
 | 
						|
 | 
						|
 | 
						|
 | 
						|
static void do_p1_asgoto (infile, outfile)
 | 
						|
FILE *infile, *outfile;
 | 
						|
{
 | 
						|
    expptr expr;
 | 
						|
 | 
						|
    expr = do_format (infile, outfile);
 | 
						|
    out_asgoto (outfile, expr);
 | 
						|
 | 
						|
} /* do_p1_asgoto */
 | 
						|
 | 
						|
 | 
						|
static void do_p1_goto (infile, outfile)
 | 
						|
FILE *infile, *outfile;
 | 
						|
{
 | 
						|
    int status;
 | 
						|
    long stateno;
 | 
						|
    char *user_label ();
 | 
						|
 | 
						|
    status = p1getd (infile, &stateno);
 | 
						|
 | 
						|
    if (status == EOF)
 | 
						|
	err ("do_p1_goto:  Missing goto label at end of file");
 | 
						|
    else if (status == 0)
 | 
						|
	err ("do_p1_goto:  Missing goto label in p1 file");
 | 
						|
    else {
 | 
						|
	nice_printf (outfile, "goto %s;\n", user_label (stateno));
 | 
						|
    } /* else */
 | 
						|
} /* do_p1_goto */
 | 
						|
 | 
						|
 | 
						|
static void do_p1_if (infile, outfile)
 | 
						|
FILE *infile, *outfile;
 | 
						|
{
 | 
						|
    expptr cond;
 | 
						|
 | 
						|
    do {
 | 
						|
        cond = do_format (infile, outfile);
 | 
						|
    } while (cond == ENULL);
 | 
						|
 | 
						|
    out_if (outfile, cond);
 | 
						|
} /* do_p1_if */
 | 
						|
 | 
						|
 | 
						|
static void do_p1_else (outfile)
 | 
						|
FILE *outfile;
 | 
						|
{
 | 
						|
    out_else (outfile);
 | 
						|
} /* do_p1_else */
 | 
						|
 | 
						|
 | 
						|
static void do_p1_elif (infile, outfile)
 | 
						|
FILE *infile, *outfile;
 | 
						|
{
 | 
						|
    expptr cond;
 | 
						|
 | 
						|
    do {
 | 
						|
        cond = do_format (infile, outfile);
 | 
						|
    } while (cond == ENULL);
 | 
						|
 | 
						|
    elif_out (outfile, cond);
 | 
						|
} /* do_p1_elif */
 | 
						|
 | 
						|
static void do_p1_endif (outfile)
 | 
						|
FILE *outfile;
 | 
						|
{
 | 
						|
    endif_out (outfile);
 | 
						|
} /* do_p1_endif */
 | 
						|
 | 
						|
 | 
						|
static void do_p1_endelse (outfile)
 | 
						|
FILE *outfile;
 | 
						|
{
 | 
						|
    end_else_out (outfile);
 | 
						|
} /* do_p1_endelse */
 | 
						|
 | 
						|
 | 
						|
static expptr do_p1_addr (infile, outfile)
 | 
						|
FILE *infile, *outfile;
 | 
						|
{
 | 
						|
    Addrp addrp = (Addrp) NULL;
 | 
						|
    int status;
 | 
						|
 | 
						|
    status = p1getn (infile, sizeof (struct Addrblock), (char **) &addrp);
 | 
						|
 | 
						|
    if (status == EOF)
 | 
						|
	err ("do_p1_addr:  Missing Addrp at end of file");
 | 
						|
    else if (status == 0)
 | 
						|
	err ("do_p1_addr:  Missing Addrp in p1 file");
 | 
						|
    else if (addrp == (Addrp) NULL)
 | 
						|
	err ("do_p1_addr:  Null addrp in p1 file");
 | 
						|
    else if (addrp -> tag != TADDR)
 | 
						|
	erri ("do_p1_addr: bad tag in p1 file '%d'", addrp -> tag);
 | 
						|
    else {
 | 
						|
	addrp -> vleng = do_format (infile, outfile);
 | 
						|
	addrp -> memoffset = do_format (infile, outfile);
 | 
						|
    }
 | 
						|
 | 
						|
    return (expptr) addrp;
 | 
						|
} /* do_p1_addr */
 | 
						|
 | 
						|
 | 
						|
 | 
						|
static void do_p1_subr_ret (infile, outfile)
 | 
						|
FILE *infile, *outfile;
 | 
						|
{
 | 
						|
    expptr retval;
 | 
						|
 | 
						|
    nice_printf (outfile, "return ");
 | 
						|
    retval = do_format (infile, outfile);
 | 
						|
    if (!multitype)
 | 
						|
	if (retval)
 | 
						|
		expr_out (outfile, retval);
 | 
						|
 | 
						|
    nice_printf (outfile, ";\n");
 | 
						|
} /* do_p1_subr_ret */
 | 
						|
 | 
						|
 | 
						|
 | 
						|
static void do_p1_comp_goto (infile, outfile)
 | 
						|
FILE *infile, *outfile;
 | 
						|
{
 | 
						|
    expptr index;
 | 
						|
    expptr labels;
 | 
						|
 | 
						|
    index = do_format (infile, outfile);
 | 
						|
 | 
						|
    if (index == ENULL) {
 | 
						|
	err ("do_p1_comp_goto:  no expression for computed goto");
 | 
						|
	return;
 | 
						|
    } /* if index == ENULL */
 | 
						|
 | 
						|
    labels = do_format (infile, outfile);
 | 
						|
 | 
						|
    if (labels && labels -> tag != TLIST)
 | 
						|
	erri ("do_p1_comp_goto:  expected list, got tag '%d'", labels -> tag);
 | 
						|
    else
 | 
						|
	compgoto_out (outfile, index, labels);
 | 
						|
} /* do_p1_comp_goto */
 | 
						|
 | 
						|
 | 
						|
static void do_p1_for (infile, outfile)
 | 
						|
FILE *infile, *outfile;
 | 
						|
{
 | 
						|
    expptr init, test, inc;
 | 
						|
 | 
						|
    init = do_format (infile, outfile);
 | 
						|
    test = do_format (infile, outfile);
 | 
						|
    inc = do_format (infile, outfile);
 | 
						|
 | 
						|
    out_for (outfile, init, test, inc);
 | 
						|
} /* do_p1_for */
 | 
						|
 | 
						|
static void do_p1_end_for (outfile)
 | 
						|
FILE *outfile;
 | 
						|
{
 | 
						|
    out_end_for (outfile);
 | 
						|
} /* do_p1_end_for */
 | 
						|
 | 
						|
 | 
						|
 static void
 | 
						|
do_p1_fortran(infile, outfile)
 | 
						|
 FILE *infile, *outfile;
 | 
						|
{
 | 
						|
	char buf[P1_STMTBUFSIZE];
 | 
						|
	if (!p1gets(infile, buf, P1_STMTBUFSIZE))
 | 
						|
		return;
 | 
						|
	/* bypass nice_printf nonsense */
 | 
						|
	fprintf(outfile, "/*< %s >*/\n", buf+1);	/* + 1 to skip by '$' */
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
static expptr do_p1_expr (infile, outfile)
 | 
						|
FILE *infile, *outfile;
 | 
						|
{
 | 
						|
    int status;
 | 
						|
    long opcode, type;
 | 
						|
    struct Exprblock *result = (struct Exprblock *) NULL;
 | 
						|
 | 
						|
    status = p1getd (infile, &opcode);
 | 
						|
 | 
						|
    if (status == EOF)
 | 
						|
	err ("do_p1_expr:  Missing expr opcode at end of file");
 | 
						|
    else if (status == 0)
 | 
						|
	err ("do_p1_expr:  Missing expr opcode in p1 file");
 | 
						|
    else {
 | 
						|
 | 
						|
	status = p1getd (infile, &type);
 | 
						|
 | 
						|
	if (status == EOF)
 | 
						|
	    err ("do_p1_expr:  Missing expr type at end of file");
 | 
						|
	else if (status == 0)
 | 
						|
	    err ("do_p1_expr:  Missing expr type in p1 file");
 | 
						|
	else if (opcode == 0)
 | 
						|
	    return ENULL;
 | 
						|
	else {
 | 
						|
	    result = ALLOC (Exprblock);
 | 
						|
 | 
						|
	    result -> tag = TEXPR;
 | 
						|
	    result -> vtype = type;
 | 
						|
	    result -> opcode = opcode;
 | 
						|
	    result -> vleng = do_format (infile, outfile);
 | 
						|
 | 
						|
	    if (is_unary_op (opcode))
 | 
						|
		result -> leftp = do_format (infile, outfile);
 | 
						|
	    else if (is_binary_op (opcode)) {
 | 
						|
		result -> leftp = do_format (infile, outfile);
 | 
						|
		result -> rightp = do_format (infile, outfile);
 | 
						|
	    } else
 | 
						|
		errl("do_p1_expr:  Illegal opcode %ld", opcode);
 | 
						|
	} /* else */
 | 
						|
    } /* else */
 | 
						|
 | 
						|
    return (expptr) result;
 | 
						|
} /* do_p1_expr */
 | 
						|
 | 
						|
 | 
						|
static expptr do_p1_ident(infile)
 | 
						|
FILE *infile;
 | 
						|
{
 | 
						|
	Addrp addrp;
 | 
						|
	int status;
 | 
						|
	long vtype, vstg;
 | 
						|
 | 
						|
	addrp = ALLOC (Addrblock);
 | 
						|
	addrp -> tag = TADDR;
 | 
						|
 | 
						|
	status = p1getd (infile, &vtype);
 | 
						|
	if (status == EOF)
 | 
						|
	    err ("do_p1_ident:  Missing identifier type at end of file\n");
 | 
						|
	else if (status == 0 || vtype < 0 || vtype >= NTYPES)
 | 
						|
	    errl("do_p1_ident:  Bad type in intermediate file: %ld\n", vtype);
 | 
						|
	else
 | 
						|
	    addrp -> vtype = vtype;
 | 
						|
 | 
						|
	status = p1getd (infile, &vstg);
 | 
						|
	if (status == EOF)
 | 
						|
	    err ("do_p1_ident:  Missing identifier storage at end of file\n");
 | 
						|
	else if (status == 0 || vstg < 0 || vstg > STGNULL)
 | 
						|
	    errl("do_p1_ident:  Bad storage in intermediate file: %ld\n", vtype);
 | 
						|
	else
 | 
						|
	    addrp -> vstg = vstg;
 | 
						|
 | 
						|
	status = p1gets(infile, addrp->user.ident, IDENT_LEN);
 | 
						|
 | 
						|
	if (status == EOF)
 | 
						|
	    err ("do_p1_ident:  Missing ident string at end of file");
 | 
						|
	else if (status == 0)
 | 
						|
	    err ("do_p1_ident:  Missing ident string in intermediate file");
 | 
						|
	addrp->uname_tag = UNAM_IDENT;
 | 
						|
	return (expptr) addrp;
 | 
						|
} /* do_p1_ident */
 | 
						|
 | 
						|
static expptr do_p1_charp(infile)
 | 
						|
FILE *infile;
 | 
						|
{
 | 
						|
	Addrp addrp;
 | 
						|
	int status;
 | 
						|
	long vtype, vstg;
 | 
						|
	char buf[64];
 | 
						|
 | 
						|
	addrp = ALLOC (Addrblock);
 | 
						|
	addrp -> tag = TADDR;
 | 
						|
 | 
						|
	status = p1getd (infile, &vtype);
 | 
						|
	if (status == EOF)
 | 
						|
	    err ("do_p1_ident:  Missing identifier type at end of file\n");
 | 
						|
	else if (status == 0 || vtype < 0 || vtype >= NTYPES)
 | 
						|
	    errl("do_p1_ident:  Bad type in intermediate file: %ld\n", vtype);
 | 
						|
	else
 | 
						|
	    addrp -> vtype = vtype;
 | 
						|
 | 
						|
	status = p1getd (infile, &vstg);
 | 
						|
	if (status == EOF)
 | 
						|
	    err ("do_p1_ident:  Missing identifier storage at end of file\n");
 | 
						|
	else if (status == 0 || vstg < 0 || vstg > STGNULL)
 | 
						|
	    errl("do_p1_ident:  Bad storage in intermediate file: %ld\n", vtype);
 | 
						|
	else
 | 
						|
	    addrp -> vstg = vstg;
 | 
						|
 | 
						|
	status = p1gets(infile, buf, (int)sizeof(buf));
 | 
						|
 | 
						|
	if (status == EOF)
 | 
						|
	    err ("do_p1_ident:  Missing charp ident string at end of file");
 | 
						|
	else if (status == 0)
 | 
						|
	    err ("do_p1_ident:  Missing charp ident string in intermediate file");
 | 
						|
	addrp->uname_tag = UNAM_CHARP;
 | 
						|
	addrp->user.Charp = strcpy(mem(strlen(buf)+1,0), buf);
 | 
						|
	return (expptr) addrp;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static expptr do_p1_extern (infile)
 | 
						|
FILE *infile;
 | 
						|
{
 | 
						|
    Addrp addrp;
 | 
						|
 | 
						|
    addrp = ALLOC (Addrblock);
 | 
						|
    if (addrp) {
 | 
						|
	int status;
 | 
						|
 | 
						|
	addrp->tag = TADDR;
 | 
						|
	addrp->vstg = STGEXT;
 | 
						|
	addrp->uname_tag = UNAM_EXTERN;
 | 
						|
	status = p1getd (infile, &(addrp -> memno));
 | 
						|
	if (status == EOF)
 | 
						|
	    err ("do_p1_extern:  Missing memno at end of file");
 | 
						|
	else if (status == 0)
 | 
						|
	    err ("do_p1_extern:  Missing memno in intermediate file");
 | 
						|
	if (addrp->vtype = extsymtab[addrp->memno].extype)
 | 
						|
		addrp->vclass = CLPROC;
 | 
						|
    } /* if addrp */
 | 
						|
 | 
						|
    return (expptr) addrp;
 | 
						|
} /* do_p1_extern */
 | 
						|
 | 
						|
 | 
						|
 | 
						|
static expptr do_p1_head (infile, outfile)
 | 
						|
FILE *infile, *outfile;
 | 
						|
{
 | 
						|
    int status;
 | 
						|
    int add_n_;
 | 
						|
    long class;
 | 
						|
    char storage[256];
 | 
						|
 | 
						|
    status = p1getd (infile, &class);
 | 
						|
    if (status == EOF)
 | 
						|
	err ("do_p1_head:  missing header class at end of file");
 | 
						|
    else if (status == 0)
 | 
						|
	err ("do_p1_head:  missing header class in p1 file");
 | 
						|
    else {
 | 
						|
	status = p1gets (infile, storage, (int)sizeof(storage));
 | 
						|
	if (status == EOF || status == 0)
 | 
						|
	    storage[0] = '\0';
 | 
						|
    } /* else */
 | 
						|
 | 
						|
    if (class == CLPROC || class == CLMAIN) {
 | 
						|
	chainp lengths;
 | 
						|
 | 
						|
	add_n_ = nentry > 1;
 | 
						|
	lengths = length_comp(entries, add_n_);
 | 
						|
 | 
						|
	if (!add_n_ && protofile && class != CLMAIN)
 | 
						|
		protowrite(protofile, proctype, storage, entries, lengths);
 | 
						|
 | 
						|
	if (class == CLMAIN)
 | 
						|
	    nice_printf (outfile, "/* Main program */ ");
 | 
						|
	else
 | 
						|
	    nice_printf(outfile, "%s ", multitype ? "VOID"
 | 
						|
			: c_type_decl(proctype, 1));
 | 
						|
 | 
						|
	nice_printf(outfile, add_n_ ? "%s0_" : "%s", storage);
 | 
						|
	if (!Ansi) {
 | 
						|
		listargs(outfile, entries, add_n_, lengths);
 | 
						|
		nice_printf (outfile, "\n");
 | 
						|
		}
 | 
						|
	list_arg_types (outfile, entries, lengths, add_n_, "\n");
 | 
						|
	nice_printf (outfile, "{\n");
 | 
						|
	frchain(&lengths);
 | 
						|
	next_tab (outfile);
 | 
						|
	strcpy(this_proc_name, storage);
 | 
						|
	list_decls (outfile);
 | 
						|
 | 
						|
    } else if (class == CLBLOCK)
 | 
						|
        next_tab (outfile);
 | 
						|
    else
 | 
						|
	errl("do_p1_head: got class %ld", class);
 | 
						|
 | 
						|
    return NULL;
 | 
						|
} /* do_p1_head */
 | 
						|
 | 
						|
 | 
						|
static expptr do_p1_list (infile, outfile)
 | 
						|
FILE *infile, *outfile;
 | 
						|
{
 | 
						|
    long tag, type, count;
 | 
						|
    int status;
 | 
						|
    expptr result;
 | 
						|
 | 
						|
    status = p1getd (infile, &tag);
 | 
						|
    if (status == EOF)
 | 
						|
	err ("do_p1_list:  missing list tag at end of file");
 | 
						|
    else if (status == 0)
 | 
						|
	err ("do_p1_list:  missing list tag in p1 file");
 | 
						|
    else {
 | 
						|
	status = p1getd (infile, &type);
 | 
						|
	if (status == EOF)
 | 
						|
	    err ("do_p1_list:  missing list type at end of file");
 | 
						|
	else if (status == 0)
 | 
						|
	    err ("do_p1_list:  missing list type in p1 file");
 | 
						|
	else {
 | 
						|
	    status = p1getd (infile, &count);
 | 
						|
	    if (status == EOF)
 | 
						|
		err ("do_p1_list:  missing count at end of file");
 | 
						|
	    else if (status == 0)
 | 
						|
		err ("do_p1_list:  missing count in p1 file");
 | 
						|
	} /* else */
 | 
						|
    } /* else */
 | 
						|
 | 
						|
    result = (expptr) ALLOC (Listblock);
 | 
						|
    if (result) {
 | 
						|
	chainp pointer;
 | 
						|
 | 
						|
	result -> tag = tag;
 | 
						|
	result -> listblock.vtype = type;
 | 
						|
 | 
						|
/* Assume there will be enough data */
 | 
						|
 | 
						|
	if (count--) {
 | 
						|
	    pointer = result->listblock.listp =
 | 
						|
		mkchain((char *)do_format(infile, outfile), CHNULL);
 | 
						|
	    while (count--) {
 | 
						|
		pointer -> nextp =
 | 
						|
			mkchain((char *)do_format(infile, outfile), CHNULL);
 | 
						|
		pointer = pointer -> nextp;
 | 
						|
	    } /* while (count--) */
 | 
						|
	} /* if (count) */
 | 
						|
    } /* if (result) */
 | 
						|
 | 
						|
    return result;
 | 
						|
} /* do_p1_list */
 | 
						|
 | 
						|
 | 
						|
chainp length_comp(e, add_n)	/* get lengths of characters args */
 | 
						|
 struct Entrypoint *e;
 | 
						|
 int add_n;
 | 
						|
{
 | 
						|
	chainp lengths;
 | 
						|
	chainp args, args1;
 | 
						|
	Namep arg, np;
 | 
						|
	int nchargs;
 | 
						|
	Argtypes *at;
 | 
						|
	Atype *a;
 | 
						|
	extern int init_ac[TYSUBR+1];
 | 
						|
 | 
						|
	args = args1 = add_n ? allargs : e->arglist;
 | 
						|
	nchargs = 0;
 | 
						|
	for (lengths = NULL; args; args = args -> nextp)
 | 
						|
		if (arg = (Namep)args->datap) {
 | 
						|
			if (arg->vclass == CLUNKNOWN)
 | 
						|
				arg->vclass = CLVAR;
 | 
						|
			if (arg->vtype == TYCHAR && arg->vclass != CLPROC) {
 | 
						|
				lengths = mkchain((char *)arg, lengths);
 | 
						|
				nchargs++;
 | 
						|
				}
 | 
						|
			}
 | 
						|
	if (!add_n && (np = e->enamep)) {
 | 
						|
		/* one last check -- by now we know all we ever will
 | 
						|
		 * about external args...
 | 
						|
		 */
 | 
						|
		save_argtypes(e->arglist, &e->entryname->arginfo,
 | 
						|
			&np->arginfo, 0, np->fvarname, STGEXT, nchargs,
 | 
						|
			np->vtype, 1);
 | 
						|
		at = e->entryname->arginfo;
 | 
						|
		a = at->atypes + init_ac[np->vtype];
 | 
						|
		for(; args1; a++, args1 = args1->nextp) {
 | 
						|
			frchain(&a->cp);
 | 
						|
			if (arg = (Namep)args1->datap)
 | 
						|
			    switch(arg->vclass) {
 | 
						|
				case CLPROC:
 | 
						|
					if (arg->vimpltype
 | 
						|
					&& a->type >= 300)
 | 
						|
						a->type = TYUNKNOWN + 200;
 | 
						|
					break;
 | 
						|
				case CLUNKNOWN:
 | 
						|
					a->type %= 100;
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	return revchain(lengths);
 | 
						|
	}
 | 
						|
 | 
						|
void listargs(outfile, entryp, add_n_, lengths)
 | 
						|
 FILE *outfile;
 | 
						|
 struct Entrypoint *entryp;
 | 
						|
 int add_n_;
 | 
						|
 chainp lengths;
 | 
						|
{
 | 
						|
	chainp args;
 | 
						|
	char *s;
 | 
						|
	Namep arg;
 | 
						|
	int did_one = 0;
 | 
						|
 | 
						|
	nice_printf (outfile, "(");
 | 
						|
 | 
						|
	if (add_n_) {
 | 
						|
		nice_printf(outfile, "n__");
 | 
						|
		did_one = 1;
 | 
						|
		args = allargs;
 | 
						|
		}
 | 
						|
	else
 | 
						|
		args = entryp->arglist;
 | 
						|
 | 
						|
	if (multitype)
 | 
						|
		{
 | 
						|
		nice_printf(outfile, ", ret_val");
 | 
						|
		did_one = 1;
 | 
						|
		args = allargs;
 | 
						|
		}
 | 
						|
	else if (ONEOF(proctype, MSKCOMPLEX|MSKCHAR))
 | 
						|
		{
 | 
						|
		s = xretslot[proctype]->user.ident;
 | 
						|
		nice_printf(outfile, did_one ? ", %s" : "%s",
 | 
						|
			*s == '(' /*)*/ ? "r_v" : s);
 | 
						|
		did_one = 1;
 | 
						|
		if (proctype == TYCHAR)
 | 
						|
			nice_printf (outfile, ", ret_val_len");
 | 
						|
		}
 | 
						|
	for (; args; args = args -> nextp)
 | 
						|
		if (arg = (Namep)args->datap) {
 | 
						|
			nice_printf (outfile, "%s", did_one ? ", " : "");
 | 
						|
			out_name (outfile, arg);
 | 
						|
			did_one = 1;
 | 
						|
			}
 | 
						|
 | 
						|
	for (args = lengths; args; args = args -> nextp)
 | 
						|
		nice_printf(outfile, ", %s",
 | 
						|
			new_arg_length((Namep)args->datap));
 | 
						|
	nice_printf (outfile, ")");
 | 
						|
} /* listargs */
 | 
						|
 | 
						|
 | 
						|
void list_arg_types(outfile, entryp, lengths, add_n_, finalnl)
 | 
						|
FILE *outfile;
 | 
						|
struct Entrypoint *entryp;
 | 
						|
chainp lengths;
 | 
						|
int add_n_;
 | 
						|
char *finalnl;
 | 
						|
{
 | 
						|
    chainp args;
 | 
						|
    int last_type = -1, last_class = -1;
 | 
						|
    int did_one = 0, done_one, is_ext;
 | 
						|
    char *s, *sep = "", *sep1;
 | 
						|
 | 
						|
    if (outfile == (FILE *) NULL) {
 | 
						|
	err ("list_arg_types:  null output file");
 | 
						|
	return;
 | 
						|
    } else if (entryp == (struct Entrypoint *) NULL) {
 | 
						|
	err ("list_arg_types:  null procedure entry pointer");
 | 
						|
	return;
 | 
						|
    } /* else */
 | 
						|
 | 
						|
    if (Ansi) {
 | 
						|
	done_one = 0;
 | 
						|
	sep1 = ", ";
 | 
						|
	nice_printf(outfile, "(" /*)*/);
 | 
						|
	}
 | 
						|
    else {
 | 
						|
	done_one = 1;
 | 
						|
	sep1 = ";\n";
 | 
						|
	}
 | 
						|
    args = entryp->arglist;
 | 
						|
    if (add_n_) {
 | 
						|
	nice_printf(outfile, "int n__");
 | 
						|
	did_one = done_one;
 | 
						|
	sep = sep1;
 | 
						|
	args = allargs;
 | 
						|
	}
 | 
						|
    if (multitype) {
 | 
						|
	nice_printf(outfile, "%sMultitype *ret_val", sep);
 | 
						|
	did_one = done_one;
 | 
						|
	sep = sep1;
 | 
						|
	}
 | 
						|
    else if (ONEOF (proctype, MSKCOMPLEX|MSKCHAR)) {
 | 
						|
	s = xretslot[proctype]->user.ident;
 | 
						|
	nice_printf(outfile, "%s%s *%s", sep, c_type_decl(proctype, 0),
 | 
						|
			*s == '(' /*)*/ ? "r_v" : s);
 | 
						|
	did_one = done_one;
 | 
						|
	sep = sep1;
 | 
						|
	if (proctype == TYCHAR)
 | 
						|
	    nice_printf (outfile, "%sftnlen ret_val_len", sep);
 | 
						|
    } /* if ONEOF proctype */
 | 
						|
    for (; args; args = args -> nextp) {
 | 
						|
	Namep arg = (Namep) args->datap;
 | 
						|
 | 
						|
/* Scalars are passed by reference, and arrays will have their lower bound
 | 
						|
   adjusted, so nearly everything is printed with a star in front.  The
 | 
						|
   exception is character lengths, which are passed by value. */
 | 
						|
 | 
						|
	if (arg) {
 | 
						|
	    int type = arg -> vtype, class = arg -> vclass;
 | 
						|
 | 
						|
	    if (class == CLPROC)
 | 
						|
		if (arg->vimpltype)
 | 
						|
			type = Castargs ? TYUNKNOWN : TYSUBR;
 | 
						|
		else if (type == TYREAL && forcedouble && !Castargs)
 | 
						|
			type = TYDREAL;
 | 
						|
 | 
						|
	    if (type == last_type && class == last_class && did_one)
 | 
						|
		nice_printf (outfile, ", ");
 | 
						|
	    else
 | 
						|
		if ((is_ext = class == CLPROC) && Castargs)
 | 
						|
			nice_printf(outfile, "%s%s ", sep,
 | 
						|
				usedcasts[type] = casttypes[type]);
 | 
						|
		else
 | 
						|
			nice_printf(outfile, "%s%s ", sep,
 | 
						|
				c_type_decl(type, is_ext));
 | 
						|
	    if (class == CLPROC)
 | 
						|
		if (Castargs)
 | 
						|
			out_name(outfile, arg);
 | 
						|
		else {
 | 
						|
			nice_printf(outfile, "(*");
 | 
						|
			out_name(outfile, arg);
 | 
						|
			nice_printf(outfile, ") %s", parens);
 | 
						|
			}
 | 
						|
	    else {
 | 
						|
		nice_printf (outfile, "*");
 | 
						|
		out_name (outfile, arg);
 | 
						|
		}
 | 
						|
 | 
						|
	    last_type = type;
 | 
						|
	    last_class = class;
 | 
						|
	    did_one = done_one;
 | 
						|
	    sep = sep1;
 | 
						|
	} /* if (arg) */
 | 
						|
    } /* for args = entryp -> arglist */
 | 
						|
 | 
						|
    for (args = lengths; args; args = args -> nextp)
 | 
						|
	nice_printf(outfile, "%sftnlen %s", sep,
 | 
						|
			new_arg_length((Namep)args->datap));
 | 
						|
    if (did_one)
 | 
						|
	nice_printf (outfile, ";\n");
 | 
						|
    else if (Ansi)
 | 
						|
	nice_printf(outfile,
 | 
						|
		/*((*/ sep != sep1 && Ansi == 1 ? "void)%s" : ")%s",
 | 
						|
		finalnl);
 | 
						|
} /* list_arg_types */
 | 
						|
 | 
						|
 static void
 | 
						|
write_formats(outfile)
 | 
						|
 FILE *outfile;
 | 
						|
{
 | 
						|
	register struct Labelblock *lp;
 | 
						|
	int first = 1;
 | 
						|
	char *fs;
 | 
						|
 | 
						|
	for(lp = labeltab ; lp < highlabtab ; ++lp)
 | 
						|
		if (lp->fmtlabused) {
 | 
						|
			if (first) {
 | 
						|
				first = 0;
 | 
						|
				nice_printf(outfile, "/* Format strings */\n");
 | 
						|
				}
 | 
						|
			nice_printf(outfile, "static char fmt_%ld[] = \"",
 | 
						|
				lp->stateno);
 | 
						|
			if (!(fs = lp->fmtstring))
 | 
						|
				fs = "";
 | 
						|
			nice_printf(outfile, "%s\";\n", fs);
 | 
						|
			}
 | 
						|
	if (!first)
 | 
						|
		nice_printf(outfile, "\n");
 | 
						|
	}
 | 
						|
 | 
						|
 static void
 | 
						|
write_ioblocks(outfile)
 | 
						|
 FILE *outfile;
 | 
						|
{
 | 
						|
	register iob_data *L;
 | 
						|
	register char *f, **s, *sep;
 | 
						|
 | 
						|
	nice_printf(outfile, "/* Fortran I/O blocks */\n");
 | 
						|
	L = iob_list = (iob_data *)revchain((chainp)iob_list);
 | 
						|
	do {
 | 
						|
		nice_printf(outfile, "static %s %s = { ",
 | 
						|
			L->type, L->name);
 | 
						|
		sep = 0;
 | 
						|
		for(s = L->fields; f = *s; s++) {
 | 
						|
			if (sep)
 | 
						|
				nice_printf(outfile, sep);
 | 
						|
			sep = ", ";
 | 
						|
			if (*f == '"') {	/* kludge */
 | 
						|
				nice_printf(outfile, "\"");
 | 
						|
				nice_printf(outfile, "%s\"", f+1);
 | 
						|
				}
 | 
						|
			else
 | 
						|
				nice_printf(outfile, "%s", f);
 | 
						|
			}
 | 
						|
		nice_printf(outfile, " };\n");
 | 
						|
		}
 | 
						|
		while(L = L->next);
 | 
						|
	nice_printf(outfile, "\n\n");
 | 
						|
	}
 | 
						|
 | 
						|
 static void
 | 
						|
write_assigned_fmts(outfile)
 | 
						|
 FILE *outfile;
 | 
						|
{
 | 
						|
	register chainp cp;
 | 
						|
	Namep np;
 | 
						|
	int did_one = 0;
 | 
						|
 | 
						|
	cp = assigned_fmts = revchain(assigned_fmts);
 | 
						|
	nice_printf(outfile, "/* Assigned format variables */\nchar ");
 | 
						|
	do {
 | 
						|
		np = (Namep)cp->datap;
 | 
						|
		if (did_one)
 | 
						|
			nice_printf(outfile, ", ");
 | 
						|
		did_one = 1;
 | 
						|
		nice_printf(outfile, "*%s_fmt", np->fvarname);
 | 
						|
		}
 | 
						|
		while(cp = cp->nextp);
 | 
						|
	nice_printf(outfile, ";\n\n");
 | 
						|
	}
 | 
						|
 | 
						|
 static char *
 | 
						|
to_upper(s)
 | 
						|
 register char *s;
 | 
						|
{
 | 
						|
	static char buf[64];
 | 
						|
	register char *t = buf;
 | 
						|
	register int c;
 | 
						|
	while(*t++ = (c = *s++) >= 'a' && c <= 'z' ? c + 'A' - 'a' : c);
 | 
						|
	return buf;
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
/* This routine creates static structures representing a namelist.
 | 
						|
   Declarations of the namelist and related structures are:
 | 
						|
 | 
						|
	struct Vardesc {
 | 
						|
		char *name;
 | 
						|
		char *addr;
 | 
						|
		ftnlen *dims;	/* laid out as struct dimensions below *//*
 | 
						|
		int  type;
 | 
						|
		};
 | 
						|
	typedef struct Vardesc Vardesc;
 | 
						|
 | 
						|
	struct Namelist {
 | 
						|
		char *name;
 | 
						|
		Vardesc **vars;
 | 
						|
		int nvars;
 | 
						|
		};
 | 
						|
 | 
						|
	struct dimensions
 | 
						|
		{
 | 
						|
		ftnlen numberofdimensions;
 | 
						|
		ftnlen numberofelements
 | 
						|
		ftnlen baseoffset;
 | 
						|
		ftnlen span[numberofdimensions-1];
 | 
						|
		};
 | 
						|
 | 
						|
   If dims is not null, then the corner element of the array is at
 | 
						|
   addr.  However,  the element with subscripts (i1,...,in) is at
 | 
						|
   addr + sizeoftype * (i1+span[0]*(i2+span[1]*...) - dimp->baseoffset)
 | 
						|
*/
 | 
						|
 | 
						|
 static void
 | 
						|
write_namelists(nmch, outfile)
 | 
						|
 chainp nmch;
 | 
						|
 FILE *outfile;
 | 
						|
{
 | 
						|
	Namep var;
 | 
						|
	struct Hashentry *entry;
 | 
						|
	struct Dimblock *dimp;
 | 
						|
	int i, nd, type;
 | 
						|
	char *comma, *name;
 | 
						|
	register chainp q;
 | 
						|
	register Namep v;
 | 
						|
 | 
						|
	nice_printf(outfile, "/* Namelist stuff */\n\n");
 | 
						|
	for (entry = hashtab; entry < lasthash; ++entry) {
 | 
						|
		if (!(v = entry->varp) || !v->vnamelist)
 | 
						|
			continue;
 | 
						|
		type = v->vtype;
 | 
						|
		name = v->cvarname;
 | 
						|
		if (dimp = v->vdim) {
 | 
						|
			nd = dimp->ndim;
 | 
						|
			nice_printf(outfile,
 | 
						|
				"static ftnlen %s_dims[] = { %d, %ld, %ld",
 | 
						|
				name, nd,
 | 
						|
				dimp->nelt->constblock.Const.ci,
 | 
						|
				dimp->baseoffset->constblock.Const.ci);
 | 
						|
			for(i = 0, --nd; i < nd; i++)
 | 
						|
				nice_printf(outfile, ", %ld",
 | 
						|
				  dimp->dims[i].dimsize->constblock.Const.ci);
 | 
						|
			nice_printf(outfile, " };\n");
 | 
						|
			}
 | 
						|
		nice_printf(outfile, "static Vardesc %s_dv = { \"%s\", %s",
 | 
						|
			name, to_upper(name),
 | 
						|
			type == TYCHAR ? "" : dimp ? "(char *)" : "(char *)&");
 | 
						|
		out_name(outfile, v);
 | 
						|
		nice_printf(outfile, dimp ? ", %s_dims" : ", (ftnlen *)0", name);
 | 
						|
		nice_printf(outfile, ", %ld };\n",
 | 
						|
			type != TYCHAR  ? (long)type
 | 
						|
					: -v->vleng->constblock.Const.ci);
 | 
						|
		}
 | 
						|
 | 
						|
	do {
 | 
						|
		var = (Namep)nmch->datap;
 | 
						|
		name = var->cvarname;
 | 
						|
		nice_printf(outfile, "\nstatic Vardesc *%s_vl[] = ", name);
 | 
						|
		comma = "{";
 | 
						|
		i = 0;
 | 
						|
		for(q = var->varxptr.namelist ; q ; q = q->nextp) {
 | 
						|
			v = (Namep)q->datap;
 | 
						|
			if (!v->vnamelist)
 | 
						|
				continue;
 | 
						|
			i++;
 | 
						|
			nice_printf(outfile, "%s &%s_dv", comma, v->cvarname);
 | 
						|
			comma = ",";
 | 
						|
			}
 | 
						|
		nice_printf(outfile, " };\n");
 | 
						|
		nice_printf(outfile,
 | 
						|
			"static Namelist %s = { \"%s\", %s_vl, %d };\n",
 | 
						|
			name, to_upper(name), name, i);
 | 
						|
		}
 | 
						|
		while(nmch = nmch->nextp);
 | 
						|
	nice_printf(outfile, "\n");
 | 
						|
	}
 | 
						|
 | 
						|
/* fixextype tries to infer from usage in previous procedures
 | 
						|
   the type of an external procedure declared
 | 
						|
   external and passed as an argument but never typed or invoked.
 | 
						|
 */
 | 
						|
 | 
						|
 static int
 | 
						|
fixexttype(var)
 | 
						|
 Namep var;
 | 
						|
{
 | 
						|
	Extsym *e;
 | 
						|
	int type, type1;
 | 
						|
	extern void changedtype();
 | 
						|
 | 
						|
	type = var->vtype;
 | 
						|
	e = &extsymtab[var->vardesc.varno];
 | 
						|
	if ((type1 = e->extype) && type == TYUNKNOWN)
 | 
						|
		return var->vtype = type1;
 | 
						|
	if (var->visused) {
 | 
						|
		if (e->exused && type != type1)
 | 
						|
			changedtype(var);
 | 
						|
		e->exused = 1;
 | 
						|
		e->extype = type;
 | 
						|
		}
 | 
						|
	return type;
 | 
						|
	}
 | 
						|
 | 
						|
list_decls (outfile)
 | 
						|
FILE *outfile;
 | 
						|
{
 | 
						|
    extern chainp used_builtins;
 | 
						|
    extern struct Hashentry *hashtab;
 | 
						|
    extern ftnint wr_char_len();
 | 
						|
    struct Hashentry *entry;
 | 
						|
    int write_header = 1;
 | 
						|
    int last_class = -1, last_stg = -1;
 | 
						|
    Namep var;
 | 
						|
    int Alias, Define, did_one, last_type, type;
 | 
						|
    extern int def_equivs, useauto;
 | 
						|
    extern chainp new_vars;	/* Compiler-generated locals */
 | 
						|
    chainp namelists = 0;
 | 
						|
    char *ctype;
 | 
						|
    long lineno_save = lineno;
 | 
						|
    int useauto1 = useauto && !saveall;
 | 
						|
    long x;
 | 
						|
    extern int hsize;
 | 
						|
 | 
						|
    lineno = old_lineno;
 | 
						|
 | 
						|
/* First write out the statically initialized data */
 | 
						|
 | 
						|
    if (initfile)
 | 
						|
	list_init_data(&initfile, initfname, outfile);
 | 
						|
 | 
						|
/* Next come formats */
 | 
						|
    write_formats(outfile);
 | 
						|
 | 
						|
/* Now write out the system-generated identifiers */
 | 
						|
 | 
						|
    if (new_vars || nequiv) {
 | 
						|
	chainp args, next_var, this_var;
 | 
						|
	chainp nv[TYVOID], nv1[TYVOID];
 | 
						|
	int i, j;
 | 
						|
	Addrp Var;
 | 
						|
	Namep arg;
 | 
						|
 | 
						|
	/* zap unused dimension variables */
 | 
						|
 | 
						|
	for(args = allargs; args; args = args->nextp) {
 | 
						|
		arg = (Namep)args->datap;
 | 
						|
		if (this_var = arg->vlastdim) {
 | 
						|
			frexpr((tagptr)this_var->datap);
 | 
						|
			this_var->datap = 0;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
	/* sort new_vars by type, skipping entries just zapped */
 | 
						|
 | 
						|
	for(i = TYADDR; i < TYVOID; i++)
 | 
						|
		nv[i] = 0;
 | 
						|
	for(this_var = new_vars; this_var; this_var = next_var) {
 | 
						|
		next_var = this_var->nextp;
 | 
						|
		if (Var = (Addrp)this_var->datap) {
 | 
						|
			if (!(this_var->nextp = nv[j = Var->vtype]))
 | 
						|
				nv1[j] = this_var;
 | 
						|
			nv[j] = this_var;
 | 
						|
			}
 | 
						|
		else {
 | 
						|
			this_var->nextp = 0;
 | 
						|
			frchain(&this_var);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	new_vars = 0;
 | 
						|
	for(i = TYVOID; --i >= TYADDR;)
 | 
						|
		if (this_var = nv[i]) {
 | 
						|
			nv1[i]->nextp = new_vars;
 | 
						|
			new_vars = this_var;
 | 
						|
			}
 | 
						|
 | 
						|
	/* write the declarations */
 | 
						|
 | 
						|
	did_one = 0;
 | 
						|
	last_type = -1;
 | 
						|
 | 
						|
	for (this_var = new_vars; this_var; this_var = this_var -> nextp) {
 | 
						|
	    Var = (Addrp) this_var->datap;
 | 
						|
 | 
						|
	    if (Var == (Addrp) NULL)
 | 
						|
		err ("list_decls:  null variable");
 | 
						|
	    else if (Var -> tag != TADDR)
 | 
						|
		erri ("list_decls:  bad tag on new variable '%d'",
 | 
						|
			Var -> tag);
 | 
						|
 | 
						|
	    type = nv_type (Var);
 | 
						|
	    if (Var->vstg == STGINIT
 | 
						|
	    ||  Var->uname_tag == UNAM_IDENT
 | 
						|
			&& *Var->user.ident == ' '
 | 
						|
			&& multitype)
 | 
						|
		continue;
 | 
						|
	    if (!did_one)
 | 
						|
		nice_printf (outfile, "/* System generated locals */\n");
 | 
						|
 | 
						|
	    if (last_type == type && did_one)
 | 
						|
		nice_printf (outfile, ", ");
 | 
						|
	    else {
 | 
						|
		if (did_one)
 | 
						|
		    nice_printf (outfile, ";\n");
 | 
						|
		nice_printf (outfile, "%s ",
 | 
						|
			c_type_decl (type, Var -> vclass == CLPROC));
 | 
						|
	    } /* else */
 | 
						|
 | 
						|
/* Character type is really a string type.  Put out a '*' for parameters
 | 
						|
   with unknown length and functions returning character */
 | 
						|
 | 
						|
	    if (Var -> vtype == TYCHAR && (!ISICON ((Var -> vleng))
 | 
						|
		    || Var -> vclass == CLPROC))
 | 
						|
		nice_printf (outfile, "*");
 | 
						|
 | 
						|
	    write_nv_ident(outfile, (Addrp)this_var->datap);
 | 
						|
	    if (Var -> vtype == TYCHAR && Var->vclass != CLPROC &&
 | 
						|
		    ISICON((Var -> vleng))
 | 
						|
			&& (i = Var->vleng->constblock.Const.ci) > 0)
 | 
						|
		nice_printf (outfile, "[%d]", i);
 | 
						|
 | 
						|
	    did_one = 1;
 | 
						|
	    last_type = nv_type (Var);
 | 
						|
	} /* for this_var */
 | 
						|
 | 
						|
/* Handle the uninitialized equivalences */
 | 
						|
 | 
						|
	do_uninit_equivs (outfile, &did_one);
 | 
						|
 | 
						|
	if (did_one)
 | 
						|
	    nice_printf (outfile, ";\n\n");
 | 
						|
    } /* if new_vars */
 | 
						|
 | 
						|
/* Write out builtin declarations */
 | 
						|
 | 
						|
    if (used_builtins) {
 | 
						|
	chainp cp;
 | 
						|
	Extsym *es;
 | 
						|
 | 
						|
	last_type = -1;
 | 
						|
	did_one = 0;
 | 
						|
 | 
						|
	nice_printf (outfile, "/* Builtin functions */");
 | 
						|
 | 
						|
	for (cp = used_builtins; cp; cp = cp -> nextp) {
 | 
						|
	    Addrp e = (Addrp)cp->datap;
 | 
						|
 | 
						|
	    switch(type = e->vtype) {
 | 
						|
		case TYDREAL:
 | 
						|
		case TYREAL:
 | 
						|
			/* if (forcedouble || e->dbl_builtin) */
 | 
						|
			/* libF77 currently assumes everything double */
 | 
						|
			type = TYDREAL;
 | 
						|
			ctype = "double";
 | 
						|
			break;
 | 
						|
		case TYCOMPLEX:
 | 
						|
		case TYDCOMPLEX:
 | 
						|
			type = TYVOID;
 | 
						|
			/* no break */
 | 
						|
		default:
 | 
						|
			ctype = c_type_decl(type, 0);
 | 
						|
		}
 | 
						|
 | 
						|
	    if (did_one && last_type == type)
 | 
						|
		nice_printf(outfile, ", ");
 | 
						|
	    else
 | 
						|
		nice_printf(outfile, "%s\n%s ", did_one ? ";" : "", ctype);
 | 
						|
 | 
						|
	    extern_out(outfile, es = &extsymtab[e -> memno]);
 | 
						|
	    proto(outfile, es->arginfo, es->fextname);
 | 
						|
	    last_type = type;
 | 
						|
	    did_one = 1;
 | 
						|
	} /* for cp = used_builtins */
 | 
						|
 | 
						|
	nice_printf (outfile, ";\n\n");
 | 
						|
    } /* if used_builtins */
 | 
						|
 | 
						|
    last_type = -1;
 | 
						|
    for (entry = hashtab; entry < lasthash; ++entry) {
 | 
						|
	var = entry -> varp;
 | 
						|
 | 
						|
	if (var) {
 | 
						|
	    int procclass = var -> vprocclass;
 | 
						|
	    char *comment = NULL;
 | 
						|
	    int stg = var -> vstg;
 | 
						|
	    int class = var -> vclass;
 | 
						|
	    type = var -> vtype;
 | 
						|
 | 
						|
	    if (ONEOF(stg, M(STGARG)|M(STGLENG)|M(STGINIT)))
 | 
						|
		continue;
 | 
						|
 | 
						|
	    if (useauto1 && stg == STGBSS && !var->vsave)
 | 
						|
		stg = STGAUTO;
 | 
						|
 | 
						|
	    switch (class) {
 | 
						|
	        case CLVAR:
 | 
						|
		    break;
 | 
						|
		case CLPROC:
 | 
						|
		    switch(procclass) {
 | 
						|
			case PTHISPROC:
 | 
						|
				extsymtab[var->vardesc.varno].extype = type;
 | 
						|
				continue;
 | 
						|
			case PSTFUNCT:
 | 
						|
			case PINTRINSIC:
 | 
						|
				continue;
 | 
						|
			case PUNKNOWN:
 | 
						|
				err ("list_decls:  unknown procedure class");
 | 
						|
				continue;
 | 
						|
			case PEXTERNAL:
 | 
						|
				if (stg == STGUNKNOWN) {
 | 
						|
					warn1(
 | 
						|
					"%.64s declared EXTERNAL but never used.",
 | 
						|
						var->fvarname);
 | 
						|
					/* to retain names declared EXTERNAL */
 | 
						|
					/* but not referenced, change
 | 
						|
					/* "continue" to "stg = STGEXT" */
 | 
						|
					continue;
 | 
						|
					}
 | 
						|
				else
 | 
						|
					type = fixexttype(var);
 | 
						|
			}
 | 
						|
		    break;
 | 
						|
		case CLUNKNOWN:
 | 
						|
			/* declared but never used */
 | 
						|
			continue;
 | 
						|
		case CLPARAM:
 | 
						|
			continue;
 | 
						|
		case CLNAMELIST:
 | 
						|
			if (var->visused)
 | 
						|
				namelists = mkchain((char *)var, namelists);
 | 
						|
			continue;
 | 
						|
		default:
 | 
						|
		    erri("list_decls:  can't handle class '%d' yet",
 | 
						|
			    class);
 | 
						|
		    Fatal(var->fvarname);
 | 
						|
		    continue;
 | 
						|
	    } /* switch */
 | 
						|
 | 
						|
	    /* Might be equivalenced to a common.  If not, don't process */
 | 
						|
	    if (stg == STGCOMMON && !var->vcommequiv)
 | 
						|
		continue;
 | 
						|
 | 
						|
/* Only write the header if system-generated locals, builtins, or
 | 
						|
   uninitialized equivs were already output */
 | 
						|
 | 
						|
	    if (write_header == 1 && (new_vars || nequiv || used_builtins)
 | 
						|
		    && oneof_stg ( var, stg,
 | 
						|
		    M(STGBSS)|M(STGEXT)|M(STGAUTO)|M(STGCOMMON)|M(STGEQUIV))) {
 | 
						|
		nice_printf (outfile, "/* Local variables */\n");
 | 
						|
		write_header = 2;
 | 
						|
		}
 | 
						|
 | 
						|
 | 
						|
	    Alias = oneof_stg(var, stg, M(STGEQUIV)|M(STGCOMMON));
 | 
						|
	    if (Define = (Alias && def_equivs)) {
 | 
						|
		if (!write_header)
 | 
						|
			nice_printf(outfile, ";\n");
 | 
						|
		def_start(outfile, var->cvarname, CNULL, "(");
 | 
						|
		goto Alias1;
 | 
						|
		}
 | 
						|
	    else if (type == last_type && class == last_class &&
 | 
						|
		    stg == last_stg && !write_header)
 | 
						|
		nice_printf (outfile, ", ");
 | 
						|
	    else {
 | 
						|
		if (!write_header && ONEOF(stg, M(STGBSS)|
 | 
						|
		    M(STGEXT)|M(STGAUTO)|M(STGEQUIV)|M(STGCOMMON)))
 | 
						|
		    nice_printf (outfile, ";\n");
 | 
						|
 | 
						|
		switch (stg) {
 | 
						|
		    case STGARG:
 | 
						|
		    case STGLENG:
 | 
						|
			/* Part of the argument list, don't write them out
 | 
						|
			   again */
 | 
						|
			continue;	    /* Go back to top of the loop */
 | 
						|
		    case STGBSS:
 | 
						|
		    case STGEQUIV:
 | 
						|
		    case STGCOMMON:
 | 
						|
			nice_printf (outfile, "static ");
 | 
						|
			break;
 | 
						|
		    case STGEXT:
 | 
						|
			nice_printf (outfile, "extern ");
 | 
						|
			break;
 | 
						|
		    case STGAUTO:
 | 
						|
			break;
 | 
						|
		    case STGINIT:
 | 
						|
		    case STGUNKNOWN:
 | 
						|
			/* Don't want to touch the initialized data, that will
 | 
						|
			   be handled elsewhere.  Unknown data have
 | 
						|
			   already been complained about, so skip them */
 | 
						|
			continue;
 | 
						|
		    default:
 | 
						|
			erri("list_decls:  can't handle storage class %d",
 | 
						|
				stg);
 | 
						|
			continue;
 | 
						|
		} /* switch */
 | 
						|
 | 
						|
		if (type == TYCHAR && halign && class != CLPROC
 | 
						|
		&& ISICON(var->vleng)) {
 | 
						|
			nice_printf(outfile, "struct { %s fill; char val",
 | 
						|
				halign);
 | 
						|
			x = wr_char_len(outfile, var->vdim,
 | 
						|
				var->vleng->constblock.Const.ci, 1);
 | 
						|
			if (x %= hsize)
 | 
						|
				nice_printf(outfile, "; char fill2[%ld]",
 | 
						|
					hsize - x);
 | 
						|
			nice_printf(outfile, "; } %s_st;\n", var->cvarname);
 | 
						|
			def_start(outfile, var->cvarname, CNULL, var->cvarname);
 | 
						|
			ind_printf(0, outfile, "_st.val\n");
 | 
						|
			last_type = -1;
 | 
						|
			write_header = 2;
 | 
						|
			continue;
 | 
						|
			}
 | 
						|
		nice_printf(outfile, "%s ",
 | 
						|
			c_type_decl(type, class == CLPROC));
 | 
						|
	    } /* else */
 | 
						|
 | 
						|
/* Character type is really a string type.  Put out a '*' for variable
 | 
						|
   length strings, and also for equivalences */
 | 
						|
 | 
						|
	    if (type == TYCHAR && class != CLPROC
 | 
						|
		    && (!var->vleng || !ISICON (var -> vleng))
 | 
						|
	    || oneof_stg(var, stg, M(STGEQUIV)|M(STGCOMMON)))
 | 
						|
		nice_printf (outfile, "*%s", var->cvarname);
 | 
						|
	    else {
 | 
						|
		nice_printf (outfile, "%s", var->cvarname);
 | 
						|
		if (class == CLPROC)
 | 
						|
			proto(outfile, var->arginfo, var->fvarname);
 | 
						|
		else if (type == TYCHAR && ISICON ((var -> vleng)))
 | 
						|
			wr_char_len(outfile, var->vdim,
 | 
						|
				(int)var->vleng->constblock.Const.ci, 0);
 | 
						|
		else if (var -> vdim &&
 | 
						|
		    !oneof_stg (var, stg, M(STGEQUIV)|M(STGCOMMON)))
 | 
						|
			comment = wr_ardecls(outfile, var->vdim, 1L);
 | 
						|
		}
 | 
						|
 | 
						|
	    if (comment)
 | 
						|
		nice_printf (outfile, "%s", comment);
 | 
						|
 Alias1:
 | 
						|
	    if (Alias) {
 | 
						|
		char *amp, *lp, *name, *rp;
 | 
						|
		char *equiv_name ();
 | 
						|
		ftnint voff = var -> voffset;
 | 
						|
		int et0, expr_type, k;
 | 
						|
		Extsym *E;
 | 
						|
		struct Equivblock *eb;
 | 
						|
		char buf[16];
 | 
						|
 | 
						|
/* We DON'T want to use oneof_stg here, because we need to distinguish
 | 
						|
   between them */
 | 
						|
 | 
						|
		if (stg == STGEQUIV) {
 | 
						|
			name = equiv_name(k = var->vardesc.varno, CNULL);
 | 
						|
			eb = eqvclass + k;
 | 
						|
			if (eb->eqvinit) {
 | 
						|
				amp = "&";
 | 
						|
				et0 = TYERROR;
 | 
						|
				}
 | 
						|
			else {
 | 
						|
				amp = "";
 | 
						|
				et0 = eb->eqvtype;
 | 
						|
				}
 | 
						|
			expr_type = et0;
 | 
						|
		    }
 | 
						|
		else {
 | 
						|
			E = &extsymtab[var->vardesc.varno];
 | 
						|
			sprintf(name = buf, "%s%d", E->cextname, E->curno);
 | 
						|
			expr_type = type;
 | 
						|
			et0 = -1;
 | 
						|
			amp = "&";
 | 
						|
		} /* else */
 | 
						|
 | 
						|
		if (!Define)
 | 
						|
			nice_printf (outfile, " = ");
 | 
						|
		if (voff) {
 | 
						|
			k = typesize[type];
 | 
						|
			switch((int)(voff % k)) {
 | 
						|
				case 0:
 | 
						|
					voff /= k;
 | 
						|
					expr_type = type;
 | 
						|
					break;
 | 
						|
				case SZSHORT:
 | 
						|
				case SZSHORT+SZLONG:
 | 
						|
					expr_type = TYSHORT;
 | 
						|
					voff /= SZSHORT;
 | 
						|
					break;
 | 
						|
				case SZLONG:
 | 
						|
					expr_type = TYLONG;
 | 
						|
					voff /= SZLONG;
 | 
						|
					break;
 | 
						|
				default:
 | 
						|
					expr_type = TYCHAR;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
		if (expr_type == type) {
 | 
						|
			lp = rp = "";
 | 
						|
			if (et0 == -1 && !voff)
 | 
						|
				goto cast;
 | 
						|
			}
 | 
						|
		else {
 | 
						|
			lp = "(";
 | 
						|
			rp = ")";
 | 
						|
 cast:
 | 
						|
			nice_printf(outfile, "(%s *)", c_type_decl(type, 0));
 | 
						|
			}
 | 
						|
 | 
						|
/* Now worry about computing the offset */
 | 
						|
 | 
						|
		if (voff) {
 | 
						|
		    if (expr_type == et0)
 | 
						|
			nice_printf (outfile, "%s%s + %ld%s",
 | 
						|
				lp, name, voff, rp);
 | 
						|
		    else
 | 
						|
			nice_printf(outfile, "%s(%s *)%s%s + %ld%s", lp,
 | 
						|
				c_type_decl (expr_type, 0), amp,
 | 
						|
				name, voff, rp);
 | 
						|
		} else
 | 
						|
		    nice_printf(outfile, "%s%s", amp, name);
 | 
						|
/* Always put these at the end of the line */
 | 
						|
		last_type = last_class = last_stg = -1;
 | 
						|
		write_header = 0;
 | 
						|
		if (Define) {
 | 
						|
			ind_printf(0, outfile, ")\n");
 | 
						|
			write_header = 2;
 | 
						|
			}
 | 
						|
		continue;
 | 
						|
		}
 | 
						|
	    write_header = 0;
 | 
						|
	    last_type = type;
 | 
						|
	    last_class = class;
 | 
						|
	    last_stg = stg;
 | 
						|
	} /* if (var) */
 | 
						|
    } /* for (entry = hashtab */
 | 
						|
 | 
						|
    if (!write_header)
 | 
						|
	nice_printf (outfile, ";\n\n");
 | 
						|
    else if (write_header == 2)
 | 
						|
	nice_printf(outfile, "\n");
 | 
						|
 | 
						|
/* Next, namelists, which may reference equivs */
 | 
						|
 | 
						|
    if (namelists) {
 | 
						|
	write_namelists(namelists = revchain(namelists), outfile);
 | 
						|
	frchain(&namelists);
 | 
						|
	}
 | 
						|
 | 
						|
/* Finally, ioblocks (which may reference equivs and namelists) */
 | 
						|
    if (iob_list)
 | 
						|
	write_ioblocks(outfile);
 | 
						|
    if (assigned_fmts)
 | 
						|
	write_assigned_fmts(outfile);
 | 
						|
    lineno = lineno_save;
 | 
						|
} /* list_decls */
 | 
						|
 | 
						|
do_uninit_equivs (outfile, did_one)
 | 
						|
FILE *outfile;
 | 
						|
int *did_one;
 | 
						|
{
 | 
						|
    extern int nequiv;
 | 
						|
    struct Equivblock *eqv, *lasteqv = eqvclass + nequiv;
 | 
						|
    int k, last_type = -1, t;
 | 
						|
 | 
						|
    for (eqv = eqvclass; eqv < lasteqv; eqv++)
 | 
						|
	if (!eqv -> eqvinit && eqv -> eqvtop != eqv -> eqvbottom) {
 | 
						|
	    if (!*did_one)
 | 
						|
		nice_printf (outfile, "/* System generated locals */\n");
 | 
						|
	    t = eqv->eqvtype;
 | 
						|
	    if (last_type == t)
 | 
						|
		nice_printf (outfile, ", ");
 | 
						|
	    else {
 | 
						|
		if (*did_one)
 | 
						|
		    nice_printf (outfile, ";\n");
 | 
						|
		nice_printf (outfile, "static %s ", c_type_decl(t, 0));
 | 
						|
		k = typesize[t];
 | 
						|
	    } /* else */
 | 
						|
	    nice_printf(outfile, "%s", equiv_name((int)(eqv - eqvclass), CNULL));
 | 
						|
	    nice_printf(outfile, "[%ld]",
 | 
						|
		(eqv->eqvtop - eqv->eqvbottom + k - 1) / k);
 | 
						|
	    last_type = t;
 | 
						|
	    *did_one = 1;
 | 
						|
	} /* if !eqv -> eqvinit */
 | 
						|
} /* do_uninit_equivs */
 | 
						|
 | 
						|
 | 
						|
/* wr_ardecls -- Writes the brackets and size for an array
 | 
						|
   declaration.  Because of the inner workings of the compiler,
 | 
						|
   multi-dimensional arrays get mapped directly into a one-dimensional
 | 
						|
   array, so we have to compute the size of the array here.  When the
 | 
						|
   dimension is greater than 1, a string comment about the original size
 | 
						|
   is returned */
 | 
						|
 | 
						|
char *wr_ardecls(outfile, dimp, size)
 | 
						|
FILE *outfile;
 | 
						|
struct Dimblock *dimp;
 | 
						|
long size;
 | 
						|
{
 | 
						|
    int i, k;
 | 
						|
    static char buf[1000];
 | 
						|
 | 
						|
    if (dimp == (struct Dimblock *) NULL)
 | 
						|
	return NULL;
 | 
						|
 | 
						|
    sprintf(buf, "\t/* was ");	/* would like to say  k = sprintf(...), but */
 | 
						|
    k = strlen(buf);		/* BSD doesn't return char transmitted count */
 | 
						|
 | 
						|
    for (i = 0; i < dimp -> ndim; i++) {
 | 
						|
	expptr this_size = dimp -> dims[i].dimsize;
 | 
						|
 | 
						|
	if (!ISICON (this_size))
 | 
						|
	    err ("wr_ardecls:  nonconstant array size");
 | 
						|
	else {
 | 
						|
	    size *= this_size -> constblock.Const.ci;
 | 
						|
	    sprintf(buf+k, "[%ld]", this_size -> constblock.Const.ci);
 | 
						|
	    k += strlen(buf+k);	/* BSD prevents combining this with prev stmt */
 | 
						|
	} /* else */
 | 
						|
    } /* for i = 0 */
 | 
						|
 | 
						|
    nice_printf (outfile, "[%ld]", size);
 | 
						|
    strcat(buf+k, " */");
 | 
						|
 | 
						|
    return (i > 1) ? buf : NULL;
 | 
						|
} /* wr_ardecls */
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/* ----------------------------------------------------------------------
 | 
						|
 | 
						|
	The following routines read from the p1 intermediate file.  If
 | 
						|
   that format changes, only these routines need be changed
 | 
						|
 | 
						|
   ---------------------------------------------------------------------- */
 | 
						|
 | 
						|
static int get_p1_token (infile)
 | 
						|
FILE *infile;
 | 
						|
{
 | 
						|
    int token = P1_UNKNOWN;
 | 
						|
 | 
						|
/* NOT PORTABLE!! */
 | 
						|
 | 
						|
    if (fscanf (infile, "%d", &token) == EOF)
 | 
						|
	return P1_EOF;
 | 
						|
 | 
						|
/* Skip over the ": " */
 | 
						|
 | 
						|
    if (getc (infile) != '\n')
 | 
						|
	getc (infile);
 | 
						|
 | 
						|
    return token;
 | 
						|
} /* get_p1_token */
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/* Returns a (null terminated) string from the input file */
 | 
						|
 | 
						|
static int p1gets (fp, str, size)
 | 
						|
FILE *fp;
 | 
						|
char *str;
 | 
						|
int size;
 | 
						|
{
 | 
						|
    char *fgets ();
 | 
						|
    char c;
 | 
						|
 | 
						|
    if (str == NULL)
 | 
						|
	return 0;
 | 
						|
 | 
						|
    if ((c = getc (fp)) != ' ')
 | 
						|
	ungetc (c, fp);
 | 
						|
 | 
						|
    if (fgets (str, size, fp)) {
 | 
						|
	int length;
 | 
						|
 | 
						|
	str[size - 1] = '\0';
 | 
						|
	length = strlen (str);
 | 
						|
 | 
						|
/* Get rid of the newline */
 | 
						|
 | 
						|
	if (str[length - 1] == '\n')
 | 
						|
	    str[length - 1] = '\0';
 | 
						|
	return 1;
 | 
						|
 | 
						|
    } else if (feof (fp))
 | 
						|
	return EOF;
 | 
						|
    else
 | 
						|
	return 0;
 | 
						|
} /* p1gets */
 | 
						|
 | 
						|
 | 
						|
static int p1get_const (infile, type, resultp)
 | 
						|
FILE *infile;
 | 
						|
int type;
 | 
						|
struct Constblock **resultp;
 | 
						|
{
 | 
						|
    int status;
 | 
						|
    struct Constblock *result;
 | 
						|
 | 
						|
	if (type != TYCHAR) {
 | 
						|
		*resultp = result = ALLOC(Constblock);
 | 
						|
		result -> tag = TCONST;
 | 
						|
		result -> vtype = type;
 | 
						|
		}
 | 
						|
 | 
						|
    switch (type) {
 | 
						|
        case TYSHORT:
 | 
						|
	case TYLONG:
 | 
						|
	case TYLOGICAL:
 | 
						|
	    status = p1getd (infile, &(result -> Const.ci));
 | 
						|
	    break;
 | 
						|
	case TYREAL:
 | 
						|
	case TYDREAL:
 | 
						|
	    status = p1getf(infile, &result->Const.cds[0]);
 | 
						|
	    result->vstg = 1;
 | 
						|
	    break;
 | 
						|
	case TYCOMPLEX:
 | 
						|
	case TYDCOMPLEX:
 | 
						|
	    status = p1getf(infile, &result->Const.cds[0]);
 | 
						|
	    if (status && status != EOF)
 | 
						|
		status = p1getf(infile, &result->Const.cds[1]);
 | 
						|
	    result->vstg = 1;
 | 
						|
	    break;
 | 
						|
	case TYCHAR:
 | 
						|
	    status = fscanf(infile, "%lx", resultp);
 | 
						|
	    break;
 | 
						|
	default:
 | 
						|
	    erri ("p1get_const:  bad constant type '%d'", type);
 | 
						|
	    status = 0;
 | 
						|
	    break;
 | 
						|
    } /* switch */
 | 
						|
 | 
						|
    return status;
 | 
						|
} /* p1get_const */
 | 
						|
 | 
						|
static int p1getd (infile, result)
 | 
						|
FILE *infile;
 | 
						|
long *result;
 | 
						|
{
 | 
						|
    return fscanf (infile, "%ld", result);
 | 
						|
} /* p1getd */
 | 
						|
 | 
						|
 static int
 | 
						|
p1getf(infile, result)
 | 
						|
 FILE *infile;
 | 
						|
 char **result;
 | 
						|
{
 | 
						|
 | 
						|
	char buf[1324];
 | 
						|
	register int k;
 | 
						|
 | 
						|
	k = fscanf (infile, "%s", buf);
 | 
						|
	if (k < 1)
 | 
						|
		k = EOF;
 | 
						|
	else
 | 
						|
		strcpy(*result = mem(strlen(buf)+1,0), buf);
 | 
						|
	return k;
 | 
						|
}
 | 
						|
 | 
						|
static int p1getn (infile, count, result)
 | 
						|
FILE *infile;
 | 
						|
int count;
 | 
						|
char **result;
 | 
						|
{
 | 
						|
 | 
						|
    char *bufptr;
 | 
						|
    extern ptr ckalloc ();
 | 
						|
 | 
						|
    bufptr = (char *) ckalloc (count);
 | 
						|
 | 
						|
    if (result)
 | 
						|
	*result = bufptr;
 | 
						|
 | 
						|
    for (; !feof (infile) && count > 0; count--)
 | 
						|
	*bufptr++ = getc (infile);
 | 
						|
 | 
						|
    return feof (infile) ? EOF : 1;
 | 
						|
} /* p1getn */
 | 
						|
 | 
						|
 static void
 | 
						|
proto(outfile, at, fname)
 | 
						|
 FILE *outfile;
 | 
						|
 Argtypes *at;
 | 
						|
 char *fname;
 | 
						|
{
 | 
						|
	int i, j, k, n;
 | 
						|
	char *comma;
 | 
						|
	Atype *atypes;
 | 
						|
	Namep np;
 | 
						|
	chainp cp;
 | 
						|
	extern void bad_atypes();
 | 
						|
 | 
						|
	if (at) {
 | 
						|
		/* Correct types that we learn on the fly, e.g.
 | 
						|
			subroutine gotcha(foo)
 | 
						|
			external foo
 | 
						|
			call zap(...,foo,...)
 | 
						|
			call foo(...)
 | 
						|
		*/
 | 
						|
		atypes = at->atypes;
 | 
						|
		n = at->nargs;
 | 
						|
		for(i = 0; i++ < n; atypes++) {
 | 
						|
			if (!(cp = atypes->cp))
 | 
						|
				continue;
 | 
						|
			j = atypes->type;
 | 
						|
			do {
 | 
						|
				np = (Namep)cp->datap;
 | 
						|
				k = np->vtype;
 | 
						|
				if (np->vclass == CLPROC) {
 | 
						|
					if (!np->vimpltype && k)
 | 
						|
						k += 200;
 | 
						|
					else {
 | 
						|
						if (j >= 300)
 | 
						|
							j = TYUNKNOWN + 200;
 | 
						|
						continue;
 | 
						|
						}
 | 
						|
					}
 | 
						|
				if (j == k)
 | 
						|
					continue;
 | 
						|
				if (j >= 300
 | 
						|
				||  j == 200 && k >= 200)
 | 
						|
					j = k;
 | 
						|
				else {
 | 
						|
					bad_atypes(at,fname,i,j,k,""," and");
 | 
						|
					goto break2;
 | 
						|
					}
 | 
						|
				}
 | 
						|
				while(cp = cp->nextp);
 | 
						|
			atypes->type = j;
 | 
						|
			frchain(&atypes->cp);
 | 
						|
			}
 | 
						|
		}
 | 
						|
 break2:
 | 
						|
	if (parens) {
 | 
						|
		nice_printf(outfile, parens);
 | 
						|
		return;
 | 
						|
		}
 | 
						|
 | 
						|
	if (!at || (n = at->nargs) < 0) {
 | 
						|
		nice_printf(outfile, Ansi == 1 ? "()" : "(...)");
 | 
						|
		return;
 | 
						|
		}
 | 
						|
 | 
						|
	if (n == 0) {
 | 
						|
		nice_printf(outfile, Ansi == 1 ? "(void)" : "()");
 | 
						|
		return;
 | 
						|
		}
 | 
						|
 | 
						|
	atypes = at->atypes;
 | 
						|
	nice_printf(outfile, "(");
 | 
						|
	comma = "";
 | 
						|
	for(; --n >= 0; atypes++) {
 | 
						|
		k = atypes->type;
 | 
						|
		if (k == TYADDR)
 | 
						|
			nice_printf(outfile, "%schar **", comma);
 | 
						|
		else if (k >= 200) {
 | 
						|
			k -= 200;
 | 
						|
			nice_printf(outfile, "%s%s", comma,
 | 
						|
				usedcasts[k] = casttypes[k]);
 | 
						|
			}
 | 
						|
		else if (k >= 100)
 | 
						|
			nice_printf(outfile,
 | 
						|
					k == TYCHAR + 100 ? "%s%s *" : "%s%s",
 | 
						|
					comma, c_type_decl(k-100, 0));
 | 
						|
		else
 | 
						|
			nice_printf(outfile, "%s%s *", comma,
 | 
						|
					c_type_decl(k, 0));
 | 
						|
		comma = ", ";
 | 
						|
		}
 | 
						|
	nice_printf(outfile, ")");
 | 
						|
	}
 | 
						|
 | 
						|
 void
 | 
						|
protowrite(protofile, type, name, e, lengths)
 | 
						|
 FILE *protofile;
 | 
						|
 char *name;
 | 
						|
 struct Entrypoint *e;
 | 
						|
 chainp lengths;
 | 
						|
{
 | 
						|
	extern char used_rets[];
 | 
						|
 | 
						|
	nice_printf(protofile, "extern %s %s", protorettypes[type], name);
 | 
						|
	list_arg_types(protofile, e, lengths, 0, ";\n");
 | 
						|
	used_rets[type] = 1;
 | 
						|
	}
 | 
						|
 | 
						|
 static void
 | 
						|
do_p1_1while(outfile)
 | 
						|
 FILE *outfile;
 | 
						|
{
 | 
						|
	if (*wh_next) {
 | 
						|
		nice_printf(outfile,
 | 
						|
			"for(;;) { /* while(complicated condition) */\n" /*}*/ );
 | 
						|
		next_tab(outfile);
 | 
						|
		}
 | 
						|
	else
 | 
						|
		nice_printf(outfile, "while(" /*)*/ );
 | 
						|
	}
 | 
						|
 | 
						|
 static void
 | 
						|
do_p1_2while(infile, outfile)
 | 
						|
 FILE *infile, *outfile;
 | 
						|
{
 | 
						|
	expptr test;
 | 
						|
 | 
						|
	test = do_format(infile, outfile);
 | 
						|
	if (*wh_next)
 | 
						|
		nice_printf(outfile, "if (!(");
 | 
						|
	expr_out(outfile, test);
 | 
						|
	if (*wh_next++)
 | 
						|
		nice_printf(outfile, "))\n\tbreak;\n");
 | 
						|
	else {
 | 
						|
		nice_printf(outfile, /*(*/ ") {\n");
 | 
						|
		next_tab(outfile);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
 static void
 | 
						|
do_p1_elseifstart(outfile)
 | 
						|
 FILE *outfile;
 | 
						|
{
 | 
						|
	if (*ei_next++) {
 | 
						|
		prev_tab(outfile);
 | 
						|
		nice_printf(outfile, /*{*/
 | 
						|
			"} else /* if(complicated condition) */ {\n" /*}*/ );
 | 
						|
		next_tab(outfile);
 | 
						|
		}
 | 
						|
	}
 |