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 const int ML_DEFINED = 0x01;
39 
40 /* Only Windows LIBC does support itoa, so we add this
41    function for other systems here manually. Thank you
42    Peter Hettkamp for your work. */
43 
44 #ifndef WIN32
45 char *
itoa(int num,char * str,const int number_format)46 itoa(int num, char *str, const int number_format)
47 {
48 	int num1 = num;
49 	int num_chars = 0;
50 	int pos;
51 
52 	while (num1>0) {
53 		num_chars++;
54 		num1 /= number_format;
55 	}
56 
57 	if (num_chars == 0) num_chars = 1;
58 
59 	str[num_chars] = 0;
60 
61 	for (pos = num_chars-1; pos>=0; pos--) {
62 		int cur_char = num % number_format;
63 
64 		if (cur_char < 10) { /* Insert number */
65 			str[pos] = cur_char + '0';
66 		} else {
67 			str[pos] = cur_char-10 + 'A';
68 		}
69 
70 		num /= number_format;
71 	}
72 	return (str);
73 }
74 #endif
75 
76 
77 int
read_macro(struct prog_info * pi,char * name)78 read_macro(struct prog_info *pi, char *name)
79 {
80 	int loopok;
81 	int i;
82 	int start;
83 	struct macro *macro;
84 	struct macro_line *macro_line;
85 	struct macro_line **last_macro_line = NULL;
86 	struct macro_label *macro_label;
87 
88 	if (pi->pass == PASS_1) {
89 		if (!name) {
90 			print_msg(pi, MSGTYPE_ERROR, "missing macro name");
91 			return (True);
92 		}
93 		get_next_token(name, TERM_END);
94 
95 		for (i = 0; !IS_END_OR_COMMENT(name[i]); i++) {
96 			if (!IS_LABEL(name[i])) {
97 				print_msg(pi, MSGTYPE_ERROR, "illegal characters used in macro name '%s'",name);
98 				return (False);
99 			}
100 		}
101 
102 		macro = calloc(1, sizeof(struct macro));
103 		if (!macro) {
104 			print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL);
105 			return (False);
106 		}
107 
108 		if (pi->last_macro)
109 			pi->last_macro->next = macro;
110 		else
111 			pi->first_macro = macro;
112 		pi->last_macro = macro;
113 		macro->name = malloc(strlen(name) + 1);
114 		if (!macro->name) {
115 			print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL);
116 			return (False);
117 		}
118 		strcpy(macro->name, name);
119 		macro->include_file = pi->fi->include_file;
120 		macro->first_line_number = pi->fi->line_number;
121 		last_macro_line = &macro->first_macro_line;
122 	} else { /* pi->pass == PASS_2 */
123 		if (pi->list_line && pi->list_on) {
124 			fprintf(pi->list_file, "          %s\n", pi->list_line);
125 			pi->list_line = NULL;
126 		}
127 		/* reset macro label running numbers */
128 		get_next_token(name, TERM_END);
129 		macro = get_macro(pi, name);
130 		if (!macro) {
131 			print_msg(pi, MSGTYPE_ERROR, "macro inconsistency in '%s'", name);
132 			return (True);
133 		}
134 		for (macro_label = macro->first_label; macro_label; macro_label = macro_label->next) {
135 			macro_label->running_number = 0;
136 			macro_label->flags = 0;
137 		}
138 	}
139 
140 	loopok = True;
141 	while (loopok) {
142 		if (fgets_new(pi,pi->fi->buff, LINEBUFFER_LENGTH, pi->fi->fp)) {
143 			pi->fi->line_number++;
144 			i = 0;
145 			while (IS_HOR_SPACE(pi->fi->buff[i]) && !IS_END_OR_COMMENT(pi->fi->buff[i])) i++;
146 			if (pi->fi->buff[i] == '.') {
147 				i++;
148 				if (!nocase_strncmp(&pi->fi->buff[i], "endm", 4))
149 					loopok = False;
150 				if (!nocase_strncmp(&pi->fi->buff[i], "endmacro", 8))
151 					loopok = False;
152 			}
153 			if (pi->pass == PASS_1) {
154 				if (loopok) {
155 					i = 0; /* find start of line */
156 					while (IS_HOR_SPACE(pi->fi->buff[i]) && !IS_END_OR_COMMENT(pi->fi->buff[i])) {
157 						i++;
158 					}
159 					start = i;
160 					/* find end of line */
161 					while (!IS_END_OR_COMMENT(pi->fi->buff[i]) && (IS_LABEL(pi->fi->buff[i]) || pi->fi->buff[i] == ':')) {
162 						i++;
163 					}
164 					if (pi->fi->buff[i-1] == ':' && (pi->fi->buff[i-2] == '%'
165 					                                 && (IS_HOR_SPACE(pi->fi->buff[i]) || IS_END_OR_COMMENT(pi->fi->buff[i])))) {
166 						if (macro->first_label) {
167 							for (macro_label = macro->first_label; macro_label->next; macro_label=macro_label->next) {}
168 							macro_label->next = calloc(1,sizeof(struct macro_label));
169 							macro_label = macro_label->next;
170 						} else {
171 							macro_label = calloc(1,sizeof(struct macro_label));
172 							macro->first_label = macro_label;
173 						}
174 						macro_label->label = malloc(strlen(&pi->fi->buff[start])+1);
175 						pi->fi->buff[i-1] = '\0';
176 						strcpy(macro_label->label, &pi->fi->buff[start]);
177 						pi->fi->buff[i-1] = ':';
178 						macro_label->running_number = 0;
179 						macro_label->flags |= ML_DEFINED;
180 					}
181 
182 					macro_line = calloc(1, sizeof(struct macro_line));
183 					if (!macro_line) {
184 						print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL);
185 						return (False);
186 					}
187 					*last_macro_line = macro_line;
188 					last_macro_line = &macro_line->next;
189 					macro_line->line = malloc(strlen(pi->fi->buff) + 1);
190 					if (!macro_line->line) {
191 						print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL);
192 						return (False);
193 					}
194 					strcpy(macro_line->line, &pi->fi->buff[start]);
195 				}
196 			} else if (pi->fi->buff && pi->list_file && pi->list_on) {
197 				if (pi->fi->buff[i] == ';')
198 					fprintf(pi->list_file, "         %s\n", pi->fi->buff);
199 				else
200 					fprintf(pi->list_file, "          %s\n", pi->fi->buff);
201 			}
202 		} else {
203 			if (feof(pi->fi->fp)) {
204 				print_msg(pi, MSGTYPE_ERROR, "Found no closing .ENDMACRO");
205 				return (True);
206 			} else {
207 				perror(pi->fi->include_file->name);
208 				return (False);
209 			}
210 		}
211 	}
212 	return (True);
213 }
214 
215 
get_macro(struct prog_info * pi,char * name)216 struct macro *get_macro(struct prog_info *pi, char *name)
217 {
218 	struct macro *macro;
219 
220 	for (macro = pi->first_macro; macro; macro = macro->next)
221 		if (!nocase_strcmp(macro->name, name))
222 			return (macro);
223 	return (NULL);
224 }
225 
226 void
append_type(struct prog_info * pi,char * name,int c,char * value)227 append_type(struct prog_info *pi, char *name, int c, char *value)
228 {
229 	int p, l;
230 	struct def *def;
231 
232 	p = strlen(name);
233 	name[p++] = '_';
234 
235 	if (c == 0) {
236 		name[p++] = 'v';
237 		name[p] = '\0';
238 		return;
239 	}
240 
241 	l = strlen(value);
242 	if ((l==2 || l==3) && (tolower(value[0])=='r') && isdigit(value[1]) && (l==3?isdigit(value[2]):1) && (atoi(&value[1])<32)) {
243 		itoa((c*8),&name[p],10);
244 		return;
245 	}
246 
247 
248 	for (def = pi->first_def; def; def = def->next)
249 		if (!nocase_strcmp(def->name, value)) {
250 			itoa((c*8),&name[p],10);
251 			return;
252 		}
253 
254 	name[p++] = 'i';
255 	name[p] = '\0';
256 }
257 
258 
259 /* Replace the macro call with mnemonics.  */
260 int
expand_macro(struct prog_info * pi,struct macro * macro,char * rest_line)261 expand_macro(struct prog_info *pi, struct macro *macro, char *rest_line)
262 {
263 	int 	ok = True, macro_arg_count = 0, off, a, b = 0, c, i = 0, j = 0;
264 	char 	*line = NULL;
265 	char  *temp;
266 	char  *macro_args[MAX_MACRO_ARGS];
267 	char  tmp[7];
268 	char 	buff[LINEBUFFER_LENGTH];
269 	char	arg = False;
270 	char	*nmn; /* string buffer for 'n'ew 'm'acro 'n'ame */
271 	struct 	macro_line *old_macro_line;
272 	struct 	macro_call *macro_call;
273 	struct	macro_label *macro_label;
274 
275 	if (rest_line) {
276 		/* we reserve some extra space for extended macro parameters */
277 		line = malloc(strlen(rest_line) + 20);
278 		if (!line) {
279 			print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL);
280 			return (False);
281 		}
282 
283 		/* exchange amca word 'src' with YH:YL and 'dst' with ZH:ZL */
284 		for (c = 0, a = strlen(rest_line); c < a; c++) {
285 			switch (tolower(rest_line[c])) {
286 			case 's':
287 				if (IS_SEPARATOR(rest_line[c-1]) && (rest_line[c+1] == 'r') && (rest_line[c+2] == 'c') && IS_SEPARATOR(rest_line[c+3])) {
288 					strcpy(&line[b],"YH:YL");
289 					b += 5;
290 					c += 2;
291 				} else {
292 					line[b++] = rest_line[c];
293 				}
294 				break;
295 			case 'd':
296 				if (IS_SEPARATOR(rest_line[c-1]) && (rest_line[c+1] == 's') && (rest_line[c+2] == 't') && IS_SEPARATOR(rest_line[c+3])) {
297 					strcpy(&line[b],"ZH:ZL");
298 					b += 5;
299 					c += 2;
300 				} else {
301 					line[b++] = rest_line[c];
302 				}
303 				break;
304 			default:
305 				line[b++] = rest_line[c];
306 			}
307 		}
308 		strcpy(&line[b],"\n"); /* set CR/LF at the end of the line */
309 
310 
311 		/*  here we split up the macro arguments into "macro_args"
312 		 *  Extended macro code interpreter added by TW 2002 */
313 
314 		temp = line;
315 		/* test for advanced parameters */
316 		if (temp[0] == '[') {  /* there must be "[" " then "]", else it is garbage */
317 			if (!strchr(temp, ']')) {
318 				print_msg(pi, MSGTYPE_ERROR, "found no closing ']'");
319 				return (False);
320 			}
321 
322 			/* Okay now we are within the advanced code interpreter */
323 
324 			temp++; /* skip the first bracket */
325 			nmn = malloc(LINEBUFFER_LENGTH);
326 			if (!nmn) {
327 				print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL);
328 				return (False);
329 			}
330 			strcpy(nmn,macro->name); /* create a new macro name buffer */
331 			c = 1; /* byte counter */
332 			arg = True; /* loop flag */
333 
334 			while (arg) {
335 				while (IS_HOR_SPACE(temp[0])) { /* skip leading spaces */
336 					temp++;
337 				}
338 				off = 0; /* pointer offset */
339 				do {
340 					switch (temp[off]) { /* test current character code */
341 					case ':':
342 						temp[off] = '\0';
343 						if (off > 0) {
344 							c++;
345 							macro_args[macro_arg_count++] = temp;
346 						} else {
347 							print_msg(pi, MSGTYPE_ERROR, "missing register before ':'",nmn);
348 							return (False);
349 						}
350 						break;
351 					case ']':
352 						arg = False;
353 					case ',':
354 						a = off;
355 						do temp[a--] = '\0';
356 						while (IS_HOR_SPACE(temp[a]));
357 						if (off > 0) {
358 							macro_args[macro_arg_count++] = temp;
359 							append_type(pi, nmn, c, temp);
360 							c = 1;
361 						} else {
362 							append_type(pi, nmn, 0, temp);
363 							c = 1;
364 						}
365 						break;
366 
367 					default:
368 						off++;
369 					}
370 				} while (temp[off] != '\0');
371 
372 				if (arg) temp = &temp[off+1];
373 				else break;
374 			}
375 
376 			macro = get_macro(pi,nmn);
377 			if (macro == NULL) {
378 				print_msg(pi, MSGTYPE_ERROR, "Macro %s is not defined !",nmn);
379 				return (False);
380 			}
381 			free(nmn);
382 		}
383 		/* or else, we handle the macro as normal macro */
384 		else {
385 			line = malloc(strlen(rest_line) + 1);
386 			if (!line) {
387 				print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL);
388 				return (False);
389 			}
390 			strcpy(line, rest_line);
391 			temp = line;
392 			while (temp) {
393 				macro_args[macro_arg_count++] = temp;
394 				temp = get_next_token(temp, TERM_COMMA);
395 			}
396 		}
397 	}
398 
399 	if (pi->pass == PASS_1) {
400 		macro_call = calloc(1, sizeof(struct macro_call));
401 		if (!macro_call) {
402 			print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL);
403 			return (False);
404 		}
405 		if (pi->last_macro_call)
406 			pi->last_macro_call->next = macro_call;
407 		else
408 			pi->first_macro_call = macro_call;
409 
410 		pi->last_macro_call = macro_call;
411 		macro_call->line_number = pi->fi->line_number;
412 		macro_call->include_file = pi->fi->include_file;
413 		macro_call->macro = macro;
414 		macro_call->prev_on_stack = pi->macro_call;
415 
416 		if (macro_call->prev_on_stack) {
417 			macro_call->nest_level = macro_call->prev_on_stack->nest_level + 1;
418 			macro_call->prev_line_index = macro_call->prev_on_stack->line_index;
419 		}
420 	} else {
421 		for (macro_call = pi->first_macro_call; macro_call; macro_call = macro_call->next) {
422 			if ((macro_call->include_file->num == pi->fi->include_file->num) && (macro_call->line_number == pi->fi->line_number)) {
423 				if (pi->macro_call) {
424 					/* Find correct macro_call when using recursion and nesting */
425 					if (macro_call->prev_on_stack == pi->macro_call)
426 						if ((macro_call->nest_level == (pi->macro_call->nest_level + 1)) && (macro_call->prev_line_index == pi->macro_call->line_index))
427 							break;
428 				} else break;
429 			}
430 		}
431 		if (pi->list_line && pi->list_on) {
432 			fprintf(pi->list_file, "%c:%06lx   +  %s\n",
433 			        pi->cseg->ident, pi->cseg->addr, pi->list_line);
434 			pi->list_line = NULL;
435 		}
436 	}
437 
438 	macro_call->line_index = 0;
439 	pi->macro_call = macro_call;
440 	old_macro_line = pi->macro_line;
441 
442 	for (macro_label = macro->first_label; macro_label; macro_label = macro_label->next) {
443 		/* mark all local flags as not yet defined */
444 		macro_label->flags &= ~ML_DEFINED;
445 	}
446 
447 	for (pi->macro_line = macro->first_macro_line; pi->macro_line && ok; pi->macro_line = pi->macro_line->next) {
448 		macro_call->line_index++;
449 		if (GET_ARG_I(pi->args, ARG_LISTMAC))
450 			pi->list_line = buff;
451 		else
452 			pi->list_line = NULL;
453 
454 		/* here we change jumps/calls within macro that corresponds to macro labels.
455 		 * Only in case there is an entry in macro_label list */
456 
457 		strcpy(buff,"\0");
458 		macro_label = get_macro_label(pi->macro_line->line,macro);
459 		if (macro_label)	{
460 			/* test if the right macro label has been found */
461 			temp = strstr(pi->macro_line->line,macro_label->label);
462 			c = strlen(macro_label->label);
463 			if (temp[c] == ':') { /* it is a label definition */
464 				macro_label->running_number++;
465 				macro_label->flags |= ML_DEFINED;
466 				strncpy(buff, macro_label->label, c - 1);
467 				buff[c - 1] = 0;
468 				i = strlen(buff) + 2; /* we set the process indeafter label */
469 				/* add running number to it */
470 				strcpy(&buff[c-1],itoa(macro_label->running_number, tmp, 10));
471 				strcat(buff, ":\0");
472 			} else if (IS_HOR_SPACE(temp[c]) || IS_END_OR_COMMENT(temp[c]))	{ /* it is a jump to a macro defined label */
473 				int target_number = macro_label->running_number;
474 				if ((macro_label->flags & ML_DEFINED) == 0)
475 					/* Allow forward reference if label is not yet defined */
476 					target_number++;
477 				strcpy(buff,pi->macro_line->line);
478 				temp = strstr(buff, macro_label->label);
479 				i = temp - buff + strlen(macro_label->label);
480 				strncpy(temp, macro_label->label, c - 1);
481 				strcpy(&temp[c-1], itoa(target_number, tmp, 10));
482 			}
483 		} else {
484 			i = 0;
485 		}
486 
487 		/* here we check every character of current line */
488 		for (j = i; pi->macro_line->line[i] != '\0'; i++) {
489 			/* check for register place holders */
490 			if (pi->macro_line->line[i] == '@') {
491 				i++;
492 				if (!isdigit(pi->macro_line->line[i]))
493 					print_msg(pi, MSGTYPE_ERROR, "@ must be followed by a number");
494 				else if ((pi->macro_line->line[i] - '0') >= macro_arg_count)
495 					print_msg(pi, MSGTYPE_ERROR, "Missing macro argument (for @%c)", pi->macro_line->line[i]);
496 				else {
497 					/* and replace them with given registers */
498 					strcat(&buff[j], macro_args[pi->macro_line->line[i] - '0']);
499 					j += strlen(macro_args[pi->macro_line->line[i] - '0']);
500 				}
501 			} else if (pi->macro_line->line[i] == ';') {
502 				strncat(buff, "\n", 1);
503 				break;
504 			} else {
505 				strncat(buff, &pi->macro_line->line[i], 1);
506 			}
507 		}
508 
509 		ok = parse_line(pi, buff);
510 		if (ok) {
511 			if ((pi->pass == PASS_2) && pi->list_line && pi->list_on)
512 				fprintf(pi->list_file, "         %s\n", pi->list_line);
513 			if (pi->error_count >= pi->max_errors) {
514 				print_msg(pi, MSGTYPE_MESSAGE, "Maximum error count reached. Exiting...");
515 				ok = False;
516 				break;
517 			}
518 		}
519 	}
520 
521 	pi->macro_line = old_macro_line;
522 	pi->macro_call = macro_call->prev_on_stack;
523 	if (rest_line)
524 		free(line);
525 	return (ok);
526 }
527 
get_macro_label(char * line,struct macro * macro)528 struct macro_label *get_macro_label(char *line, struct macro *macro)
529 {
530 	char *temp ;
531 	struct macro_label *macro_label;
532 
533 	for (macro_label = macro->first_label; macro_label; macro_label = macro_label->next) {
534 		temp = strstr(line,macro_label->label);
535 		if (temp) {
536 			return macro_label;
537 		}
538 	}
539 	return NULL;
540 }
541 
542 /* end of macro.c */
543 
544