/***** spin: pangen4.c *****/

/* Copyright (c) 1991 by AT&T Bell Telephone Laboratories, Inc.
 * All Rights Reserved. This software is for educational purposes only.
 * No part of this source code may be reproduced in any form
 * without explicit written permission from the copyright owner.
 * This software was written by Gerard J. Holzmann, as part of the book
 * ``Design and Validation of Computer Protocols,'' ISBN 0-13-539925-4,
 * Prentice Hall, Englewood Cliffs, NJ, 07632.
 * Send bug-reports to: gerard@research.att.com
 */

#include <stdio.h>
#include "spin.h"
#include "y.tab.h"

extern FILE	*tc, *tb;
extern Queue	*qtab;
extern int	nocast;
extern int	lineno;
extern char	*R13[], *R14[], *R15[];

void
undostmnt(now, m)
	Node *now;
{
	Node *v;
	int i, j; extern int m_loss;

	if (!now)
	{	fprintf(tb, "0");
		return;
	}
	lineno = now->nval;
	switch (now->ntyp) {
	case CONST:	case '!':	case UMIN:
	case '~':	case '/':	case '*':
	case '-':	case '+':	case '%':
	case '<':	case '>':	case '&':
	case '|':	case LE:	case GE:
	case NE:	case EQ:	case OR:
	case AND:	case LSHIFT:	case RSHIFT:
	case TIMEOUT:	case LEN:	case NAME:
	case 'R':	putstmnt(tb, now, m);
			break;
	case RUN:	fprintf(tb, "delproc(0, now._nr_pr-1)");
			break;
	case 's':	if (m_loss)
			{	fprintf(tb, "if (m == 2) m = unsend");
				putname(tb, "(", now->lft, m, ")");
			} else
			{	fprintf(tb, "m = unsend");
				putname(tb, "(", now->lft, m, ")");
			}
			break;
	case 'r':	for (v = now->rgt, j = 0; v; v = v->rgt)
				if (v->lft->ntyp != CONST)
					j++;
			if (j > 0)	/* variables were set */
			{	fprintf(tb, "sv_restor()");
				break;
			}
			for (v = now->rgt, i = 0; v; v = v->rgt, i++)
			{	fprintf(tb, "unrecv");
				putname(tb, "(", now->lft, m, ", 0, ");
				fprintf(tb, "%d, ", i);
				undostmnt(v->lft, m);
				fprintf(tb, ", %d);\n\t\t", (i==0)?1:0);
			}
			break;
	case '@':	fprintf(tb, "p_restor(II)");
			break;
	case ASGN:	nocast=1; putstmnt(tb,now->lft,m);
			nocast=0; fprintf(tb, " = trpt->oval");
			check_proc(now->rgt, m);
			break;
	case 'c':	check_proc(now->lft, m);
			break;
	case '.':
	case GOTO:
	case BREAK:	break;
	case ASSERT:
	case PRINT:	check_proc(now, m);
			break;
	default:	printf("spin: bad node type %d (.b)\n",
							now->ntyp);
			exit(1);
	}
}

any_undo(now)
	Node *now;
{	/* is there anything to undo on a return move? */

	if (!now) return 1;
	switch (now->ntyp) {
	case 'c':	return any_proc(now->lft);
	case ASSERT:
	case PRINT:	return any_proc(now);

	case '.':
	case GOTO:
	case BREAK:	return 0;
	default:	return 1;
	}
}

any_proc(now)
	Node *now;
{	/* check if an expression refers to a process */
	if (!now) return 0;
	if (now->ntyp == '@' || now->ntyp == RUN)
		return 1;
	return (any_proc(now->lft) || any_proc(now->rgt));
}

void
check_proc(now, m)
	Node *now;
{
	if (!now)
		return;
	if (now->ntyp == '@' || now->ntyp == RUN)
	{	fprintf(tb, ";\n\t\t");
		undostmnt(now, m);
	}
	check_proc(now->lft, m);
	check_proc(now->rgt, m);
}

void
genunio()
{	char *buf1;
	Queue *q; int i;

	buf1 = (char *) emalloc(128);
	ntimes(tc, 0, 1, R13);
	for (q = qtab; q; q = q->nxt)
	{	sprintf(buf1, "((Q%d *)z)->contents[j].fld", q->qid);
		fprintf(tc, "	case %d:\n", q->qid);
		for (i = 0; i < q->nflds; i++)
			fprintf(tc, "\t\t%s%d = 0;\n", buf1, i);
		if (q->nslots==0)
		{	/* check if rendezvous succeeded, 1 level down */
			fprintf(tc, "\t\tm = (trpt+1)->o_m;\n");
			fprintf(tc, "\t\tUnBlock;\n");
		} else
			fprintf(tc, "\t\tm = trpt->o_m;\n");
		fprintf(tc, "\t\tbreak;\n");
	}
	ntimes(tc, 0, 1, R14);
	for (q = qtab; q; q = q->nxt)
	{	sprintf(buf1, "((Q%d *)z)->contents", q->qid);
		fprintf(tc, "	case %d:\n", q->qid);
		if (q->nslots == 0)
			fprintf(tc, "\t\tif (strt) boq = from;\n");
		else if (q->nslots > 1)	/* shift */
		{	fprintf(tc, "\t\tif (strt && slot<%d)\n",
							q->nslots-1);
			fprintf(tc, "\t\t{\tfor (j--; j>=slot; j--)\n");
			fprintf(tc, "\t\t\t{");
			for (i = 0; i < q->nflds; i++)
			{	fprintf(tc, "\t%s[j+1].fld%d =\n\t\t\t",
							buf1, i);
				fprintf(tc, "\t%s[j].fld%d;\n\t\t\t",
							buf1, i);
			}
			fprintf(tc, "}\n\t\t}\n");
		}
		strcat(buf1, "[slot].fld");
		fprintf(tc, "\t\tif (strt) {\n");
		for (i = 0; i < q->nflds; i++)
			fprintf(tc, "\t\t\t%s%d = 0;\n", buf1, i);
		fprintf(tc, "\t\t}\n");
		if (q->nflds == 1)	/* set */
			fprintf(tc, "\t\tif (fld == 0) %s0 = fldvar;\n",
							buf1);
		else
		{	fprintf(tc, "\t\tswitch (fld) {\n");
			for (i = 0; i < q->nflds; i++)
			{	fprintf(tc, "\t\tcase %d:\t%s", i, buf1);
				fprintf(tc, "%d = fldvar; break;\n", i);
			}
			fprintf(tc, "\t\t}\n");
		}
		fprintf(tc, "\t\tbreak;\n");
	}
	ntimes(tc, 0, 1, R15);
}
