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 = ¯o->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 = ¯o_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