1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <ctype.h>
5 #include "defs.h"
6 #include "externs.h"
7 #include "protos.h"
8 
9 int  mopt;
10 int  in_macro;
11 int  expand_macro;
12 char marg[8][10][80];
13 int  midx;
14 int  mcounter, mcntmax;
15 int  mcntstack[8];
16 struct t_line  *mstack[8];
17 struct t_line  *mlptr;
18 struct t_macro *macro_tbl[256];
19 struct t_macro *mptr;
20 
21 /* .macro pseudo */
22 
23 void
do_macro(int * ip)24 do_macro(int *ip)
25 {
26 	if (pass == LAST_PASS)
27 		println();
28 	else {
29 		/* error checking */
30 		if (expand_macro) {
31 			error("Can not nest macro definitions!");
32 			return;
33 		}
34 		if (lablptr == NULL) {
35 			/* skip spaces */
36 			while (isspace(prlnbuf[*ip]))
37 				(*ip)++;
38 
39 			/* search a label after the .macro */
40 			if (colsym(ip) == 0) {
41 				error("No name for this macro!");
42 				return;
43 			}
44 
45 			/* put the macro name in the symbol table */
46 			if ((lablptr = stlook(1)) == NULL)
47 				return;
48 		}
49 		if (lablptr->refcnt) {
50 			switch (lablptr->type) {
51 			case MACRO:
52 				fatal_error("Macro already defined!");
53 				return;
54 
55 			case FUNC:
56 				fatal_error("Symbol already used by a function!");
57 				return;
58 
59 			default:
60 				fatal_error("Symbol already used by a label!");
61 				return;
62 			}
63 		}
64 		if (!check_eol(ip))
65 			return;
66 
67 		/* install this new macro in the hash table */
68 		if (!macro_install())
69 			return;
70 	}
71 	in_macro = 1;
72 }
73 
74 /* .endm pseudo */
75 
76 void
do_endm(int * ip)77 do_endm(int *ip)
78 {
79 	error("Unexpected ENDM!");
80 	return;
81 }
82 
83 /* search a macro in the hash table */
84 
macro_look(int * ip)85 struct t_macro *macro_look(int *ip)
86 {
87 	struct t_macro *ptr;
88 	char name[32];
89 	char c;
90 	int  hash;
91 	int  l;
92 
93 	/* calculate the symbol hash value and check syntax */
94 	l = 0;
95 	hash = 0;
96 	for (;;) {
97 		c = prlnbuf[*ip];
98 		if (c == '\0' || c == ' ' || c == '\t' || c == ';')
99 			break;
100 		if (!isalnum(c) && c != '_')
101 			return (NULL);
102 		if (l == 0) {
103 			if (isdigit(c))
104 				return (NULL);
105 		}
106 		if (l == 31)
107 			return (NULL);
108 		name[l++] = c;
109 		hash += c;
110 		hash  = (hash << 3) + (hash >> 5) + c;
111 		(*ip)++;
112 	}
113 	name[l] = '\0';
114 	hash &= 0xFF;
115 
116 	/* browse the hash table */
117 	ptr = macro_tbl[hash];
118 	while (ptr) {
119 		if (!strcmp(name, ptr->name))
120 			break;
121 		ptr = ptr->next;
122 	}
123 
124 	/* return result */
125 	return (ptr);
126 }
127 
128 /* extract macro arguments */
129 
130 int
macro_getargs(int ip)131 macro_getargs(int ip)
132 {
133 	char *ptr;
134 	char  c, t;
135 	int   i, j, f, arg;
136 	int   level;
137 
138 	/* can not nest too much macros */
139 	if (midx == 7) {
140 		error("Too many nested macro calls!");
141 		return (0);
142 	}
143 
144 	/* initialize args */
145 	mcntstack[midx] = mcounter;
146 	mstack[midx++] = mlptr;
147 	ptr = marg[midx][0];
148 	arg = 0;
149 
150 	for (i = 0; i < 9; i++)
151 		marg[midx][i][0] = '\0';
152 
153 	/* extract args */
154 	for (;;) {
155 		/* skip spaces */
156 		while (isspace(prlnbuf[ip]))
157 			ip++;
158 
159 		c = prlnbuf[ip++];
160 		switch (c) {
161 		/* no arg */
162 		case ',':
163 			arg++;
164 			ptr = marg[midx][arg];
165 			if (arg == 9) {
166 				error("Too many arguments for a macro!");
167 				return (0);
168 			}
169 			break;
170 
171 		/* string */
172 		case '{':
173 			c = '}';
174 		case '\"':
175 			i = 0;
176 			if (c == '\"')
177 				ptr[i++] = c;
178 			for (;;) {
179 				t = prlnbuf[ip++];
180 				if (t == '\0') {
181 					error("Unterminated string!");
182 					return (0);
183 				}
184 				if (i == 80) {
185 					error("String too long, max. 80 characters!");
186 					return (0);
187 				}
188 				if (t == c)
189 					break;
190 				ptr[i++] = t;
191 			}
192 			if (c == '\"')
193 				ptr[i++] = t;
194 
195 			/* skip spaces */
196 			while (isspace(prlnbuf[ip]))
197 				ip++;
198 
199 			/* check end of arg */
200 			switch (prlnbuf[ip]) {
201 			case '\0':
202 			case ',':
203 			case ';':
204 				break;
205 
206 			default:
207 				error("Syntax error!");
208 				return (0);
209 			}
210 
211 			/* end arg string */
212 			ptr[i] = '\0';
213 			break;
214 
215 		/* end of line */
216 		case ';':
217 		case '\0':
218 			return (1);
219 
220 		/* continuation char */
221 		case '\\':
222 			/* skip spaces */
223 			i = ip;
224 			while (isspace(prlnbuf[i]))
225 				i++;
226 
227 			/* check */
228 			if (prlnbuf[i] == ';' || prlnbuf[i] == '\0') {
229 				/* output line */
230 				if (pass == LAST_PASS) {
231 					println();
232 					clearln();
233 				}
234 
235 				/* read a new line */
236 				if (readline() == -1)
237 					return (0);
238 
239 				/* rewind line pointer and continue */
240 				ip = SFIELD;
241 				break;
242 			}
243 
244 		/* other */
245 		default:
246 			i = 0;
247 			j = 0;
248 			f = 0;
249 			level = 0;
250 			while (c) {
251 				if (c == ',') {
252 					if (level == 0)
253 						break;
254 				}
255 				else if ((c == '(') || (c == '[')) {
256 					level++;
257 				}
258 				else if ((c == ')') || (c == ']')) {
259 					if (level)
260 						level--;
261 				}
262 				else if (c == ';') {
263 					break;
264 				}
265 				if (f) {
266 					if (c != ' ') {
267 						while (i < j)
268 							ptr[i++] = ' ';
269 						ptr[i++] = c;
270 						f = 0;
271 					}
272 				}
273 				else if (c == ' ') {
274 					f = 1;
275 				}
276 				else {
277 					ptr[i++] = c;
278 				}
279 				if (i == 80) {
280 					error("Macro argument string too long, max. 80 characters!");
281 					return (0);
282 				}
283 				j++;
284 				c = prlnbuf[ip++];
285 			}
286 			ptr[i] = '\0';
287 			ip--;
288 
289 			/* check if arg is X or Y */
290 			if (strlen(ptr) && arg) {
291 				c = tolower(ptr[0]);
292 
293 				if ((c == 'x') || (c == 'y')) {
294 					if ((strcasecmp(ptr, "x++") == 0) ||
295 						(strcasecmp(ptr, "y++") == 0) ||
296 						(strlen(ptr) == 1))
297 					{
298 						arg--;
299 						ptr = marg[midx][arg];
300 
301 						/* check string length */
302 						if (strlen(ptr) > 75) {
303 							error("Macro argument string too long, max. 80 characters!");
304 							return (0);
305 						}
306 
307 						/* attach current arg to the previous one */
308 						strcat(ptr, ",");
309 						strcat(ptr, marg[midx][arg + 1]);
310 						ptr = marg[midx][arg + 1];
311 						ptr[0] = '\0';
312 					}
313 			 	}
314 			}
315 			break;
316 		}
317 	}
318 }
319 
320 /* install a macro in the hash table */
321 
322 int
macro_install(void)323 macro_install(void)
324 {
325 	char c;
326 	int hash = 0;
327 	int i;
328 
329 	/* mark the macro name as reserved */
330 	lablptr->type = MACRO;
331 
332 	/* check macro name syntax */
333 	if (strchr(&symbol[1], '.')) {
334 		error("Invalid macro name!");
335 		return (0);
336 	}
337 
338 	/* calculate symbol hash value */
339 	for (i = 1; i <= symbol[0]; i++) {
340 		c = symbol[i];
341 		hash += c;
342 		hash  = (hash << 3) + (hash >> 5) + c;
343 	}
344 	hash &= 0xFF;
345 
346 	/* allocate a macro struct */
347 	mptr = (void *)malloc(sizeof(struct t_macro));
348 	if (mptr == NULL) {
349 		error("Out of memory!");
350 		return (0);
351 	}
352 
353 	/* initialize it */
354 	strcpy(mptr->name, &symbol[1]);
355 	mptr->line = NULL;
356 	mptr->next = macro_tbl[hash];
357 	macro_tbl[hash] = mptr;
358 	mlptr = NULL;
359 
360 	/* ok */
361 	return (1);
362 }
363 
364 /* send back the addressing mode of a macro arg */
365 
366 int
macro_getargtype(char * arg)367 macro_getargtype(char *arg)
368 {
369 	struct t_symbol *sym;
370 	char c;
371 	int  i;
372 
373 	/* skip spaces */
374 	while (isspace(*arg))
375 		arg++;
376 
377 	/* get type */
378 	switch (toupper(*arg++)) {
379 	case '\0':
380 		return (NO_ARG);
381 
382 	case '"':
383 		return (ARG_STRING);
384 
385 	case '#':
386 		return (ARG_IMM);
387 
388 	case '[':
389 		return (ARG_INDIRECT);
390 
391 	case 'A':
392 	case 'X':
393 	case 'Y':
394 		if (*arg == '\0')
395 			return (ARG_REG);
396 
397 	default:
398 		/* symbol */
399 		for(i = 0; i < SBOLSZ; i++) {
400 			c = arg[i];
401 			if (isdigit(c) && (i == 0))
402 				break;
403 			if ((!isalnum(c)) && (c != '_') && (c != '.'))
404 				break;
405 		}
406 
407 		if (i == 0)
408 			return (ARG_ABS);
409 		else {
410 			if (c != '\0')
411 				return (ARG_ABS);
412 			else {
413 				strncpy(&symbol[1], arg, i);
414 				symbol[0] = i;
415 				symbol[i+1] = '\0';
416 
417 				if ((sym = stlook(0)) == NULL)
418 					return (ARG_LABEL);
419 				else {
420 					if((sym->type == UNDEF) || (sym->type == IFUNDEF))
421 						return (ARG_LABEL);
422 					if (sym->bank == RESERVED_BANK)
423 						return (ARG_ABS);
424 					else
425 						return (ARG_LABEL);
426 				}
427 			}
428 		}
429 	}
430 }
431 
432