1 /***********************************************************************
2  *
3  *  AVRA - Assembler for the Atmel AVR microcontroller series
4  *
5  *  Copyright (C) 1998-2020 The AVRA Authors
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; see the file COPYING.  If not, write to
19  *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  *  Boston, MA 02111-1307, USA.
21  *
22  *
23  *  Authors of AVRA can be reached at:
24  *     email: jonah@omegav.ntnu.no, tobiw@suprafluid.com
25  *     www: https://github.com/Ro5bert/avra
26  */
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <ctype.h>
32 
33 #include "misc.h"
34 #include "args.h"
35 #include "avra.h"
36 #include "device.h"
37 
38 enum {
39 	DIRECTIVE_BYTE = 0,
40 	DIRECTIVE_CSEG,
41 	DIRECTIVE_CSEGSIZE,
42 	DIRECTIVE_DB,
43 	DIRECTIVE_DEF,
44 	DIRECTIVE_DEVICE,
45 	DIRECTIVE_DSEG,
46 	DIRECTIVE_DW,
47 	DIRECTIVE_ENDM,
48 	DIRECTIVE_ENDMACRO,
49 	DIRECTIVE_EQU,
50 	DIRECTIVE_ESEG,
51 	DIRECTIVE_EXIT,
52 	DIRECTIVE_INCLUDE,
53 	DIRECTIVE_INCLUDEPATH,
54 	DIRECTIVE_LIST,
55 	DIRECTIVE_LISTMAC,
56 	DIRECTIVE_MACRO,
57 	DIRECTIVE_NOLIST,
58 	DIRECTIVE_ORG,
59 	DIRECTIVE_SET,
60 	DIRECTIVE_DEFINE,
61 	DIRECTIVE_UNDEF,
62 	DIRECTIVE_IFDEF,
63 	DIRECTIVE_IFNDEF,
64 	DIRECTIVE_IF,
65 	DIRECTIVE_ELSE,
66 	DIRECTIVE_ELSEIF,			/* The Atmel AVR Assembler version 1.71 and later use ELSEIF and not ELIF */
67 	DIRECTIVE_ELIF,
68 	DIRECTIVE_ENDIF,
69 	DIRECTIVE_MESSAGE,
70 	DIRECTIVE_WARNING,
71 	DIRECTIVE_ERROR,
72 	DIRECTIVE_PRAGMA,
73 	DIRECTIVE_OVERLAP,
74 	DIRECTIVE_NOOVERLAP,
75 	DIRECTIVE_COUNT
76 };
77 
78 static const char *const directive_list[] = {
79 	"BYTE",
80 	"CSEG",
81 	"CSEGSIZE",
82 	"DB",
83 	"DEF",
84 	"DEVICE",
85 	"DSEG",
86 	"DW",
87 	"ENDM",
88 	"ENDMACRO",
89 	"EQU",
90 	"ESEG",
91 	"EXIT",
92 	"INCLUDE",
93 	"INCLUDEPATH",
94 	"LIST",
95 	"LISTMAC",
96 	"MACRO",
97 	"NOLIST",
98 	"ORG",
99 	"SET",
100 	"DEFINE",
101 	"UNDEF",
102 	"IFDEF",
103 	"IFNDEF",
104 	"IF",
105 	"ELSE",
106 	"ELSEIF",		/* The Atmel AVR Assembler version 1.71 and later use ELSEIF and not ELIF */
107 	"ELIF",
108 	"ENDIF",
109 	"MESSAGE",
110 	"WARNING",
111 	"ERROR",
112 	"PRAGMA",
113 	"OVERLAP",
114 	"NOOVERLAP",
115 	NULL
116 };
117 
118 enum {
119 	PRAGMA_OVERLAP,
120 	PRAGMA_COUNT
121 };
122 
123 static const char *const pragma_list[] = {
124 	"OVERLAP",
125 	NULL
126 };
127 
128 static const char *const overlap_value[] = {
129 	"DEFAULT",
130 	"IGNORE",
131 	"WARNING",
132 	"ERROR",
133 	NULL
134 };
135 
136 /* caller has to free result */
137 static char *
joinpaths(const char * dirname,const char * fname)138 joinpaths(const char *dirname, const char *fname)
139 {
140 	char *res;
141 	int len;
142 
143 	len = strlen(dirname);
144 	res = malloc(len + strlen(fname) + 2);
145 	if (!res) {
146 		return NULL;
147 	}
148 	strcpy(res, dirname);
149 	if ((res[len - 1] != '\\') && (res[len - 1] != '/'))
150 		res[len++] = '/';
151 	strcpy(&res[len], fname);
152 	return res;
153 }
154 
155 int
parse_directive(struct prog_info * pi)156 parse_directive(struct prog_info *pi)
157 {
158 	int directive, pragma;
159 	int ok = True;
160 	int i;
161 	char *next, *data, buf[140];
162 	struct file_info *fi_bak;
163 
164 	struct def *def;
165 	struct data_list *incpath, *dl;
166 
167 	next = get_next_token(pi->fi->scratch, TERM_SPACE);
168 
169 	my_strupr(pi->fi->scratch);
170 	directive = lookup_keyword(directive_list, pi->fi->scratch + 1, True);
171 	if (directive == -1) {
172 		print_msg(pi, MSGTYPE_ERROR, "Unknown directive: %s", pi->fi->scratch);
173 		return (True);
174 	}
175 	switch (directive) {
176 	case DIRECTIVE_BYTE:
177 		if (!next) {
178 			print_msg(pi, MSGTYPE_ERROR, ".BYTE needs a size operand");
179 			return (True);
180 		}
181 		if (pi->segment == pi->cseg) {
182 			print_msg(pi, MSGTYPE_ERROR, ".BYTE directive cannot be used within the code segment (.CSEG)");
183 			return False;
184 		}
185 		get_next_token(next, TERM_END);
186 		if (!get_expr(pi, next, &i))
187 			return (False);
188 		if (i < 0) {
189 			print_msg(pi, MSGTYPE_ERROR, ".BYTE directive must have nonnegative operand");
190 			return False;
191 		}
192 		if ((pi->pass == PASS_2) && pi->list_line && pi->list_on) {
193 			fprintf(pi->list_file, "%c:%06lx    %s\n",
194 			        pi->segment->ident, pi->segment->addr, pi->list_line);
195 			pi->list_line = NULL;
196 		}
197 		advance_ip(pi->segment, i);
198 		break;
199 	case DIRECTIVE_CSEG:
200 		fix_orglist(pi->segment);
201 		def_orglist(pi->cseg);
202 		break;
203 	case DIRECTIVE_CSEGSIZE:
204 		break;
205 	case DIRECTIVE_DB:
206 		if ((pi->pass == PASS_2) && pi->list_line && pi->list_on) {
207 			fprintf(pi->list_file, "          %s\n", pi->list_line);
208 			pi->list_line = NULL;
209 		}
210 		return (parse_db(pi, next));
211 	/* Directive .def */
212 	case DIRECTIVE_DEF:
213 		if (!next) {
214 			print_msg(pi, MSGTYPE_ERROR, ".DEF needs an operand");
215 			return (True);
216 		}
217 		data = get_next_token(next, TERM_EQUAL);
218 		if (!(data && (tolower(data[0]) == 'r') && isdigit(data[1]))) {
219 			print_msg(pi, MSGTYPE_ERROR, "%s needs a register (e.g. .def BZZZT = r16)", next);
220 			return (True);
221 		}
222 		i = atoi(&data[1]);
223 		/* check range of given register */
224 		if (i > 31)
225 			print_msg(pi, MSGTYPE_ERROR, "R%d is not a valid register", i);
226 		/* check if this reg is already assigned */
227 		for (def = pi->first_def; def; def = def->next) {
228 			if (def->reg == i && pi->pass == PASS_1 && !pi->NoRegDef) {
229 				print_msg(pi, MSGTYPE_WARNING, "r%d is already assigned to '%s'!", i, def->name);
230 				return (True);
231 			}
232 		}
233 		/* check if this regname is already defined */
234 		for (def = pi->first_def; def; def = def->next) {
235 			if (!nocase_strcmp(def->name, next)) {
236 				if (pi->pass == PASS_1 && !pi->NoRegDef) {
237 					print_msg(pi, MSGTYPE_WARNING, "'%s' is already assigned as r%d but will now be set to r%i!", next, def->reg, i);
238 				}
239 				def->reg = i;
240 				return (True);
241 			}
242 		}
243 		/* Check, if symbol is already defined as a label or constant */
244 		if (pi->pass == PASS_2) {
245 			if (get_label(pi,next,NULL))
246 				print_msg(pi, MSGTYPE_WARNING, "Name '%s' is used for a register and a label", next);
247 			if (get_constant(pi,next,NULL))
248 				print_msg(pi, MSGTYPE_WARNING, "Name '%s' is used for a register and a constant", next);
249 		}
250 
251 		def = malloc(sizeof(struct def));
252 		if (!def) {
253 			print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL);
254 			return (False);
255 		}
256 		def->next = NULL;
257 		if (pi->last_def)
258 			pi->last_def->next = def;
259 		else
260 			pi->first_def = def;
261 		pi->last_def = def;
262 		def->name = malloc(strlen(next) + 1);
263 		if (!def->name) {
264 			print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL);
265 			return (False);
266 		}
267 		strcpy(def->name, next);
268 		def->reg = i;
269 		break;
270 	case DIRECTIVE_DEVICE:
271 		if (pi->pass == PASS_2)
272 			return (True);
273 		if (!next) {
274 			print_msg(pi, MSGTYPE_ERROR, ".DEVICE needs an operand");
275 			return (True);
276 		}
277 		if (pi->device->name != NULL) { /* Check for multiple device definitions */
278 			print_msg(pi, MSGTYPE_ERROR, "More than one .DEVICE definition");
279 		}
280 		if (pi->cseg->count || pi->dseg->count || pi->eseg->count) {
281 			/* Check if something was already assembled */
282 			print_msg(pi, MSGTYPE_ERROR, ".DEVICE definition must be before any code lines");
283 		} else {
284 			if ((pi->cseg->addr != pi->cseg->lo_addr)
285 			        || (pi->dseg->addr != pi->dseg->lo_addr)
286 			        || (pi->eseg->addr != pi->eseg->lo_addr)) {
287 				/* Check if something was already assembled */
288 				print_msg(pi, MSGTYPE_ERROR, ".DEVICE definition must be before any .ORG directive");
289 			}
290 		}
291 
292 		get_next_token(next, TERM_END);
293 		pi->device = get_device(pi,next);
294 		if (!pi->device) {
295 			print_msg(pi, MSGTYPE_ERROR, "Unknown device: %s", next);
296 			pi->device = get_device(pi,NULL); /* Fix segmentation fault if device is unknown */
297 		}
298 
299 		/* Now that we know the device type, we can
300 		 * start memory allocation from the correct offsets.
301 		 */
302 		fix_orglist(pi->segment);
303 
304 		init_segment_size(pi, pi->device); 	/* Resync. ...->lo_addr variables */
305 		def_orglist(pi->segment);
306 		break;
307 	case DIRECTIVE_DSEG:
308 		fix_orglist(pi->segment);
309 		def_orglist(pi->dseg);
310 		if (pi->dseg->hi_addr == 0) {
311 			/* XXX move to emit */
312 			print_msg(pi, MSGTYPE_ERROR, "Can't use .DSEG directive because device has no RAM");
313 		}
314 		break;
315 	case DIRECTIVE_DW:
316 		if (pi->segment->flags & SEG_BSS_DATA) {
317 			print_msg(pi, MSGTYPE_ERROR, "Can't use .DW directive in data segment (.DSEG)");
318 			return (True);
319 		}
320 		while (next) {
321 			data = get_next_token(next, TERM_COMMA);
322 			if (pi->pass == PASS_2) {
323 				if (!get_expr(pi, next, &i))
324 					return (False);
325 				if ((i < -32768) || (i > 65535))
326 					print_msg(pi, MSGTYPE_WARNING, "Value %d is out of range (-32768 <= k <= 65535). Will be masked", i);
327 			}
328 			if (pi->pass == PASS_2) {
329 				if (pi->list_line && pi->list_on) {
330 					fprintf(pi->list_file, "          %s\n", pi->list_line);
331 					pi->list_line = NULL;
332 					fprintf(pi->list_file, "%c:%06lx %04x\n",
333 					        pi->segment->ident, pi->segment->addr, i);
334 				}
335 				if (pi->segment == pi->eseg) {
336 					write_ee_byte(pi, pi->eseg->addr, (unsigned char)i);
337 					write_ee_byte(pi, pi->eseg->addr + 1, (unsigned char)(i >> 8));
338 				}
339 				if (pi->segment == pi->cseg) {
340 					write_prog_word(pi, pi->cseg->addr, i);
341 				}
342 			}
343 			if (pi->segment == pi->eseg)
344 				advance_ip(pi->eseg, 2);
345 			if (pi->segment == pi->cseg)
346 				advance_ip(pi->cseg, 1);
347 			next = data;
348 		}
349 		break;
350 	case DIRECTIVE_ENDM:
351 	case DIRECTIVE_ENDMACRO:
352 		print_msg(pi, MSGTYPE_ERROR, "No .MACRO found before .ENDMACRO");
353 		break;
354 	case DIRECTIVE_EQU:
355 		if (!next) {
356 			print_msg(pi, MSGTYPE_ERROR, ".EQU needs an operand");
357 			return (True);
358 		}
359 		data = get_next_token(next, TERM_EQUAL);
360 		if (!data) {
361 			print_msg(pi, MSGTYPE_ERROR, "%s needs an expression (e.g. .EQU BZZZT = 0x2a)", next);
362 			return (True);
363 		}
364 		get_next_token(data, TERM_END);
365 		if (!get_expr(pi, data, &i))
366 			return (False);
367 		if (test_label(pi,next,"%s have already been defined as a label")!=NULL)
368 			return (True);
369 		if (test_variable(pi,next,"%s have already been defined as a .SET variable")!=NULL)
370 			return (True);
371 		/* Forward references allowed. But check, if everything is ok ... */
372 		if (pi->pass==PASS_1) { /* Pass 1 */
373 			if (test_constant(pi,next,"Can't redefine constant %s, use .SET instead")!=NULL)
374 				return (True);
375 			if (def_const(pi, next, i)==False)
376 				return (False);
377 		} else { /* Pass 2 */
378 			int j;
379 			if (get_constant(pi, next, &j)==False) {  /* Defined in Pass 1 and now missing ? */
380 				print_msg(pi, MSGTYPE_ERROR, "Constant %s is missing in pass 2", next);
381 				return (False);
382 			}
383 			if (i != j) {
384 				print_msg(pi, MSGTYPE_ERROR, "Constant %s changed value from %d in pass1 to %d in pass 2", next,j,i);
385 				return (False);
386 			}
387 			/* OK. Definition is unchanged */
388 		}
389 		if ((pi->pass == PASS_2) && pi->list_line && pi->list_on) {
390 			fprintf(pi->list_file, "          %s\n", pi->list_line);
391 			pi->list_line = NULL;
392 		}
393 		break;
394 	case DIRECTIVE_ESEG:
395 		fix_orglist(pi->segment);
396 		def_orglist(pi->eseg);
397 		if (pi->device->eeprom_size == 0) { /* XXX */
398 			print_msg(pi, MSGTYPE_ERROR, "Can't use .ESEG directive because device has no EEPROM");
399 		}
400 		break;
401 	case DIRECTIVE_EXIT:
402 		pi->fi->exit_file = True;
403 		break;
404 	case DIRECTIVE_INCLUDE:
405 		if (!next) {
406 			print_msg(pi, MSGTYPE_ERROR, "Nothing to include");
407 			return (True);
408 		}
409 		next = term_string(pi, next);
410 		if ((pi->pass == PASS_2) && pi->list_line && pi->list_on) {
411 			fprintf(pi->list_file, "          %s\n", pi->list_line);
412 			pi->list_line = NULL;
413 		}
414 		/* Test if include is in local directory */
415 		ok = test_include(next);
416 		data = NULL;
417 		if (!ok) {
418 #ifdef DEFAULT_INCLUDE_PATH
419 			data = joinpaths(DEFAULT_INCLUDE_PATH, next);
420 			ok = test_include(data);
421 #endif
422 			for (incpath = GET_ARG_LIST(pi->args, ARG_INCLUDEPATH); incpath && !ok; incpath = incpath->next) {
423 				if (data != NULL) {
424 					free(data);
425 				}
426 				data = joinpaths(incpath->data, next);
427 				if (data == NULL) {
428 					print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL);
429 					return (False);
430 				}
431 				ok = test_include(data);
432 			}
433 		}
434 		if (ok) {
435 			fi_bak = pi->fi;
436 			ok = parse_file(pi, data ? data : next);
437 			pi->fi = fi_bak;
438 		} else
439 			print_msg(pi, MSGTYPE_ERROR, "Cannot find include file: %s", next);
440 		if (data)
441 			free(data);
442 		break;
443 	case DIRECTIVE_INCLUDEPATH:
444 		if (!next) {
445 			print_msg(pi, MSGTYPE_ERROR, ".INCLUDEPATH needs an operand");
446 			return (True);
447 		}
448 		data = get_next_token(next, TERM_SPACE);
449 		if (data) {
450 			print_msg(pi, MSGTYPE_ERROR, ".INCLUDEPATH needs an operand!!!");
451 			get_next_token(data, TERM_END);
452 			if (!get_expr(pi, data, &i))
453 				return (False);
454 		}
455 		next = term_string(pi, next);
456 		/* get arg list start pointer */
457 		incpath = GET_ARG_LIST(pi->args, ARG_INCLUDEPATH);
458 		/* search for last element */
459 		if (incpath == NULL) {
460 			dl = malloc(sizeof(struct data_list));
461 			data = malloc(strlen(next)+1);
462 			if (dl && data) {
463 				dl->next = NULL;
464 				strcpy(data, next);
465 				dl->data = data;
466 				SET_ARG_LIST(pi->args, ARG_INCLUDEPATH, dl);
467 			} else {
468 				printf("Error: Unable to allocate memory\n");
469 				return (False);
470 			}
471 		} else
472 			add_arg(&incpath, next);
473 		break;
474 	case DIRECTIVE_LIST:
475 		if (pi->pass == PASS_2)
476 			if (pi->list_file)
477 				pi->list_on = True;
478 		break;
479 	case DIRECTIVE_LISTMAC:
480 		if (pi->pass == PASS_2)
481 			SET_ARG_I(pi->args, ARG_LISTMAC, True);
482 		break;
483 	case DIRECTIVE_MACRO:
484 		return (read_macro(pi, next));
485 	case DIRECTIVE_NOLIST:
486 		if (pi->pass == PASS_2)
487 			pi->list_on = False;
488 		break;
489 	case DIRECTIVE_ORG:
490 		if (!next) {
491 			print_msg(pi, MSGTYPE_ERROR, ".ORG needs an operand");
492 			return (True);
493 		}
494 		get_next_token(next, TERM_END);
495 		if (!get_expr(pi, next, &i))
496 			return (False);
497 		fix_orglist(pi->segment);
498 		pi->segment->addr = i; /* XXX advance */
499 		def_orglist(pi->segment);
500 		if (pi->fi->label)
501 			pi->fi->label->value = i;
502 		if ((pi->pass == PASS_2) && pi->list_line && pi->list_on) {
503 			fprintf(pi->list_file, "          %s\n", pi->list_line);
504 			pi->list_line = NULL;
505 		}
506 		break;
507 	case DIRECTIVE_SET:
508 		if (!next) {
509 			print_msg(pi, MSGTYPE_ERROR, ".SET needs an operand");
510 			return (True);
511 		}
512 		data = get_next_token(next, TERM_EQUAL);
513 		if (!data) {
514 			print_msg(pi, MSGTYPE_ERROR, "%s needs an expression (e.g. .SET BZZZT = 0x2a)", next);
515 			return (True);
516 		}
517 		get_next_token(data, TERM_END);
518 		if (!get_expr(pi, data, &i))
519 			return (False);
520 
521 		if (test_label(pi,next,"%s have already been defined as a label")!=NULL)
522 			return (True);
523 		if (test_constant(pi,next,"%s have already been defined as a .EQU constant")!=NULL)
524 			return (True);
525 		return (def_var(pi, next, i));
526 	case DIRECTIVE_DEFINE:
527 		if (!next) {
528 			print_msg(pi, MSGTYPE_ERROR, ".DEFINE needs an operand");
529 			return (True);
530 		}
531 		data = get_next_token(next, TERM_SPACE);
532 		if (data) {
533 			get_next_token(data, TERM_END);
534 			if (!get_expr(pi, data, &i))
535 				return (False);
536 		} else
537 			i = 1;
538 		if (test_label(pi,next,"%s have already been defined as a label")!=NULL)
539 			return (True);
540 		if (test_variable(pi,next,"%s have already been defined as a .SET variable")!=NULL)
541 			return (True);
542 		/* Forward references allowed. But check, if everything is ok ... */
543 		if (pi->pass==PASS_1) { /* Pass 1 */
544 			if (test_constant(pi,next,"Can't redefine constant %s, use .SET instead")!=NULL)
545 				return (True);
546 			if (def_const(pi, next, i)==False)
547 				return (False);
548 		} else { /* Pass 2 */
549 			int j;
550 			if (get_constant(pi, next, &j)==False) {  /* Defined in Pass 1 and now missing ? */
551 				print_msg(pi, MSGTYPE_ERROR, "Constant %s is missing in pass 2", next);
552 				return (False);
553 			}
554 			if (i != j) {
555 				print_msg(pi, MSGTYPE_ERROR, "Constant %s changed value from %d in pass1 to %d in pass 2", next,j,i);
556 				return (False);
557 			}
558 			/* OK. Definition is unchanged */
559 		}
560 		if ((pi->pass == PASS_2) && pi->list_line && pi->list_on) {
561 			fprintf(pi->list_file, "          %s\n", pi->list_line);
562 			pi->list_line = NULL;
563 		}
564 		break;
565 	case DIRECTIVE_NOOVERLAP:
566 		if (pi->pass == PASS_1) {
567 			fix_orglist(pi->segment);
568 			pi->segment_overlap = SEG_DONT_OVERLAP;
569 			def_orglist(pi->segment);
570 		}
571 		break;
572 	case DIRECTIVE_OVERLAP:
573 		if (pi->pass == PASS_1) {
574 			fix_orglist(pi->segment);
575 			pi->segment_overlap = SEG_ALLOW_OVERLAP;
576 			def_orglist(pi->segment);
577 		}
578 		break;
579 	case DIRECTIVE_PRAGMA:
580 		if (!next) {
581 			print_msg(pi, MSGTYPE_ERROR, "PRAGMA needs an operand, %s should be specified",
582 			          snprint_list(buf, sizeof(buf), pragma_list));
583 			return (True);
584 		}
585 		my_strupr(next);
586 		data = get_next_token(next, TERM_SPACE);
587 		pragma = lookup_keyword(pragma_list, next, False);
588 		switch (pragma) {
589 
590 		case PRAGMA_OVERLAP:
591 			if (pi->pass == PASS_1) {
592 				int overlap_setting = OVERLAP_UNDEFINED;
593 				if (data) {
594 					my_strupr(data);
595 					overlap_setting = lookup_keyword(overlap_value, data, False);
596 				};
597 				switch (overlap_setting) {
598 				case OVERLAP_DEFAULT:
599 					pi->effective_overlap = GET_ARG_I(pi->args, ARG_OVERLAP);
600 					break;
601 
602 				case OVERLAP_IGNORE:
603 				case OVERLAP_WARNING:
604 				case OVERLAP_ERROR:
605 					pi->effective_overlap = overlap_setting;
606 					break;
607 
608 				default:
609 					print_msg(pi, MSGTYPE_ERROR, "For PRAGMA %s directive"
610 					          " %s should be specified as the parameter", next,
611 					          snprint_list(buf, sizeof(buf), overlap_value));
612 					return (False);
613 				}
614 			}
615 			return (True);
616 			break;
617 		default:
618 			if (pi->pass == PASS_2)
619 				print_msg(pi, MSGTYPE_MESSAGE, "PRAGMA %s directive currently ignored", next);
620 			return (True);
621 		}
622 		break;
623 	case DIRECTIVE_UNDEF: /* TODO */
624 		break;
625 	case DIRECTIVE_IFDEF:
626 		if (!next) {
627 			print_msg(pi, MSGTYPE_ERROR, ".IFDEF needs an operand");
628 			return True;
629 		}
630 		get_next_token(next, TERM_END);
631 		/* Store location of ifdef (line number and file number) if the condition
632 		 * fails on pass 1 so that we do not reinterpret it as succeeding on pass 2. */
633 		if ((pi->pass==PASS_1 && get_symbol(pi, next, NULL)) || (pi->pass==PASS_2 && !ifdef_is_blacklisted(pi))) {
634 			pi->conditional_depth++;
635 		} else {
636 			if (pi->pass==PASS_1) {
637 				/* Blacklist this ifdef. */
638 				if (!ifdef_blacklist(pi)) {
639 					return False;
640 				}
641 			}
642 			if (!spool_conditional(pi, False)) {
643 				return False;
644 			}
645 		}
646 		break;
647 	case DIRECTIVE_IFNDEF:
648 		if (!next) {
649 			print_msg(pi, MSGTYPE_ERROR, ".IFNDEF needs an operand");
650 			return True;
651 		}
652 		get_next_token(next, TERM_END);
653 		/* Store location of ifndef (line number and file number) if the condition
654 		 * fails on pass 1 so that we do not reinterpret it as succeeding on pass 2. */
655 		if ((pi->pass==PASS_1 && !get_symbol(pi, next, NULL)) || (pi->pass==PASS_2 && !ifndef_is_blacklisted(pi))) {
656 			pi->conditional_depth++;
657 		} else {
658 			if (pi->pass==PASS_1) {
659 				/* Blacklist this ifndef. */
660 				if (!ifndef_blacklist(pi)) {
661 					return False;
662 				}
663 			}
664 			if (!spool_conditional(pi, False)) {
665 				return False;
666 			}
667 		}
668 		break;
669 	case DIRECTIVE_IF:
670 		if (!next) {
671 			print_msg(pi, MSGTYPE_ERROR, ".IF needs an expression");
672 			return (True);
673 		}
674 		get_next_token(next, TERM_END);
675 		if (!get_expr(pi, next, &i))
676 			return (False);
677 		if (i)
678 			pi->conditional_depth++;
679 		else {
680 			if (!spool_conditional(pi, False))
681 				return (False);
682 		}
683 		break;
684 	case DIRECTIVE_ELSE:
685 	case DIRECTIVE_ELIF:
686 	case DIRECTIVE_ELSEIF:
687 		if (!spool_conditional(pi, True))
688 			return (False);
689 		break;
690 	case DIRECTIVE_ENDIF:
691 		if (pi->conditional_depth == 0)
692 			print_msg(pi, MSGTYPE_ERROR, "Too many .ENDIF");
693 		else
694 			pi->conditional_depth--;
695 		break;
696 	case DIRECTIVE_MESSAGE:
697 		if (pi->pass == PASS_1)
698 			return (True);
699 		if (!next) {
700 			print_msg(pi, MSGTYPE_ERROR, "No message parameter supplied");
701 			return (True);
702 		}
703 		print_msg(pi, MSGTYPE_MESSAGE_NO_LF, NULL); 	/* Prints Line Header (filename, linenumber) without trailing \n */
704 		while (next) {
705 			data = get_next_token(next, TERM_COMMA);
706 			if (next[0] == '\"') { 	/* string parsing */
707 				next = term_string(pi, next);
708 				print_msg(pi, MSGTYPE_APPEND,"%s",next);
709 				while (*next != '\0') {
710 					next++;
711 				}
712 			} else {
713 				if (!get_expr(pi, next, &i)) {
714 					print_msg(pi, MSGTYPE_APPEND,"\n"); /* Add newline */
715 					return (False);
716 				}
717 				print_msg(pi, MSGTYPE_APPEND,"0x%02X",i);
718 			}
719 			next = data;
720 		}
721 		print_msg(pi, MSGTYPE_APPEND,"\n"); /* Add newline */
722 		break;
723 	case DIRECTIVE_WARNING:
724 		if (pi->pass == PASS_1)
725 			return (True);
726 		if (!next) {
727 			print_msg(pi, MSGTYPE_ERROR, "No warning string supplied");
728 			return (True);
729 		}
730 		next = term_string(pi, next);
731 		print_msg(pi, MSGTYPE_WARNING, next);
732 		break;
733 	case DIRECTIVE_ERROR:
734 		if (!next) {
735 			print_msg(pi, MSGTYPE_ERROR, "No error string supplied");
736 			return (True);
737 		}
738 		next = term_string(pi, next);
739 		print_msg(pi, MSGTYPE_ERROR, "%s", next);
740 		pi->error_count = pi->max_errors;
741 		if (pi->pass == PASS_1)
742 			return (True);
743 		break;
744 	}
745 	return (ok);
746 }
747 
748 
749 int
lookup_keyword(const char * const keyword_list[],const char * const keyword,int strict)750 lookup_keyword(const char *const keyword_list[], const char *const keyword, int strict)
751 {
752 	int i;
753 
754 	for (i = 0; keyword_list[i] != NULL; i++) {
755 		if (strict) {
756 			if (!strcmp(keyword, keyword_list[i]))
757 				return (i);
758 		} else {
759 			if (!strncmp(keyword, keyword_list[i], strlen(keyword_list[i])))
760 				return (i);
761 		}
762 	}
763 	return (-1);
764 }
765 
766 char *
term_string(struct prog_info * pi,char * string)767 term_string(struct prog_info *pi, char *string)
768 {
769 	int i;
770 
771 	if (string[0] != '\"') {
772 		print_msg(pi, MSGTYPE_ERROR, "String must be enclosed in \"-signs");
773 	} else {
774 		string++;
775 	}
776 	/* skip to the end of the string*/
777 	for (i = 0; (string[i] != '\"') && !((string[i] == 10) || (string[i] == 13) || (string[i] == '\0')); i++);
778 	if ((string[i] == 10) || (string[i] == 13) || (string[i] == '\0')) {
779 		print_msg(pi, MSGTYPE_ERROR, "String is missing a closing \"-sign");
780 	}
781 	string[i] = '\0'; /* and terminate it where the " was */
782 	return (string);
783 }
784 
785 /* Parse data byte directive */
786 int
parse_db(struct prog_info * pi,char * next)787 parse_db(struct prog_info *pi, char *next)
788 {
789 	int i;
790 	int count;
791 	char *data;
792 	char prev = 0;
793 
794 	/* check if .db is allowed in this segment type */
795 	if (pi->segment->flags & SEG_BSS_DATA) {
796 		print_msg(pi, MSGTYPE_ERROR, "Can't use .DB directive in data segment (.DSEG) !");
797 		return True ;
798 	}
799 
800 	count = 0;
801 	if (pi->pass == PASS_2 && pi->list_on) {
802 		fprintf(pi->list_file, "%c:%06lX ", pi->segment->ident, pi->segment->addr);
803 	}
804 	/* get each db token */
805 	while (next) {
806 		data = get_next_token(next, TERM_COMMA);
807 		/* string parsing */
808 		if (next[0] == '\"') {
809 			next = term_string(pi, next);
810 			while (*next != '\0') {
811 				count++;
812 				write_db(pi, *next, &prev, count);
813 				if (pi->pass == PASS_2 && pi->list_on)
814 					fprintf(pi->list_file, "%02X", (unsigned char)*next);
815 				if ((unsigned char)*next > 127 && pi->pass == PASS_2)
816 					print_msg(pi, MSGTYPE_WARNING, "Found .DB string with characters > code 127. Be careful !"); /* Print warning for codes > 127 */
817 				next++;
818 			}
819 		} else {
820 			if (pi->pass == PASS_2) {
821 				if (!get_expr(pi, next, &i))
822 					return (False);
823 				if ((i < -128) || (i > 255))
824 					print_msg(pi, MSGTYPE_WARNING, "Value %d is out of range (-128 <= k <= 255). Will be masked", i);
825 				if (pi->list_on) fprintf(pi->list_file, "%02X", i);
826 			}
827 			count++;
828 			write_db(pi, (char)i, &prev, count);
829 		}
830 		next = data;
831 	}
832 	if (pi->segment == pi->cseg) { /* XXX PAD */
833 		if ((count % 2) == 1) {
834 			if (pi->pass == PASS_2)  {
835 				if (pi->list_on) fprintf(pi->list_file, "00 ; zero byte added");
836 				write_prog_word(pi, pi->segment->addr, prev & 0xFF);
837 				print_msg(pi, MSGTYPE_WARNING, "A .DB segment with an odd number of bytes is detected. A zero byte is added.");
838 			}
839 			advance_ip(pi->cseg, 1);
840 		}
841 	}
842 	if (pi->pass == PASS_2 && pi->list_on) {
843 		fprintf(pi->list_file, "\n");
844 		pi->list_line = NULL;
845 	}
846 	return True;
847 }
848 
849 
850 void
write_db(struct prog_info * pi,char byte,char * prev,int count)851 write_db(struct prog_info *pi, char byte, char *prev, int count)
852 {
853 	if (pi->segment == pi->eseg)	{
854 		if (pi->pass == PASS_2) {
855 			write_ee_byte(pi, pi->eseg->addr, byte);
856 		}
857 		advance_ip(pi->eseg, 1);
858 	}
859 	if (pi->segment == pi->cseg) {
860 		if ((count % 2) == 0) {
861 			if (pi->pass == PASS_2) {
862 				write_prog_word(pi, pi->cseg->addr, (byte << 8) | (*prev & 0xff));
863 			}
864 			advance_ip(pi->cseg, 1);
865 		} else {
866 			*prev = byte;
867 		}
868 	}
869 }
870 
871 
872 int
spool_conditional(struct prog_info * pi,int only_endif)873 spool_conditional(struct prog_info *pi, int only_endif)
874 {
875 	int current_depth = 0, do_next;
876 
877 	if (pi->macro_line) {
878 		while ((pi->macro_line = pi->macro_line->next)) {
879 			pi->macro_call->line_index++;
880 			if (check_conditional(pi, pi->macro_line->line, &current_depth,  &do_next, only_endif)) {
881 				if (!do_next)
882 					return (True);
883 			} else
884 				return (False);
885 		}
886 		print_msg(pi, MSGTYPE_ERROR, "Found no closing .ENDIF in macro");
887 	} else {
888 		if ((pi->pass == PASS_2) && pi->list_line && pi->list_on)
889 			fprintf(pi->list_file, "          %s\n", pi->list_line);
890 		while (fgets_new(pi,pi->fi->buff, LINEBUFFER_LENGTH, pi->fi->fp)) {
891 			pi->fi->line_number++;
892 			if (check_conditional(pi, pi->fi->buff, &current_depth,  &do_next, only_endif)) {
893 				if (!do_next)
894 					return (True);
895 			} else
896 				return (False);
897 		}
898 		if (feof(pi->fi->fp)) {
899 			print_msg(pi, MSGTYPE_ERROR, "Found no closing .ENDIF");
900 			return (True);
901 		} else {
902 			perror(pi->fi->include_file->name);
903 			return (False);
904 		}
905 	}
906 	return (True);
907 }
908 
909 
910 int
check_conditional(struct prog_info * pi,char * pbuff,int * current_depth,int * do_next,int only_endif)911 check_conditional(struct prog_info *pi, char *pbuff, int *current_depth, int *do_next, int only_endif)
912 {
913 	int i = 0;
914 	char *next;
915 	char linebuff[LINEBUFFER_LENGTH];
916 
917 	strcpy(linebuff, pbuff); /* avoid cutting of the end of .elif line */
918 
919 	*do_next = False;
920 	while (IS_HOR_SPACE(linebuff[i]) && !IS_END_OR_COMMENT(linebuff[i])) i++;
921 	if ((linebuff[i] == '.') || (linebuff[i] == '#')) {
922 		i++;
923 		if (!nocase_strncmp(&linebuff[i], "if", 2))
924 			(*current_depth)++;
925 		else if (!nocase_strncmp(&linebuff[i], "endif", 5)) {
926 			if (*current_depth == 0)
927 				return (True);
928 			(*current_depth)--;
929 		} else if (!only_endif && (*current_depth == 0)) {
930 			if ((!nocase_strncmp(&linebuff[i], "else", 4)) && (nocase_strncmp(&linebuff[i], "elseif", 6))) {
931 				pi->conditional_depth++;
932 				return (True);
933 			}	else if ((!nocase_strncmp(&linebuff[i], "elif", 4)) || (!nocase_strncmp(&linebuff[i], "elseif", 6))) {
934 				next = get_next_token(&linebuff[i], TERM_SPACE);
935 				if (!next) {
936 					print_msg(pi, MSGTYPE_ERROR, ".ELSEIF / .ELIF needs an operand");
937 					return (True);
938 				}
939 				get_next_token(next, TERM_END);
940 				if (!get_expr(pi, next, &i))
941 					return (False);
942 				if (i)
943 					pi->conditional_depth++;
944 				else {
945 					if (!spool_conditional(pi, False))
946 						return (False);
947 				}
948 				return (True);
949 			}
950 		}
951 	}
952 	*do_next = True;
953 	return (True);
954 }
955 
956 int
test_include(const char * filename)957 test_include(const char *filename)
958 {
959 	FILE *fp;
960 	fp = fopen(filename, "r");
961 	if (fp) {
962 		fclose(fp);
963 		return (True);
964 	} else
965 		return (False);
966 }
967 
968 /* end of directiv.c */
969 
970 
971