Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

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