1 /*
2  * label - label handling routines
3  *
4  * Copyright (C) 1999-2007,2021  David I. Bell
5  *
6  * Calc is open software; you can redistribute it and/or modify it under
7  * the terms of the version 2.1 of the GNU Lesser General Public License
8  * as published by the Free Software Foundation.
9  *
10  * Calc is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12  * or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU Lesser General
13  * Public License for more details.
14  *
15  * A copy of version 2.1 of the GNU Lesser General Public License is
16  * distributed with calc under the filename COPYING-LGPL.  You should have
17  * received a copy with calc; if not, write to Free Software Foundation, Inc.
18  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  *
20  * Under source code control:	1990/02/15 01:48:17
21  * File existed as early as:	before 1990
22  *
23  * Share and enjoy!  :-)	http://www.isthe.com/chongo/tech/comp/calc/
24  */
25 
26 
27 #include "calc.h"
28 #include "token.h"
29 #include "label.h"
30 #include "str.h"
31 #include "opcodes.h"
32 #include "func.h"
33 
34 
35 #include "banned.h"	/* include after system header <> includes */
36 
37 
38 STATIC long labelcount;			/* number of user labels defined */
39 STATIC STRINGHEAD labelnames;		/* list of user label names */
40 STATIC LABEL labels[MAXLABELS];		/* list of user labels */
41 
42 
43 /*
44  * Initialize the table of labels for a function.
45  */
46 void
initlabels(void)47 initlabels(void)
48 {
49 	labelcount = 0;
50 	initstr(&labelnames);
51 }
52 
53 
54 /*
55  * Define a user named label to have the offset of the next opcode.
56  *
57  * given:
58  *	name		label name
59  */
60 void
definelabel(char * name)61 definelabel(char *name)
62 {
63 	register LABEL *lp;		/* current label */
64 	long i;				/* current label index */
65 
66 	i = findstr(&labelnames, name);
67 	if (i >= 0) {
68 		lp = &labels[i];
69 		if (lp->l_offset >= 0) {
70 			scanerror(T_NULL, "Label \"%s\" is multiply defined",
71 				name);
72 			return;
73 		}
74 		setlabel(lp);
75 		return;
76 	}
77 	if (labelcount >= MAXLABELS) {
78 		scanerror(T_NULL, "Too many labels in use");
79 		return;
80 	}
81 	lp = &labels[labelcount++];
82 	lp->l_chain = -1L;
83 	lp->l_offset = (long)curfunc->f_opcodecount;
84 	lp->l_name = addstr(&labelnames, name);
85 	clearopt();
86 }
87 
88 
89 /*
90  * Add the offset corresponding to the specified user label name to the
91  * opcode table for a function. If the label is not yet defined, then a
92  * chain of undefined offsets is built using the offset value, and it
93  * will be fixed up when the label is defined.
94  *
95  * given:
96  *	name		user symbol name
97  */
98 void
addlabel(char * name)99 addlabel(char *name)
100 {
101 	register LABEL *lp;		/* current label */
102 	long i;				/* counter */
103 
104 	for (i = labelcount, lp = labels; --i >= 0; lp++) {
105 		if (strcmp(name, lp->l_name))
106 			continue;
107 		uselabel(lp);
108 		return;
109 	}
110 	if (labelcount >= MAXLABELS) {
111 		scanerror(T_NULL, "Too many labels in use");
112 		return;
113 	}
114 	lp = &labels[labelcount++];
115 	lp->l_offset = -1L;
116 	lp->l_chain = -1L;
117 	lp->l_name = addstr(&labelnames, name);
118 	uselabel(lp);
119 }
120 
121 
122 /*
123  * Check to make sure that all labels are defined.
124  */
125 void
checklabels(void)126 checklabels(void)
127 {
128 	register LABEL *lp;		/* label being checked */
129 	long i;				/* counter */
130 
131 	for (i = labelcount, lp = labels; --i >= 0; lp++) {
132 		if (lp->l_offset >= 0)
133 			continue;
134 		scanerror(T_NULL, "Label \"%s\" was never defined",
135 			lp->l_name);
136 	}
137 }
138 
139 
140 /*
141  * Clear an internal label for use.
142  *
143  * given:
144  *	lp		label being cleared
145  */
146 void
clearlabel(LABEL * lp)147 clearlabel(LABEL *lp)
148 {
149 	lp->l_offset = -1L;
150 	lp->l_chain = -1L;
151 	lp->l_name = NULL;
152 }
153 
154 
155 /*
156  * Set any label to have the value of the next opcode in the current
157  * function being defined.  If there were forward references to it,
158  * all such references are patched up.
159  *
160  * given:
161  *	lp		label being set
162  */
163 void
setlabel(LABEL * lp)164 setlabel(LABEL *lp)
165 {
166 	register FUNC *fp;	/* current function */
167 	long curfix;		/* offset of current location being fixed */
168 	long nextfix;		/* offset of next location to fix up */
169 	unsigned long offset;		/* offset of this label */
170 
171 	fp = curfunc;
172 	offset = fp->f_opcodecount;
173 	nextfix = (long)lp->l_chain;
174 	while (nextfix >= 0) {
175 		curfix = nextfix;
176 		nextfix = (long)fp->f_opcodes[curfix];
177 		fp->f_opcodes[curfix] = offset;
178 	}
179 	lp->l_chain = -1L;
180 	lp->l_offset = (long)offset;
181 	clearopt();
182 }
183 
184 
185 /*
186  * Use the specified label at the current location in the function
187  * being compiled.  This adds one word to the current function being
188  * compiled.  If the label is not yet defined, a patch chain is built
189  * so the reference can be fixed when the label is defined.
190  *
191  * given:
192  *	lp		label being used
193  */
194 void
uselabel(LABEL * lp)195 uselabel(LABEL *lp)
196 {
197 	unsigned long offset;		/* offset being added */
198 
199 	offset = curfunc->f_opcodecount;
200 	if (lp->l_offset >= 0) {
201 		curfunc->f_opcodes[curfunc->f_opcodecount++] = lp->l_offset;
202 		return;
203 	}
204 	curfunc->f_opcodes[curfunc->f_opcodecount++] = lp->l_chain;
205 	lp->l_chain = (long)offset;
206 }
207 
208 /* END CODE */
209