1 /* syntax.c  syntax module for vasm */
2 /* (c) in 2002-2018 by Frank Wille */
3 
4 #include "vasm.h"
5 
6 /* The syntax module parses the input (read_next_line), handles
7    assembly-directives (section, data-storage etc.) and parses
8    mnemonics. Assembly instructions are split up in mnemonic name,
9    qualifiers and operands. new_inst returns a matching instruction,
10    if one exists.
11    Routines for creating sections and adding atoms to sections will
12    be provided by the main module.
13 */
14 
15 char *syntax_copyright="vasm oldstyle syntax module 0.13e (c) 2002-2018 Frank Wille";
16 hashtable *dirhash;
17 
18 static char textname[]=".text",textattr[]="acrx";
19 static char dataname[]=".data",dataattr[]="adrw";
20 static char rodataname[]=".rodata",rodataattr[]="adr";
21 static char bssname[]=".bss",bssattr[]="aurw";
22 
23 char commentchar=';';
24 char *defsectname = textname;
25 char *defsecttype = "acrwx";
26 
27 static char macname[] = ".mac";
28 static char macroname[] = ".macro";
29 static char eqname[] = ".eq";
30 static char equname[] = ".equ";
31 static char setname[] = ".set";
32 
33 static char endmname[] = ".endmacro";
34 static char endrname[] = ".endrepeat";
35 static char reptname[] = ".rept";
36 static char repeatname[] = ".repeat";
37 static struct namelen endm_dirlist[] = {
38   { 4,&endmname[1] }, { 6,&endmname[1] }, { 8,&endmname[1] }, { 0,0 }
39 };
40 static struct namelen rept_dirlist[] = {
41   { 4,&reptname[1] }, { 6,&repeatname[1] }, { 0,0 }
42 };
43 static struct namelen endr_dirlist[] = {
44   { 4,&endrname[1] }, { 6,&endrname[1] }, { 9,&endrname[1] }, { 0,0 }
45 };
46 static struct namelen dendm_dirlist[] = {
47   { 5,&endmname[0] }, { 7,&endmname[0] }, { 9,&endmname[0] }, { 0,0 }
48 };
49 static struct namelen drept_dirlist[] = {
50   { 5,&reptname[0] }, { 7,&repeatname[0] }, { 0,0 }
51 };
52 static struct namelen dendr_dirlist[] = {
53   { 5,&endrname[0] }, { 7,&endrname[0] }, { 10,&endrname[0] }, { 0,0 }
54 };
55 
56 static int dotdirs,autoexport,parse_end,igntrail,nocprefix,nointelsuffix;
57 static taddr orgmode = ~0;
58 
59 
skip(char * s)60 char *skip(char *s)
61 {
62   while (isspace((unsigned char )*s))
63     s++;
64   return s;
65 }
66 
67 
68 /* check for end of line, issue error, if not */
eol(char * s)69 void eol(char *s)
70 {
71   if (igntrail) {
72     if (!ISEOL(s) && !isspace((unsigned char)*s))
73       syntax_error(6);
74   }
75   else {
76     s = skip(s);
77     if (!ISEOL(s))
78       syntax_error(6);
79   }
80 }
81 
82 
exp_skip(char * s)83 char *exp_skip(char *s)
84 {
85   if (!igntrail) {
86     s = skip(s);
87     if (*s == commentchar)
88       *s = '\0';  /* rest of operand is ignored */
89   }
90   else if (isspace((unsigned char)*s) || *s==commentchar)
91     *s = '\0';  /* rest of operand is ignored */
92   return s;
93 }
94 
95 
skip_oper(int instoper,char * s)96 static char *skip_oper(int instoper,char *s)
97 {
98 #ifdef VASM_CPU_Z80
99   unsigned char lastuc = 0;
100 #endif
101   int par_cnt = 0;
102   char c = 0;
103 
104   for (;;) {
105     s = exp_skip(s);
106 #ifdef VASM_CPU_Z80
107     if (c)
108       lastuc = toupper((unsigned char)*(s-1));
109 #endif
110     c = *s;
111 
112     if (START_PARENTH(c))
113       par_cnt++;
114     else if (END_PARENTH(c)) {
115       if (par_cnt>0)
116         par_cnt--;
117       else
118         syntax_error(3);  /* too many closing parentheses */
119     }
120 #ifdef VASM_CPU_Z80
121     /* For the Z80 ignore ' behind a letter, as it may be a register */
122     else if ((c=='\'' && (lastuc<'A' || lastuc>'Z')) || c=='\"')
123 #else
124     else if (c=='\'' || c=='\"')
125 #endif
126       s = skip_string(s,c,NULL) - 1;
127     else if (instoper && OPERSEP_COMMA && c==',' && par_cnt==0)
128       break;
129     else if (instoper && OPERSEP_BLANK && isspace((unsigned char)c)
130              && par_cnt==0)
131       break;
132     else if (!instoper && c==',' && par_cnt==0)
133       break;
134     else if (c == '\0')
135       break;
136 
137     s++;
138   }
139   if(par_cnt != 0)
140     syntax_error(4);  /* missing closing parentheses */
141   return s;
142 }
143 
144 
skip_operand(char * s)145 char *skip_operand(char *s)
146 {
147   return skip_oper(1,s);
148 }
149 
150 
my_skip_macro_arg(char * s)151 char *my_skip_macro_arg(char *s)
152 {
153   if (*s == '\\')
154     s++;  /* leading \ in argument list is optional */
155   return skip_identifier(s);
156 }
157 
158 
159 #define handle_data(a,b) handle_data_offset(a,b,0)
160 
handle_data_offset(char * s,int size,int offset)161 static void handle_data_offset(char *s,int size,int offset)
162 {
163   for (;;) {
164     char *opstart = s;
165     operand *op;
166     dblock *db = NULL;
167 
168     if (size==8 && (*s=='\"' || *s=='\'')) {
169       if (db = parse_string(&opstart,*s,8)) {
170 #if defined(VASM_CPU_650X) || defined(VASM_CPU_Z80) || defined(VASM_CPU_6800)
171         if (offset != 0) {
172           int i;
173 
174           for (i=0; i<db->size; i++)
175             db->data[i] = db->data[i] + offset;
176         }
177 #endif
178         add_atom(0,new_data_atom(db,1));
179         s = opstart;
180       }
181     }
182     if (!db) {
183       op = new_operand();
184       s = skip_oper(0,s);
185       if (parse_operand(opstart,s-opstart,op,DATA_OPERAND(size))) {
186         atom *a;
187 
188 #if defined(VASM_CPU_650X) || defined(VASM_CPU_Z80) || defined(VASM_CPU_6800)
189         if (offset != 0)
190           op->value = make_expr(ADD,number_expr(offset),op->value);
191 #endif
192         a = new_datadef_atom(abs(size),op);
193         a->align = 1;
194         add_atom(0,a);
195       }
196       else
197         syntax_error(8);  /* invalid data operand */
198     }
199 
200     s = skip(s);
201     if (*s == ',') {
202       s = skip(s+1);
203     }
204     else if (*s == commentchar) {
205       break;
206     }
207     else if (*s) {
208       syntax_error(9);  /* , expected */
209       return;
210     }
211     else
212       break;
213   }
214 
215   eol(s);
216 }
217 
218 
handle_text(char * s)219 static void handle_text(char *s)
220 {
221   char *opstart = s;
222   operand *op;
223   dblock *db = NULL;
224 
225   if (db = parse_string(&opstart,*s,8)) {
226     add_atom(0,new_data_atom(db,1));
227     s = opstart;
228   }
229   if (!db) {
230     op = new_operand();
231     s = skip_oper(0,s);
232     if (parse_operand(opstart,s-opstart,op,DATA_OPERAND(8))) {
233       atom *a;
234 
235       a = new_datadef_atom(8,op);
236       a->align = 1;
237       add_atom(0,a);
238     }
239     else
240       syntax_error(8);  /* invalid data operand */
241   }
242   eol(s);
243 }
244 
245 
handle_d8(char * s)246 static void handle_d8(char *s)
247 {
248   handle_data(s,8);
249 }
250 
251 
handle_d16(char * s)252 static void handle_d16(char *s)
253 {
254   handle_data(s,16);
255 }
256 
257 
handle_d24(char * s)258 static void handle_d24(char *s)
259 {
260   handle_data(s,24);
261 }
262 
263 
handle_d32(char * s)264 static void handle_d32(char *s)
265 {
266   handle_data(s,32);
267 }
268 
269 
270 #if defined(VASM_CPU_650X) || defined(VASM_CPU_Z80) || defined(VASM_CPU_6800)
handle_d8_offset(char * s)271 static void handle_d8_offset(char *s)
272 {
273   taddr offs = parse_constexpr(&s);
274 
275   s = skip(s);
276   if (*s == ',') {
277     s = skip(s+1);
278     handle_data_offset(s,8,offs);
279   }
280   else
281     syntax_error(9);  /* , expected */
282 }
283 #endif
284 
285 
do_alignment(taddr align,expr * offset)286 static void do_alignment(taddr align,expr *offset)
287 {
288   atom *a = new_space_atom(offset,1,0);
289 
290   a->align = align;
291   add_atom(0,a);
292 }
293 
294 
handle_align(char * s)295 static void handle_align(char *s)
296 {
297   taddr a = parse_constexpr(&s);
298 
299   if (a > 63)
300     syntax_error(21);  /* bad alignment */
301   do_alignment(1LL<<a,number_expr(0));
302   eol(s);
303 }
304 
305 
handle_even(char * s)306 static void handle_even(char *s)
307 {
308   do_alignment(2,number_expr(0));
309   eol(s);
310 }
311 
312 
do_space(int size,expr * cnt,expr * fill)313 static void do_space(int size,expr *cnt,expr *fill)
314 {
315   add_atom(0,new_space_atom(cnt,size>>3,fill));
316 }
317 
318 
handle_space(char * s,int size)319 static void handle_space(char *s,int size)
320 {
321   expr *cnt,*fill=0;
322 
323   cnt = parse_expr_tmplab(&s);
324   s = skip(s);
325   if (*s == ',') {
326     s = skip(s+1);
327     fill = parse_expr_tmplab(&s);
328   }
329   do_space(size,cnt,fill);
330   eol(s);
331 }
332 
333 
handle_fixedspc1(char * s)334 static void handle_fixedspc1(char *s)
335 {
336   do_space(8,number_expr(1),0);
337   eol(s);
338 }
339 
340 
handle_fixedspc2(char * s)341 static void handle_fixedspc2(char *s)
342 {
343   do_space(8,number_expr(2),0);
344   eol(s);
345 }
346 
347 
handle_spc8(char * s)348 static void handle_spc8(char *s)
349 {
350   handle_space(s,8);
351 }
352 
353 
handle_spc16(char * s)354 static void handle_spc16(char *s)
355 {
356   handle_space(s,16);
357 }
358 
359 
360 #if 0
361 static void handle_spc24(char *s)
362 {
363   handle_space(s,24);
364 }
365 
366 
367 static void handle_spc32(char *s)
368 {
369   handle_space(s,32);
370 }
371 #endif
372 
373 
handle_string(char * s)374 static void handle_string(char *s)
375 {
376   handle_data(s,8);
377   add_atom(0,new_space_atom(number_expr(1),1,0));  /* terminating zero */
378 }
379 
380 
handle_end(char * s)381 static void handle_end(char *s)
382 {
383   parse_end = 1;
384   eol(s);
385 }
386 
387 
handle_fail(char * s)388 static void handle_fail(char *s)
389 {
390   add_atom(0,new_assert_atom(NULL,NULL,mystrdup(s)));
391 }
392 
393 
handle_org(char * s)394 static void handle_org(char *s)
395 {
396   if (*s == current_pc_char) {
397     char *s2 = skip(s+1);
398 
399     if (*s2++ == '+') {
400       handle_space(skip(s2),8);  /*  "* = * + <expr>" to reserves bytes */
401       return;
402     }
403   }
404   set_section(new_org(parse_constexpr(&s)));
405   eol(s);
406 }
407 
408 
handle_rorg(char * s)409 static void handle_rorg(char *s)
410 {
411   start_rorg(parse_constexpr(&s));
412   eol(s);
413 }
414 
415 
handle_rend(char * s)416 static void handle_rend(char *s)
417 {
418   if (end_rorg())
419     eol(s);
420 }
421 
422 
handle_roffs(char * s)423 static void handle_roffs(char *s)
424 {
425   add_atom(0,new_roffs_atom(parse_expr_tmplab(&s)));
426 }
427 
428 
handle_section(char * s)429 static void handle_section(char *s)
430 {
431   char *name,*attr;
432 
433   if (!(name=parse_name(&s)))
434     return;
435   if (*s==',') {
436     s = skip(s+1);
437     attr = s;
438     if (*s!= '\"')
439       syntax_error(7,'\"');  /* " expected */
440     else
441       s++;
442     attr = s;
443     while (*s&&*s!='\"')
444       s++;
445     attr = cnvstr(attr,s-attr);
446     s = skip(s+1);
447   }
448   else {
449     if (!strcmp(name,textname)) attr = textattr;
450     if (!strcmp(name,dataname)) attr = dataattr;
451     if (!strcmp(name,rodataname)) attr = rodataattr;
452     if (!strcmp(name,bssname)) attr = bssattr;
453     else attr = defsecttype;
454   }
455 
456   new_section(name,attr,1);
457   switch_section(name,attr);
458   eol(s);
459 }
460 
461 
do_binding(char * s,int bind)462 static void do_binding(char *s,int bind)
463 {
464   symbol *sym;
465   char *name;
466 
467   while (1) {
468     if (!(name=parse_identifier(&s)))
469       return;
470     sym = new_import(name);
471     myfree(name);
472     if (sym->flags&(EXPORT|WEAK|LOCAL)!=0 &&
473         sym->flags&(EXPORT|WEAK|LOCAL)!=bind)
474       general_error(62,sym->name,get_bind_name(sym)); /* binding already set */
475     else
476       sym->flags |= bind;
477     s = skip(s);
478     if (*s != ',')
479       break;
480     s = skip(s+1);
481   }
482   eol(s);
483 }
484 
485 
handle_global(char * s)486 static void handle_global(char *s)
487 {
488   do_binding(s,EXPORT);
489 }
490 
491 
handle_weak(char * s)492 static void handle_weak(char *s)
493 {
494   do_binding(s,WEAK);
495 }
496 
497 
handle_local(char * s)498 static void handle_local(char *s)
499 {
500   do_binding(s,LOCAL);
501 }
502 
503 
ifdef(char * s,int b)504 static void ifdef(char *s,int b)
505 {
506   char *name;
507   symbol *sym;
508   int result;
509 
510   if (!(name = parse_symbol(&s))) {
511     syntax_error(10);  /* identifier expected */
512     return;
513   }
514   if (sym = find_symbol(name))
515     result = sym->type != IMPORT;
516   else
517     result = 0;
518   myfree(name);
519   cond_if(result == b);
520   eol(s);
521 }
522 
523 
ifused(char * s,int b)524 static void ifused(char *s, int b)
525 {
526   char *name;
527   symbol *sym;
528   int result;
529 
530   if (!(name = parse_identifier(&s))) {
531       syntax_error(10);  /* identifier expected */
532       return;
533   }
534 
535   if (sym = find_symbol(name)) {
536     if (sym->type != IMPORT) {
537       syntax_error(22,name);
538       result = 0;
539     }
540     else
541       result = 1;
542   }
543   else
544     result = 0;
545 
546   myfree(name);
547   cond_if(result == b);
548   eol(s);
549 }
550 
551 
handle_ifused(char * s)552 static void handle_ifused(char *s)
553 {
554   ifused(s,1);
555 }
556 
557 
handle_ifnused(char * s)558 static void handle_ifnused(char *s)
559 {
560   ifused(s,0);
561 }
562 
563 
handle_ifd(char * s)564 static void handle_ifd(char *s)
565 {
566   ifdef(s,1);
567 }
568 
569 
handle_ifnd(char * s)570 static void handle_ifnd(char *s)
571 {
572   ifdef(s,0);
573 }
574 
575 
ifexp(char * s,int c)576 static char *ifexp(char *s,int c)
577 {
578   expr *condexp = parse_expr_tmplab(&s);
579   taddr val;
580   int b;
581 
582   if (eval_expr(condexp,&val,NULL,0)) {
583     switch (c) {
584       case 0: b = val == 0; break;
585       case 1: b = val != 0; break;
586       case 2: b = val > 0; break;
587       case 3: b = val >= 0; break;
588       case 4: b = val < 0; break;
589       case 5: b = val <= 0; break;
590       default: ierror(0); break;
591     }
592   }
593   else {
594     general_error(30);  /* expression must be constant */
595     b = 0;
596   }
597   cond_if(b);
598   free_expr(condexp);
599   return s;
600 }
601 
602 
handle_ifeq(char * s)603 static void handle_ifeq(char *s)
604 {
605   eol(ifexp(s,0));
606 }
607 
608 
handle_ifne(char * s)609 static void handle_ifne(char *s)
610 {
611   eol(ifexp(s,1));
612 }
613 
614 
handle_ifgt(char * s)615 static void handle_ifgt(char *s)
616 {
617   eol(ifexp(s,2));
618 }
619 
620 
handle_ifge(char * s)621 static void handle_ifge(char *s)
622 {
623   eol(ifexp(s,3));
624 }
625 
626 
handle_iflt(char * s)627 static void handle_iflt(char *s)
628 {
629   eol(ifexp(s,4));
630 }
631 
632 
handle_ifle(char * s)633 static void handle_ifle(char *s)
634 {
635   eol(ifexp(s,5));
636 }
637 
638 
handle_else(char * s)639 static void handle_else(char *s)
640 {
641   eol(s);
642   cond_skipelse();
643 }
644 
645 
handle_endif(char * s)646 static void handle_endif(char *s)
647 {
648   eol(s);
649   cond_endif();
650 }
651 
652 
handle_assert(char * s)653 static void handle_assert(char *s)
654 {
655   char *expstr,*msgstr;
656   size_t explen;
657   expr *aexp;
658   atom *a;
659 
660   expstr = skip(s);
661   aexp = parse_expr(&s);
662   explen = s - expstr;
663   s = skip(s);
664   if (*s == ',') {
665     s = skip(s+1);
666     msgstr = parse_name(&s);
667   }
668   else
669     msgstr = NULL;
670 
671   a = new_assert_atom(aexp,cnvstr(expstr,explen),msgstr);
672   add_atom(0,a);
673 }
674 
675 
handle_incdir(char * s)676 static void handle_incdir(char *s)
677 {
678   char *name;
679 
680   if (name = parse_name(&s))
681     new_include_path(name);
682   eol(s);
683 }
684 
685 
handle_include(char * s)686 static void handle_include(char *s)
687 {
688   char *name;
689 
690   if (name = parse_name(&s)) {
691     eol(s);
692     include_source(name);
693   }
694 }
695 
696 
handle_incbin(char * s)697 static void handle_incbin(char *s)
698 {
699   char *name;
700   long delta = 0;
701   unsigned long nbbytes = 0;
702 
703   if (name = parse_name(&s)) {
704     s = skip(s);
705     if (*s == ',') {
706       s = skip(s+1);
707       delta = parse_constexpr(&s);
708       if (delta < 0)
709         delta = 0;
710       s = skip(s);
711       if (*s == ',') {
712         s = skip(s+1);
713         nbbytes = parse_constexpr(&s);
714       }
715     }
716     eol(s);
717     include_binary_file(name,delta,nbbytes);
718   }
719 }
720 
721 
handle_rept(char * s)722 static void handle_rept(char *s)
723 {
724   utaddr cnt = parse_constexpr(&s);
725 
726   eol(s);
727   new_repeat((int)cnt,NULL,NULL,
728              dotdirs?drept_dirlist:rept_dirlist,
729              dotdirs?dendr_dirlist:endr_dirlist);
730 }
731 
732 
handle_endr(char * s)733 static void handle_endr(char *s)
734 {
735   syntax_error(12,&endrname[1],&repeatname[1]);  /* unexpected endr without rept */
736 }
737 
738 
handle_macro(char * s)739 static void handle_macro(char *s)
740 {
741   char *name;
742 
743   if (name = parse_identifier(&s)) {
744     s = skip(s);
745     if (*s == ',') {  /* named macro arguments are given? */
746       s++;
747     }
748     else {
749       eol(s);
750       s = NULL;
751     }
752     new_macro(name,dotdirs?dendm_dirlist:endm_dirlist,s);
753     myfree(name);
754   }
755   else
756     syntax_error(10);  /* identifier expected */
757 }
758 
759 
handle_endm(char * s)760 static void handle_endm(char *s)
761 {
762   syntax_error(12,&endmname[1],&macroname[1]);  /* unexpected endm without macro */
763 }
764 
765 
handle_defc(char * s)766 static void handle_defc(char *s)
767 {
768   char *name;
769 
770   s = skip(s);
771   name = parse_identifier(&s);
772   if ( name != NULL ) {
773     s = skip(s);
774     if ( *s == '=' ) {
775       s = skip(s+1);
776       new_abs(name,parse_expr_tmplab(&s));
777     }
778     myfree(name);
779   }
780   else
781     syntax_error(10);
782 }
783 
784 
handle_list(char * s)785 static void handle_list(char *s)
786 {
787   set_listing(1);
788 }
789 
handle_nolist(char * s)790 static void handle_nolist(char *s)
791 {
792   set_listing(0);
793 }
794 
handle_listttl(char * s)795 static void handle_listttl(char *s)
796 {
797   /* set listing file title */
798 }
799 
handle_listsubttl(char * s)800 static void handle_listsubttl(char *s)
801 {
802   /* set listing file sub-title */
803 }
804 
handle_listpage(char * s)805 static void handle_listpage(char *s)
806 {
807   /* new listing page */
808 }
809 
handle_listspace(char * s)810 static void handle_listspace(char *s)
811 {
812   /* insert listing space */
813 }
814 
815 
handle_struct(char * s)816 static void handle_struct(char *s)
817 {
818   char *name;
819 
820   if (name = parse_identifier(&s)) {
821     s = skip(s);
822     eol(s);
823     if (new_structure(name))
824       current_section->flags |= LABELS_ARE_LOCAL;
825     myfree(name);
826   }
827   else
828     syntax_error(10);  /* identifier expected */
829 }
830 
831 
handle_endstruct(char * s)832 static void handle_endstruct(char *s)
833 {
834   section *prevsec;
835   symbol *szlabel;
836 
837   if (end_structure(&prevsec)) {
838     /* create the structure name as label defining the structure size */
839     current_section->flags &= ~LABELS_ARE_LOCAL;
840     szlabel = new_labsym(0,current_section->name);
841     add_atom(0,new_label_atom(szlabel));
842     /* end structure declaration by switching to previous section */
843     set_section(prevsec);
844   }
845   eol(s);
846 }
847 
848 
849 struct {
850   char *name;
851   void (*func)(char *);
852 } directives[] = {
853   "org",handle_org,
854   "rorg",handle_rorg,
855   "rend",handle_rend,
856   "phase",handle_rorg,
857   "dephase",handle_rend,
858   "roffs",handle_roffs,
859   "align",handle_align,
860   "even",handle_even,
861   "byte",handle_d8,
862   "db",handle_d8,
863   "dfb",handle_d8,
864   "defb",handle_d8,
865   "asc",handle_d8,
866   "data",handle_d8,
867   "defm",handle_text,
868   "text",handle_text,
869   "wor",handle_d16,
870   "word",handle_d16,
871   "addr",handle_d16,
872   "dw",handle_d16,
873   "dfw",handle_d16,
874   "defw",handle_d16,
875   "dd",handle_d32,
876 #if defined(VASM_CPU_650X) || defined(VASM_CPU_Z80) || defined(VASM_CPU_6800)
877   "abyte",handle_d8_offset,
878 #endif
879   "ds",handle_spc8,
880   "dsb",handle_spc8,
881   "fill",handle_spc8,
882   "reserve",handle_spc8,
883   "spc",handle_spc8,
884   "dsw",handle_spc16,
885   "blk",handle_spc8,
886   "blkw",handle_spc16,
887   "dc",handle_spc8,
888   "byt",handle_fixedspc1,
889   "wrd",handle_fixedspc2,
890   "assert",handle_assert,
891 #if defined(VASM_CPU_TR3200) /* Clash with IFxx instructions of TR3200 cpu */
892   "if_def",handle_ifd,
893   "if_ndef",handle_ifnd,
894   "if_eq",handle_ifeq,
895   "if_ne",handle_ifne,
896   "if_gt",handle_ifgt,
897   "if_ge",handle_ifge,
898   "if_lt",handle_iflt,
899   "if_le",handle_ifle,
900   "if_used",handle_ifused,
901   "if_nused",handle_ifnused,
902 #else
903   "ifdef",handle_ifd,
904   "ifndef",handle_ifnd,
905   "ifd",handle_ifd,
906   "ifnd",handle_ifnd,
907   "ifeq",handle_ifeq,
908   "ifne",handle_ifne,
909   "ifgt",handle_ifgt,
910   "ifge",handle_ifge,
911   "iflt",handle_iflt,
912   "ifle",handle_ifle,
913   "ifused",handle_ifused,
914   "ifnused",handle_ifnused,
915 #endif
916   "if",handle_ifne,
917   "else",handle_else,
918   "el",handle_else,
919   "endif",handle_endif,
920 #if !defined(VASM_CPU_Z80) && !defined(VASM_CPU_6800)
921   "ei",handle_endif,  /* Clashes with z80 opcode */
922 #endif
923   "incbin",handle_incbin,
924   "mdat",handle_incbin,
925   "incdir",handle_incdir,
926   "include",handle_include,
927   "rept",handle_rept,
928   "repeat",handle_rept,
929   "endr",handle_endr,
930   "endrep",handle_endr,
931   "endrepeat",handle_endr,
932   "mac",handle_macro,
933   "macro",handle_macro,
934   "endm",handle_endm,
935   "endmac",handle_endm,
936   "endmacro",handle_endm,
937   "end",handle_end,
938   "fail",handle_fail,
939   "section",handle_section,
940   "binary",handle_incbin,
941   "defs",handle_spc8,
942   "defp",handle_d24,
943   "defl",handle_d32,
944   "defc",handle_defc,
945   "xdef",handle_global,
946   "xref",handle_global,
947   "lib",handle_global,
948   "xlib",handle_global,
949   "global",handle_global,
950   "extern",handle_global,
951   "local",handle_local,
952   "weak",handle_weak,
953   "ascii",handle_string,
954   "asciiz",handle_string,
955   "string",handle_string,
956   "list",handle_list,
957   "nolist",handle_nolist,
958   "struct",handle_struct,
959   "structure",handle_struct,
960   "endstruct",handle_endstruct,
961   "endstructure",handle_endstruct,
962   "rmb",handle_spc8,
963   "fcc",handle_text,
964   "fcb",handle_d8,
965   "fdb",handle_d16,
966   "bsz",handle_spc8,
967   "zmb",handle_spc8,
968   "nam",handle_listttl,
969   "subttl",handle_listsubttl,
970   "page",handle_listpage,
971   "space",handle_listspace
972 };
973 
974 int dir_cnt = sizeof(directives) / sizeof(directives[0]);
975 
976 
977 /* checks for a valid directive, and return index when found, -1 otherwise */
check_directive(char ** line)978 static int check_directive(char **line)
979 {
980   char *s,*name;
981   hashdata data;
982 
983   s = skip(*line);
984   if (!ISIDSTART(*s))
985     return -1;
986   name = s++;
987   while (ISIDCHAR(*s))
988     s++;
989   if (*name=='.' && dotdirs)
990     name++;
991   if (!find_namelen_nc(dirhash,name,s-name,&data))
992     return -1;
993   *line = s;
994   return data.idx;
995 }
996 
997 
998 /* Handles assembly directives; returns non-zero if the line
999    was a directive. */
handle_directive(char * line)1000 static int handle_directive(char *line)
1001 {
1002   int idx = check_directive(&line);
1003 
1004   if (idx >= 0) {
1005     directives[idx].func(skip(line));
1006     return 1;
1007   }
1008   return 0;
1009 }
1010 
1011 
oplen(char * e,char * s)1012 static int oplen(char *e,char *s)
1013 {
1014   while(s!=e&&isspace((unsigned char)e[-1]))
1015     e--;
1016   return e-s;
1017 }
1018 
1019 
1020 /* When a structure with this name exists, insert its atoms and either
1021    initialize with new values or accept its default values. */
execute_struct(char * name,int name_len,char * s)1022 static int execute_struct(char *name,int name_len,char *s)
1023 {
1024   section *str;
1025   atom *p;
1026 
1027   str = find_structure(name,name_len);
1028   if (str == NULL)
1029     return 0;
1030 
1031   for (p=str->first; p; p=p->next) {
1032     atom *new;
1033     char *opp;
1034     int opl;
1035 
1036     if (p->type==DATA || p->type==SPACE || p->type==DATADEF) {
1037       opp = s = skip(s);
1038       s = skip_oper(0,s);
1039       opl = oplen(s,opp);
1040 
1041       if (opl > 0) {
1042         /* initialize this atom with a new expression */
1043 
1044         if (p->type == DATADEF) {
1045           /* parse a new data operand of the declared bitsize */
1046           operand *op;
1047 
1048           op = new_operand();
1049           if (parse_operand(opp,opl,op,
1050                             DATA_OPERAND(p->content.defb->bitsize))) {
1051             new = new_datadef_atom(p->content.defb->bitsize,op);
1052             new->align = p->align;
1053             add_atom(0,new);
1054           }
1055           else
1056             syntax_error(8);  /* invalid data operand */
1057         }
1058         else if (p->type == SPACE) {
1059           /* parse the fill expression for this space */
1060           new = clone_atom(p);
1061           new->content.sb = new_sblock(p->content.sb->space_exp,
1062                                        p->content.sb->size,
1063                                        parse_expr_tmplab(&opp));
1064           new->content.sb->space = p->content.sb->space;
1065           add_atom(0,new);
1066         }
1067         else {
1068           /* parse constant data - probably a string, or a single constant */
1069           dblock *db;
1070 
1071           db = new_dblock();
1072           db->size = p->content.db->size;
1073           db->data = db->size ? mycalloc(db->size) : NULL;
1074           if (db->data) {
1075             if (*opp=='\"' || *opp=='\'') {
1076               dblock *strdb;
1077 
1078               strdb = parse_string(&opp,*opp,8);
1079               if (strdb->size) {
1080                 if (strdb->size > db->size)
1081                   syntax_error(24,strdb->size-db->size);  /* cut last chars */
1082                 memcpy(db->data,strdb->data,
1083                        strdb->size > db->size ? db->size : strdb->size);
1084                 myfree(strdb->data);
1085               }
1086               myfree(strdb);
1087             }
1088             else {
1089               taddr val = parse_constexpr(&opp);
1090               void *p;
1091 
1092               if (db->size > sizeof(taddr) && BIGENDIAN)
1093                 p = db->data + db->size - sizeof(taddr);
1094               else
1095                 p = db->data;
1096               setval(BIGENDIAN,p,sizeof(taddr),val);
1097             }
1098           }
1099           add_atom(0,new_data_atom(db,p->align));
1100         }
1101       }
1102       else {
1103         /* empty: use default values from original atom */
1104         add_atom(0,clone_atom(p));
1105       }
1106 
1107       s = skip(s);
1108       if (*s == ',')
1109         s++;
1110     }
1111     else if (p->type == INSTRUCTION)
1112       syntax_error(23);  /* skipping instruction in struct init */
1113 
1114     /* other atoms are silently ignored */
1115   }
1116 
1117   eol(s);
1118   return 1;
1119 }
1120 
1121 
parse_label_or_pc(char ** start)1122 static char *parse_label_or_pc(char **start)
1123 {
1124   char *s,*name;
1125 
1126   name = parse_labeldef(start,0);
1127   s = skip(*start);
1128   if (name==NULL && *s==current_pc_char && !ISIDCHAR(*(s+1))) {
1129     name = cnvstr(s,1);
1130     s = skip(s+1);
1131   }
1132   if (name)
1133     *start = s;
1134   return name;
1135 }
1136 
1137 
1138 #ifdef STATEMENT_DELIMITER
read_next_statement(void)1139 static char *read_next_statement(void)
1140 {
1141   static char *s = NULL;
1142   char *line,c;
1143 
1144   if (s == NULL) {
1145     char *lab;
1146 
1147     s = line = read_next_line();
1148     if (s == NULL)
1149       return NULL;  /* no more lines in source */
1150 
1151     /* skip label field and possible statement delimiters therein */
1152     if (lab = parse_label_or_pc(&s))
1153       myfree(lab);
1154   }
1155   else {
1156     /* make the new statement start with a blank - there is no label field */
1157     *s = ' ';
1158     line = s++;
1159   }
1160 
1161   /* find next statement delimiter in line buffer */
1162   for (;;) {
1163 #ifdef VASM_CPU_Z80
1164     unsigned char lastuc;
1165 #endif
1166 
1167     c = *s;
1168 #ifdef VASM_CPU_Z80
1169     /* For the Z80 ignore ' behind a letter, as it may be a register */
1170     lastuc = toupper((unsigned char)*(s-1));
1171     if ((c=='\'' && (lastuc<'A' || lastuc>'Z')) || c=='\"') {
1172 #else
1173     if (c=='\'' || c=='\"') {
1174 #endif
1175       s = skip_string(s,c,NULL);
1176     }
1177     else if (c == STATEMENT_DELIMITER) {
1178       *s = '\0';  /* terminate the statement here temporarily */
1179       break;
1180     }
1181     else if (c=='\0' || c==commentchar) {
1182       s = NULL;  /* ignore delimiters in rest of line */
1183       break;
1184     }
1185     else
1186       s++;
1187   }
1188   return line;
1189 }
1190 #endif
1191 
1192 
1193 void parse(void)
1194 {
1195   char *s,*line,*inst,*labname;
1196   char *ext[MAX_QUALIFIERS?MAX_QUALIFIERS:1];
1197   char *op[MAX_OPERANDS];
1198   int ext_len[MAX_QUALIFIERS?MAX_QUALIFIERS:1];
1199   int op_len[MAX_OPERANDS];
1200   int ext_cnt,op_cnt,inst_len;
1201   instruction *ip;
1202 
1203 #ifdef STATEMENT_DELIMITER
1204   while (line = read_next_statement()) {
1205 #else
1206   while (line = read_next_line()) {
1207 #endif
1208     if (parse_end)
1209       continue;
1210 
1211     if (!cond_state()) {
1212       /* skip source until ELSE or ENDIF */
1213       int idx;
1214 
1215       s = line;
1216       if (labname = parse_label_or_pc(&s))
1217         myfree(labname);
1218       idx = check_directive(&s);
1219       if (idx >= 0) {
1220         if (!strncmp(directives[idx].name,"if",2))
1221           cond_skipif();
1222         else if (directives[idx].func == handle_else)
1223           cond_else();
1224         else if (directives[idx].func == handle_endif)
1225           cond_endif();
1226       }
1227       continue;
1228     }
1229 
1230     s = line;
1231     if (labname = parse_label_or_pc(&s)) {
1232       /* we have found a global or local label, or current-pc character */
1233       symbol *label,*labsym;
1234       int equlen = 0;
1235 
1236       if (!strnicmp(s,equname+!dotdirs,3+dotdirs) &&
1237           isspace((unsigned char)*(s+3+dotdirs)))
1238         equlen = 3+dotdirs;
1239       else if (!strnicmp(s,eqname+!dotdirs,2+dotdirs) &&
1240                isspace((unsigned char)*(s+2+dotdirs)))
1241         equlen = 2+dotdirs;
1242       else if (*s == '=')
1243         equlen = 1;
1244 
1245       if (equlen) {
1246         /* found a kind of equate directive */
1247         if (*labname == current_pc_char) {
1248           handle_org(skip(s+equlen));
1249           continue;
1250         }
1251         else {
1252           s = skip(s+equlen);
1253           label = new_equate(labname,parse_expr_tmplab(&s));
1254         }
1255       }
1256       else if (!strnicmp(s,setname+!dotdirs,3+dotdirs) &&
1257                isspace((unsigned char)*(s+3+dotdirs))) {
1258         /* SET allows redefinitions */
1259         if (*labname == current_pc_char) {
1260           syntax_error(10);  /* identifier expected */
1261         }
1262         else {
1263           s = skip(s+3+dotdirs);
1264           label = new_abs(labname,parse_expr_tmplab(&s));
1265         }
1266       }
1267       else if (!strnicmp(s,macname+!dotdirs,3+dotdirs) &&
1268                (isspace((unsigned char)*(s+3+dotdirs)) ||
1269                 *(s+3+dotdirs)=='\0') ||
1270                !strnicmp(s,macroname+!dotdirs,5+dotdirs) &&
1271                (isspace((unsigned char)*(s+5+dotdirs)) ||
1272                 *(s+5+dotdirs)=='\0')) {
1273         char *params = skip(s + (*(s+3+dotdirs)=='r'?5+dotdirs:3+dotdirs));
1274 
1275         s = line;
1276         myfree(labname);
1277         if (!(labname = parse_identifier(&s)))
1278           ierror(0);
1279         new_macro(labname,dotdirs?dendm_dirlist:endm_dirlist,params);
1280         myfree(labname);
1281         continue;
1282       }
1283       else {
1284         /* it's just a label */
1285         label = new_labsym(0,labname);
1286         add_atom(0,new_label_atom(label));
1287       }
1288 
1289       if (!is_local_label(labname) && autoexport)
1290           label->flags |= EXPORT;
1291       myfree(labname);
1292     }
1293 
1294     /* check for directives first */
1295     s = skip(s);
1296     if (*s==commentchar)
1297       continue;
1298 
1299     s = parse_cpu_special(s);
1300     if (ISEOL(s))
1301       continue;
1302 
1303     if (*s==current_pc_char && *(s+1)=='=') {   /* "*=" org directive */
1304       handle_org(skip(s+2));
1305       continue;
1306     }
1307     if (handle_directive(s))
1308       continue;
1309 
1310     s = skip(s);
1311     if (ISEOL(s))
1312       continue;
1313 
1314     /* read mnemonic name */
1315     inst = s;
1316     ext_cnt = 0;
1317     if (!ISIDSTART(*s)) {
1318       syntax_error(10);  /* identifier expected */
1319       continue;
1320     }
1321 #if MAX_QUALIFIERS==0
1322     while (*s && !isspace((unsigned char)*s))
1323       s++;
1324     inst_len = s - inst;
1325 #else
1326     s = parse_instruction(s,&inst_len,ext,ext_len,&ext_cnt);
1327 #endif
1328     if (!isspace((unsigned char)*s) && *s!='\0')
1329       syntax_error(2);  /* no space before operands */
1330     s = skip(s);
1331 
1332     if (execute_macro(inst,inst_len,ext,ext_len,ext_cnt,s))
1333       continue;
1334     if (execute_struct(inst,inst_len,s))
1335       continue;
1336 
1337     /* read operands, terminated by comma or blank (unless in parentheses) */
1338     op_cnt = 0;
1339     while (!ISEOL(s) && op_cnt<MAX_OPERANDS) {
1340       op[op_cnt] = s;
1341       s = skip_oper(1,s);
1342       op_len[op_cnt] = oplen(s,op[op_cnt]);
1343 #if !ALLOW_EMPTY_OPS
1344       if (op_len[op_cnt] <= 0)
1345         syntax_error(5);  /* missing operand */
1346       else
1347 #endif
1348         op_cnt++;
1349 
1350       if (igntrail) {
1351         if (*s != ',')
1352           break;
1353         s++;
1354       }
1355       else {
1356         s = skip(s);
1357         if (OPERSEP_COMMA) {
1358           if (*s == ',')
1359             s = skip(s+1);
1360           else if (!(OPERSEP_BLANK))
1361             break;
1362         }
1363       }
1364     }
1365     eol(s);
1366 
1367     ip = new_inst(inst,inst_len,op_cnt,op,op_len);
1368 
1369 #if MAX_QUALIFIERS>0
1370     if (ip) {
1371       int i;
1372 
1373       for (i=0; i<ext_cnt; i++)
1374         ip->qualifiers[i] = cnvstr(ext[i],ext_len[i]);
1375       for(; i<MAX_QUALIFIERS; i++)
1376         ip->qualifiers[i] = NULL;
1377     }
1378 #endif
1379 
1380     if (ip)
1381       add_atom(0,new_inst_atom(ip));
1382   }
1383 
1384   cond_check();
1385 }
1386 
1387 
1388 /* parse next macro argument */
1389 char *parse_macro_arg(struct macro *m,char *s,
1390                       struct namelen *param,struct namelen *arg)
1391 {
1392   arg->len = 0;  /* cannot select specific named arguments */
1393   param->name = s;
1394 
1395   if (*s=='\"' || *s=='\'') {
1396     s = skip_string(s,*s,NULL);
1397     param->len = s - param->name;
1398   }
1399   else {
1400     s = skip_operand(s);
1401     param->len = s - param->name;
1402   }
1403 
1404   return s;
1405 }
1406 
1407 
1408 /* expands arguments and special escape codes into macro context */
1409 int expand_macro(source *src,char **line,char *d,int dlen)
1410 {
1411   int nc = 0;
1412   int n;
1413   char *s = *line;
1414   char *end;
1415 
1416   if (*s++ == '\\') {
1417     /* possible macro expansion detected */
1418 
1419     if (*s == '\\') {
1420       if (dlen >= 1) {
1421         *d++ = *s++;
1422         if (esc_sequences) {
1423           if (dlen >= 2) {
1424             *d++ = '\\';  /* make it a double \ again */
1425             nc = 2;
1426           }
1427           else
1428             nc = -1;
1429         }
1430         else
1431           nc = 1;
1432       }
1433       else
1434         nc = -1;
1435     }
1436 
1437     else if (*s == '@') {
1438       /* \@: insert a unique id */
1439       nc = snprintf(d,dlen,"_%06lu",src->id);
1440       s++;
1441       if (nc >= dlen)
1442         nc = -1;
1443     }
1444     else if (*s=='(' && *(s+1)==')') {
1445       /* \() is just skipped, useful to terminate named macro parameters */
1446       nc = 0;
1447       s += 2;
1448     }
1449     else if (*s == '<') {
1450       /* \<symbol> : insert absolute unsigned symbol value */
1451       char *name;
1452       symbol *sym;
1453       taddr val;
1454 
1455       s++;
1456       if (name = parse_symbol(&s)) {
1457         if ((sym = find_symbol(name)) && sym->type==EXPRESSION) {
1458           if (eval_expr(sym->expr,&val,NULL,0))
1459             nc = sprintf(d,"%lu",(unsigned long)(uint32_t)val);
1460         }
1461         myfree(name);
1462         if (*s++!='>' || nc<0) {
1463           syntax_error(11);  /* invalid numeric expansion */
1464           return 0;
1465         }
1466       }
1467       else {
1468         syntax_error(10);  /* identifier expected */
1469         return 0;
1470       }
1471     }
1472     else if (isdigit((unsigned char)*s)) {
1473       /* \1..\9,\0 : insert macro parameter 1..9,10 */
1474       nc = copy_macro_param(src,*s=='0'?0:*s-'1',d,dlen);
1475       s++;
1476     }
1477     else if ((end = skip_identifier(s)) != NULL) {
1478       if ((n = find_macarg_name(src,s,end-s)) >= 0) {
1479         /* \argname: insert named macro parameter n */
1480         nc = copy_macro_param(src,n,d,dlen);
1481         s = end;
1482       }
1483     }
1484 
1485     if (nc >= 0)
1486       *line = s;  /* update line pointer when expansion took place */
1487   }
1488 
1489   return nc;  /* number of chars written to line buffer, -1: out of space */
1490 }
1491 
1492 
1493 static int intel_suffix(char *s)
1494 /* check for constants with h, d, o, q or b suffix */
1495 {
1496   int base,lastbase;
1497   char c;
1498 
1499   base = 2;
1500   while (isxdigit((unsigned char)*s)) {
1501     lastbase = base;
1502     switch (base) {
1503       case 2:
1504         if (*s <= '1') break;
1505         base = 8;
1506       case 8:
1507         if (*s <= '7') break;
1508         base = 10;
1509       case 10:
1510         if (*s <= '9') break;
1511         base = 16;
1512     }
1513     s++;
1514   }
1515 
1516   c = tolower((unsigned char)*s);
1517   if (c == 'h')
1518     return 16;
1519   if ((c=='o' || c=='q') && base<=8)
1520     return 8;
1521 
1522   c = tolower((unsigned char)*(s-1));
1523   if (c=='d' && lastbase<=10)
1524     return 10;
1525   if (c=='b' && lastbase<=2)
1526     return 2;
1527 
1528   return 0;
1529 }
1530 
1531 
1532 char *const_prefix(char *s,int *base)
1533 {
1534   if (isdigit((unsigned char)*s)) {
1535     if (!nointelsuffix && (*base = intel_suffix(s)))
1536       return s;
1537     if (!nocprefix) {
1538       if (*s == '0') {
1539         if (s[1]=='x' || s[1]=='X'){
1540           *base = 16;
1541           return s+2;
1542         }
1543         if (s[1]=='b' || s[1]=='B'){
1544           *base = 2;
1545           return s+2;
1546         }
1547         *base = 8;
1548         return s;
1549       }
1550       else if (s[1]=='#' && *s>='2' && *s<='9') {
1551         *base = *s & 0xf;
1552         return s+2;
1553       }
1554     }
1555     *base = 10;
1556     return s;
1557   }
1558 
1559   if (*s=='$' && isxdigit((unsigned char)s[1])) {
1560     *base = 16;
1561     return s+1;
1562   }
1563 #if defined(VASM_CPU_Z80)
1564   if ((*s=='&' || *s=='#') && isxdigit((unsigned char)s[1])) {
1565     *base = 16;
1566     return s+1;
1567   }
1568 #endif
1569   if (*s=='@') {
1570 #if defined(VASM_CPU_Z80)
1571     *base = 2;
1572 #else
1573     *base = 8;
1574 #endif
1575     return s+1;
1576   }
1577   if (*s == '%') {
1578     *base = 2;
1579     return s+1;
1580   }
1581   *base = 0;
1582   return s;
1583 }
1584 
1585 
1586 char *const_suffix(char *start,char *end)
1587 {
1588   if (intel_suffix(start))
1589     return end+1;
1590 
1591   return end;
1592 }
1593 
1594 
1595 static char *skip_local(char *p)
1596 {
1597   char *s;
1598 
1599   if (ISIDSTART(*p) || isdigit((unsigned char)*p)) {  /* may start with digit */
1600     s = p++;
1601     while (ISIDCHAR(*p))
1602       p++;
1603   }
1604   else
1605     p = NULL;
1606 
1607   return p;
1608 }
1609 
1610 
1611 char *get_local_label(char **start)
1612 /* Local labels start with a '.' or end with '$': "1234$", ".1" */
1613 {
1614   char *s,*p,*name;
1615 
1616   name = NULL;
1617   s = *start;
1618   p = skip_local(s);
1619 
1620   if (p!=NULL && *p=='.' && ISIDCHAR(*(p+1)) &&
1621       ISIDSTART(*s) && *s!='.' && *(p-1)!='$') {
1622     /* skip local part of global.local label */
1623     s = p + 1;
1624     p = skip_local(p);
1625     name = make_local_label(*start,(s-1)-*start,s,p-s);
1626     *start = skip(p);
1627   }
1628   else if (p!=NULL && p>(s+1) && *s=='.') {  /* .label */
1629     s++;
1630     name = make_local_label(NULL,0,s,p-s);
1631     *start = skip(p);
1632   }
1633   else if (p!=NULL && p>s && *p=='$') { /* label$ */
1634     p++;
1635     name = make_local_label(NULL,0,s,p-s);
1636     *start = skip(p);
1637   }
1638 
1639   return name;
1640 }
1641 
1642 
1643 int init_syntax()
1644 {
1645   size_t i;
1646   hashdata data;
1647 
1648   dirhash = new_hashtable(0x200); /* @@@ */
1649   for (i=0; i<dir_cnt; i++) {
1650     data.idx = i;
1651     add_hashentry(dirhash,directives[i].name,data);
1652   }
1653 
1654   cond_init();
1655   set_internal_abs(REPTNSYM,-1); /* reserve the REPTN symbol */
1656   current_pc_char = '*';
1657 
1658   if (orgmode != ~0)
1659     set_section(new_org(orgmode));
1660   return 1;
1661 }
1662 
1663 
1664 int syntax_args(char *p)
1665 {
1666   if (!strcmp(p,"-dotdir")) {
1667     dotdirs = 1;
1668     return 1;
1669   }
1670   else if (!strcmp(p,"-autoexp")) {
1671     autoexport = 1;
1672     return 1;
1673   }
1674   else if (!strncmp(p,"-org=",5)) {
1675     orgmode = atoi(p+5);
1676     return 1;
1677   }
1678   else if (OPERSEP_COMMA && !strcmp(p,"-i")) {
1679     igntrail = 1;
1680     return 1;
1681   }
1682   else if (!strcmp(p,"-noc")) {
1683     nocprefix = 1;
1684     return 1;
1685   }
1686   else if (!strcmp(p,"-noi")) {
1687     nointelsuffix = 1;
1688     return 1;
1689   }
1690   return 0;
1691 }
1692