1 /* parse.c - global parser support functions */
2 /* (c) in 2009-2017 by Volker Barthelmann and Frank Wille */
3 
4 #include "vasm.h"
5 
6 int esc_sequences = 0;  /* do not handle escape sequences by default */
7 int nocase_macros = 0;  /* macro names are case-insensitive */
8 int maxmacparams = MAXMACPARAMS;
9 int maxmacrecurs = MAXMACRECURS;
10 
11 #ifndef MACROHTABSIZE
12 #define MACROHTABSIZE 0x800
13 #endif
14 static hashtable *macrohash;
15 
16 #ifndef STRUCTHTABSIZE
17 #define STRUCTHTABSIZE 0x800
18 #endif
19 static hashtable *structhash;
20 
21 static macro *first_macro;
22 static macro *cur_macro;
23 static struct namelen *enddir_list;
24 static size_t enddir_minlen;
25 static struct namelen *reptdir_list;
26 
27 static int rept_cnt = -1;
28 static char *rept_start,*rept_name,*rept_vals;
29 
30 static section *cur_struct;
31 static section *struct_prevsect;
32 
33 
escape(char * s,char * code)34 char *escape(char *s,char *code)
35 {
36   char dummy;
37   int cnt;
38 
39   if (*s++ != '\\')
40     ierror(0);
41   if (code == NULL)
42     code = &dummy;
43 
44   if (!esc_sequences) {
45     *code='\\';
46     return s;
47   }
48 
49   switch (*s) {
50     case 'b':
51       *code='\b';
52       return s+1;
53     case 'f':
54       *code='\f';
55       return s+1;
56     case 'n':
57       *code='\n';
58       return s+1;
59     case 'r':
60       *code='\r';
61       return s+1;
62     case 't':
63       *code='\t';
64       return s+1;
65     case '\\':
66       *code='\\';
67       return s+1;
68     case '\"':
69       *code='\"';
70       return s+1;
71     case '\'':
72       *code='\'';
73       return s+1;
74     case 'e':
75       *code=27;
76       return s+1;
77     case '0': case '1': case '2': case '3': case '4':
78     case '5': case '6': case '7': case '8': case '9':
79       *code=0;
80       cnt=0;
81       while (*s>='0' && *s<='9' && ++cnt<=3) {
82         *code = *code*8 + *s-'0';
83         s++;
84       }
85       return s;
86     case 'x': case 'X':
87       *code=0;
88       s++;
89       while ((*s>='0' && *s<='9') ||
90              (*s>='a' && *s<='f') || (*s>='A' && *s<='F')) {
91         if (*s>='0' && *s<='9')
92           *code = *code*16 + *s-'0';
93         else if (*s>='a' && *s<='f')
94           *code = *code*16 + *s-'a' + 10;
95         else
96           *code = *code*16 + *s -'A' + 10;
97         s++;
98       }
99       return s;
100     default:
101       general_error(35,*s);
102       return s;
103   }
104 }
105 
106 
cut_trail_blanks(char * s)107 char *cut_trail_blanks(char *s)
108 {
109   while (isspace((unsigned char)*(s-1)))  /* cut trailing blanks */
110     s--;
111   return s;
112 }
113 
114 
parse_name(char ** start)115 char *parse_name(char **start)
116 /* parses a quoted or unquoted name-string and returns a pointer to it */
117 {
118   char *s = *start;
119   char c,*name;
120 
121   if (*s=='\"' || *s=='\'') {
122     c = *s++;
123     name = s;
124     while (*s && *s!=c)
125       s++;
126     name = cnvstr(name,s-name);
127     if (*s)
128       s = skip(s+1);
129   }
130 #ifdef VASM_CPU_M68K
131   else if (*s=='<') {
132     s++;
133     name = s;
134     while (*s && *s!='>')
135       s++;
136     name = cnvstr(name,s-name);
137     if (*s)
138       s = skip(s+1);
139   }
140 #endif
141   else {
142     name = s;
143     while (!ISEOL(s) && !isspace((unsigned char)*s) && *s!=',')
144       s++;
145     if (s != name) {
146       name = cnvstr(name,s-name);
147       s = skip(s);
148     }
149     else
150       name = NULL;  /* nothing read */
151   }
152   *start = s;
153   return name;
154 }
155 
156 
skip_eol(char * s,char * e)157 static char *skip_eol(char *s,char *e)
158 {
159   while (s<e && *s!='\0' && *s!='\n' && *s!='\r')
160     s++;
161   return s;
162 }
163 
164 
skip_line(char * s)165 char *skip_line(char *s)
166 {
167   while (*s!='\0')
168     s++;
169   return s;
170 }
171 
172 
skip_identifier(char * s)173 char *skip_identifier(char *s)
174 {
175   char *name = s;
176 
177   if (ISIDSTART(*s)) {
178     s++;
179     while (ISIDCHAR(*s))
180       s++;
181     if (s = CHKIDEND(name,s))
182       if (!ISBADID(name,s-name))
183         return s;
184   }
185   return NULL;
186 }
187 
188 
parse_identifier(char ** s)189 char *parse_identifier(char **s)
190 {
191   char *name = *s;
192   char *endname;
193 
194   if (endname = skip_identifier(name)) {
195     *s = endname;
196     return cnvstr(name,endname-name);
197   }
198   return NULL;
199 }
200 
201 
skip_string(char * s,char delim,size_t * size)202 char *skip_string(char *s,char delim,size_t *size)
203 /* skip a string, optionally store the size in bytes in size, when not NULL */
204 {
205   size_t n = 0;
206 
207   if (*s != delim)
208     general_error(6,delim);  /* " expected */
209   else
210     s++;
211 
212   while (*s) {
213     if (*s == '\\') {
214       s = escape(s,NULL);
215     }
216     else {
217       if (*s++ == delim) {
218         if (*s == delim)
219           s++;  /* allow """" to be recognized as " */
220         else
221           break;
222       }
223     }
224     n++;
225   }
226 
227   if (*(s-1) != delim)
228     general_error(6,delim);  /* " expected */
229   if (size)
230     *size = n;
231   return s;
232 }
233 
234 
read_string(char * p,char * s,char delim,int width)235 char *read_string(char *p,char *s,char delim,int width)
236 /* read string contents with width bits for each character into a buffer p,
237    optionally starting with a delim-character, excluding the terminating
238    character */
239 {
240   char c;
241 
242   if (width & 7)
243     ierror(0);
244   width >>= 3;
245 
246   if (*s == delim)
247     s++;
248 
249   while (*s) {
250     if (*s == '\\') {
251       s = escape(s,&c);
252     }
253     else {
254       c = *s++;
255       if (c == delim) {
256         if (*s == delim)
257           s++;  /* allow """" to be recognized as " */
258         else
259           break;
260       }
261     }
262     setval(BIGENDIAN,p,width,(unsigned char)c);
263     p += width;
264   }
265   return s;
266 }
267 
268 
parse_string(char ** str,char delim,int width)269 dblock *parse_string(char **str,char delim,int width)
270 {
271   size_t size;
272   dblock *db;
273   char *p,c;
274   char *s = *str;
275 
276   if (width & 7)
277     ierror(0);
278 
279   /* how many bytes do we need for the string? */
280   skip_string(s,delim,&size);
281   if (size == 1)
282     return NULL; /* it's just one char, so use eval_expr() on it */
283 
284   db = new_dblock();
285   db->size = size * (size_t)(width>>3);
286   db->data = db->size ? mymalloc(db->size) : NULL;
287 
288   /* now copy the string for real into the dblock */
289   s = read_string(db->data,s,delim,width);
290   *str = s;
291   return db;
292 }
293 
294 
parse_symbol(char ** s)295 char *parse_symbol(char **s)
296 /* return pointer to an allocated local/global symbol string, or NULL */
297 {
298   char *name;
299 
300   name = get_local_label(s);
301   if (name == NULL)
302     name = parse_identifier(s);
303   return name;
304 }
305 
306 
parse_labeldef(char ** line,int needcolon)307 char *parse_labeldef(char **line,int needcolon)
308 /* Parse a global or local label definition at the beginning of a line.
309    Return pointer to its allocate buffer, when valid.
310    A trailing colon may be required or optional, but becomes mandatory
311    when label is not starting at first column. */
312 {
313   char *s = *line;
314   char *labname;
315 
316   if (isspace((unsigned char )*s)) {
317     s = skip(s);
318     needcolon = 1;  /* colon required, when label doesn't start at 1st column */
319   }
320 
321   if (labname = parse_symbol(&s)) {
322     s = skip(s);
323     if (*s == ':') {
324       s++;
325       needcolon = 0;
326     }
327     if (needcolon) {
328       myfree(labname);
329       labname = NULL;
330     }
331     else
332       *line = s;
333   }
334   return labname;
335 }
336 
337 
338 
check_indir(char * p,char * q)339 int check_indir(char *p,char *q)
340 /* returns true when the whole sequence between p and q starts and ends with */
341 /* parentheses and there are no unbalanced parentheses within */
342 {
343   char c;
344   int n;
345 
346   p = skip(p);
347   if (*p++ != '(')
348     return 0;
349 
350   n = 1;
351   while (n>0 && p<q) {
352     c = *p++;
353     if (c == '(')
354       n++;
355     else if (c == ')')
356       n--;
357   }
358   if (p < q)
359     p = skip(p);
360 
361   return n==0 && p>=q;
362 }
363 
364 
include_binary_file(char * inname,long nbskip,unsigned long nbkeep)365 void include_binary_file(char *inname,long nbskip,unsigned long nbkeep)
366 /* locate a binary file and convert into a data atom */
367 {
368   char *filename;
369   FILE *f;
370 
371   filename = convert_path(inname);
372   if (f = locate_file(filename,"rb")) {
373     size_t size = filesize(f);
374 
375     if (size > 0) {
376       if (nbskip>=0 && nbskip<=size) {
377         dblock *db = new_dblock();
378 
379         if (nbkeep > (unsigned long)(size - nbskip) || nbkeep==0)
380           db->size = size - (size_t)nbskip;
381         else
382           db->size = nbkeep;
383 
384         db->data = mymalloc(size);
385         if (nbskip > 0)
386           fseek(f,nbskip,SEEK_SET);
387 
388         fread(db->data,1,db->size,f);
389         add_atom(0,new_data_atom(db,1));
390       }
391       else
392         general_error(46);  /* bad file-offset argument */
393     }
394     fclose(f);
395   }
396   myfree(filename);
397 }
398 
399 
dirlist_match(char * s,char * e,struct namelen * list)400 static struct namelen *dirlist_match(char *s,char *e,struct namelen *list)
401 /* check if a directive from the list matches the current source location */
402 {
403   size_t len;
404   size_t maxlen = e - s;
405 
406   while (len = list->len) {
407     if (len <= maxlen) {
408       if (!strnicmp(s,list->name,len) && isspace((unsigned char)*(s + len)))
409         return list;
410     }
411     list++;
412   }
413   return NULL;
414 }
415 
416 
dirlist_minlen(struct namelen * list)417 static size_t dirlist_minlen(struct namelen *list)
418 {
419   size_t minlen;
420 
421   if (list == NULL)
422     ierror(0);
423   for (minlen=list->len; list->len; list++) {
424     if (list->len < minlen)
425       minlen = list->len;
426   }
427   return minlen;
428 }
429 
430 
431 /* return the line number of the last real source text instance, i.e.
432    not the line within a macro or repetition */
real_line(void)433 int real_line(void)
434 {
435   source *src = cur_src;
436   int line = src->line;
437 
438   while (src->num_params >= 0) {
439     line = src->parent_line;
440     src = src->parent;
441     if (src == NULL)
442       ierror(0);  /* macro must have a parent */
443   }
444   return line;
445 }
446 
447 
new_repeat(int rcnt,char * name,char * vals,struct namelen * reptlist,struct namelen * endrlist)448 void new_repeat(int rcnt,char *name,char *vals,
449                 struct namelen *reptlist,struct namelen *endrlist)
450 {
451   if (cur_macro==NULL && cur_src!=NULL && enddir_list==NULL) {
452     enddir_list = endrlist;
453     enddir_minlen = dirlist_minlen(endrlist);
454     reptdir_list = reptlist;
455     rept_start = cur_src->srcptr;
456     rept_name = name;
457     rept_vals = vals;
458     rept_cnt = rcnt;  /* also REPT_IRP or REPT_IRPC */
459   }
460   else
461     ierror(0);
462 }
463 
464 
find_macarg_name(source * src,char * name,size_t len)465 int find_macarg_name(source *src,char *name,size_t len)
466 {
467   struct macarg *ma;
468   int idx;
469 
470   /* named macro arguments */
471   if (src->macro != NULL) {
472     for (idx=0,ma=src->argnames; ma!=NULL && idx<maxmacparams;
473          idx++,ma=ma->argnext) {
474       /* @@@ case-sensitive comparison? */
475       if (ma->arglen==len && strncmp(ma->argname,name,len)==0)
476         return idx;
477     }
478   }
479 
480   /* repeat-loop iterator name */
481   if (src->irpname != NULL) {
482     if (strlen(src->irpname)==len && strncmp(src->irpname,name,len)==0) {
483       /* copy current iterator value to param[MAXMACPARAMS] */
484       src->param[MAXMACPARAMS] = src->irpvals->argname;
485       src->param_len[MAXMACPARAMS] = src->irpvals->arglen;
486       return IRPVAL;
487     }
488   }
489 
490   return -1;
491 }
492 
493 
494 /* append a macarg object at the end of the given list */
addmacarg(struct macarg ** list,char * start,char * end)495 struct macarg *addmacarg(struct macarg **list,char *start,char *end)
496 {
497   struct macarg *lastarg,*newarg;
498   int len = end-start;
499 
500   /* count arguments */
501   if (lastarg = *list) {
502     while (lastarg->argnext)
503       lastarg = lastarg->argnext;
504   }
505 
506   newarg = mymalloc(sizeof(struct macarg) + len);
507   newarg->argnext = NULL;
508   if (start != NULL) {
509     memcpy(newarg->argname,start,len);
510     newarg->argname[len] = '\0';
511     newarg->arglen = len;
512   }
513   else
514     newarg->arglen = MACARG_REQUIRED;
515   if (lastarg)
516     lastarg->argnext = newarg;
517   else
518     *list = newarg;
519 
520   return newarg;
521 }
522 
523 
new_macro(char * name,struct namelen * endmlist,char * args)524 macro *new_macro(char *name,struct namelen *endmlist,char *args)
525 {
526   hashdata data;
527   macro *m = NULL;
528 
529   if (cur_macro==NULL && cur_src!=NULL && enddir_list==NULL) {
530     m = mymalloc(sizeof(macro));
531     m->name = mystrdup(name);
532     if (nocase_macros)
533       strtolower(m->name);
534     m->num_argnames = -1;
535     m->argnames = m->defaults = NULL;
536     m->recursions = 0;
537     m->vararg = -1;
538 
539     if (find_name_nc(mnemohash,name,&data)) {
540       int idx;
541 
542       m->text = cur_src->srcptr;
543       for (idx=data.idx;
544            idx<mnemonic_cnt && !stricmp(mnemonics[idx].name,name); idx++) {
545         if (MNEMONIC_VALID(idx)) {
546           m->text = NULL;
547           general_error(51);  /* name conflicts with mnemonic */
548           break;
549         }
550       }
551     }
552     else if (find_name_nc(dirhash,name,&data)) {
553       m->text = NULL;
554       general_error(52);  /* name conflicts with directive */
555     }
556     else
557       m->text = cur_src->srcptr;
558 
559     cur_macro = m;
560     enddir_list = endmlist;
561     enddir_minlen = dirlist_minlen(endmlist);
562     rept_cnt = -1;
563     rept_start = NULL;
564 
565     if (args) {
566       /* named arguments have been given */
567       struct macarg *ma;
568       char *end;
569       int n = 0;
570 
571       m->num_argnames = 0;
572       args = skip(args);
573       while (args!=NULL && !ISEOL(args)) {
574         end = SKIP_MACRO_ARGNAME(args);
575 
576         if (end!=NULL && end-args!=0 && m->vararg<0) {
577           /* add another argument name */
578           ma = addmacarg(&m->argnames,args,end);
579           m->num_argnames++;
580           args = skip(end);
581           if (end = MACRO_ARG_OPTS(m,n,ma->argname,args))
582             args = skip(end);  /* got defaults and qualifiers */
583           else
584             addmacarg(&m->defaults,args,args);  /* default is empty */
585           n++;
586         }
587         else {
588           general_error(42);  /* illegal macro argument */
589           break;
590         }
591         args = MACRO_ARG_SEP(args);  /* check for separator between names */
592       }
593     }
594   }
595   else
596     ierror(0);
597 
598   return m;
599 }
600 
601 
find_macro(char * name,int name_len)602 macro *find_macro(char *name,int name_len)
603 {
604   hashdata data;
605 
606   if (nocase_macros) {
607     if (!find_namelen_nc(macrohash,name,name_len,&data))
608       return NULL;
609   }
610   else {
611     if (!find_namelen(macrohash,name,name_len,&data))
612       return NULL;
613   }
614   return data.ptr;
615 }
616 
617 
618 /* check if 'name' is a known macro, then execute macro context */
execute_macro(char * name,int name_len,char ** q,int * q_len,int nq,char * s)619 int execute_macro(char *name,int name_len,char **q,int *q_len,int nq,
620                   char *s)
621 {
622   macro *m;
623   source *src;
624   struct macarg *ma;
625   int n;
626   struct namelen param,arg;
627 #if MAX_QUALIFIERS>0
628   char *defq[MAX_QUALIFIERS];
629   int defq_len[MAX_QUALIFIERS];
630 #endif
631 #ifdef NO_MACRO_QUALIFIERS
632   char *nptr = name;
633 
634   /* Instruction qualifiers are ignored for macros on this architecture.
635      So we have to determine the length of the mnemonic again. */
636   while (*nptr && !isspace((unsigned char)*nptr))
637     nptr++;
638   name_len = nptr - name;
639   nq = 0;
640 #endif
641 
642   if (!(m = find_macro(name,name_len)))
643     return 0;
644 
645   /* it's a macro: read arguments and execute it */
646   if (m->recursions >= maxmacrecurs) {
647     general_error(56,maxmacrecurs);  /* maximum macro recursions reached */
648     return 0;
649   }
650   m->recursions++;
651   src = new_source(m->name,m->text,m->size);
652   src->argnames = m->argnames;
653 
654 #if MAX_QUALIFIERS>0
655   /* remember given qualifiers, or use the cpu's default qualifiers */
656   for (n=0; n<nq; n++) {
657     src->qual[n] = q[n];
658     src->qual_len[n] = q_len[n];
659   }
660   nq = set_default_qualifiers(defq,defq_len);
661   for (; n<nq; n++) {
662     src->qual[n] = defq[n];
663     src->qual_len[n] = defq_len[n];
664   }
665   src->num_quals = nq;
666 #endif
667 
668   /* fill in the defaults first */
669   for (n=0,ma=m->defaults; n<maxmacparams; n++) {
670     if (ma != NULL) {
671       src->param[n] = ma->arglen==MACARG_REQUIRED ? NULL : ma->argname;
672       src->param_len[n] = ma->arglen==MACARG_REQUIRED ? 0 : ma->arglen;
673       ma = ma->argnext;
674     }
675     else {
676       src->param[n] = emptystr;
677       src->param_len[n] = 0;
678     }
679   }
680 
681   /* read macro arguments from operand field */
682   s = skip(s);
683   n = 0;
684   while (!ISEOL(s) && n<maxmacparams) {
685     if (n>=0 && m->vararg==n) {
686       /* Varargs: take rest of line as argument */
687       char *start = s;
688       char *end = s;
689 
690       while (!ISEOL(s)) {
691         s++;
692         if (!isspace((unsigned char)*s))
693           end = s;  /* remember last non-blank character */
694       }
695       src->param[n] = start;
696       src->param_len[n] = end - start;
697       n++;
698       break;
699     }
700     else if ((s = parse_macro_arg(m,s,&param,&arg)) != NULL) {
701       if (arg.len) {
702         /* argument selected by keyword */
703         if (n <= 0) {
704           n = find_macarg_name(src,arg.name,arg.len);
705           if (n >= 0) {
706             src->param[n] = param.name;
707             src->param_len[n] = param.len;
708           }
709           else
710             general_error(72);  /* undefined macro argument name */
711           n = -1;
712         }
713         else
714           general_error(71);  /* cannot mix positional and keyword arguments */
715       }
716       else {
717         /* argument selected by position n */
718         if (n >= 0) {
719           if (param.len > 0) {
720             src->param[n] = param.name;
721             src->param_len[n] = param.len;
722           }
723           n++;
724         }
725         else
726           general_error(71);  /* cannot mix positional and keyword arguments */
727       }
728     }
729     else
730       break;
731 
732     s = skip(s);
733     if (!(s = MACRO_PARAM_SEP(s)))  /* check for separator between params. */
734       break;
735   }
736 
737   if (n < 0)
738     n = m->num_argnames>=0 ? m->num_argnames : 0;
739   if (n > maxmacparams) {
740     general_error(27,maxmacparams);  /* number of args exceeded */
741     n = maxmacparams;
742   }
743 
744   src->macro = m;
745   src->num_params = n;      /* >=0 indicates macro source */
746 
747   for (n=0; n<maxmacparams; n++) {
748     if (src->param[n] == NULL) {
749       /* required, but missing */
750       src->param[n] = emptystr;
751       src->param_len[n] = 0;
752       general_error(73,n+1);  /* required macro argument was left out */
753     }
754   }
755 
756   EXEC_MACRO(src);          /* syntax-module dependant initializations */
757   cur_src = src;            /* execute! */
758   return 1;
759 }
760 
761 
leave_macro(void)762 int leave_macro(void)
763 {
764   if (cur_src->macro != NULL) {
765     end_source(cur_src);
766     return 0;  /* ok */
767   }
768   general_error(36);  /* no current macro to exit */
769   return -1;
770 }
771 
772 
773 /* remove an already defined macro from the hash table */
undef_macro(char * name)774 int undef_macro(char *name)
775 {
776   if (find_macro(name,strlen(name))) {
777     rem_hashentry(macrohash,name,nocase_macros);
778     return 1;
779   }
780   general_error(68);  /* macro does not exist */
781   return 0;
782 }
783 
784 
start_repeat(char * rept_end)785 static void start_repeat(char *rept_end)
786 {
787   char buf[MAXPATHLEN];
788   source *src;
789   char *p,*val;
790   int i;
791 
792   reptdir_list = NULL;
793   if ((rept_cnt<0 && rept_cnt!=REPT_IRP && rept_cnt!=REPT_IRPC) ||
794       cur_src==NULL || strlen(cur_src->name) + 24 >= MAXPATHLEN)
795     ierror(0);
796 
797   if (rept_cnt != 0) {
798     sprintf(buf,"REPEAT:%s:line %d",cur_src->name,cur_src->line);
799     src = new_source(mystrdup(buf),rept_start,rept_end-rept_start);
800     src->irpname = rept_name;
801     src->irpvals = NULL;
802 #ifdef REPTNSYM
803     src->reptn = 0;
804     set_internal_abs(REPTNSYM,0);
805 #endif
806 
807     switch (rept_cnt) {
808       case REPT_IRP:  /* iterate with comma separated values */
809         p = rept_vals;
810         if (!*p) {
811           addmacarg(&src->irpvals,p,p);
812           src->repeat = 1;
813         }
814         else {
815           src->repeat = 0;
816           while (val = parse_name(&p)) {
817             addmacarg(&src->irpvals,val,val+strlen(val));
818             myfree(val);
819             src->repeat++;
820             p = skip(p);
821             if (*p == ',')
822               p = skip(p+1);
823           }
824         }
825         break;
826 
827       case REPT_IRPC:  /* iterate with each character */
828         p = rept_vals;
829         if (!*p) {
830           addmacarg(&src->irpvals,p,p);
831           src->repeat = 1;
832         }
833         else {
834           src->repeat = 0;
835           do {
836             while (!isspace((unsigned char )*p) && *p!=',' && !ISEOL(p)) {
837               addmacarg(&src->irpvals,p,p+1);
838               src->repeat++;
839               p++;
840             }
841             p = skip(p);
842             if (*p == ',')
843               p = skip(p+1);
844           }
845           while (!ISEOL(p));
846         }
847         break;
848 
849       default:  /* iterate rept_cnt times */
850         src->repeat = (unsigned long)rept_cnt;
851         break;
852     }
853 
854     if (cur_src->macro != NULL) {
855       /* repetition in a macro: get parameters */
856       src->num_params = cur_src->num_params;
857       for (i=0; i<src->num_params; i++) {
858         src->param[i] = cur_src->param[i];
859         src->param_len[i] = cur_src->param_len[i];
860       }
861 #if MAX_QUALIFIERS > 0
862       src->num_quals = cur_src->num_quals;
863       for (i=0; i<src->num_quals; i++) {
864         src->qual[i] = cur_src->qual[i];
865         src->qual_len[i] = cur_src->qual_len[i];
866       }
867 #endif
868       src->argnames = cur_src->argnames;
869     }
870 
871     if (src->repeat == 0)
872       ierror(0);
873     cur_src = src;  /* repeat it */
874   }
875 }
876 
877 
add_macro(void)878 static void add_macro(void)
879 {
880   if (cur_macro!=NULL && cur_src!=NULL) {
881     if (cur_macro->text != NULL) {
882       hashdata data;
883 
884       cur_macro->size = cur_src->srcptr - cur_macro->text;
885       cur_macro->next = first_macro;
886       first_macro = cur_macro;
887       data.ptr = cur_macro;
888       add_hashentry(macrohash,cur_macro->name,data);
889     }
890     cur_macro = NULL;
891   }
892   else
893     ierror(0);
894 }
895 
896 
897 /* copy macro parameter n to line buffer, return -1 when out of space */
copy_macro_param(source * src,int n,char * d,int len)898 int copy_macro_param(source *src,int n,char *d,int len)
899 {
900   if (n < 0) {
901     ierror(0);
902   }
903   else if ((n<src->num_params && n<maxmacparams) || n==IRPVAL) {
904     int i;
905 
906     if (n == IRPVAL)
907       n = MAXMACPARAMS;
908 
909     for (i=0; i<src->param_len[n] && len>0; i++,len--)
910       *d++ = src->param[n][i];
911 
912     return i==src->param_len[n] ? i : -1;
913   }
914   else
915     return 0;
916 }
917 
918 
919 /* copy nth macro qualifier to line buffer, return -1 when out of space */
copy_macro_qual(source * src,int n,char * d,int len)920 int copy_macro_qual(source *src,int n,char *d,int len)
921 {
922 #if MAX_QUALIFIERS > 0
923   int i;
924 
925   if (n < src->num_quals) {
926     for (i=0; i<src->qual_len[n] && len>0; i++,len--)
927       *d++ = src->qual[n][i];
928   }
929   return i==src->qual_len[n] ? i : -1;
930 #else
931   return 0;
932 #endif
933 }
934 
935 /* Switch to a named offset section which defines the structure. */
new_structure(char * name)936 int new_structure(char *name)
937 {
938   hashdata data;
939 
940   if (cur_struct) {
941     general_error(48);  /* cannot declare structure within structure */
942     return 0;
943   }
944 
945   struct_prevsect = current_section;
946   switch_offset_section(name,-1);
947   data.ptr = cur_struct = current_section;
948   add_hashentry(structhash,cur_struct->name,data);
949   return 1;
950 }
951 
952 /* Finish the structure definition and return the previous section. */
end_structure(section ** prev)953 int end_structure(section **prev)
954 {
955   if (cur_struct) {
956     *prev = struct_prevsect;
957     cur_struct = struct_prevsect = NULL;
958     return 1;
959   }
960   general_error(49);  /* no structure */
961   return 0;
962 }
963 
964 
find_structure(char * name,int name_len)965 section *find_structure(char *name,int name_len)
966 {
967   hashdata data;
968   section *s;
969 
970   if (cur_struct!=NULL && !strcmp(cur_struct->name,name))
971     general_error(55);  /* illegal structure recursion */
972 
973   if (find_namelen(structhash,name,name_len,&data))
974     s = data.ptr;
975   else
976     s = NULL;
977   return s;
978 }
979 
980 
981 /* reads the next input line */
read_next_line(void)982 char *read_next_line(void)
983 {
984   char *s,*srcend,*d;
985   int nparam,len;
986   char *rept_end = NULL;
987 
988   /* check if end of source is reached */
989   for (;;) {
990     srcend = cur_src->text + cur_src->size;
991     if (cur_src->srcptr >= srcend || *(cur_src->srcptr) == '\0') {
992       if (--cur_src->repeat > 0) {
993         struct macarg *irpval;
994 
995         cur_src->srcptr = cur_src->text;  /* back to start */
996         cur_src->line = 0;
997         if (cur_src->irpname!=NULL && (irpval=cur_src->irpvals)!=NULL) {
998           /* remove and deallocate leading irpval of last iteration */
999           cur_src->irpvals = irpval->argnext;
1000           myfree(irpval);
1001         }
1002 #ifdef REPTNSYM
1003         set_internal_abs(REPTNSYM,++cur_src->reptn);
1004 #endif
1005       }
1006       else {
1007         if (cur_src->macro != NULL) {
1008           if (--cur_src->macro->recursions < 0)
1009             ierror(0);
1010         }
1011         myfree(cur_src->linebuf);  /* linebuf is no longer needed, saves memory */
1012         cur_src->linebuf = NULL;
1013         if (cur_src->parent == NULL)
1014           return NULL;  /* no parent source means end of assembly! */
1015         cur_src = cur_src->parent;  /* return to parent source */
1016 #ifdef CARGSYM
1017         if (cur_src->cargexp) {
1018           symbol *carg = internal_abs(CARGSYM);
1019           carg->expr = cur_src->cargexp;  /* restore parent CARG */
1020         }
1021 #endif
1022 #ifdef REPTNSYM
1023         set_internal_abs(REPTNSYM,cur_src->reptn);  /* restore parent REPTN */
1024 #endif
1025       }
1026     }
1027     else
1028       break;
1029   }
1030 
1031   cur_src->line++;
1032   s = cur_src->srcptr;
1033   d = cur_src->linebuf;
1034   len = cur_src->bufsize - 2;  /* excluding \0 at start and beginning */
1035   nparam = cur_src->num_params;
1036 
1037   /* line buffer starts with 0, to allow checks for left-hand character */
1038   *d++ = 0;
1039 
1040   if (enddir_list!=NULL && (srcend-s)>enddir_minlen) {
1041     /* reading a definition, like a macro or a repeat-block, until an
1042        end directive is found */
1043     struct namelen *dir;
1044     int rept_nest = 1;
1045 
1046     if (nparam>=0 && cur_macro!=NULL)
1047         general_error(26,cur_src->name);  /* macro definition inside macro */
1048 
1049     while (s <= (srcend-enddir_minlen)) {
1050       if (dir = dirlist_match(s,srcend,enddir_list)) {
1051         if (cur_macro != NULL) {
1052           add_macro();  /* link macro-definition into hash-table */
1053           enddir_list = NULL;
1054           break;
1055         }
1056         else if (--rept_nest == 0) {
1057           rept_end = s;
1058           enddir_list = NULL;
1059           break;
1060         }
1061         s += dir->len;
1062       }
1063       else if (cur_macro==NULL && reptdir_list!=NULL &&
1064                (dir = dirlist_match(s,srcend,reptdir_list)) != NULL) {
1065         s += dir->len;
1066         rept_nest++;
1067       }
1068 
1069       if (*s=='\"' || *s=='\'') {
1070         char c = *s++;
1071 
1072         while (s<=(srcend-enddir_minlen) && *s!=c && *s!='\n' && *s!='\r') {
1073           if (*s=='\\' && (*(s+1)=='\"' || *(s+1)=='\''))
1074             s = escape(s,NULL);
1075           else
1076             s++;
1077         }
1078       }
1079 
1080       if (ISEOL(s))
1081         s = skip_eol(s,srcend);
1082 
1083       if (*s == '\n') {
1084         cur_src->srcptr = s + 1;
1085         cur_src->line++;
1086       }
1087       else if (*s=='\r' && *(s-1)!='\n' && (s>=(srcend-1) || *(s+1)!='\n')) {
1088         cur_src->srcptr = s + 1;
1089         cur_src->line++;
1090       }
1091       s++;
1092     }
1093 
1094     if (enddir_list) {
1095       if (cur_macro)
1096         general_error(25,cur_macro->name);  /* missing ENDM directive */
1097       else
1098         general_error(32);  /* missing ENDR directive */
1099     }
1100 
1101     /* ignore rest of line, treat as comment */
1102     s = skip_eol(s,srcend);
1103   }
1104 
1105   if (nparam<0 && cur_src->irpname!=NULL)
1106     nparam = 0;  /* expand current repeat-iterator symbol into source */
1107 
1108   /* copy next line to linebuf */
1109   while (s<srcend && *s!='\0') {
1110     int nc;
1111 
1112     if (nparam >= 0)
1113       nc = expand_macro(cur_src,&s,d,len);  /* try macro arg. expansion */
1114     else
1115       nc = 0;
1116 
1117     if (nc > 0) {
1118       /* expanded macro arguments */
1119       len -= nc;
1120       d += nc;
1121     }
1122     else if (nc == 0) {
1123       /* copy next character */
1124       if (*s == '\r') {
1125         if ((s>cur_src->srcptr && *(s-1)=='\n') ||
1126             (s<(srcend-1) && *(s+1)=='\n')) {
1127           /* ignore \r in \r\n and \n\r combinations */
1128           s++;
1129         }
1130         else {
1131           /* treat a single \r as \n */
1132           s++;
1133           break;
1134         }
1135       }
1136       else if (*s == '\n') {
1137         s++;
1138         break;
1139       }
1140       else if (len > 0) {
1141         *d++ = *s++;
1142         len--;
1143       }
1144       else
1145       	nc = -1;
1146     }
1147 
1148     if (nc < 0) {
1149       /* line buffer ran out of space, allocate a bigger one */
1150       int offs = d - cur_src->linebuf;
1151 
1152       /* double its size */
1153       len += cur_src->bufsize;
1154       cur_src->bufsize += cur_src->bufsize;
1155       cur_src->linebuf = myrealloc(cur_src->linebuf,cur_src->bufsize);
1156       d = cur_src->linebuf + offs;
1157       if (debug)
1158         printf("Doubled line buffer size to %lu bytes.\n",cur_src->bufsize);
1159     }
1160   }
1161 
1162   *d = '\0';
1163   cur_src->srcptr = s;
1164 
1165   if (listena) {
1166     listing *new = mymalloc(sizeof(*new));
1167 
1168     new->next = 0;
1169     new->line = cur_src->line;
1170     new->error = 0;
1171     new->atom = 0;
1172     new->sec = 0;
1173     new->pc = 0;
1174     new->src = cur_src;
1175     strncpy(new->txt,cur_src->linebuf+1,MAXLISTSRC);
1176     if (first_listing) {
1177       last_listing->next = new;
1178       last_listing = new;
1179     }
1180     else {
1181       first_listing = last_listing = new;
1182     }
1183     cur_listing = new;
1184   }
1185 
1186   s = cur_src->linebuf+1;
1187   if (rept_end)
1188     start_repeat(rept_end);
1189   return s;
1190 }
1191 
1192 
init_parse(void)1193 int init_parse(void)
1194 {
1195   macrohash = new_hashtable(MACROHTABSIZE);
1196   structhash = new_hashtable(STRUCTHTABSIZE);
1197   return 1;
1198 }
1199