4.4BSD/usr/src/contrib/calc-1.26.4/label.c

/*
 * Copyright (c) 1993 David I. Bell
 * Permission is granted to use, distribute, or modify this source,
 * provided that this copyright notice remains intact.
 *
 * Label handling routines.
 */

#include "calc.h"
#include "token.h"
#include "label.h"
#include "string.h"
#include "opcodes.h"
#include "func.h"

static long labelcount;			/* number of user labels defined */
static STRINGHEAD labelnames;		/* list of user label names */
static LABEL labels[MAXLABELS];		/* list of user labels */


/*
 * Initialize the table of labels for a function.
 */
void
initlabels()
{
	labelcount = 0;
	initstr(&labelnames);
}


/*
 * Define a user named label to have the offset of the next opcode.
 */
void
definelabel(name)
	char *name;			/* label name */
{
	register LABEL *lp;		/* current label */
	long i;				/* current label index */

	i = findstr(&labelnames, name);
	if (i >= 0) {
		lp = &labels[i];
		if (lp->l_offset) {
			scanerror(T_NULL, "Label \"%s\" is multiply defined",
				name);
			return;
		}
		setlabel(lp);
		return;
	}
	if (labelcount >= MAXLABELS) {
		scanerror(T_NULL, "Too many labels in use");
		return;
	}
	lp = &labels[labelcount++];
	lp->l_chain = 0;
	lp->l_offset = curfunc->f_opcodecount;
	lp->l_name = addstr(&labelnames, name);
	clearopt();
}


/*
 * Add the offset corresponding to the specified user label name to the
 * opcode table for a function. If the label is not yet defined, then a
 * chain of undefined offsets is built using the offset value, and it
 * will be fixed up when the label is defined.
 */
void
addlabel(name)
	char *name;			/* user symbol name */
{
	register LABEL *lp;		/* current label */
	long i;				/* counter */

	for (i = labelcount, lp = labels; --i >= 0; lp++) {
		if (strcmp(name, lp->l_name))
			continue;
		uselabel(lp);
		return;
	}
	if (labelcount >= MAXLABELS) {
		scanerror(T_NULL, "Too many labels in use");
		return;
	}
	lp = &labels[labelcount++];
	lp->l_offset = 0;
	lp->l_chain = curfunc->f_opcodecount;
	lp->l_name = addstr(&labelnames, name);
	addop((long)0);
}


/*
 * Check to make sure that all labels are defined.
 */
void
checklabels()
{
	register LABEL *lp;		/* label being checked */
	long i;				/* counter */

	for (i = labelcount, lp = labels; --i >= 0; lp++) {
		if (lp->l_offset > 0)
			continue;
		scanerror(T_NULL, "Label \"%s\" was never defined",
			lp->l_name);
	}
}


/*
 * Clear an internal label for use.
 */
void
clearlabel(lp)
	register LABEL *lp;	/* label being cleared */
{
	lp->l_offset = 0;
	lp->l_chain = 0;
	lp->l_name = NULL;
}


/*
 * Set any label to have the value of the next opcode in the current
 * function being defined.  If there were forward references to it,
 * all such references are patched up.
 */
void
setlabel(lp)
	register LABEL *lp;	/* label being set */
{
	register FUNC *fp;	/* current function */
	long curfix;		/* offset of current location being fixed */
	long nextfix;		/* offset of next location to fix up */
	long offset;		/* offset of this label */

	fp = curfunc;
	offset = fp->f_opcodecount;
	nextfix = lp->l_chain;
	while (nextfix > 0) {
		curfix = nextfix;
		nextfix = fp->f_opcodes[curfix];
		fp->f_opcodes[curfix] = offset;
	}
	lp->l_chain = 0;
	lp->l_offset = offset;
	clearopt();
}


/*
 * Use the specified label at the current location in the function
 * being compiled.  This adds one word to the current function being
 * compiled.  If the label is not yet defined, a patch chain is built
 * so the reference can be fixed when the label is defined.
 */
void
uselabel(lp)
	register LABEL *lp;		/* label being used */
{
	long offset;			/* offset being added */

	offset = curfunc->f_opcodecount;
	if (lp->l_offset > 0) {
		addop(lp->l_offset);
		return;
	}
	addop(lp->l_chain);
	lp->l_chain = offset;
}

/* END CODE */