/*
 * Copyright (c) 1980 Regents of the University of California.
 * All rights reserved.  The Berkeley software License Agreement
 * specifies the terms and conditions for redistribution.
 */

#ifndef lint
static char sccsid[] = "@(#)printdecl.c	5.2 (Berkeley) 6/7/85";
#endif not lint

/*
 * Print out the type of a symbol.
 */

#include "defs.h"
#include "sym.h"
#include "symtab.h"
#include "tree.h"
#include "btypes.h"
#include "classes.h"
#include "sym.rep"

printdecl(s)
SYM *s;
{
    register SYM *t;
    BOOLEAN semicolon;

    semicolon = TRUE;
    switch(s->class) {
	case CONST:
	    t = rtype(s->type);
	    if (t->class == SCAL) {
		printf("(enumeration constant, ord %ld)", s->symvalue.iconval);
	    } else {
		printf("const %s = ", s->symbol);
		if (t == t_real) {
		    printf("%g", s->symvalue.fconval);
		} else {
		    printordinal(s->symvalue.iconval, t);
		}
	    }
	    break;

	case TYPE:
	    printf("type %s = ", s->symbol);
	    printtype(s, s->type);
	    break;

	case VAR:
	    if (isparam(s)) {
		printf("(parameter) %s : ", s->symbol);
	    } else {
		printf("var %s : ", s->symbol);
	    }
	    printtype(s, s->type);
	    break;

	case REF:
	    printf("(var parameter) %s : ", s->symbol);
	    printtype(s, s->type);
	    break;

	case RANGE:
	case ARRAY:
	case RECORD:
	case VARNT:
	case PTR:
	    printtype(s, s);
	    semicolon = FALSE;
	    break;

	case FVAR:
	    printf("(function variable) %s : ", s->symbol);
	    printtype(s, s->type);
	    break;

	case FIELD:
	    printf("(field) %s : ", s->symbol);
	    printtype(s, s->type);
	    break;

	case PROC:
	    printf("procedure %s", s->symbol);
	    listparams(s);
	    break;

	case PROG:
	    printf("program %s", s->symbol);
	    t = s->chain;
	    if (t != NIL) {
		printf("(%s", t->symbol);
		for (t = t->chain; t != NIL; t = t->chain) {
		    printf(", %s", t->symbol);
		}
		printf(")");
	    }
	    break;

	case FUNC:
	    printf("function %s", s->symbol);
	    listparams(s);
	    printf(" : ");
	    printtype(s, s->type);
	    break;

	default:
	    error("class %s in printdecl", classname(s));
    }
    if (semicolon) {
	putchar(';');
    }
    putchar('\n');
}

/*
 * Recursive whiz-bang procedure to print the type portion
 * of a declaration.  Doesn't work quite right for variant records.
 *
 * The symbol associated with the type is passed to allow
 * searching for type names without getting "type blah = blah".
 */

LOCAL printtype(s, t)
SYM *s;
SYM *t;
{
    register SYM *tmp;
    long r0, r1;

    tmp = findtype(t);
    if (tmp != NIL && tmp != s) {
	printf("%s", tmp->symbol);
	return;
    }
    switch(t->class) {
	case VAR:
	case CONST:
	case FUNC:
	case PROC:
	    panic("printtype: class %s", classname(t));
	    break;

	case ARRAY:
	    printf("array[");
	    tmp = t->chain;
	    for (;;) {
		printtype(tmp, tmp);
		tmp = tmp->chain;
		if (tmp == NIL) {
		    break;
		}
		printf(", ");
	    }
	    printf("] of ");
	    printtype(t, t->type);
	    break;

	case RECORD:
	    printf("record\n");
	    if (t->chain != NIL) {
		printtype(t->chain, t->chain);
	    }
	    printf("end");
	    break;

	case FIELD:
	    if (t->chain != NIL) {
		printtype(t->chain, t->chain);
	    }
	    printf("\t%s : ", t->symbol);
	    printtype(t, t->type);
	    printf(";\n");
	    break;

	case RANGE:
	    r0 = t->symvalue.rangev.lower;
	    r1 = t->symvalue.rangev.upper;
	    printordinal(r0, rtype(t->type));
	    printf("..");
	    printordinal(r1, rtype(t->type));
	    break;

	case PTR:
	    putchar('^');
	    printtype(t, t->type);
	    break;

	case TYPE:
	    if (t->symbol != NIL) {
		printf("%s", t->symbol);
	    } else {
		printtype(t, t->type);
	    }
	    break;

	case SCAL:
	    printf("(");
	    t = t->type->chain;
	    if (t != NIL) {
		printf("%s", t->symbol);
		t = t->chain;
		while (t != NIL) {
		    printf(", %s", t->symbol);
		    t = t->chain;
		}
	    } else {
		panic("empty enumeration");
	    }
	    printf(")");
	    break;

	default:
	    printf("(class %d)", t->class);
	    break;
    }
}

/*
 * List the parameters of a procedure or function.
 * No attempt is made to combine like types.
 */

listparams(s)
SYM *s;
{
    SYM *t;

    if (s->chain != NIL) {
	putchar('(');
	for (t = s->chain; t != NIL; t = t->chain) {
	    switch (t->class) {
		case REF:
		    printf("var ");
		    break;

		case FPROC:
		    printf("procedure ");
		    break;

		case FFUNC:
		    printf("function ");
		    break;

		case VAR:
		    break;

		default:
		    panic("unexpected class %d for parameter", t->class);
	    }
	    printf("%s : ", t->symbol);
	    printtype(t, t->type);
	    if (t->chain != NIL) {
		printf("; ");
	    }
	}
	putchar(')');
    }
}
